Back to home@leonardoxr

dsh-companion

Read-only workspace and session JSON API plugin for DeepSeek Harness native clients.

Stars
0
Language
TypeScript
Created
Aug 22, 2026
Updated
Aug 22, 2026
GitHub repo

Introduction

dsh-companion

CI License: MIT

A small DeepSeek Harness plugin that gives native clients a read-only JSON view of DSH workspaces and live sessions, a configurable notification event feed, and a Web settings card.

It is designed for client shells such as dsh-native that need project and session metadata without loading or scraping the Harness web UI.

[!IMPORTANT] This project is not the unscoped dsh-companion package on npm. That name belongs to an unrelated project. Install this plugin from this repository or one of its GitHub Release archives.

What it provides

  • Three small, cache-free JSON endpoints for workspaces and live sessions.
  • A reconnectable server-sent-event feed for native completion, failure, question, and approval alerts.
  • A Settings → Plugins → DSH Companion notifications card that filters alert kinds and subagent events at the source.
  • An optional Images tab for the dsh-better-sidebar workbench: every image in the conversation — attachments, assistant images, and images the model reads — as a clickable gallery.
  • Explicit field projection: internal Harness objects are never serialized wholesale.
  • DSH trusted-host and same-origin checks on every request.
  • An installable DSH bundle with compiled JavaScript and a small settings-schema dependency.
  • Clean unloading: all registered routes are removed with the plugin.

Install

From a GitHub Release (recommended)

Download dsh-companion-<version>.tgz from the latest release, then add it to the Web profile:

dsh plugin --profile web add ./dsh-companion-<version>.tgz
dsh web

Each release also includes SHA256SUMS.txt so the archive can be verified before installation.

Directly from GitHub

For the newest revision on main:

dsh plugin --profile web add github:leonardoxr/dsh-companion
dsh web

A local checkout can be linked in place while developing:

dsh plugin --profile web add /absolute/path/to/dsh-companion
dsh web

Verify the plugin after DSH starts:

curl http://127.0.0.1:3080/api/companion/workspaces

API

RouteResponse
GET /api/companion/workspaces{ workspaces: [...] } — durable workspaces and their member session IDs
GET /api/companion/sessions{ sessions: [...] } — live sessions and their latest folded titles
GET /api/companion/session/<id>One live-session summary, or a JSON 404
GET /api/companion/notificationstext/event-stream feed of configured native alerts

Example session-list response:

{
  "sessions": [
    {
      "id": "session-1",
      "title": "Implement native navigation",
      "cwd": "/work/dsh-native",
      "createdAt": 1787356800000
    }
  ]
}

JSON responses use Content-Type: application/json and all routes use Cache-Control: no-store. The notification route uses SSE, emits 15-second heartbeats, accepts a prior cursor in Last-Event-ID or ?since=, and keeps a bounded in-memory replay window. A fresh connection starts at the live tail but receives interactions that are still waiting for a question answer or approval. Non-GET requests return 405.

Notification settings

Open Settings → Plugins → DSH Companion notifications in the Harness Web UI to configure:

SettingDefaultAlert
completedonSuccessful turn/end events
blockedonBlocked turns
errorsonFailed turns and live agent errors
maxTokensonTurns that reach the output-token limit
abortedoffCancelled or aborted turns
questionsonPending ask_user_question interactions
approvalsonPending tool approvals
subagentsoffInclude events from sessions marked as subagents

Changes are persisted through the Harness settings service and apply immediately to subsequent events without restarting the companion feed. Reset defaults clears the user overrides and restores the values above.

Each notification payload is versioned and contains only a stable key, kind, session ID/title, short body, and timestamp. Raw messages, tool arguments, commands, icons, and click-through URLs are never forwarded.

Images tab (optional)

When dsh-better-sidebar is installed, the client plugin registers an Images tab in its + menu. It scans the current session's folded timeline for durable image references — user attachments, assistant image blocks, and image blocks inside tool results (for example a read_image tool output) — resolves them through the Harness session attachment route, and renders them as a thumbnail gallery with a full-size lightbox.

The integration is a soft dependency:

  • Without better-sidebar, nothing changes — no tab, no styles, no host routes.
  • The client never imports better-sidebar code; it restates the small registration contract locally, so either plugin can load, unload, or hot-reload independently.
  • Images are fetched lazily while the tab is visible and cached as object URLs for the lifetime of the view.

Security model

The endpoints expose workspace paths, session IDs, titles, timestamps, session lineage, and—when enabled—short question, approval, and error text. They enforce the Harness web runtime's trustedHosts policy and reject cross-site browser requests, but this is a network trust boundary, not user authentication.

Do not expose the DSH server to networks whose clients should not read that metadata. See SECURITY.md for private vulnerability reporting.

How it works

The package is a Cordis host module with name, Config, inject, and apply exports plus a small Web client plugin. The host declares webServer, webRuntime, apiProxy, settings, sessions, sessionTitle, and workspaceRegistry as required services, registers a durable notification-settings namespace, then consumes the existing event streams when the bundle loads.

The host entry point is emitted to dist/index.js; the settings card is bundled to client/client.js and injected into the standard plugin-settings slot. Unloading or reconfiguring the host plugin aborts event subscriptions, closes SSE clients, and removes every route.

Compatibility

DeepSeek Harness is currently in developer preview, so its plugin service contracts may change. This version targets the service contracts in the DSH 0.1.1 release-candidate line and requires Node.js 22 or newer. CI covers Node.js 22 and 24.

Development

npm ci
npm test
npm pack --dry-run

npm test rebuilds dist/ before running tests against the compiled entry point. The committed dist/ directory is intentional: GitHub dependencies are installed under node_modules, where Node does not strip TypeScript syntax at runtime.

If a source change alters generated output, include the updated dist/ files in the same pull request.

Contributing and releases

Contributions are welcome. Read CONTRIBUTING.md for the local workflow and pull-request expectations, and follow the Code of Conduct.

Successful CI runs publish a short-lived, installable package artifact. Version tags such as v0.1.1 publish the same compiled .tgz plus its checksum as a permanent GitHub Release. Maintainers can follow docs/RELEASING.md.

License

MIT