Skip to content

fix(startup): auto-disable a migrated preset row a plugin registers again - #819

Merged
yaojin3616 merged 1 commit into
dataelement:mainfrom
eatmoreduck:fix/814-preset-duplicate-migration
Oct 29, 2026
Merged

yaojin3616 merged 1 commit into
dataelement:mainfrom
eatmoreduck:fix/814-preset-duplicate-migration

Conversation

@eatmoreduck

Copy link
Copy Markdown
Contributor

Motivation & Context

A plugin that registers a preset at runtime (ctx.agentPresets.register({ id: 'aitoearn', ... })) and also ships the old-form preset directory ($DSH_HOME/.agent-presets/aitoearn/) makes every desktop startup abort: migrateLegacyAgentPresets() converts the directory into an inline preset-aitoearn row in cordis.patch.yml without knowing the runtime registration exists, the registry rejects the duplicate id (error agent-preset: Error: Duplicate agent preset: aitoearn), the row is required, and startup fails. Relaunching cannot clear it — the migration's existingIds check keeps the row in place forever. Reported in #814 with a manual workaround (hand-adding disabled: true to the generated row), which this PR automates.

Description & Review Guide

  • What are the major changes? Three pieces: extractDuplicateAgentPresetId() in harness-runtime.ts reads the duplicate id from the latest stderr attempt logs (same shape as the existing extractDuplicateLoaderEntryId / extractSlotConflictName); disableMigratedLegacyPreset() in legacy-preset-migration.ts locates that one row inside the # dsh-desktop legacy presets block and inserts disabled: true at the entry's field indent (both the - id: built-in shape and the - insert: / - id: plugin shape), atomically; the plugin-recovery loop in index.ts checks this before blaming plugins, auto-disables at most once per id per session, and relaunches via launchWithFreshEvidence().
  • What is the impact of the changes? The startup loop self-heals: the disabled row neither mounts nor joins the startup audit (the registry's auditRows skips entry.disabled), while existingIds still matches the retained preset-<id> line so the migration never rewrites or duplicates it. The plugin's own runtime registration stays the single live preset — the legacy copy steps aside instead of the user's plugin being quarantined. Rows outside the migration block are never touched, already-disabled rows are left alone, and a non-matching or missing row leaves the file unchanged so the existing recovery flow takes over.
  • What do you want reviewers to focus on? The row-indent walk in disableMigratedLegacyPreset (entry fields end at the next - row at the entry indent) and the one-shot-per-id session set, which prevents a relaunch loop when the duplicate comes from something other than a migrated row.

The tests cover: id extraction from attempt logs (stderr-only, latest attempt); disabling only the named row in both shapes; idempotency (no second disabled:); and rows outside the block being ignored. Migration and recovery suites pass (32); the 39 office/ppt/docx template failures reproduce identically on a clean checkout of main and are unrelated.

Fixes #814

…gain

When an installed plugin registers a preset at runtime and the same id
also exists as a legacy directory, the migration row and the registration
collide in the registry and abort every startup, and the row regenerates
nothing only while it exists, so relaunching never clears it. Extract
'Duplicate agent preset: <id>' from the harness attempt logs, disable
that one migrated row in place (a disabled row neither mounts nor joins
the startup audit, and existingIds still sees it as migrated), then
relaunch — the plugin's own registration remains the single live preset.

Fixes dataelement#814
@yaojin3616
yaojin3616 merged commit 995b23d into dataelement:main Oct 29, 2026
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] Legacy preset migration duplicates a plugin-registered preset — startup aborts with "Duplicate agent preset"

2 participants