fix(agent-presets,web): broken presets are roster rows, not gaps

A hand-damaged preset was silent until the worst moment. An unparsable
composition listed as an ordinary selectable row and failed only at the
next session start — set as default, every new session failed. A
directory whose composition file was deleted vanished from the roster
while still occupying its id: copy answered "delete the existing preset
first" while remove answered "not found", a dead end.

Discovery now owns health: every id-shaped directory is a roster slot,
broken when its composition is missing or unloadable, checked with the
loader's own entryListSchema dialect (!!js included) so health never
rejects what the loader accepts. `broken` rides AgentPreset, the
agentPreset.list entry, and the UI row; mount/recompose/standingKeyFor
refuse broken up front with the discovery-reported reason, while
resolve/read/remove still answer. The section renders marked red cards —
unselectable, uncopyable, deletable, location kept on custom rows — and
both pickers drop broken rows entirely.

The cordis preset's persona now forbids editing the shipped install
(corrupting cordis would disable the mode itself) and points authoring
at $DSH_HOME/.agent-presets; its skill teaches preset.yml metadata, the
copy-first workflow, the one-escalation sandbox reality, and honest
verification. Exercised live: asked to edit the shipped composition the
composed agent refuses citing both rules; asked for real presets (simple
and complex) it lands them under the user root with one approved
escalation each and self-checks with the loader dialect.
This commit is contained in:
Yichen Jiang
2026-08-09 02:17:56 +08:00
parent bf31797e95
commit c56f23ae1f
36 changed files with 720 additions and 87 deletions
@@ -42,6 +42,8 @@ chip 以部署默认值打开,其选择是**暂存**的——该界面先于
删除会移除整个 preset 目录。已据其组装的会话继续运行——组装在会话创建时挂载一次,此后没有任何东西会重新读取该文件。
名单行携带 `broken`(宿主的形状检查发现组装缺失或不可加载)时渲染为标记卡片:红色边框、「已损坏」徽记、原样展示的原因、卡片主体禁用——它不能成为默认——复制也禁用,因为损坏 preset 的副本只是又一个损坏的 preset。损坏的自定义行保留位置与删除动作:文件正是修复它的地方,而删除正是清掉幽灵目录(组装文件被手动删除、目录仍占着 id)的方式;损坏的内置行连查看器也不提供——没有可读的组装可展示。两个选择器(通用设置行与新会话 chip)则完全不列出损坏的 preset:它们选的是下一个会话的组装,列出无法组装的选项只会把失败推迟到会话启动。
设置默认值写入的是 `agent-presets` settings 命名空间,宿主需将其暴露给配置客户端([`dsh-apiproxy`](../../host/apiproxy/README.md) 维护一份显式白名单——不在其中的命名空间会让选择器动一下然后悄悄忘记)。
`agentPreset.read`、`copy`、`openDocument` 与 `remove` 被固定在环回地址(见 [`dsh-client-connection`](../connection/README.md)):组装指明了一个会话所运行的插件,因此读取它是侦察,其余几个则管理名单并驱动宿主桌面。`agentPreset.list` 不在其中——它携带 id、信任级别与两个不含路径的能力标志,而局域网客户端的选择器需要它。