Merge remote-tracking branch 'origin/master' into worktree/align-core-web-rl-prompt

# Conflicts:
#	apps/cli/reference/README.i18n.yaml
#	apps/cli/reference/README.md
#	apps/cli/reference/README.zh.md
#	apps/cli/src/app-cli-entry.ts
#	apps/cli/src/dump-config.ts
#	apps/cli/src/web.ts
#	apps/cli/tests/built-bin.e2e.ts
#	apps/cli/tests/web-prompt-context.spec.ts
#	apps/web/tests/scaffold.ts
This commit is contained in:
Yichen Jiang
2026-08-06 20:34:57 +08:00
176 changed files with 5465 additions and 2447 deletions

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# 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 .agents/notes/implemented/architecture/2026-08-05-profile-plugin-bundles.md
2026-08-05-profile-plugin-bundles.md: 11a8ac3d4005371ca9596ba237aaf42a8e770dee
2026-08-05-profile-plugin-bundles.zh.md: 0e9ebf657ccb9d05967d90a935b356acf287a24c

View File

@@ -0,0 +1,33 @@
# Agent Note: Profile plugin bundles replace the fixed surface overlays
Status: implemented
English | [中文](2026-08-05-profile-plugin-bundles.zh.md)
## Problem
The `dsh` launcher hardcoded its compositions: `base.cordis.yml` + `web.cordis.yml` shipped inside `apps/cli`, three bespoke entry modes (`--config`, `web`, `-p`) each with its own layer stack, and a single global personal overlay (`$DSH_HOME/config.yaml`). There was no way to install an out-of-tree plugin (a TUI, a provider pack) into a shipped surface without editing the repository, and no place where a third-party package could contribute a default composition.
## Decision
Everything becomes a **profile**: a directory `$DSH_HOME/profiles/<name>` with a `package.json` (pnpm-managed out-of-tree plugin `dependencies` plus the profile manifest `dsh.profile` with its ordered `bundles` layer list) and a user `cordis.patch.yml`. A **bundle** is an npm package declaring `"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`; the two manifest kinds live under distinct `dsh.profile` / `dsh.bundle` keys so a package.json states which role it plays. The tree composes over an empty root by applying each bundle's patch in `dsh.profile.bundles` order, then the user layer, then `--patch` overlays, then flag patches — one `applyEntryPatches` call, identical for boot, flag derivation, and `--dump-config`.
The shipped compositions became bundles: `@deepseek-ai/dsh-base` (the former base rows as one insert), `@deepseek-ai/dsh-web-app` (the former web overlay plus a runtime glue plugin that owns what used to be launcher code — frontend-dist resolution, the web-surface prompt section, bash runtime variables, the URL line), and `@deepseek-ai/dsh-headless` (a one-shot runner plugin over base + web-app). `dsh web` stays as an alias for `--profile web` carrying the Web flag family; `dsh --profile headless "task"` replaces `-p`; `dsh --config` is removed (its uses migrate to `--patch`). `dsh plugin --profile <name> <args...>` is a thin pnpm forwarder that initializes the profile and reconciles `dsh.profile.bundles` after `add`/`remove` (a bundle-less package warns and stays a plain dependency).
Resolution is two-anchored by construction: `dsh.profile.bundles` names resolve from the dsh installation first, then the profile directory — so in-box bundles always come from the same installation as the running `dsh` and pnpm never manages them — while bare plugin names in patch rows resolve through the profile directory's Node parent-walk into the maintained flat fallback `$DSH_HOME/profiles/node_modules` (one symlink per package the installation's app and bundles depend on, healed on every launch).
Two supporting refactors: the webserver's built-in static dist serving became the single-owner **fallback seat** (`registerFallback`/`applyIndexTaps`), with the SPA server extracted to `@deepseek-ai/dsh-frontend-static` so the web bundle owns its dist as composition, not launcher code; and the personal-overlay machinery of the [dsh CLI personal-config decision](../feature/2026-07-20-dsh-cli-personal-config.md) (`loadPersonalPatches`, `$DSH_HOME/config.yaml`) was retargeted to the per-profile and home-level `cordis.patch.yml` layers (`loadOptionalPatches`, `watchUserPatches` taking a filename), superseding that note's entry modes and file location while keeping its Harness-home root, patch semantics, and fail-loud parsing.
## Alternatives considered
- **Dependency-scan plus partial `patchOrder`** (the original sketch): scanning `dependencies` for bundles and ordering unlisted ones alphabetically has two sources of truth and an implicit tie-break; one explicit ordered `dsh.profile.bundles` list is smaller and fully deterministic. A raw `pnpm add` inside the profile installs a library without activating any patch — explicit, no spooky scan.
- **`link:` entries for in-box bundles**: pnpm cannot version, install, or update a `link:` into the installation, it embeds a machine path in a user file, and it breaks when the installation moves. The two-anchor resolution plus healed symlink fallback gives the same guarantee ("bundles come from the installation") without ceremony.
- **A pre-boot `context` module in the bundle manifest** for boot-time values (dist path, flag facts): rejected in favor of pure plugins — the glue is ordinary rows the launcher patches, so the composition stays fully dumpable and the manifest stays data-only. The launcher-owned `ctx.headlessIo` seam is the one host-provided slot, and it is provided in `boot()`'s `prepare` hook, before any config-tree entry mounts.
- **Transitive bundle auto-application**: only direct `dsh.profile.bundles` entries contribute layers; a meta-bundle wanting to re-export another bundle's patch must do so explicitly in its own patch file.
## Consequences
- New composition surfaces (a TUI, provider packs) ship as ordinary npm packages installable per profile; the repository no longer needs a row for every deployment shape.
- `apps/cli` shrank to argv parsing, profile machinery consumption, and the pnpm forwarder; `AppCLIEntry` and the per-surface boot paths are gone.
- The keyless web e2e scaffold boots the same bundle layers over the same empty-root shape as production, including the profiles module fallback, so composition drift between test and product fails loudly.
- Backends reject nothing old on disk (pre-release stance): `$DSH_HOME/config.yaml` is simply no longer read.

View File

@@ -0,0 +1,33 @@
# Agent Note: profile 插件组合包取代固定的表层 overlay
Status: implemented
[English](2026-08-05-profile-plugin-bundles.md) | 中文
## Problem
`dsh` 启动器硬编码了自己的组合:`base.cordis.yml` + `web.cordis.yml` 随 `apps/cli` 一起交付,三种各自定制的入口模式(`--config`、`web`、`-p`)各带一套层栈,外加一个全局的个人 overlay(`$DSH_HOME/config.yaml`)。想把树外插件(一个 TUI、一个提供方扩展包)装进已交付的表层,只能修改仓库;第三方包也没有任何位置可以贡献默认组合。
## Decision
一切都变成 **profile**:即目录 `$DSH_HOME/profiles/<name>`,其中包含一个 `package.json`(pnpm 管理的树外插件 `dependencies`,加上 profile manifest `dsh.profile` 及其有序的 `bundles` 层列表)和一份用户 `cordis.patch.yml`。**组合包**(bundle)是声明了 `"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }` 的 npm 包;两种 manifest 分别位于互不相同的 `dsh.profile` / `dsh.bundle` 键下,因此一份 package.json 能说明自己扮演哪种角色。配置树在空的根之上组合:按 `dsh.profile.bundles` 顺序应用每个组合包的 patch,然后是用户层,然后是 `--patch` overlay,最后是 flag patch——全部收敛为一次 `applyEntryPatches` 调用,启动、flag 派生与 `--dump-config` 使用完全相同的路径。
已交付的组合改造成了组合包:`@deepseek-ai/dsh-base`(原有基础行合并为一次插入)、`@deepseek-ai/dsh-web-app`(原 web overlay,外加一个接管原启动器代码的运行时粘合插件——前端 dist 解析、web 表层提示词段落、bash 运行时变量、URL 行)、`@deepseek-ai/dsh-headless`(叠加在 base + web-app 之上的一次性 runner 插件)。`dsh web` 保留为携带 Web flag 家族的 `--profile web` 别名;`dsh --profile headless "task"` 取代 `-p`;`dsh --config` 被移除(其用途迁移到 `--patch`)。`dsh plugin --profile <name> <args...>` 是一层薄薄的 pnpm 转发器,负责初始化 profile,并在 `add`/`remove` 后调和 `dsh.profile.bundles`(没有组合包声明的包会给出警告,保持为普通依赖)。
解析在构造上就是双锚点的:`dsh.profile.bundles` 中的名称先从 dsh 安装目录解析,再从 profile 目录解析——因此内置组合包始终来自与运行中 `dsh` 相同的安装,pnpm 从不管理它们——而 patch 行中的裸插件名称经 profile 目录的 Node 父目录逐级查找,落到受维护的扁平回退目录 `$DSH_HOME/profiles/node_modules`(安装目录的应用与各组合包所依赖的每个包各一个符号链接,每次启动时修复)。
两项配套重构:webserver 内置的静态 dist 服务改为单一所有者的**回退席位**(`registerFallback`/`applyIndexTaps`),SPA 服务器提取到 `@deepseek-ai/dsh-frontend-static`,使 web 组合包以组合的方式持有自己的 dist,而不是靠启动器代码;[dsh CLI 个人配置决策](../feature/2026-07-20-dsh-cli-personal-config.md)的个人 overlay 机制(`loadPersonalPatches`、`$DSH_HOME/config.yaml`)改为面向逐 profile 与 home 级的 `cordis.patch.yml` 层(`loadOptionalPatches`、接受文件名的 `watchUserPatches`),取代该笔记的各入口模式与文件位置,同时保留其 Harness home 根目录、patch 语义与大声失败的解析。
## Alternatives considered
- **依赖扫描加部分 `patchOrder`**(最初的草案):扫描 `dependencies` 找出组合包、未列出者按字母序排列,会产生两个真源和一条隐式决胜规则;一份显式有序的 `dsh.profile.bundles` 列表更小、完全确定。在 profile 内直接 `pnpm add` 只会安装一个库,不激活任何 patch——行为显式,没有暗中扫描。
- **内置组合包使用 `link:` 条目**:pnpm 无法对指向安装目录的 `link:` 做版本管理、安装或更新,它会把机器路径嵌进用户文件,并且在安装目录移动后失效。双锚点解析加上每次启动修复的符号链接回退提供了同样的保证(「组合包来自安装目录」),且没有这些繁文缛节。
- **在组合包 manifest(元数据清单)中放一个启动前 `context` 模块**承载启动期取值(dist 路径、flag 事实):否决,改用纯插件——粘合逻辑就是启动器 patch 的普通配置行,因此组合始终可完整 dump,manifest 保持纯数据。启动器持有的 `ctx.headlessIo` seam 是唯一由宿主提供的 slot,且在任何配置树条目挂载之前,于 `boot()` 的 `prepare` 钩子中提供。
- **组合包的传递式自动应用**:只有直接列在 `dsh.profile.bundles` 中的条目才贡献层;想重新导出另一个组合包 patch 的元组合包,必须在自己的 patch 文件中显式完成。
## Consequences
- 新的组合表层(TUI、提供方扩展包)以普通 npm 包形式交付,可按 profile 安装;仓库不再需要为每种部署形态各留一行。
- `apps/cli` 收缩为 argv 解析、profile 机制的消费方和 pnpm 转发器;`AppCLIEntry` 与各表层专属的启动路径全部移除。
- 无密钥 web e2e 脚手架以与生产相同的空根形态启动相同的组合包层,包括 profiles 模块回退,因此测试与产品之间的组合漂移会大声失败。
- 后端不拒绝磁盘上的任何旧格式(发布前姿态):`$DSH_HOME/config.yaml` 只是不再被读取。

View File

@@ -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 .agents/notes/implemented/bug-fix/2026-07-28-web-agent-runtime-context.md
2026-07-28-web-agent-runtime-context.md: 68f57e46296f34d8cf9d70f49ca18687d9573bca
2026-07-28-web-agent-runtime-context.zh.md: cabfc70962be0b99dc07dc5576e470d41793301b
2026-07-28-web-agent-runtime-context.md: 6c2bb8faf0db56d2a29b47726ab295c3501cce2d
2026-07-28-web-agent-runtime-context.zh.md: 09cbbdeabc244c265381b1ad67c3629b4c0763f5

View File

@@ -10,13 +10,13 @@ The shared CLI base configured an empty deployment persona, the Web overlay did
## Decision
The shared Web/headless overlay (`apps/cli/config/web.cordis.yml`) supplies a concise coding-agent persona containing the resolved `{{model}}` and session `{{cwd}}`. Its launcher-provided `cordis:web-runtime-context` row is disabled by default because Headless shares the tree without registering that builtin. Before mounting the tree, `dsh web` registers the builtin and applies an enable patch ahead of personal or explicit configuration; the mounted plugin resolves the harness checkout from the launcher's module URL, installs the existing `harness:source` section, and adds an `app:web-surface` section. A profile that owns its complete prompt can disable the row in the later configuration layer, while every mounted prompt contribution still activates before consumers such as the agent loop can emit a request header. The [source-checkout/workdir decision](2026-07-30-source-checkout-workdir-distinction.md) owns the source section's wording and its warning not to infer one path from the other.
The Web profile composes the `dsh-base` and `dsh-web-app` bundles. The Web bundle supplies a concise coding-agent persona containing the resolved `{{model}}` and session `{{cwd}}`; its `web-runtime` plugin adds the `app:web-surface` section when `surfaceContext` is true. Before mounting the profile tree, the `dsh web` alias reads that same composed setting and installs the existing `harness:source` section only when the surface context is enabled. The headless bundle and a profile that owns its complete prompt set `surfaceContext: false`, suppressing the Web prompt and managed shell facts; the Web alias also suppresses the source section without checking an overlay path. Every mounted prompt contribution still activates before consumers such as the agent loop can emit a request header. The [source-checkout/workdir decision](2026-07-30-source-checkout-workdir-distinction.md) owns the source section's wording and its warning not to infer one path from the other.
The Web section treats unqualified references to “this page,” “this GUI,” or “this app” as references to the DeepSeek Harness Web GUI. It also states that the browser provides no implicit DOM, route, or screenshot context, so the model can identify the product without claiming visual state it did not receive. The assembled text is logged in `request/header`, preserving the model-visible/logged invariant.
## Verification
The focused startup-order test mounts the launcher builtin, registers a later `systemPrompt` consumer, and proves that it observes both launcher sections on its first activation. The keyless fresh-round-trip Web scenario boots the shipped base plus Web overlay, registers the same launcher context as `dsh web`, runs a real session through the HTTP/SSE application, and snapshots the first four system-prompt sections with source and working-directory paths normalized. The snapshot pins the harness identity, source checkout, Web orientation, and resolved coding-agent persona in request order. The Core Web snapshot disables the builtin and pins its complete RL system prompt.
The Web runtime unit tests pin both enabled and disabled `surfaceContext` behavior, while the Web alias unit test pins default-on and explicit-off source-section gating from the composed row. The keyless fresh-round-trip Web scenario boots the shipped base plus Web bundle, runs a real session through the HTTP/SSE application, and snapshots the system-prompt prefix with source and working-directory paths normalized. The snapshot pins the harness identity, source checkout, Web orientation, and resolved coding-agent persona in request order. The Core Web snapshot applies the RL overlay and pins its complete system prompt with no source or Web section.
## Alternatives considered
@@ -30,4 +30,4 @@ The focused startup-order test mounts the launcher builtin, registers a later `s
## Consequences
Ordinary Web requests gain a short stable prompt prefix and may invalidate provider prefix caches once when this change is deployed. Agents can distinguish the GUI source checkout from the selected Workspace and resolve ordinary references to the current app without a clarification round trip. References to a specific visual state remain bounded by the explicit no-DOM/no-route/no-screenshot statement and may still require a path, description, or attachment. Complete-prompt profiles can opt out without a launcher path check.
Ordinary Web requests gain a short stable prompt prefix and may invalidate provider prefix caches once when this change is deployed. Agents can distinguish the GUI source checkout from the selected Workspace and resolve ordinary references to the current app without a clarification round trip. References to a specific visual state remain bounded by the explicit no-DOM/no-route/no-screenshot statement and may still require a path, description, or attachment. Complete-prompt profiles can opt out through the Web runtime's composition setting without a launcher path check.

View File

@@ -10,13 +10,13 @@ CLI 共享 base 配置了空的部署 persona,Web overlay 没有替换它,
## 决策
`apps/cli/config/web.cordis.yml` 这份 Web/无头共享 overlay 提供一段简洁的编码 agent persona,其中包含解析后的 `{{model}}` 与会话 `{{cwd}}`。由于无头模式共享该配置树但不会注册这个 builtin,其中由启动器提供的 `cordis:web-runtime-context` 配置行默认禁用。挂载配置树前,`dsh web` 会注册该 builtin,并先于个人配置或显式配置应用一项启用 patch;挂载后的插件会根据启动器模块的 URL 解析 harness checkout、安装现有的 `harness:source` 提示词段并添加 `app:web-surface` 提示词段。拥有完整提示词的 profile 可以在后续配置层中禁用该配置行,而每项已挂载的提示词贡献仍会在 agent loop(智能体循环)等消费方发出 request header 前激活。源码提示词段的措辞,以及其中不得从一条路径推断另一条路径的警告,均由另行记录的[源码 checkout 与工作目录区分决策](2026-07-30-source-checkout-workdir-distinction.md)负责。
Web profile 会组合 `dsh-base` 与 `dsh-web-app` 两个组合包。Web 组合包提供一段简洁的编码 agent persona,其中包含解析后的 `{{model}}` 与会话 `{{cwd}}`;当 `surfaceContext` 为 true 时,其 `web-runtime` 插件会添加 `app:web-surface` 提示词段。挂载 profile 配置树前,`dsh web` 别名会读取组合后的同一项设置,并且仅在启用表层上下文时安装现有的 `harness:source` 提示词段。无头组合包和拥有完整提示词的 profile 都会设置 `surfaceContext: false`,从而抑制 Web 提示词与受管 shell 事实;Web 别名也会抑制源码提示词段,而无需检查 overlay 路径。每项已挂载的提示词贡献仍会在 agent loop(智能体循环)等消费方发出 request header 前激活。源码提示词段的措辞,以及其中不得从一条路径推断另一条路径的警告,均由另行记录的[源码 checkout 与工作目录区分决策](2026-07-30-source-checkout-workdir-distinction.md)负责。
Web 提示词段把未限定的「这个页面」「这个 GUI」或「这个应用」解释为 DeepSeek Harness Web GUI。同时,它会明确说明浏览器不会隐式提供 DOM、路由或截图上下文,使模型能够识别产品,但不会声称掌握未收到的视觉状态。组装后的文本会记录在 `request/header` 中,从而保持「模型可见内容必须有日志记录」这一不变量。
## 验证
聚焦启动顺序的测试会挂载启动器 builtin,注册一个后续的 `systemPrompt` 消费方,并证明该消费方首次激活时就能观察到启动器的两个提示词段。无密钥的 Web fresh-round-trip 场景会启动已交付的 base 与 Web overlay,注册与 `dsh web` 相同的启动器上下文,并通过 HTTP/SSE 应用运行一个真实会话。测试会把源码路径和工作目录规范化,然后对系统提示词的前四个段落生成快照。该快照按请求顺序固定 harness 身份、源码 checkout、Web 界面定位,以及解析后的编码 agent persona。Core Web 快照会禁用该 builtin,并固定其完整的 RL 系统提示词。
Web 运行时单元测试会固定启用和禁用 `surfaceContext` 时的行为,Web 别名单元测试则会固定组合后配置行对源码提示词段的默认启用与显式禁用门控。无密钥的 Web fresh-round-trip 场景会启动已交付的 base 与 Web 组合包,通过 HTTP/SSE 应用运行一个真实会话,并在规范化源码路径与工作目录后对系统提示词前缀生成快照。该快照按请求顺序固定 harness 身份、源码 checkout、Web 界面定位,以及解析后的编码 agent persona。Core Web 快照会应用 RL overlay,并固定不含源码提示词段或 Web 提示词段的完整系统提示词。
## 考虑过的替代方案
@@ -30,4 +30,4 @@ Web 提示词段把未限定的「这个页面」「这个 GUI」或「这个应
## 影响
常规 Web 请求会增加一段较短且稳定的提示词前缀;部署此变更时,模型提供方的前缀缓存可能失效一次。agent 可以区分 GUI 源码 checkout 与所选 Workspace,并且无需再经过一轮澄清即可解析对当前应用的一般指代。对特定视觉状态的指代仍受「无 DOM/无路由/无截图」这一显式边界约束,必要时仍需用户提供路径、描述或附件。拥有完整提示词的 profile 无需检查启动器路径即可选择退出。
常规 Web 请求会增加一段较短且稳定的提示词前缀;部署此变更时,模型提供方的前缀缓存可能失效一次。agent 可以区分 GUI 源码 checkout 与所选 Workspace,并且无需再经过一轮澄清即可解析对当前应用的一般指代。对特定视觉状态的指代仍受「无 DOM/无路由/无截图」这一显式边界约束,必要时仍需用户提供路径、描述或附件。拥有完整提示词的 profile 可以通过 Web 运行时的组合设置选择退出,而无需检查启动器路径。

View File

@@ -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 .agents/notes/implemented/bug-fix/2026-07-28-web-gui-feedback-loop.md
2026-07-28-web-gui-feedback-loop.md: 04f0e9383db03b84e1998212782342034ffb9d96
2026-07-28-web-gui-feedback-loop.zh.md: 4ce0144bc6aba8d1b2b99d072541bf7fc24057b2
2026-07-28-web-gui-feedback-loop.md: aa488e1df087722c072d98c67d47cdf63a42f6b8
2026-07-28-web-gui-feedback-loop.zh.md: d9de988e5a2cc57794ff628b65eb050dee610747

View File

@@ -12,7 +12,7 @@ The [incident post-mortem](../../../../docs/postmortem/0003-web-agent-gui-feedba
## Decision
The ordinary `dsh web` composition mounts the launcher-provided `cordis:web-runtime-context` builtin, which publishes one canonical loopback URL and its actual runtime mode as both model-visible orientation and managed shell facts. The `app:web-surface` prompt section says that unqualified references identify this GUI and names the URL; `DSH_WEB_URL` and `DSH_WEB_MODE=production|development` carry the same facts into every foreground or managed background bash call. The section preserves the no-implicit-DOM, route, or screenshot boundary and does not claim that a LAN alias equals the browser's literal address. A complete-prompt profile can disable the row and receives neither the prompt section nor the managed variables.
The ordinary `dsh web` composition mounts the Web bundle's `web-runtime` plugin, which publishes one canonical loopback URL and its actual runtime mode as both model-visible orientation and managed shell facts. The `app:web-surface` prompt section says that unqualified references identify this GUI and names the URL; `DSH_WEB_URL` and `DSH_WEB_MODE=production|development` carry the same facts into every foreground or managed background bash call. The section preserves the no-implicit-DOM, route, or screenshot boundary and does not claim that a LAN alias equals the browser's literal address. A complete-prompt profile sets the row's `surfaceContext` to false and receives neither the prompt section nor the managed variables; the Web launcher uses the same setting to suppress its source-checkout prompt section.
The mode-specific prompt makes the agent, rather than the user, own the hidden startup contract. Production mode defines acceptance as rebuilding the affected artifacts and refreshing the existing URL. Development mode states that `dsh web --dev` activates only the HMR receiver: automatic client-plugin reload additionally requires a same-checkout `pnpm run dev:web` watcher, which the agent verifies before promising no-refresh updates. Shell and other plain-package changes still require rebuild plus refresh. An agent in production mode explains both commands when a user requests no-refresh updates; it does not launch a replacement GUI unless asked.
@@ -36,4 +36,4 @@ The keyless fresh-round-trip browser scenario boots the shipped production Web c
## Consequences
Ordinary Web prompts gain a dynamic URL-and-mode paragraph, so provider prefix reuse now varies by bound port and mode. Their Bash processes gain two non-secret managed environment variables. Bare Vite can no longer be used as a shell-only visual sandbox; developers use the full host or build mode instead. In exchange, GUI work has one mechanically observable target, the agent can teach the user the exact update behavior of the process actually serving their session, and the unsupported startup path fails before a white screen. The URL/mode contract guides the agent away from replacement ports; it does not prohibit arbitrary shell commands from starting one. Profiles that disable the runtime-context builtin also give up this feedback-loop guidance and shell context.
Ordinary Web prompts gain a dynamic URL-and-mode paragraph, so provider prefix reuse now varies by bound port and mode. Their Bash processes gain two non-secret managed environment variables. Bare Vite can no longer be used as a shell-only visual sandbox; developers use the full host or build mode instead. In exchange, GUI work has one mechanically observable target, the agent can teach the user the exact update behavior of the process actually serving their session, and the unsupported startup path fails before a white screen. The URL/mode contract guides the agent away from replacement ports; it does not prohibit arbitrary shell commands from starting one. Profiles that disable `surfaceContext` also give up this feedback-loop guidance and shell context.

View File

@@ -12,7 +12,7 @@ Web agent(智能体)既无法识别承载当前会话的 GUI,也不知道
## 决策
常规 `dsh web` 组合会挂载启动器提供的 `cordis:web-runtime-context` builtin,由它发布一个规范的回环 URL 及其实际运行时模式,同时将二者作为模型可见的界面定位信息和受管 shell 事实。`app:web-surface` 提示词段说明:未加限定的指代指向此 GUI,并给出 URL;`DSH_WEB_URL` 和 `DSH_WEB_MODE=production|development` 会把同样的事实传入每次前台或受管后台 bash 调用。该段保留「不会隐式获得 DOM、路由或截图」这一边界,也不声称局域网别名等于浏览器中的实际地址。拥有完整提示词的 profile 可以禁用该配置行,并且不会收到该提示词段和这些受管变量中的任何一个。
常规 `dsh web` 组合会挂载 Web 组合包的 `web-runtime` 插件,由它发布一个规范的回环 URL 及其实际运行时模式,同时将二者作为模型可见的界面定位信息和受管 shell 事实。`app:web-surface` 提示词段说明:未加限定的指代指向此 GUI,并给出 URL;`DSH_WEB_URL` 和 `DSH_WEB_MODE=production|development` 会把同样的事实传入每次前台或受管后台 bash 调用。该段保留「不会隐式获得 DOM、路由或截图」这一边界,也不声称局域网别名等于浏览器中的实际地址。拥有完整提示词的 profile 会把该配置行的 `surfaceContext` 设为 false,并且不会收到该提示词段和这些受管变量中的任何一个;Web 启动器也会使用同一项设置来抑制其源码 checkout 提示词段。
按模式区分的提示词让 agent 而非用户负责隐藏的启动契约。生产模式将验收定义为重新构建受影响的产物并刷新现有 URL。开发模式说明,`dsh web --dev` 只会启用 HMR(热模块替换)接收端:客户端插件要自动重新加载,还需要在同一检出中运行 `pnpm run dev:web` 监听进程,agent 会在承诺无需刷新即可更新前验证这一点。外壳和其他普通包的变更仍然需要重新构建并刷新。生产模式下的 agent 会在用户要求无需刷新即可更新时说明这两个命令;除非用户要求,否则不会启动替代 GUI。
@@ -36,4 +36,4 @@ Web agent(智能体)既无法识别承载当前会话的 GUI,也不知道
## 影响
常规 Web 提示词会增加一个动态 URL 和模式段落,因此模型提供方的前缀复用会随绑定端口和模式变化。相应的 Bash 进程会增加两个非敏感的受管环境变量。裸 Vite 不再能用作只依赖 shell 的视觉沙箱;开发者应改用完整宿主或构建模式。作为交换,GUI 工作有了一个可由机制观察的唯一目标,agent 可以向用户说明实际承载其会话的进程究竟如何更新,不受支持的启动路径也会在出现白屏前失败。URL/模式契约会引导 agent 避免使用替代端口,但不会禁止任意 shell 命令启动替代服务。禁用 runtime-context builtin 的 profile 也会放弃这项反馈闭环指引与 shell 上下文。
常规 Web 提示词会增加一个动态 URL 和模式段落,因此模型提供方的前缀复用会随绑定端口和模式变化。相应的 Bash 进程会增加两个非敏感的受管环境变量。裸 Vite 不再能用作只依赖 shell 的视觉沙箱;开发者应改用完整宿主或构建模式。作为交换,GUI 工作有了一个可由机制观察的唯一目标,agent 可以向用户说明实际承载其会话的进程究竟如何更新,不受支持的启动路径也会在出现白屏前失败。URL/模式契约会引导 agent 避免使用替代端口,但不会禁止任意 shell 命令启动替代服务。禁用 `surfaceContext` 的 profile 也会放弃这项反馈闭环指引与 shell 上下文。

View File

@@ -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 .agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md
2026-07-20-dsh-cli-personal-config.md: 1fa8cda2b34b58cc7a28b722872520b68a9b7009
2026-07-20-dsh-cli-personal-config.zh.md: e70b8914cf005e0a2e54ba2b29d3b7def84b00db
2026-07-20-dsh-cli-personal-config.md: 10f16a1cbabdd8cd383c59ad8e09787c02d0109a
2026-07-20-dsh-cli-personal-config.zh.md: 22435efbec8ea661c546ffd0c1aa9bb0ff2ebbb2

View File

@@ -10,6 +10,8 @@ A developer's own preferences — which provider and model the TUI uses, persona
## Decision
The entry modes and the personal file's name and location below are superseded by the [profile plugin bundles decision](../architecture/2026-08-05-profile-plugin-bundles.md): `dsh` boots profiles, and the personal layer became the per-profile and home-level `cordis.patch.yml`. What survives unchanged is this note's substance — the Harness home as the machine-level layer's root, patch semantics over a shipped composition, and fail-loud parsing.
Two coupled pieces, aligned with the `apps/` assembly tier proposed by the `dsh web` PR (#443):
**The `dsh` CLI (`apps/cli`, npm name `@deepseek-ai/dsh`).** `apps/*` is the product-assembly tier over `packages/*` libraries. One bin dispatches the default interactive TUI, `-p`/`--prompt` headless turns, and the `web` surface. The TUI boots `examples/tui-agent/cordis.yml` (or `--config`) with the invoking directory as the workspace. The committed `bin/dsh` launcher resolves the checkout through its own real path and runs the app with tsx's ESM hook; the [source-launch decision](../architecture/2026-07-29-dsh-source-launch-tsx-esm.md) owns that contract. `pnpm run demo:tui` runs the same entry.
@@ -46,4 +48,4 @@ The TUI and Web register the exact personal path through Cordis HMR after boot.
## Testing
`packages/ui/app-boot/tests/personal-config.spec.ts` pins parsing, startup application, exact-path add/failure/recovery/removal, last-good rollback, failure broadcast, and preservation of app-owned patches. `examples/tui-agent/tests/tui-keyless-smoke.e2e.ts` boots the real dsh bin with no overlay, a personal environment and UI patch, a config-only cached repository skill, and invalid personal YAML. Test launchers isolate `$DSH_HOME`, so a developer's real overlay cannot leak into fixtures.
`packages/ui/app-boot/tests/user-patches.spec.ts` pins parsing, startup application, exact-path add/failure/recovery/removal, last-good rollback, failure broadcast, and preservation of app-owned patches. `apps/cli/tests/built-bin.e2e.ts` boots the real dsh bin over a profile and exercises the live patch layer end to end. Test launchers isolate `$DSH_HOME`, so a developer's real overlay cannot leak into fixtures.

View File

@@ -10,6 +10,8 @@ Status: implemented
## Decision
下文的各入口模式,以及个人文件的名称与位置,已被 [profile 插件组合包决策](../architecture/2026-08-05-profile-plugin-bundles.md)取代:`dsh` 启动 profile,个人层变成逐 profile 与 home 级的 `cordis.patch.yml`。保留不变的是本笔记的实质:以 Harness home 作为机器级层的根目录、在随附组合之上使用 patch 语义,以及解析时的大声失败。
两个耦合的部分,与 `dsh web` PR(#443)提出的 `apps/` 装配层对齐:
**`dsh` CLI(`apps/cli`,npm 名 `@deepseek-ai/dsh`)。** `apps/*` 是位于 `packages/*` 库之上的产品组装层。一个 bin 负责分发默认交互式 TUI、`-p`/`--prompt` 无头轮次和 `web` 界面。TUI 以调用目录为 workspace,启动 `examples/tui-agent/cordis.yml`(或 `--config` 指定的配置)。已提交的 `bin/dsh` 启动器通过自身真实路径解析 checkout,并使用 tsx 的 ESM hook 运行应用;该契约由[源码启动决策](../architecture/2026-07-29-dsh-source-launch-tsx-esm.md)维护。`pnpm run demo:tui` 运行同一入口。
@@ -46,4 +48,4 @@ TUI 和 Web 启动后通过 Cordis HMR(热模块替换)注册确切的个人
## Testing
`packages/ui/app-boot/tests/personal-config.spec.ts` 固定解析、启动时应用、确切路径的新增/失败/恢复/移除、最后可用状态回滚、失败广播以及应用自有 patch 的保留。`examples/tui-agent/tests/tui-keyless-smoke.e2e.ts` 启动真实 dsh bin,覆盖无 overlay、个人环境与 UI patch、纯配置的缓存 repository skill,以及无效个人 YAML。测试启动器会隔离 `$DSH_HOME`,因此开发者的真实 overlay 不会泄漏进 fixture。
`packages/ui/app-boot/tests/user-patches.spec.ts` 固定解析、启动时应用、确切路径的新增/失败/恢复/移除、最后可用状态回滚、失败广播以及应用自有 patch 的保留。`apps/cli/tests/built-bin.e2e.ts` 启动真实 dsh bin 并基于 profile 端到端验证实时 patch 层。测试启动器会隔离 `$DSH_HOME`,因此开发者的真实 overlay 不会泄漏进 fixture。

View File

@@ -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 .agents/notes/implemented/feature/2026-07-31-even-out-shipped-tool-rosters.md
2026-07-31-even-out-shipped-tool-rosters.md: 312e61d017abad1a6ac57f2ba491a715f8fd92d0
2026-07-31-even-out-shipped-tool-rosters.zh.md: c77370c312004052bc4f8ee9545ed287a6d92554
2026-07-31-even-out-shipped-tool-rosters.md: d12db993654d9f2b41a16a4663dc64aefe8e3a2f
2026-07-31-even-out-shipped-tool-rosters.zh.md: 8381a457def1a909b300de52dc011e2437c7e9f3

View File

@@ -12,7 +12,7 @@ The result was a user-visible difference nobody had decided: the same model, ask
## Decision
The rows that are not surface-specific move into [`base.cordis.yml`](../../../../apps/cli/config/base.cordis.yml), and three more join them: `tool-session-query`, `tool-str-replace-editor`, and `repeat-tool-guard`. Web search moves there too; its [deployment decision](2026-07-31-web-default-search.md) owns the security boundary while the shared base owns its surface-neutral mount. Both surfaces assemble the same roster: twenty-two tools on every host — the twenty shared rows plus `glob` and `grep`, which are fixed members because `dsh-tool-fs-search` spawns the [packaged ripgrep binary](../architecture/2026-08-01-packaged-ripgrep-search.md). `tool-session-query` joined and then left again — the [session-search-not-shipped-default decision](2026-08-02-session-search-not-shipped-default.md) keeps the model-facing consumer opt-in — while the rest of this roster stands.
The rows that are not surface-specific move into [`base.cordis.yml`](../../../../packages/bundle/base/cordis.patch.yml), and three more join them: `tool-session-query`, `tool-str-replace-editor`, and `repeat-tool-guard`. Web search moves there too; its [deployment decision](2026-07-31-web-default-search.md) owns the security boundary while the shared base owns its surface-neutral mount. Both surfaces assemble the same roster: twenty-two tools on every host — the twenty shared rows plus `glob` and `grep`, which are fixed members because `dsh-tool-fs-search` spawns the [packaged ripgrep binary](../architecture/2026-08-01-packaged-ripgrep-search.md). `tool-session-query` joined and then left again — the [session-search-not-shipped-default decision](2026-08-02-session-search-not-shipped-default.md) keeps the model-facing consumer opt-in — while the rest of this roster stands.
Two rows stay surface-specific. `tmux-context` is TUI-only because a browser surface has no terminal multiplexer to describe. `session-reference` is TUI-only because it drives the shared session-query index from the launcher's process-local path, and the browser sidebar reconciles that index on its own first search.

View File

@@ -12,7 +12,7 @@ Status: implemented
## 决策
那些并非 surface 专属的行移入 [`base.cordis.yml`](../../../../apps/cli/config/base.cordis.yml),另有三行加入:`tool-session-query`、`tool-str-replace-editor` 和 `repeat-tool-guard`。Web 搜索也一并移入;其[部署决策](2026-07-31-web-default-search.md)负责安全边界,共享 base 则负责与 surface 无关的挂载。两个 surface 组装同一份清单:每台宿主上都有二十二个工具——二十个共享行加上 `glob` 和 `grep`,它们成为固定成员,因为 `dsh-tool-fs-search` 直接 spawn [打包的 ripgrep 二进制](../architecture/2026-08-01-packaged-ripgrep-search.md)。`tool-session-query` 加入后又退出了——[session-search-not-shipped-default 决策](2026-08-02-session-search-not-shipped-default.md)让面向模型的消费方保持需显式启用——而这份清单的其余部分保持不变。
那些并非 surface 专属的行移入 [`base.cordis.yml`](../../../../packages/bundle/base/cordis.patch.yml),另有三行加入:`tool-session-query`、`tool-str-replace-editor` 和 `repeat-tool-guard`。Web 搜索也一并移入;其[部署决策](2026-07-31-web-default-search.md)负责安全边界,共享 base 则负责与 surface 无关的挂载。两个 surface 组装同一份清单:每台宿主上都有二十二个工具——二十个共享行加上 `glob` 和 `grep`,它们成为固定成员,因为 `dsh-tool-fs-search` 直接 spawn [打包的 ripgrep 二进制](../architecture/2026-08-01-packaged-ripgrep-search.md)。`tool-session-query` 加入后又退出了——[session-search-not-shipped-default 决策](2026-08-02-session-search-not-shipped-default.md)让面向模型的消费方保持需显式启用——而这份清单的其余部分保持不变。
有两行仍是 surface 专属。`tmux-context` 只在 TUI,因为浏览器 surface 没有终端复用器可描述。`session-reference` 只在 TUI,因为它以 launcher 的进程本地路径驱动共享的 session-query 索引,而浏览器侧边栏会在自己的首次搜索里重建该索引。

View File

@@ -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 .agents/notes/implemented/feature/2026-07-31-workspace-write-surface-default.md
2026-07-31-workspace-write-surface-default.md: a0b216122e301b5332ed761155d743dc78fa3bab
2026-07-31-workspace-write-surface-default.zh.md: 4391daa32b142ea976e3b04833163936913c17bc
2026-07-31-workspace-write-surface-default.md: e6a36ad4ee7179cabf958114681728c3ac7340b4
2026-07-31-workspace-write-surface-default.zh.md: 5ced928b167892d9abe1f4423da72a0243590735

View File

@@ -10,7 +10,7 @@ The shipped terminal and browser surfaces exposed the same coding tools under di
## Decision
[`base.cordis.yml`](../../../../apps/cli/config/base.cordis.yml) owns one sandbox and permission stack for every shipped TUI, Web, and browser-backed headless session: `dsh-sandbox-local`, `dsh-sandbox-policy`, `dsh-bash-sandbox`, `dsh-fs-sandbox`, `dsh-user-approval`, and `dsh-permission`. The composition fallback is the `workspace-write` preset, which bundles `workspace-write` file effects with the `ask` approval policy. `DSH_PERMISSION_MODE` remains an explicit process override; a stored `permission.defaultPreset` remains the user preference for later sessions and outranks the fallback through the Settings seam.
[`base.cordis.yml`](../../../../packages/bundle/base/cordis.patch.yml) owns one sandbox and permission stack for every shipped TUI, Web, and browser-backed headless session: `dsh-sandbox-local`, `dsh-sandbox-policy`, `dsh-bash-sandbox`, `dsh-fs-sandbox`, `dsh-user-approval`, and `dsh-permission`. The composition fallback is the `workspace-write` preset, which bundles `workspace-write` file effects with the `ask` approval policy. `DSH_PERMISSION_MODE` remains an explicit process override; a stored `permission.defaultPreset` remains the user preference for later sessions and outranks the fallback through the Settings seam.
A genuinely fresh session pins `permission/preset: workspace-write`, `sandbox/mode: workspace-write`, and `approval/policy: ask` before execution. Existing and resumed sessions retain their logged permission, and changing the General-settings default affects only sessions created afterward. The browser keeps its Access picker, answerable approval cards, and risk confirmation for Full access. The TUI gains the existing `/permission` command because the shared Permission service activates its command child there.

View File

@@ -10,7 +10,7 @@ Status: implemented
## 决策
[`base.cordis.yml`](../../../../apps/cli/config/base.cordis.yml) 为所有已交付的 TUI、Web 以及由浏览器支撑的无头会话统一持有一套沙箱与权限栈:`dsh-sandbox-local`、`dsh-sandbox-policy`、`dsh-bash-sandbox`、`dsh-fs-sandbox`、`dsh-user-approval` 和 `dsh-permission`。组合回退值为 `workspace-write` preset,其中包含 `workspace-write` 文件效果模式与 `ask` 审批策略。`DSH_PERMISSION_MODE` 仍是显式的进程级覆盖;已存储的 `permission.defaultPreset` 仍是面向后续会话的用户偏好,并通过 Settings seam 优先于该回退值。
[`base.cordis.yml`](../../../../packages/bundle/base/cordis.patch.yml) 为所有已交付的 TUI、Web 以及由浏览器支撑的无头会话统一持有一套沙箱与权限栈:`dsh-sandbox-local`、`dsh-sandbox-policy`、`dsh-bash-sandbox`、`dsh-fs-sandbox`、`dsh-user-approval` 和 `dsh-permission`。组合回退值为 `workspace-write` preset,其中包含 `workspace-write` 文件效果模式与 `ask` 审批策略。`DSH_PERMISSION_MODE` 仍是显式的进程级覆盖;已存储的 `permission.defaultPreset` 仍是面向后续会话的用户偏好,并通过 Settings seam 优先于该回退值。
真正的新会话会在执行前固定 `permission/preset: workspace-write`、`sandbox/mode: workspace-write` 和 `approval/policy: ask`。现有会话和恢复的会话保留日志中记录的权限,更改「通用」设置中的默认值只影响之后创建的会话。浏览器保留 Access 选择器、可应答的审批卡片,以及选择 Full access 时的风险确认。共享 Permission 服务在 TUI 中激活其命令子件,因此 TUI 会获得现有的 `/permission` 命令。

View File

@@ -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 .agents/notes/implemented/feature/2026-08-02-session-search-not-shipped-default.md
2026-08-02-session-search-not-shipped-default.md: ba7299712c0ba3db5e807e928f6f5d98ac917187
2026-08-02-session-search-not-shipped-default.zh.md: 1678ebfb5514003eabe0221e460c619bab1aa444
2026-08-02-session-search-not-shipped-default.md: 65bd72fff76210b726e7562fb8e88e5f8802434a
2026-08-02-session-search-not-shipped-default.zh.md: 5e42a2c2323904117f9322b5c4a53c43c6ed3f2a

View File

@@ -6,11 +6,11 @@ English | [中文](2026-08-02-session-search-not-shipped-default.zh.md)
## Problem
The [shipped-roster decision](2026-07-31-even-out-shipped-tool-rosters.md) made `tool-session-query` a default row of the shared [`base.cordis.yml`](../../../../apps/cli/config/base.cordis.yml), so the shipped TUI and Web surfaces put the five session-search tools (`session_search`, `session_event_search`, `session_trace`, `session_event_trace`, `session_event_read`) in front of the model. That contradicted the [model-facing session-query-tools decision](2026-07-24-model-facing-session-query-tools.md), whose opt-in stance the package README recorded as "shipped host compositions do not mount it by default". The default also shipped a prompt section teaching a prior-work search workflow that no user had asked for.
The [shipped-roster decision](2026-07-31-even-out-shipped-tool-rosters.md) made `tool-session-query` a default row of the shared [`cordis.patch.yml`](../../../../packages/bundle/base/cordis.patch.yml), so the shipped TUI and Web surfaces put the five session-search tools (`session_search`, `session_event_search`, `session_trace`, `session_event_trace`, `session_event_read`) in front of the model. That contradicted the [model-facing session-query-tools decision](2026-07-24-model-facing-session-query-tools.md), whose opt-in stance the package README recorded as "shipped host compositions do not mount it by default". The default also shipped a prompt section teaching a prior-work search workflow that no user had asked for.
## Decision
The shipped TUI, Web, and headless surfaces no longer mount `@deepseek-ai/dsh-tool-session-query`: the row is removed from the shared `base.cordis.yml`, the now-dangling `disabled` patch in the opt-in [`core-web.cordis.yml`](../../../../apps/cli/config/core-web.cordis.yml) profile goes with it, and the workspace dependency drops from `apps/cli/package.json`. The consumer stays opt-in exactly as the model-facing-session-query-tools note describes: the ACP example's [`session-query.cordis.yml`](../../../../examples/acp-agent/session-query.cordis.yml) and its snapshot counterpart remain the mounted reference, and a custom composition can mount the package with the timeout and spill policies.
The shipped TUI, Web, and headless surfaces no longer mount `@deepseek-ai/dsh-tool-session-query`: the row is removed from the shared `cordis.patch.yml`, the now-dangling `disabled` patch in the opt-in [`core-web.cordis.yml`](../../../../apps/cli/config/core-web.cordis.yml) profile goes with it, and the workspace dependency drops from `apps/cli/package.json`. The consumer stays opt-in exactly as the model-facing-session-query-tools note describes: the ACP example's [`session-query.cordis.yml`](../../../../examples/acp-agent/session-query.cordis.yml) and its snapshot counterpart remain the mounted reference, and a custom composition can mount the package with the timeout and spill policies.
The `ctx.sessionQuery` service itself stays mounted. `session-query-sqlite` remains a base row — the TUI's `session-reference` consumes it for `/resume` — and the Web overlay keeps patching it to an in-memory index for the browser content search. Only the model-facing consumer is removed.

View File

@@ -6,11 +6,11 @@ Status: implemented
## 问题
[交付清单决策](2026-07-31-even-out-shipped-tool-rosters.md)把 `tool-session-query` 设为共享 [`base.cordis.yml`](../../../../apps/cli/config/base.cordis.yml) 的默认行,于是交付的 TUI 与 Web surface 把这五个会话搜索工具(`session_search`、`session_event_search`、`session_trace`、`session_event_trace`、`session_event_read`)呈现给了模型。这与[面向模型的会话查询工具决策](2026-07-24-model-facing-session-query-tools.md)相抵触,该决策持需显式启用的立场,包 README 将其记录为「shipped host compositions do not mount it by default」。这份默认还交付了一个提示词段,向模型讲授一套既往工作搜索工作流,而没有任何用户要求过。
[交付清单决策](2026-07-31-even-out-shipped-tool-rosters.md)把 `tool-session-query` 设为共享 [`cordis.patch.yml`](../../../../packages/bundle/base/cordis.patch.yml) 的默认行,于是交付的 TUI 与 Web surface 把这五个会话搜索工具(`session_search`、`session_event_search`、`session_trace`、`session_event_trace`、`session_event_read`)呈现给了模型。这与[面向模型的会话查询工具决策](2026-07-24-model-facing-session-query-tools.md)相抵触,该决策持需显式启用的立场,包 README 将其记录为「shipped host compositions do not mount it by default」。这份默认还交付了一个提示词段,向模型讲授一套既往工作搜索工作流,而没有任何用户要求过。
## 决策
交付的 TUI、Web 与无头 surface 不再挂载 `@deepseek-ai/dsh-tool-session-query`:该行从共享的 `base.cordis.yml` 移除,opt-in 的 [`core-web.cordis.yml`](../../../../apps/cli/config/core-web.cordis.yml) profile 中那条已悬空的 `disabled` patch 也随之删除,workspace 依赖也从 `apps/cli/package.json` 中移除。该消费方仍保持 opt-in,与面向模型的会话查询工具决策所述完全一致:ACP 示例的 [`session-query.cordis.yml`](../../../../examples/acp-agent/session-query.cordis.yml) 及其快照对侧文件仍是挂载参考,自定义组合也可以连同超时与 spill 策略一起挂载该包。
交付的 TUI、Web 与无头 surface 不再挂载 `@deepseek-ai/dsh-tool-session-query`:该行从共享的 `cordis.patch.yml` 移除,opt-in 的 [`core-web.cordis.yml`](../../../../apps/cli/config/core-web.cordis.yml) profile 中那条已悬空的 `disabled` patch 也随之删除,workspace 依赖也从 `apps/cli/package.json` 中移除。该消费方仍保持 opt-in,与面向模型的会话查询工具决策所述完全一致:ACP 示例的 [`session-query.cordis.yml`](../../../../examples/acp-agent/session-query.cordis.yml) 及其快照对侧文件仍是挂载参考,自定义组合也可以连同超时与 spill 策略一起挂载该包。
`ctx.sessionQuery` 服务本身保持挂载。`session-query-sqlite` 仍是 base 的一行,TUI 的 `session-reference` 消费它来实现 `/resume`,Web overlay 也继续把它 patch 成内存索引,供浏览器内容搜索使用。被移除的只有面向模型的消费方。