Back to home@Robin1987China

dsh-plugin-preset-default-guard

Repairs a stale agent-presets.default so New Session stops failing silently after a preset rename (DeepSeek Harness plugin).

Stars
0
Language
JavaScript
Created
Sep 10, 2026
Updated
Sep 10, 2026

Introduction

dsh-plugin-preset-default-guard

English | 中文

A DeepSeek Harness plugin that repairs a stale default agent preset, so New Session stops failing silently after a preset rename.

Maintained by @Robin1987China · Repository

Symptoms this plugin fixes

If a search brought you here, check whether your symptom is in this list.

English: new session does nothing · clicking New Session has no effect · the New Session button is dead · cannot create a session after upgrading · nothing happens when starting a session · agent-preset/not-found · preset "code" not found · session create failed

中文(同样命中): 点「新会话」没反应 · 新建会话没有任何反应 · 升级后无法新建会话 · 新建对话失败 · 「新会话」按钮点了没用 · 无法创建新会话 · 预设找不到 · 会话创建失败

The manual fix is one line. In ~/.dsh/settings.yaml, change agent-presets.default from code to ptc — the roster this release ships is standard, ptc, minimal, cordis. This plugin applies that repair at startup, and keeps applying it after every future preset rename.

The problem

You upgrade DeepSeek Harness, click New Session in the sidebar, and nothing happens. No error, no toast, no new session.

The cause is a settings value that survived the upgrade:

# ~/.dsh/settings.yaml
agent-presets:
  default: code      # this preset id no longer exists

Preset ids are not stable across releases. When a shipped preset is renamed — code became ptc in 0.1.5-rc.1 — every settings file still naming the old id keeps pointing at it. Creating a session resolves that id, finds nothing, and fails:

agent-preset/not-found: agent-presets: preset "code" not found
(available: standard, ptc, minimal, cordis)

Existing sessions keep working, because a session records the preset it was composed from when it is created. Only new sessions resolve the setting, which is why the symptom looks like "the button is dead".

The client folds that failure into a console.warn, so the UI shows nothing at all.

What this plugin does

At process start it compares the resolved agent-presets.default against the presets this deployment actually ships, and repairs the mismatch:

  1. The default resolves to a preset that exists — nothing to do.
  2. Otherwise clear the stale value, so the deployment's own default applies again.
  3. If that still leaves nothing usable, install a valid id: the configured fallback, else standard, else the first preset in the roster.

Every repair is logged with the old id, the new id, and the full roster.

Install

Install into the profile — the official path forwards to pnpm in the profile directory:

dsh plugin --profile web add dsh-plugin-preset-default-guard

Without pnpm installed, install it directly instead:

cd ~/.dsh/profiles/web
npm install dsh-plugin-preset-default-guard

Mount it in the profile's patch layer — ~/.dsh/profiles/web/cordis.patch.yml:

- insert:
    - id: preset-default-guard
      name: 'dsh-plugin-preset-default-guard'
      config:
        fix: true

Then restart dsh web. No other file is touched.

Verify it works

Write a bogus default, restart, and compare the file before and after:

# ~/.dsh/settings.yaml  (before)
agent-presets:
  default: does-not-exist
# ~/.dsh/settings.yaml  (after)
agent-presets: {}

The stale id is gone, so the deployment's own default applies again and New Session works.

The plugin reports every repair through the host logger. Whether that line reaches your terminal depends on the logging the deployment composes, so treat the settings file as the source of truth.

Config

fieldtypedefaultmeaning
fixbooleantrueRepair a stale default. false reports the mismatch and leaves the document untouched.
fallbackstring''Preset id to install when clearing the stale value leaves no usable default. Absent prefers standard, then the first id in the roster.

Scope and limits

  • It repairs the setting, not the client. It removes the cause of the failure; it does not add UI feedback to the New Session button.
  • It runs once per process, at startup — the point where a rename introduced by an upgrade first becomes visible.
  • It never touches session logs. A session that was created while a since-renamed preset was current keeps that id in its own log header, so reopening such a session fails independently of this setting — see discussions #5657 and #5873. Repairing those sessions means rewriting their logs; this plugin deliberately does not do that, because editing session logs is not a settings concern.
  • Read-only deployments should run it with fix: false; it then reports the mismatch instead of writing.
  • It only ever writes one key: agent-presets.default, through the public settings.mutate path.

Compatibility

Written against @deepseek-ai/dsh@0.1.5-rc.1 and depending only on the documented settings and agentPresets services. See discussion #6119 for the upstream report.

Development

npm install
npm test                      # unit tests, no host needed
scripts/local-test.sh         # end-to-end check of the published package
scripts/local-test.sh "$PWD"  # end-to-end check of this checkout

npm test drives the plugin through its own apply() against a settings double that resolves a user layer over a base layer, so every branch of the repair is covered without a host.

scripts/local-test.sh goes further: it builds a throwaway DSH_HOME, installs the package into it, and boots the real Web profile twice — once with the plugin mounted and a stale agent-presets.default planted, once without it. The first boot must repair the value and the second must leave it untouched, so a passing run proves the repair comes from this plugin and not from the host. Your own DSH_HOME is never touched. Set DSH_BIN if dsh is not on your PATH.

Publishing (maintainers)

npm requires every publish to carry a credential that can bypass 2FA. A login token from npm login is not enough — it fails with:

403 Two-factor authentication or granular access token with bypass 2fa enabled is required to publish packages.

That happens even on an account whose profile reports 2FA as disabled, so the error is easy to misread as a permissions problem.

Create a granular access token with the bypass flag, use it for one publish, then revoke it:

  1. Open https://www.npmjs.com/settings/<account>/tokensGenerate New TokenGranular Access Token.
  2. Expiration: 30 days. Allowed IP ranges: leave empty — the field rejects IPv6 CIDR, and a dynamic address would silently break the token later.
  3. Packages and scopes → Packages: All packages (a package that is not published yet cannot be selected) · Permissions: Read and write (publish and stage)not stage only, which cannot publish.
  4. Organizations → Permissions: No access.
  5. Check Bypass two-factor authentication (2FA).
  6. Publish, then revoke the token.
npm publish --//registry.npmjs.org/:_authToken=npm_your_token

Passing the token on the command line avoids npm config set //registry.npmjs.org/:_authToken, which overwrites the login token in ~/.npmrc.

Links

License

MIT