feat(agent-presets): own the writable preset root instead of awaiting an app

`Config.roots` defaulted to `[]`, so a deployment that did not patch both roots
in got a roster with none — `dsh run` once booted exactly that and failed
resolving `standard`. The user root never needed an app: `<dshHome>/.agent-presets`
is the same place in every deployment, resolvable here the way
`dsh-skill-local` resolves `<dshHome>/skills`.

The roster now derives that root itself unless `includeUserRoot` is false, and
`apps/cli` supplies only the SHIPPED root, whose path an installed app alone
can resolve. The derived root is appended after every configured root, so a
shipped id still shadows a home directory claiming it and `writableRoot()`
still prefers an explicitly configured `user` root; the set is resolved once at
construction, because a root set that changed between a `list()` and the
`copy()` acting on its answer would author into a directory the caller never
saw.

Every test that pins an exact roster now says `includeUserRoot: false` — the
machine's real harness home must not decide what a golden or an assertion
counts.
This commit is contained in:
Yichen Jiang
2026-08-11 20:20:16 +08:00
parent ac266ed2de
commit 5c7dd6f8eb
21 changed files with 253 additions and 38 deletions

View File

@@ -93,7 +93,11 @@ async function bootWeb(settingsFile: string, extra: PatchOptions[] = []): Promis
// document overrides.
{
id: 'agent-presets',
config: { default: 'standard', roots: [{ path: join(CONFIG_DIR, 'agent-presets'), trust: 'system' }] },
config: {
default: 'standard',
roots: [{ path: join(CONFIG_DIR, 'agent-presets'), trust: 'system' }],
includeUserRoot: false,
},
},
...extra,
]
@@ -447,6 +451,7 @@ describe('product subagent rows in user presets', () => {
{ path: join(CONFIG_DIR, 'agent-presets'), trust: 'system' },
{ path: userRoot, trust: 'user' },
],
includeUserRoot: false,
},
}])
}, 120_000)
@@ -647,6 +652,7 @@ describe('authoring a preset on the shipped composition', () => {
// nothing is the normal first-run state.
{ path: userRoot, trust: 'user' },
],
includeUserRoot: false,
},
}])
})