dsh-git-status-pill
A floating git status pill for DeepSeek Harness. It shows, live, for the session's repository:
- the branch and repository name
- +/− line changes (
git diff HEAD --shortstat) - changed-file and untracked-file counts, upstream, and ahead/behind
- a Create PR prompt: an editable title, the generated
gh pr createcommand, and a ready-to-send agent prompt
It renders into the harness shell.overlay slot — the frame-wide, click-through
floating layer — so it sits above every column without blocking the app. Drag it
by the grip handle; hide it with ✕.
Install
# from a registry
dsh plugin --profile web add dsh-git-status-pill
# or straight from a checkout / tarball
dsh plugin --profile web add /absolute/path/to/dsh-git-status-pill
dsh plugin … add forwards to pnpm inside the profile directory, so the
package lands in the profile's node_modules.
Then make sure the package is in the profile's dsh.profile.bundles list in
$DSH_HOME/profiles/web/package.json:
{
"dsh": {
"profile": {
"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-git-status-pill"]
}
}
}
That list is what applies this package's cordis.patch.yml, which inserts the
host row:
- insert:
- id: git-status-pill
name: dsh-git-status-pill
Restart the web profile. The pill appears at the bottom-right of the frame.
Publish
npm login
npm publish --access public
publishConfig/access is not set in package.json because the package is
unscoped; add "publishConfig": { "access": "public" } if you rename it under a
scope. Before publishing, set the real repository.url in package.json.
How it is wired
| Half | File | Mechanism |
|---|---|---|
| Host | lib/index.js |
ESM Cordis plugin. inject: ['webServer'], registers one exact HTTP route, reads git through the ctx.shell service. |
| Client | lib/client.js |
window.__ModuleLoader__ bundle. Injects slots, claims shell.overlay, polls the host route with fetch. |
| Composition | cordis.patch.yml |
Inserts the host row when the bundle is applied. |
Why an HTTP route instead of a typert Remote
The canonical host→client bridge in the harness is a typert Remote
namespace — the client calls ctx.remote.<namespace>.<method>(), the host
declares @Remote(...) methods, and a plugin's client half mounts its own
descriptor with await ctx.remote.$mount(contribution). That is how shipped
plugins and community plugins like dsh-cost-meter do it.
The catch is that the descriptors on both sides
(lib/typert.host.js and the client contribution) are generated by
@deepseek-ai/dsh-typert-generator from a Host FaceModel. That generator is not
part of an installed harness (0.1.5-rc.1), and hand-writing generated schema
descriptors is brittle.
Since the harness web server is a public service, this plugin uses a plain
exact-path HTTP route instead: no codegen, no build step, plain JavaScript on
both sides. The tradeoff is that it does not participate in typert's scope and
schema validation. If you later want the first-class transport, port the route
in lib/index.js to a TypertRemoteService subclass and run the generator.
Configuration
Both the route path and the poll interval are constants at the top of the
relevant file. The route must be unique across the composition — a duplicate
(kind, path) throws at registration.
| Constant | File | Default |
|---|---|---|
ROUTE |
lib/index.js, lib/client.js |
/git-status-pill/status |
POLL_MS |
lib/client.js |
4000 |
DEFAULT_POS |
lib/client.js |
bottom-right, above the composer |
Behaviour notes
- Non-repository workspaces. When the session workspace is not a checkout,
the pill scans the workspace and its parent for
.gitdirectories and offers them as chips, plus a field for an absolute path. A downward-only scan misses sibling repositories, which is why the parent is included. - Sandbox. Reads outside the session workspace can be refused by the
harness sandbox. A refusal is reported in the payload (
denied: true) rather than silently rendered as zeros. gh. The host reports whetherghis onPATH; without it the panel says so and points at the agent prompt.- Clipboard. Uses
navigator.clipboardand falls back to a selectable textarea.
Status
The widget logic is verified against real repositories. The package
packaging — module-loader wrapper, cordis.patch.yml, and the HTTP route —
has not yet been installed into a profile and booted end-to-end. Treat 0.1.0
as a first cut: install it, restart, and check the run card / browser console.
License
MIT
No comments yet. Be the first to write one.