Skip to content

fix(profile): restore selectedDefault when dsh-ops is disabled or uninstalled (#881) - #940

Open
Y-fyan wants to merge 1 commit into
T-Auto:mainfrom
Y-fyan:fix/881-uninstall-selected-default
Open

Y-fyan wants to merge 1 commit into
T-Auto:mainfrom
Y-fyan:fix/881-uninstall-selected-default

Conversation

@Y-fyan

@Y-fyan Y-fyan commented Nov 14, 2026

Copy link
Copy Markdown
Contributor

Closes #881

Split out from #899 per review feedback, with all profile-default-repair and register.ts review items addressed:

  • findDanglingDefault deletes only selectedDefault: ops-ptc at the direct child indentation level under config: (and a directly preceding config: that becomes childless); it never deletes a - id: agent-preset-registry row and never touches comments.
  • Trailing # comments require preceding whitespace ((?:\s+#.*)?\s*$), so scalars such as selectedDefault: ops-ptc#x are left untouched.
  • Strips a leading UTF-8 BOM (\uFEFF) before scanning and repairs every matching agent-preset-registry row in the file.
  • repairDanglingDefault reports three states (status: 'clean' | 'repaired' | 'unrecognized'), warns on 'unrecognized' shapes or when <profile.dir>/package.json.lock is present, removes the unused dryRun parameter, and is wrapped in try/catch in profileCommand so a filesystem error never turns a completed uninstall into a non-zero exit.
  • waitForHostIdle in src/presets/ops-ptc/register.ts warns and skips the settings write if <profile.dir>/package.json.lock does not clear before the deadline.

What was wrong

  • In live profiles (desktop, web, dsh-tui) where @deepseek-ai/dsh-hmr is active, disabling or removing dsh-ops runs inside hmr.runExclusive (executing in AsyncLocalStorage is true). When the dsh-ops fiber disposal called settings.update('agent-preset-registry', { selectedDefault }), ConfigEditor.edit invoked hmr.runExclusive again, which immediately rejected with Error: HMR transactions cannot be nested.
  • During PluginManager.removeBundle('dsh-ops'), <profile.dir>/package.json.lock is held across two hmr.runExclusive phases while ConfigEditor.edit acquires hmr.runExclusive before package.json.lock, causing lock contention/timeout if the restore enters hmr.runExclusive before the outer lock clears.
  • Offline removal via dsh-ops uninstall --profile <desktop|web|tui> delegates to dsh plugin remove dsh-ops while the host is not running, so runtime teardown never executes and selectedDefault: ops-ptc remains in <profile.dir>/cordis.patch.yml, causing every new session to fail with Unknown agent preset: ops-ptc.

The change

  • src/presets/ops-ptc/register.ts:
    • Exit the active HMR AsyncLocalStorage transaction (hmr.executing.exit) and wait for both hmr.operations and <profile.dir>/package.json.lock to settle before persisting default preset changes in forceDefault and restoreDefault; warn and skip the write if the lock does not clear before the deadline.
    • Track the pre-force operator default per registry instance so remounts and subsequent boots that start with ops-ptc already saved still restore the operator's prior default or the registry's official default.
  • src/profile-default-repair.ts & src/profile-install.ts:
    • Add findDanglingDefault and repairDanglingDefault to remove a leftover selectedDefault: ops-ptc line under config: on every agent-preset-registry entry in <profile.dir>/cordis.patch.yml (never deleting rows or comments), and invoke repairDanglingDefault after dsh-ops uninstall succeeds.
  • test/preset-registration.test.mjs, test/profile-temp.test.mjs & docs/CHANGELOG.md:
    • Add regression checks covering HMR transactions, two-phase removeBundle under package.json.lock, lock timeout skip, row/comment preservation, nested keys under config:, ops-ptc#x, UTF-8 BOM, multiple registry rows, held package.json.lock, and filesystem error tolerance.

Validation

  • One pull_request-triggered CI required run, URL below
  • npm run build, npm run typecheck, npm run check:size, node test/run.mjs preset-registration, and node test/run.mjs profile-temp pass
  • Reverting src/presets/ops-ptc/register.ts and src/profile-install.ts turns the new assertions in preset-registration and profile-temp red
  • docs/CHANGELOG.md ## [Unreleased] entry added (English and Chinese)
  • No dependency, package.json version, or optionalDependencies change; no model-facing schema/prompt change
$ npm run build
build: bundled 11 browser modules (92116 bytes)
build: generated PTC declarations for 18 capabilities (120684 bytes)
build: compiled src/ to lib/ and copied 60 assets

$ npm run typecheck
(exit 0)

$ npm run check:size
check-file-size: 823 code file(s) checked, all at or under 1000 lines (longest: native/crates/ops-search/src/search.rs (930))

$ node test/run.mjs preset-registration
dsh-ops preset-registration: all 28 checks passed

$ node test/run.mjs profile-temp
dsh-ops profile-temp: all 13 checks passed

Revert-red verification:

$ git checkout HEAD~1 -- src/presets/ops-ptc/register.ts src/profile-install.ts && npm run build
$ node test/run.mjs preset-registration
  FAIL live HMR transactions and profile file locks do not block or reject default restoration (#881)
dsh-ops preset-registration: 1 of 28 check(s) failed

$ node test/run.mjs profile-temp
  FAIL uninstall repairs a dangling selectedDefault: ops-ptc in cordis.patch.yml (#881)
dsh-ops profile-temp: 1 of 13 check(s) failed

Environment

Linux x64, Node v22.22.1, based on upstream main commit 88ecc72, local source checkout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] 卸载后会有配置残留导致Dsh歇逼

1 participant