diff --git a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.i18n.yaml index 7addc991d2..a8c9c28d58 100644 --- a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-20-dsh-cli-personal-config.md: 514bb5b12a3e04c7deaad1e8616472eed1c920e1 -2026-07-20-dsh-cli-personal-config.zh.md: 16fada82c59c8a356e6df112234e6b7565aae1bf +2026-07-20-dsh-cli-personal-config.md: e349374a6bc7fc0137bf14836469aef8bae8d49d +2026-07-20-dsh-cli-personal-config.zh.md: 88210dc386a245002de927950dab2852e40218ea diff --git a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md index 514bb5b12a..e349374a6b 100644 --- a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md +++ b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md @@ -22,8 +22,6 @@ Two coupled pieces, aligned with the `apps/` assembly tier proposed by the `dsh The PTY smoke's launcher isolates `$DSH_HOME` to a per-test directory, exactly as it already isolates `DSH_AGENTS_HOME`, so a developer's real personal overlay cannot leak into fixtures; only the dsh CLI reads personal config, so no other test launcher needed changes. -Hot-reload interplay: the include re-applies its `patches` on every config re-read (the [config hot-reload resilience Agent Note](../bug-fix/2026-07-20-config-hot-reload-resilience.md)), so a live `cordis.yml` edit keeps the personal overlay applied. - ## Alternatives considered **A standalone `bin/dsh` wrapper owning the `dsh` name.** Rejected after reading PR #443: that PR establishes `apps/cli` as the `dsh` CLI with subcommand dispatch (`web`, `-p`) and leaves the default slot unclaimed. Two competing `dsh` entrypoints would collide in `$PATH` and in product identity; claiming the default slot inside the same package shape confines the eventual merge conflict to the small dispatch chain. diff --git a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.zh.md b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.zh.md index 16fada82c5..88210dc386 100644 --- a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.zh.md @@ -22,8 +22,6 @@ Status: implemented PTY 冒烟测试的启动器把 `$DSH_HOME` 隔离到每个测试自己的目录,与它已有的 `DSH_AGENTS_HOME` 隔离方式完全一致,开发者真实的个人 overlay 不可能泄漏进 fixture;只有 dsh CLI 读取个人配置,因此其他测试启动器无需改动。 -与热重载的交互:include 在每次配置重读时重新应用其 `patches`(见[配置热重载韧性 Agent Note](../bug-fix/2026-07-20-config-hot-reload-resilience.md)),因此运行中编辑 `cordis.yml` 后个人 overlay 仍保持生效。 - ## Alternatives considered **独立的 `bin/dsh` 包装脚本占有 `dsh` 这个名字。** 读过 PR #443 后否决:该 PR 把 `apps/cli` 确立为带子命令分发(`web`、`-p`)的 `dsh` CLI,并且默认位空缺。两个互相竞争的 `dsh` 入口会在 `$PATH` 和产品身份上冲突;在同一包形态内认领默认位,把最终的合并冲突限制在小小的分发链上。 diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.i18n.yaml b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.i18n.yaml index f3fba8a006..321131ac96 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-21-tui-reload-command.md: e5600f0ab5cd82dc556df76006fcf532d8c7d302 -2026-07-21-tui-reload-command.zh.md: 3798b0518df1c379cca808bd4af38490016567cb +2026-07-21-tui-reload-command.md: de9a5502214a610d88024730b1c0c1044a396c92 +2026-07-21-tui-reload-command.zh.md: 25d1d448459221698ca63377f8f18d05a0fa3d21 diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.md b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.md index e5600f0ab5..de9a550221 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.md +++ b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.md @@ -10,7 +10,7 @@ HMR's file watcher only reacts to in-place `change` events under its configured ## Decision -`dsh-tui` gains an **experimental, dev-only** `/reload` slash command: it walks `ctx.loader.entries()` and calls `refresh()` on every file-backed subtree (`Include`), i.e. the exact code path the HMR watcher's config-change branch drives, invoked manually and watcher-independent. Unchanged files are no-ops (content comparison in `Include.read`); invalid files warn and keep the running tree (the hot-reload-resilience contract); include `patches` — including the dsh CLI's personal overlay — re-apply on every re-read. +`dsh-tui` gains an **experimental, dev-only** `/reload` slash command: it walks `ctx.loader.entries()` and calls `refresh()` on every file-backed subtree (`Include`), i.e. the exact code path the HMR watcher's config-change branch drives, invoked manually and watcher-independent. Unchanged files are no-ops (content comparison in `Include.read`). The TUI reaches the Loader **structurally** (`ctx.loader` via a local type, not `inject`): tests and embedders run the TUI without a Loader, where `/reload` degrades to a warning notice instead of failing the mount. Module-source hot reload stays watcher-owned; `/reload` refreshes configs only. @@ -28,8 +28,8 @@ The TUI reaches the Loader **structurally** (`ctx.loader` via a local type, not - The command reports tree count and completion as transcript notices; per-file failures surface only in loader logs, which the TUI does not display — acceptable for a dev-only surface, noted in the completion message. - A re-entrancy guard serializes reloads: `/reload` while one is in flight is refused with a warning, keeping the loader's unmutexed tree-update pass single-writer; the guard releases on completion or failure. - `/reload` runs only while the agent is idle: a reload can dispose and re-mount entries, which under an active turn could tear tools or the adapter out from under in-flight calls. The check is advisory (a send can race in after it) but removes the common footgun. -- If `refresh()`'s never-reject contract ever changes, the command reports the failure instead of leaving an unhandled rejection. +- If any `refresh()` rejects, the command reports the failure instead of leaving an unhandled rejection. ## Testing -`packages/ui/tui/tests/tui.spec.ts` pins: `/reload` refreshes every file-backed subtree and skips plain entries (structural fake Loader), reports completion, refuses re-entry while a gated refresh is in flight and runs again after release, releases the guard on the failure arm, refuses a running agent and runs again at idle, reports a rejecting refresh, and degrades to a warning without a Loader — including mounted as a real plugin fiber, where a throwing service lookup would escape. Verified live in tmux against the real tree: probe edit → reload applies; invalid edit → reload keeps the running tree. +`packages/ui/tui/tests/tui.spec.ts` pins: `/reload` refreshes every file-backed subtree and skips plain entries (structural fake Loader), reports completion, refuses re-entry while a gated refresh is in flight and runs again after release, releases the guard on the failure arm, refuses a running agent and runs again at idle, reports a rejecting refresh, and degrades to a warning without a Loader — including mounted as a real plugin fiber, where a throwing service lookup would escape. Verified live in tmux against the real tree: a probe edit reloads successfully. diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.zh.md b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.zh.md index 3798b0518d..25d1d44845 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.zh.md +++ b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.zh.md @@ -10,7 +10,7 @@ HMR 的文件监听器只对其配置根目录(示例中即配置叶子所在 ## Decision -`dsh-tui` 增加一个**实验性、仅供开发**的 `/reload` 斜杠命令:遍历 `ctx.loader.entries()`,对每个文件后端的子树(`Include`)调用 `refresh()`——即 HMR 监听器配置变更分支所走的同一条代码路径,改为手动触发、不依赖监听器。未变化的文件是无操作(`Include.read` 做内容比较);无效文件记录警告并保留运行中的树(热重载韧性契约);include 的 `patches`——包括 dsh CLI 的个人 overlay——在每次重读时重新应用。 +`dsh-tui` 增加一个**实验性、仅供开发**的 `/reload` 斜杠命令:遍历 `ctx.loader.entries()`,对每个文件后端的子树(`Include`)调用 `refresh()`——即 HMR 监听器配置变更分支所走的同一条代码路径,改为手动触发、不依赖监听器。未变化的文件是无操作(`Include.read` 做内容比较)。 TUI 以**结构方式**访问 Loader(通过局部类型访问 `ctx.loader`,而非 `inject`):测试和嵌入方在没有 Loader 的情况下运行 TUI,此时 `/reload` 退化为一条警告通知而不是挂载失败。模块源码热重载仍由监听器负责;`/reload` 只刷新配置。 @@ -28,8 +28,8 @@ TUI 以**结构方式**访问 Loader(通过局部类型访问 `ctx.loader`, - 命令以 transcript 通知报告树数量与完成;单文件失败只出现在 loader 日志里,TUI 不显示——对仅供开发的表面可以接受,完成消息中已注明。 - 重入保护串行化重载:前一次进行中时 `/reload` 会被拒绝并提示警告,使 loader 无互斥的树更新过程保持单写者;保护在完成或失败时释放。 - `/reload` 只在 agent 空闲时运行:重载可能卸载并重新挂载配置项,在活跃轮次下这会把工具或适配器从进行中的调用脚下抽掉。检查是建议性的(检查后仍可能有 send 竞争进来),但消除了常见的坑。 -- 若 `refresh()` 的永不 reject 契约将来改变,命令会报告失败而不是留下未处理的 rejection。 +- 任一 `refresh()` 若 reject,命令会报告失败而不是留下未处理的 rejection。 ## Testing -`packages/ui/tui/tests/tui.spec.ts` 固定:`/reload` 刷新每个文件后端子树并跳过普通配置项(结构化的假 Loader)、报告完成、在门控的刷新进行中拒绝重入并在释放后可再次运行、失败分支同样释放保护、拒绝运行中的 agent 并在空闲后可再次运行、报告 reject 的 refresh、无 Loader 时退化为警告——包括作为真实插件 fiber 挂载的情形,在那里会抛出的服务查找会泄露出去。已在 tmux 中对真实配置树实机验证:探针编辑 → reload 生效;无效编辑 → reload 保留运行中的树。 +`packages/ui/tui/tests/tui.spec.ts` 固定:`/reload` 刷新每个文件后端子树并跳过普通配置项(结构化的假 Loader)、报告完成、在门控的刷新进行中拒绝重入并在释放后可再次运行、失败分支同样释放保护、拒绝运行中的 agent 并在空闲后可再次运行、报告 reject 的 refresh、无 Loader 时退化为警告——包括作为真实插件 fiber 挂载的情形,在那里会抛出的服务查找会泄露出去。已在 tmux 中对真实配置树实机验证:探针编辑后 reload 成功生效。