@deepseek-ai/dsh-client-ui-commands 0.1.1-rc.2 → 0.1.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-commands/README.md
5
- README.md: 7f1a54c99e4f9cf52af09e10b4c008b5c0f3e8da
6
- README.zh.md: c69790b6e690d1d0654b0ddd6e6cf657ccfec434
5
+ README.md: 0c1c3e8310177f3f26678afdf414baf2543e798d
6
+ README.zh.md: 8699f5b213d634c3ad06b3f48a4d6c1c1e16fbb4
package/README.md CHANGED
@@ -1,31 +1,91 @@
1
+ ---
2
+ description: "Client command API for the Web GUI: the / command source, three dispatch kinds, the per-session command directory, and popupSelect registration for business packages; for users and maintainers of slash commands."
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-client-ui-commands
2
7
 
3
8
  English | [中文](README.zh.md)
4
9
 
5
- Client command API (`ctx.commandUi`): the session-keyed command-directory cache, the `/` command source with `matchSpace`/`matchEnter` decision hooks, three-kind dispatch (`execute` / `popupSelect` / `leadingInput`), and popupSelect registration for business packages. The [web command Agent Note](../../../.agents/notes/implemented/architecture/2026-07-25-web-command-surfaces-and-assembly.md) records the decision.
10
+ ## Summary
11
+
12
+ Typing a `/` command in the composer opens the matching surface — a registered popup, a host command's input, or a direct execution — and a command line is never silently downgraded to a plain prompt. Business packages contribute command surfaces through `ctx.commandUi`, registering a popupSelect spec (`/model`, `/permission`) or decorating an existing host command with a picker while the host keeps its catalog row and argument claim. Space and Enter resolve the line against the session's directory: a host descriptor with `input` is `leadingInput`, a registered `CommandUiSpec` is `popupSelect`, and everything else is `execute`.
13
+
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Model Experience](#model-experience)
20
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
21
+ - [Dev Note](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## Use this package
27
+
28
+ Mount this plugin alongside `ui-input-trigger` and `ui-conversation`; the `/` source then appears in the trigger menu, and business packages register their command surfaces through `ctx.commandUi`. Typing `/model` opens the registered popup; a host command with an argument claim opens its input or executes directly.
29
+
30
+ ### Kinds and decorations
31
+
32
+ A contribution is a client-owned command — a host-name collision fails loud. A decoration adds a bare-invocation popup to an EXISTING host command: the host command keeps its catalog row, its argument claim, and its lifecycle logging, and a decorated name with no host row in the session's directory never fires. Menu queries fuzzy-match ordered, case-insensitive subsequences of command names; prefixes rank first.
33
+
34
+ ### Image-carrying submissions
35
+
36
+ When the composer submits with image attachments, only a host command declaring `input.images` proceeds; every other command route throws the localized `imagesUnsupported` refusal, which renders as a transient toast while the draft and images stay in place — a command can never consume the text and strand the images.
6
37
 
7
- `src/client/contract.ts` is the fixed business contract: `CommandUiContract.register(name, spec)` and `decorate(name, spec)` are everything a business package consumes; `CommandUiSpec{options, onSelect}` keeps popup data self-contained — the shell component belongs to this package and business packages never see it. A contribution is a client-owned command (a host-name collision fails loud); a decoration adds a bare-invocation popup to an EXISTING host command. The host keeps its catalog row, argument claim (space / argued Enter), and lifecycle logging, and a decorated name with no host row in the session's directory never fires. Command kinds derive per dispatch, never per registration: a host descriptor with `input` is `leadingInput`, a registered `CommandUiSpec` is `popupSelect`, and everything else is `execute`.
38
+ -----
8
39
 
9
- `CommandDirectory` (`src/client/directory.ts`) is the one wire-derived cache, keyed by session. Ordinary sessions fetch through `command.list({sessionId})`, and the source's scope-birth `warm` hook prewarms the session's entry. Catalog-addressed continuable children resolve an empty command directory locally: `command.list` is Agent-bound, so prewarming it would activate a child merely to view persisted history. Entries are soft-invalidated by the forwarded `commands/change` owner event (old snapshots serve while the repull flies) and by forwarded `agent-preset/selected` for that one session (recomposing an agent registers nothing, so the registry-wide signal never fires for it), hard-invalidated by `connection/reset`, and epoch-guarded so a superseded pull can never overwrite a newer one. `matchSpace` answers synchronously from this cache only; `matchEnter` strong-waits it on the SubmitAttempt signal and rejects on warmup failure — a `/` line is never silently downgraded to a plain prompt.
40
+ <a id="understand-the-implementation"></a>
41
+ ## Understand the implementation
10
42
 
11
- `matchEnter` also enforces the submission envelope: when the composer submits with image attachments, only a host command declaring `input.images` proceeds (its claim carries `images: true` and its submit forwards the serialized payloads to `command.execute`); every other command route — contribution popup, decorated popup, non-declaring claim, bare detached execute — throws the localized `notice.imagesUnsupported` refusal, which the input machine publishes as one error notice and the composer renders as a transient Toast banner with the draft and images retained. An image-carrying submit whose host handler answers an error result maps to an error outcome so the composer keeps the images; imageless submits keep the plain success mapping because the durable flow node owns the outcome rendering.
43
+ <details>
44
+ <summary>Implementation internals — click to expand</summary>
12
45
 
13
- After `command.execute` returns a matched command result, this browser emits local `command/executed(sessionId, name, result)`. Other clients receive the durable command nodes through the Host event stream but never this acknowledgment, so a browser-only side effect can select successful results from the client that submitted the command without treating Session replay as an action request. Listener failures are logged and contained one by one; they cannot change the already-admitted command result or prevent later listeners from running.
46
+ `src/client/contract.ts` is the fixed business contract: `CommandUiContract.register(name, spec)` and `decorate(name, spec)` are everything a business package consumes. `CommandDirectory` is the one wire-derived cache, keyed by session: ordinary sessions fetch through `command.list({sessionId})`, entries are soft-invalidated by the forwarded `commands/change` owner event and hard-invalidated by `connection/reset`, and epoch-guarded so a superseded pull can never overwrite a newer one. `matchSpace` answers synchronously from this cache only; `matchEnter` strong-waits it on the SubmitAttempt signal and rejects on warmup failure. After `command.execute` returns a matched result, the browser emits a local `command/executed` acknowledgment; other clients receive the durable command nodes through the Host event stream but never this acknowledgment. `PopupSelectController` is the headless shell state; `PopupSelectView` self-registers into `conversation.input.overlay` with per-session resolution. Decision record: the [web command surfaces note](../../../.agents/notes/implemented/architecture/2026-07-25-web-command-surfaces-and-assembly.md); the [fuzzy discovery note](../../../.agents/notes/implemented/feature/2026-08-04-web-slash-command-fuzzy-discovery.md) covers menu ranking.
14
47
 
15
- Menu queries fuzzy-match ordered, case-insensitive subsequences of command names. Prefixes rank first; separator boundaries, adjacent characters, and shorter gaps rank the remaining matches, with directory and contribution order breaking ties. This affects discovery only: space and Enter still require an exact command name. Rationale: [Web slash-command fuzzy discovery](../../../.agents/notes/implemented/feature/2026-08-04-web-slash-command-fuzzy-discovery.md).
48
+ </details>
16
49
 
17
- `PopupSelectController` (`src/client/popup.ts`) is the headless shell state: `PopupSelectView` self-registers into `conversation.input.overlay` (the SlotMap key is ui-conversation's; this package pulls the declaration in with a type-only import — no runtime edge). The shell is a transient layer holding focus while open; token-segment consumption after onSelect runs both branches through `consumeTokenSegment` (menu-path span CAS, enter-path bare-token equality) against the draft face the wiring layer binds via `bindDraft`.
50
+ -----
18
51
 
19
- The `/client` entrypoint exports the plugin body (`apply`/`inject`), `CommandUiRuntime`, the directory and popup classes with their state types, and the fixed contract types; the shell component itself is internal to the overlay registration.
52
+ <a id="further-exploration"></a>
53
+ ## Further Exploration
20
54
 
55
+ Read these pages when the command surface is not enough. They move from the command API to the trigger pipeline and the host command registry.
56
+
57
+ - [ui-input-trigger](../ui-input-trigger/README.md) — the pipeline the `/` source registers into.
58
+ - [ui-conversation](../ui-conversation/README.md) — declares the input overlay slot and owns the composer.
59
+ - [Web command surfaces and assembly](../../../.agents/notes/implemented/architecture/2026-07-25-web-command-surfaces-and-assembly.md) — the design decision behind the command surfaces.
60
+ - [Web slash-command fuzzy discovery](../../../.agents/notes/implemented/feature/2026-08-04-web-slash-command-fuzzy-discovery.md) — the menu ranking rationale.
61
+ - [Client package map](../README.md) — adjacent browser UI packages.
62
+
63
+ -----
64
+
65
+ <a id="model-experience"></a>
21
66
  ## Model Experience
22
67
 
23
- Indirectly, through the host `command.execute` RPC this package's dispatch and `claim.submit` paths trigger: a matched command's handler mutates host domain state that other packages project into the next request (the `/plan` handler flips plan mode, whose owning package injects its `plan:policy` system-prompt section), while the command line itself, the detached result, and every menu/notice rendering stay client-side and never enter the session log.
68
+ Indirectly, through the host `command.execute` RPC the dispatch paths trigger: each command handler's host package owns any model-visible effect (the `/plan` handler flips plan mode, whose owning package injects its policy section), while the command line, the detached result, and every menu and notice rendering stay client-side and never enter the session log.
24
69
 
25
70
  #### KV Cache effect
26
71
 
27
- None directly; this package neither assembles nor sends a provider request. Command handlers it triggers may change what the owning host packages contribute to the next request's system prompt (a section appearing or disappearing replaces earlier request tokens and invalidates the provider prefix from that point), but that effect is owned and documented by each command's host package.
72
+ None directly; this package neither assembles nor sends a provider request. Command handlers it triggers may change what the owning host packages contribute to the next request's system prompt a section appearing or disappearing replaces earlier request tokens and invalidates the provider prefix from that point but that effect is owned and documented by each command's host package.
28
73
 
29
74
  ## Known Limitations and Deferred Work
30
75
 
76
+ <a id="known-limitations-and-deferred-work"></a>
77
+
78
+
79
+ These limits define the current command surface. They are current package constraints, not a general command-line comparison or a task backlog.
80
+
31
81
  - **Detached-result notices fall back to the console off-session** — the fire-and-forget paths route results to the triggering session's composer via `SessionInput.notify`; after session teardown the console line is the only remaining surface.
82
+
83
+ <a id="dev-note"></a>
84
+ ### Dev Note
85
+
86
+ <details>
87
+ <summary>Working context for maintainers — click to expand</summary>
88
+
89
+ None.
90
+
91
+ </details>
package/README.zh.md CHANGED
@@ -1,31 +1,91 @@
1
+ ---
2
+ description: "Web GUI 的客户端命令 API:/ 命令 source、三类派发、会话级命令目录,以及面向业务包的 popupSelect 注册;供斜杠命令的用户与维护者阅读。"
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-client-ui-commands
2
7
 
3
8
  [English](README.md) | 中文
4
9
 
5
- 客户端命令 API(`ctx.commandUi`):以会话为 key 的命令目录缓存、带 `matchSpace`/`matchEnter` 决策钩子的 `/` 命令 source、三类派发(`execute`/`popupSelect`/`leadingInput`),以及面向业务包的 popupSelect 注册。[Web 命令 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-25-web-command-surfaces-and-assembly.zh.md) 记录了这项决策。
10
+ ## 概述
11
+
12
+ 在 composer 中键入 `/` 命令会打开匹配的表面——已注册的弹窗、宿主命令的输入或直接执行——命令行绝不会被静默降级为普通提示词。业务包经 `ctx.commandUi` 贡献命令表面:注册 popupSelect 贡献项(`/model`、`/permission`),或用选择器装饰既有宿主命令,宿主保留其目录行与参数声明。空格与回车对照会话目录解析命令行:带 `input` 的宿主描述符是 `leadingInput`,注册了 `CommandUiSpec` 的是 `popupSelect`,其余全部是 `execute`。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
27
+
28
+ 与 `ui-input-trigger` 及 `ui-conversation` 一起挂载本插件;`/` source 随即出现在触发菜单中,业务包经 `ctx.commandUi` 注册自己的命令表面。键入 `/model` 打开已注册的弹窗;带参数声明的宿主命令打开其输入或直接执行。
29
+
30
+ ### 种类与装饰
31
+
32
+ 贡献项是客户端自有命令——与宿主命令同名会明确报错。装饰为**已存在的**宿主命令添加裸调用弹窗:宿主命令保留其目录行、参数声明与生命周期记账,被装饰的名字在会话目录中无宿主行时永不触发。菜单查询按顺序且不区分大小写地模糊匹配命令名的子序列;前缀排名最高。
33
+
34
+ ### 带图提交
35
+
36
+ composer 携带图片附件提交时,只有声明了 `input.images` 的宿主命令继续;其余每条命令路径都会抛出本地化的 `imagesUnsupported` 拒绝,以瞬态 toast 呈现,草稿与图片保持原位——命令绝不消费文本却抛下图片。
6
37
 
7
- `src/client/contract.ts` 是固定的业务 API 约定:`CommandUiContract.register(name, spec)` 与 `decorate(name, spec)` 是业务包消费的全部内容;`CommandUiSpec{options, onSelect}` 自己提供 popup 数据——外层组件归本包所有,业务包永远见不到它。贡献项是客户端自有命令(与 host 命令同名时会明确报错);装饰项则为**已存在的** host 命令添加裸调用 popup。host 保留目录行、带参 claim(空格/带参数的 Enter)与生命周期记账,被装饰的名字若在会话目录中无 host 行,则永不触发。命令类型按每次派发派生,绝不在注册时定型:带 `input` 的 host descriptor 是 `leadingInput`,注册了 `CommandUiSpec` 的是 `popupSelect`,其余全部是 `execute`。
38
+ -----
8
39
 
9
- `CommandDirectory`(`src/client/directory.ts`)是唯一的 wire 派生缓存,以会话为 key。普通会话通过 `command.list({sessionId})` 拉取,source 的 scope 出生 `warm` 钩子会预热该会话的缓存项。由目录寻址的可继续子代理会在客户端解析为空命令目录:`command.list` 绑定 Agent,若预热它,就会仅因查看持久化历史而激活子代理。缓存项由转发的 owner 事件 `commands/change` 软失效(重拉在途期间旧快照继续服务),也由转发的 `agent-preset/selected` 对该会话单独软失效(重组 agent 不产生任何注册,注册表级信号不会为它触发),由 `connection/reset` 硬失效,并以 epoch 把关,被取代的旧拉取永远无法覆盖更新的结果。`matchSpace` 只凭该缓存同步应答;`matchEnter` 在 SubmitAttempt 信号上强等缓存,预热失败即拒绝——`/` 开头的一行绝不会被静默降级为普通提示词。
40
+ <a id="understand-the-implementation"></a>
41
+ ## 理解实现
10
42
 
11
- `matchEnter` 还强制执行提交信封:composer 携带图片附件提交时,只有声明了 `input.images` 的宿主命令继续(其 claim 携带 `images: true`,其 submit 把序列化载荷转交 `command.execute`);其余每条命令路径——contribution 弹窗、decoration 弹窗、未声明的 claim、bare 分离执行——都会抛出本地化的 `notice.imagesUnsupported` 拒绝,输入状态机发布一条错误通知,composer 以瞬态 Toast 横幅呈现它,草稿与图片原样保留。带图提交若宿主处理器返回错误结果,则映射为错误 outcome,composer 保留图片;不带图的提交维持原有的一律成功映射,因为结果呈现由持久化 flow 节点负责。
43
+ <details>
44
+ <summary>实现细节——点击展开</summary>
12
45
 
13
- `command.execute` 返回已匹配的命令结果后,当前浏览器会发布本地 `command/executed(sessionId, name, result)`。其他客户端只会通过 Host 事件流收到持久命令节点,不会收到这条确认,因此浏览器专属副作用可以筛选由实际提交命令的客户端收到的成功结果,而不会把 Session 回放当成操作请求。监听器失败会逐项记录并隔离,不会改变已经准入的命令结果,也不会阻止后续监听器运行。
46
+ `src/client/contract.ts` 是固定的业务约定:`CommandUiContract.register(name, spec)` 与 `decorate(name, spec)` 是业务包消费的全部内容。`CommandDirectory` 是唯一的 wire 派生缓存,以会话为 key:普通会话经 `command.list({sessionId})` 拉取;条目由转发的 `commands/change` owner 事件软失效、由 `connection/reset` 硬失效,并以 epoch 把关,被取代的旧拉取永远无法覆盖更新的结果。`matchSpace` 只凭该缓存同步应答;`matchEnter` 在 SubmitAttempt 信号上强等缓存,预热失败即拒绝。`command.execute` 返回匹配结果后,浏览器发布本地 `command/executed` 确认;其他客户端经宿主事件流收到持久命令节点,但收不到这条确认。`PopupSelectController` 是不含界面的外壳状态;`PopupSelectView` 自注册进 `conversation.input.overlay`,按会话解析。决策记录:[Web 命令表面笔记](../../../.agents/notes/implemented/architecture/2026-07-25-web-command-surfaces-and-assembly.zh.md);[模糊发现笔记](../../../.agents/notes/implemented/feature/2026-08-04-web-slash-command-fuzzy-discovery.zh.md) 说明菜单排名。
14
47
 
15
- 菜单查询会按顺序且不区分大小写地模糊匹配命令名的子序列。前缀排名最高;其余匹配项按分隔符边界优先、相邻字符优先、间隔越短越优先的规则排序,若仍同分,则以目录顺序和贡献项顺序打破平局。此行为只影响命令发现:space 和 Enter 仍要求命令名精确匹配。原理:[Web 斜杠命令模糊发现](../../../.agents/notes/implemented/feature/2026-08-04-web-slash-command-fuzzy-discovery.zh.md)。
48
+ </details>
16
49
 
17
- `PopupSelectController`(`src/client/popup.ts`)是不含界面的外壳状态:`PopupSelectView` 自行注册进 `conversation.input.overlay`(SlotMap key 归 ui-conversation 所有;本包只以 type-only 导入引入该声明——没有运行时依赖边)。壳是打开期间持有焦点的瞬态层;onSelect 之后的 token 片段消费在两条分支上都经 `consumeTokenSegment` 执行(菜单路径做 span CAS,回车路径做裸 token 相等比较),作用于接线层经 `bindDraft` 绑定的草稿表层。
50
+ -----
18
51
 
19
- `/client` 入口导出插件主体(`apply`/`inject`)、`CommandUiRuntime`、目录类和 popup 类及其状态类型,以及固定的约定类型;外层组件本身是 overlay 注册的内部实现。
52
+ <a id="further-exploration"></a>
53
+ ## 进一步探索
20
54
 
55
+ 当命令面不够用时阅读以下页面。它们从命令 API 进入触发流水线与宿主命令注册表。
56
+
57
+ - [ui-input-trigger](../ui-input-trigger/README.zh.md)——`/` source 注册进的流水线。
58
+ - [ui-conversation](../ui-conversation/README.zh.md)——声明输入浮层槽位并拥有 composer。
59
+ - [Web 命令表面与组装](../../../.agents/notes/implemented/architecture/2026-07-25-web-command-surfaces-and-assembly.zh.md)——命令表面背后的设计决策。
60
+ - [Web 斜杠命令模糊发现](../../../.agents/notes/implemented/feature/2026-08-04-web-slash-command-fuzzy-discovery.zh.md)——菜单排名的原理。
61
+ - [客户端包映射](../README.zh.md)——相邻的浏览器 UI 包。
62
+
63
+ -----
64
+
65
+ <a id="model-experience"></a>
21
66
  ## 模型体验
22
67
 
23
- 间接影响,途径是本包的派发与 `claim.submit` 路径触发的 host `command.execute` RPC:匹配命中的命令,其 handler 会修改 host 领域状态,其他包再把该状态投影进下一个请求(`/plan` 的 handler 翻转 plan 模式,其归属包注入 `plan:policy` 系统提示词 section),而命令行本身、detached result 与所有菜单/notice 渲染都留在客户端,永不进入会话日志。
68
+ 间接影响,经由派发路径触发的宿主 `command.execute` RPC:每个命令 handler 的宿主包拥有任何模型可见效果(`/plan` 的 handler 翻转 plan 模式,其归属包注入 policy 段),而命令行、分离结果与所有菜单和 notice 渲染都留在客户端,永不进入会话日志。
24
69
 
25
70
  #### KV Cache 影响
26
71
 
27
- 无直接影响;该包既不组装也不发送提供方请求。它触发的命令 handler 可能改变归属 host 包对下一个请求系统提示词的贡献(某个 section 的出现或消失会替换较早的请求 token,并使提供方前缀从该点起失效),但这一影响由各命令的 host 包拥有并记录。
72
+ 无直接影响;该包既不组装也不发送提供方请求。它触发的命令 handler 可能改变归属宿主包对下一个请求系统提示词的贡献——某个 section 的出现或消失会替换较早的请求 token,并使提供方前缀从该点起失效——但这一影响由各命令的宿主包拥有并记录。
73
+
74
+ ## 已知限制与延期工作
75
+
76
+ <a id="known-limitations-and-deferred-work"></a>
77
+
78
+
79
+ 这些限制界定了当前命令表面。它们是当前包约束,不是通用命令行对比或任务积压。
80
+
81
+ - **脱离会话后,分离结果 notice 回退到 console**——fire-and-forget 路径经 `SessionInput.notify` 把结果送到触发会话的 composer;会话销毁后,console 输出行是仅剩的呈现面。
82
+
83
+ <a id="dev-note"></a>
84
+ ### 开发备注
85
+
86
+ <details>
87
+ <summary>维护者的工作上下文——点击展开</summary>
28
88
 
29
- ## 已知限制与暂缓事项
89
+ 无。
30
90
 
31
- - **脱离会话后,detached result 的 notice 回退到 console**:fire-and-forget 路径经 `SessionInput.notify` 把结果送到触发会话的 composer;会话销毁后,console 输出行是仅剩的呈现面。
91
+ </details>
package/lib/client.js CHANGED
@@ -5,7 +5,7 @@ window.__ModuleLoader__.load({
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let _deepseek_ai_cordis = require("@deepseek-ai/cordis");
8
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
8
+ let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
9
9
  let react_jsx_runtime = require("react/jsx-runtime");
10
10
  let react = require("react");
11
11
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
@@ -50,6 +50,17 @@ window.__ModuleLoader__.load({
50
50
  for (const key of this.entries.keys()) this.refresh(key);
51
51
  }
52
52
  /**
53
+ * Drop one Session's obsolete composition-specific snapshot and prewarm its replacement.
54
+ * @param sessionId - Session whose effective command composition changed.
55
+ */
56
+ resetSession(sessionId) {
57
+ const entry = this.entry(sessionId);
58
+ entry.state = "cold";
59
+ entry.commands = [];
60
+ entry.lastError = void 0;
61
+ this.refresh(sessionId);
62
+ }
63
+ /**
53
64
  * Hard reset on reconnect: every entry drops its snapshot (the agent world
54
65
  * may have changed shape across the generation) and prewarms.
55
66
  */
@@ -197,7 +208,7 @@ window.__ModuleLoader__.load({
197
208
  var PopupSelectController = class {
198
209
  deps;
199
210
  /** Shell state store (the overlay component subscribes here). */
200
- state = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(CLOSED);
211
+ state = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(CLOSED);
201
212
  binding = null;
202
213
  /**
203
214
  * @param deps - session-wiring callbacks (token consumption + composer focus).
@@ -534,7 +545,7 @@ window.__ModuleLoader__.load({
534
545
  this.directory.invalidateAll();
535
546
  });
536
547
  ctx.remote.$on("agent-preset/selected", (sessionId) => {
537
- this.directory.refresh(sessionId);
548
+ this.directory.resetSession(sessionId);
538
549
  });
539
550
  ctx.on("connection/reset", () => {
540
551
  this.directory.resetConnected();
@@ -772,7 +783,7 @@ window.__ModuleLoader__.load({
772
783
  * the outcome renders as a persistent flow node — the composer never
773
784
  * echoes it. A handler error result reports an error outcome so the
774
785
  * composer keeps the submission (draft and images) for correction.
775
- * Transport failures throw.
786
+ * A refused call throws.
776
787
  */
777
788
  async execute(session, line, images = []) {
778
789
  const result = await this.ctx.remote.commands.execute(session.sessionId, line, images);
@@ -814,9 +825,9 @@ window.__ModuleLoader__.load({
814
825
  * Fire-and-forget execute for the internal ('handled') paths. Outcomes are
815
826
  * NOT surfaced here: the host executor durably logs the command lifecycle
816
827
  * (`command/run`/`command/done`), and the mux-broadcast events render as a
817
- * persistent flow node on every tab. Only a transport/admission failure —
818
- * which never entered a handler and therefore never logged — falls back to
819
- * the composer notice as immediate feedback.
828
+ * persistent flow node on every tab. Only an admission failure — which never
829
+ * entered a handler and therefore never logged — falls back to the composer
830
+ * notice as immediate feedback.
820
831
  */
821
832
  runDetached(desc, session, line) {
822
833
  this.execute(session, line).then((outcome) => {
@@ -837,7 +848,7 @@ window.__ModuleLoader__.load({
837
848
  token: segment.token
838
849
  } });
839
850
  }
840
- /** Route an admission/transport failure to the session's composer notice channel (scope gone = attempt died with it). */
851
+ /** Route an admission failure to the session's composer notice channel (scope gone = attempt died with it). */
841
852
  noticeFor(id, level, text) {
842
853
  const actx = this.scopeFor(id);
843
854
  if (actx === void 0) return;
@@ -1050,6 +1061,7 @@ window.__ModuleLoader__.load({
1050
1061
  description: confirmation.description,
1051
1062
  acknowledgeLabel: confirmation.acknowledgeLabel,
1052
1063
  cancelLabel: confirmation.cancelLabel,
1064
+ closeLabel: t("close"),
1053
1065
  confirmLabel: confirmation.confirmLabel,
1054
1066
  acknowledged: state.acknowledged,
1055
1067
  onAcknowledgedChange: (value) => {
@@ -1117,7 +1129,7 @@ window.__ModuleLoader__.load({
1117
1129
  "sessions"
1118
1130
  ], (scope) => {
1119
1131
  const command = scope.commandUi;
1120
- const sessions = scope.sessions;
1132
+ const sessions = scope.get("sessions");
1121
1133
  scope.slots.inject("conversation.input.overlay", () => scope.slots.register({
1122
1134
  name: "conversation.input.overlay",
1123
1135
  id: "command-popup",
@@ -3,7 +3,7 @@
3
3
  * CommandUiRuntime (`ctx.commandUi`) implements this face; business packages
4
4
  * consume `register` alone.
5
5
  */
6
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
6
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
7
7
  import type { ClientSessionContext } from '@deepseek-ai/dsh-client-ui-input-trigger/client';
8
8
  /** Copy for an option that must be acknowledged before onSelect can run. */
9
9
  export interface SelectConfirmation {
@@ -6,7 +6,7 @@
6
6
  * is the only extra dimension.
7
7
  */
8
8
  import type { CommandDescriptor } from '@deepseek-ai/dsh-commands/types';
9
- import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client';
9
+ import type { SessionId } from '@deepseek-ai/dsh-session/types';
10
10
  export type { CommandDescriptor } from '@deepseek-ai/dsh-commands/types';
11
11
  /**
12
12
  * cold = never pulled; pending = pull in flight with nothing servable;
@@ -36,6 +36,11 @@ export declare class CommandDirectory {
36
36
  resolve(sessionId: SessionId, name: string): CommandDescriptor | undefined;
37
37
  /** Soft invalidation (commands-changed): background repull on every touched key; ready snapshots keep serving. */
38
38
  invalidateAll(): void;
39
+ /**
40
+ * Drop one Session's obsolete composition-specific snapshot and prewarm its replacement.
41
+ * @param sessionId - Session whose effective command composition changed.
42
+ */
43
+ resetSession(sessionId: SessionId): void;
39
44
  /**
40
45
  * Hard reset on reconnect: every entry drops its snapshot (the agent world
41
46
  * may have changed shape across the generation) and prewarms.
@@ -5,7 +5,7 @@
5
5
  * popupSelect shell self-registers into conversation.input.overlay with
6
6
  * per-session resolution.
7
7
  */
8
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
8
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
9
9
  import { CommandUiRuntime } from './service.ts';
10
10
  import { type CommandKey } from './locales.ts';
11
11
  export { CommandUiRuntime } from './service.ts';
@@ -1,4 +1,4 @@
1
- import type { SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
2
2
  import type { TokenSpan } from '@deepseek-ai/dsh-client-ui-input-trigger/client';
3
3
  import type { SelectOption } from './contract.ts';
4
4
  /**
@@ -10,7 +10,8 @@
10
10
  import { Service } from '@deepseek-ai/cordis';
11
11
  import type { Context } from '@deepseek-ai/cordis';
12
12
  import type { CommandResult } from '@deepseek-ai/dsh-commands/types';
13
- import type { ClientContext, SessionId } from '@deepseek-ai/dsh-client-runtime/client';
13
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
14
+ import type { SessionId } from '@deepseek-ai/dsh-session/types';
14
15
  import type { ClientSessionContext } from '@deepseek-ai/dsh-client-ui-input-trigger/client';
15
16
  import type { CommandContribution, CommandDecoration, CommandUiContract } from './contract.ts';
16
17
  import { PopupSelectController } from './popup.ts';
@@ -104,7 +105,7 @@ export declare class CommandUiRuntime extends Service implements CommandUiContra
104
105
  * the outcome renders as a persistent flow node — the composer never
105
106
  * echoes it. A handler error result reports an error outcome so the
106
107
  * composer keeps the submission (draft and images) for correction.
107
- * Transport failures throw.
108
+ * A refused call throws.
108
109
  */
109
110
  private execute;
110
111
  /** Publish the local acknowledgment without letting an observer change command admission. */
@@ -115,14 +116,14 @@ export declare class CommandUiRuntime extends Service implements CommandUiContra
115
116
  * Fire-and-forget execute for the internal ('handled') paths. Outcomes are
116
117
  * NOT surfaced here: the host executor durably logs the command lifecycle
117
118
  * (`command/run`/`command/done`), and the mux-broadcast events render as a
118
- * persistent flow node on every tab. Only a transport/admission failure —
119
- * which never entered a handler and therefore never logged — falls back to
120
- * the composer notice as immediate feedback.
119
+ * persistent flow node on every tab. Only an admission failure — which never
120
+ * entered a handler and therefore never logged — falls back to the composer
121
+ * notice as immediate feedback.
121
122
  */
122
123
  private runDetached;
123
124
  /** Dispatch a consume-token event to one session (menu-pick / bare-enter execute paths). */
124
125
  private consumeVia;
125
- /** Route an admission/transport failure to the session's composer notice channel (scope gone = attempt died with it). */
126
+ /** Route an admission failure to the session's composer notice channel (scope gone = attempt died with it). */
126
127
  private noticeFor;
127
128
  /** id → actx interchange (registered exchange point: this service coordinates for projection-only sources). */
128
129
  private scopeFor;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-commands",
3
3
  "description": "Client command surface: global directory cache, '/' source, three command UI kinds, popupSelect registry",
4
- "version": "0.1.1-rc.2",
4
+ "version": "0.1.2-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -33,7 +33,6 @@
33
33
  "client": {
34
34
  "inject": [
35
35
  "@deepseek-ai/dsh-api-remotes",
36
- "@deepseek-ai/dsh-client-runtime",
37
36
  "@deepseek-ai/dsh-client-locale",
38
37
  "@deepseek-ai/dsh-client-ui-input-trigger",
39
38
  "@deepseek-ai/dsh-client-ui-conversation"
@@ -46,30 +45,27 @@
46
45
  "clsx": "^2.0.0"
47
46
  },
48
47
  "peerDependencies": {
49
- "@deepseek-ai/dsh-api-remotes": "^0.1.1-rc.2",
50
- "@deepseek-ai/dsh-client-locale": "^0.1.1-rc.2",
51
- "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
52
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.1-rc.2",
53
- "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.1-rc.2",
54
- "@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
55
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
56
- "@deepseek-ai/cordis": "^4.0.1"
48
+ "@deepseek-ai/cordis": "^4.0.2"
57
49
  },
58
50
  "devDependencies": {
59
51
  "@types/react": "~18.3.1",
60
52
  "react": "^18.2.0",
61
- "@deepseek-ai/dsh-client-connection": "^0.1.1-rc.2",
62
- "@deepseek-ai/dsh-client-locale": "^0.1.1-rc.2",
63
- "@deepseek-ai/dsh-api-remotes": "^0.1.1-rc.2",
64
- "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
65
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.1-rc.2",
66
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.1-rc.2",
67
- "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.1-rc.2",
68
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.1-rc.2",
69
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.1-rc.2",
70
- "@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
71
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
72
- "@deepseek-ai/cordis": "^4.0.1"
53
+ "@deepseek-ai/dsh-client-connection": "^0.1.2-alpha.2",
54
+ "@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.2",
55
+ "@deepseek-ai/dsh-client-test-runtime": "^0.1.2-alpha.2",
56
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-alpha.2",
57
+ "@deepseek-ai/dsh-api-remotes": "^0.1.2-alpha.2",
58
+ "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.2-alpha.2",
59
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.2",
60
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-alpha.2",
61
+ "@deepseek-ai/cordis": "^4.0.2",
62
+ "@deepseek-ai/dsh-client-store": "^0.1.2-alpha.2",
63
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.2-alpha.2",
64
+ "@deepseek-ai/dsh-commands": "^0.1.2-alpha.2",
65
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-alpha.2",
66
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.2-alpha.2",
67
+ "@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
68
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2"
73
69
  },
74
70
  "files": [
75
71
  "lib/index.js",