FoyonaCZY/dsh-kit0

dsh-kit

Quality-of-life plugins for DeepSeek Harness: workspace rewind, desktop notifications, auto-format, live git context, secret redaction, and a done-means-green verify gate.

包名
dsh-kit
版本
0.1.0
许可证
MIT
最近更新
2026年9月1日

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:FoyonaCZY/dsh-kit

dsh-kit

English | 中文

Six plugins that close the gap between DeepSeek Harness and a polished desktop coding agent.

DSH's core is excellent and its plugin seams are unusually well designed — but the release ships no undo, no notifications, no formatting, no git awareness, no credential filter, and nothing that checks the agent's work before it declares victory. Those are exactly the things you stop noticing in a good desktop agent because they are always there. This is that layer.

Everything here is a plugin row on a documented extension point. Nothing patches the harness.


Install

dsh plugin --profile web add github:FoyonaCZY/dsh-kit
dsh --profile web

That is the whole installation. There is no build step — the package ships plain ESM JavaScript, so a git install needs no prepare script and no allowBuilds entry in your profile's pnpm-workspace.yaml. Its only runtime dependency is @deepseek-ai/schemastery, which the harness already uses for plugin config.

Pin a commit if you want the usual supply-chain guarantee:

dsh plugin --profile web add github:FoyonaCZY/dsh-kit#

Verify the layer landed before booting:

dsh --profile web --dump-config   # look for "# == dsh-kit"

What you get

PluginThe gap it closesExtension point
checkpointNo way to take back a file the agent rewrotetools/pre-execute + ctx.commands
notifyNo idea the run finished, or that it is blocked on youagent/status, tools/pre-execute
autoformatEdits land in the model's style, not the project'stools/post-execute
git-contextAgent is blind to branch and working-tree statectx.systemPrompt.context()
secret-guardTokens in tool output ride along in every later requesttools/pre-execute, tools/post-execute
verify"Done" can mean "done and broken"agent/turn-stopping

Each is an independent row. Disable or reconfigure any one from your profile's cordis.patch.yml without touching the rest:

- id: dsh-kit-notify
  disabled: true

checkpoint

/rewind for your workspace.

DSH already has dsh-session-checkpoint-policy, but that makes the session log crash-durable — it is not an undo stack. If the agent rewrites six files down a path that turned out to be wrong, the files are simply rewritten.

Before every write, edit, or str_replace_editor call, this records the target file's current bytes. Then:

/rewind              list checkpoints, newest first
/rewind 12           restore the workspace to the state just before checkpoint 12
/rewind last         undo the most recent file-modifying call
/rewind clear        drop this session's history

Restoring is itself checkpointed, so a rewind is undoable — /rewind last right after a rewind puts everything back. Files that did not exist before are deleted rather than left behind. Content is stored by hash outside the workspace, so repeated captures of an unchanged file cost nothing and a restore never fights the repository it is restoring.

Not covered: bash. Nothing can know which files a shell command will touch before it runs.

- id: dsh-kit-checkpoint
  config:
    stateDir: ~/.dsh-kit/checkpoints   # default
    tools: [write, edit, str_replace_editor]
    maxCheckpoints: 200                # retained per session
    maxFileBytes: 2097152              # larger files are recorded as skipped
    commandName: rewind

notify

A desktop ping when the agent finishes, or when it needs you.

Two triggers:

  • the agent returns to idle after working longer than minDurationMs, so the short exchanges you were watching stay silent;
  • the tool pipeline settles on ask, meaning the run is blocked until you answer — regardless of which policy plugin asked.

Native on all three platforms with no dependencies: osascript on macOS, notify-send on Linux, and a WinRT toast through the in-box PowerShell identity on Windows. A terminal bell goes out too, which reaches you over SSH where no desktop notifier exists.

- id: dsh-kit-notify
  config:
    onIdle: true
    onApprovalRequest: true
    minDurationMs: 15000
    bell: true
    title: DeepSeek Harness
    command: ''      # e.g. 'terminal-notifier -title {title} -message {body}'

autoformat

The project's formatter, on every file the agent writes.

Otherwise the diff you review is half real change and half whitespace.

The rule that keeps this from being annoying: a formatter only runs if the project already has it. Every rule carries detect paths, and a repository with no Prettier config and no Prettier binary gets no Prettier run — no surprise reformatting, no npx reaching for the network, no cost at all in projects that never opted in. Prettier, gofmt, rustfmt, ruff, and black are detected out of the box.

When a formatter rejects the file, that is usually the fastest possible signal that the agent just wrote a syntax error, so the output is attached to the tool result and the agent sees it on its next step.

- id: dsh-kit-autoformat
  config:
    formatters:
      - extensions: ['.ts', '.tsx']
        command: npx --no-install prettier --write {file}
        detect: ['.prettierrc', 'node_modules/.bin/prettier']
      - extensions: ['.sql']
        command: sqlfluff fix --force {file}
        detect: []          # empty detect = always run
    timeoutMs: 15000
    reportFailures: true

git-context

Branch, working tree, and recent commits, in the prompt.

DSH ships context providers for the clock, tmux, referenced files, and AGENTS.md — but not for git. So the agent starts blind to the branch it is on and whether the tree is dirty, then burns tool calls rediscovering it, or does not bother and commits onto the wrong branch.

# Git
Branch: feat/rewind → origin/feat/rewind (2 ahead, 1 behind)
Working tree: 1 staged, 3 unstaged, 2 untracked
  M  src/checkpoint.js
   M README.md
  ?? test/checkpoint.test.js
Recent commits:
  a1b2c3d Add the restore planner
  d4e5f6a Capture file bytes before a mutating call

Registered on each agent's own scoped context, so a deployment driving two workspaces gives each agent its own repository's state rather than a shared guess. The first request of a session waits for the snapshot; every later refresh runs in the background, off the request's critical path. A directory that is not a repository contributes nothing at all.

- id: dsh-kit-git-context
  config:
    order: 1000
    refreshIntervalMs: 15000
    maxFiles: 20
    recentCommits: 5

secret-guard

Keep credentials out of the transcript.

The common leak is not the agent deliberately opening .env. It is env, cat .env, git log -p, a stack trace, or a curl transcript putting a token in a tool result — where it then rides along in every subsequent request to the model provider for the rest of the session.

Two defences:

  1. Redaction. Tool results are scanned on the way back to the model and credentials are replaced with labelled markers: [redacted:github-token]. Prefixed formats (GitHub, AWS, Google, Slack, Stripe, npm, OpenAI, JWTs, private-key blocks, basic-auth URLs, Authorization headers) plus one general rule for assignments to secret-shaped names.
  2. Protected paths. Reads and writes of credential-shaped files go to the approval gate instead of running unattended.

The rules are tuned for precision, because a false positive silently hides real output and wastes a turn. API_URL, CLIENT_NAME, publicKey, sessionId, and keyboardLayout are left alone; API_KEY, clientSecret, and accessToken are not. .env.example and friends stay readable, so documentation still works. Markers contain no part of the secret, so redaction is safe to log and idempotent.

PTC mode: the registry accepts a replacement for the model-facing content or the canonical value, not both. The default redacts content, which is the path to the provider. Deployments running run_code should set redactValue: true so programs cannot read the raw value.

- id: dsh-kit-secret-guard
  config:
    redactToolOutput: true
    redactValue: false          # set true in PTC deployments
    onProtectedPath: ask        # ask | deny | allow
    guardWrites: true
    disabledRules: []           # e.g. ['openai-key']
    allowPaths: ['.env.example', '**/*.pub']

verify

Make "done" mean "still compiles".

An agent's most expensive failure is not a wrong edit — it is a wrong edit reported as finished, because the cost lands on the human who reads the summary and believes it.

agent/turn-stopping is awaited before the turn boundary commits, and a listener that objects can steer another step. So when a turn that edited files is about to end, the project's check runs. If it fails, the output goes back to the agent and it keeps working. If it passes, the turn ends as it would have.

By default it auto-detects a typecheck command — a typecheck/type-check/tsc script in package.json (with the right package manager inferred from the lockfile), else a local tsc --noEmit. Test suites are never auto-detected: they are too slow to run at every turn boundary. Configure them explicitly if you want them.

maxRounds bounds the loop. Past it the turn closes even while failing, and the last message tells the agent to report the failure honestly rather than claim success.

A check naming a binary that is not on PATH is skipped with a log line rather than reported to the agent as a failure — resolved by walking PATH directly, because a shell reports a missing command in the machine's own language.

- id: dsh-kit-verify
  config:
    checks:
      - name: typecheck
        command: pnpm typecheck
      - name: unit tests
        command: pnpm test -- --run
    autoDetect: true      # ignored when `checks` is non-empty
    maxRounds: 2
    timeoutMs: 120000
    maxOutputLines: 40

Design notes

No build step. The package is plain ESM JavaScript with JSDoc types. DSH's own docs warn that installing a TypeScript plugin from a git host requires a prepare script on the author's side and an allowBuilds grant on yours — which is permission to execute the package's code on your machine at install time. Shipping JavaScript removes that requirement entirely.

No coupling to harness internals. The only runtime import from the DSH ecosystem is @deepseek-ai/schemastery, required for config schemas. User messages are built as the documented plain object (id, role, content, source) rather than through @deepseek-ai/dsh-llm, so a core version bump in a fast-moving preview does not break the kit.

Failures stay contained. A checkpoint that cannot be written, a notifier that does not exist, a formatter that is not installed, a git call in a non-repository — each degrades to a log line. None of them can cost you the tool call you actually asked for.

Everything external is bounded. One subprocess helper enforces a timeout, an output cap, and cancellation, and kills the whole process tree on Windows where killing a shell would otherwise orphan its children.

Tests

npm install
npm test

143 tests, no network, no harness required. Pure logic (redaction rules, glob matching, porcelain parsing, restore planning) is tested directly; the plugins are driven end to end against a fake context and a real temporary filesystem — a checkpoint really restores a file, a failing check really steers the turn, a formatter really rewrites what was written.

Compatibility

Built against DeepSeek Harness at main, September 2026. DSH is in developer preview and its docs warn of compatibility-breaking changes, so pin a commit and expect to update. Every extension point used here is documented in docs/cookbook/extension-cookbook.md.

License

MIT