dsh-working-activity 0.2.0 → 0.2.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/LICENSE CHANGED
@@ -1,28 +1,28 @@
1
- BSD 3-Clause License
2
-
3
- Copyright (c) 2026, chimney (ccch1mneyyy)
4
-
5
- Redistribution and use in source and binary forms, with or without
6
- modification, are permitted provided that the following conditions are met:
7
-
8
- 1. Redistributions of source code must retain the above copyright notice, this
9
- list of conditions and the following disclaimer.
10
-
11
- 2. Redistributions in binary form must reproduce the above copyright notice,
12
- this list of conditions and the following disclaimer in the documentation
13
- and/or other materials provided with the distribution.
14
-
15
- 3. Neither the name of the copyright holder nor the names of its
16
- contributors may be used to endorse or promote products derived from
17
- this software without specific prior written permission.
18
-
19
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, chimney (ccch1mneyyy)
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -1,120 +1,122 @@
1
- # dsh-working-activity
2
-
3
- A live "working line" for DeepSeek Harness: the model's real-time activity — playful thinking copy, the tool actually running, elapsed time, and a turn-end summary — shown while the agent works.
4
-
5
- ## What it does
6
-
7
- Folds the durable session stream (`turn/start`, `assistant/chunk`, `tool/call`, `tool/result`, `turn/end`) plus `agent/status` into one status line, refreshed on a render tick:
8
-
9
- - **Thinking**: short colloquial copy rotates every few seconds (`嗯…让我捋捋`, `盘一下盘一下`, `大脑转起来了`, deadpan `lol` / `hm` / `ok`), tiered when thinking runs long (30s / 1min / 5min), night-owl copy mixed in between 00:00–06:00 local time.
10
- - **Tool activity**: the running tool renders as `俏皮动词 + 参数细节 + 已耗时` (`跑个命令 npm test · 12s`); failed tools show `翻车了`-style copy in the done line.
11
- - **Turn summary**: on `turn/end` the line becomes `搞定 ✓ · N 工具 · 想Xs 干Ys` (thinking/tool split), with the last tool's fragment pinned for a few seconds.
12
- - **Minimal mode**: `phrases: false` renders plain functional labels (`思考中 · 总1m23s`, `bash npm test · 12s`).
13
-
14
- Two optional sinks, both off by default only when their seam is absent:
15
-
16
- 1. **TUI prompt slot** — registers the `${activity}` template value on `ctx.tuiPrompt` when the TUI is composed. Add `${activity}` to `theme.leftPrompt` to see it next to `cwd`/`model`/`context`.
17
- 2. **Session events** — appends log-only `activity/status` events (never surface events: the model never sees them) for Web and other UI consumers; replay ignores them.
18
-
19
- ## Installation
20
-
21
- The package is a self-mounting bundle: it declares `dsh.bundle.patch`
22
- (`cordis.patch.yml`), so the official CLI both installs it and appends it to
23
- the profile's bundle layer stack:
24
-
25
- ```sh
26
- dsh plugin --profile <profile> add dsh-working-activity
27
- ```
28
-
29
- At boot, app-boot applies the bundle's patch list over the profile root and
30
- the package inserts its own `working-activity` row — no manual configuration
31
- required. To tune a value, override the row's config by id in the profile's
32
- user layer (`$DSH_HOME/profiles/<profile>/cordis.patch.yml`) instead of
33
- inserting a second same-id row:
34
-
35
- ```yaml
36
- - id: working-activity
37
- config:
38
- publishIntervalMs: 500
39
- ```
40
-
41
- ## TUI usage
42
-
43
- Install the plugin into a profile that composes the official `dsh-tui`, then
44
- add the `${activity}` slot to the left prompt template in the profile's user
45
- layer (`$DSH_HOME/profiles/<profile>/cordis.patch.yml`):
46
-
47
- ```yaml
48
- - id: tui
49
- config:
50
- theme:
51
- leftPrompt: '${cwd}${git/worktree}${activity}${model}${token_meter/cache_hit_rate}${context}'
52
- ```
53
-
54
- While a turn runs, the prompt line shows e.g. `dsh main 跑个命令 npm test · 12s deepseek-chat …`; while thinking, `嗯…让我捋捋 · 总1m23s`; after the turn, `搞定 ✓ · 4 工具 · 想12s 干11s` briefly. Without `${activity}` in the template, the plugin is inert in the TUI (the slot is unregistered values are omitted by the template renderer).
55
-
56
- ## Web usage
57
-
58
- The Web client renders the live line two ways, both fed by the `activity/status` events:
59
-
60
- - The turn-level status label (`TurnStatus`, formerly the static "Deep diving...") shows the live line while a turn runs, keeping its sweep animation.
61
- - A working-line dock entry (`WorkingLine` on `conversation.input.dock`) renders the turn-end statistics (token/elapsed/tool summary) above the composer after a turn settles; live phases stay on the turn label.
62
-
63
- Both fall back to the previous static label while the plugin is absent, so the Web UI is unaffected by disabling it.
64
-
65
- ## Configuration
66
-
67
- | Key | Type | Default | Meaning |
68
- |---|---|---|---|
69
- | `phrases` | `boolean` | `true` | Playful copy pool; `false` renders plain functional labels |
70
- | `publish` | `boolean` | `true` | Append `activity/status` session events for UI consumers |
71
- | `tickMs` | `number` | `500` | Status render tick interval (100–5000) |
72
- | `publishIntervalMs` | `number` | `2000` | Minimum interval between published events while the line is stable (500–30000) |
73
- | `detailLimit` | `number` | `40` | Max displayed detail length (paths/commands/patterns), 8–120 |
74
- | `customActions` | `object` | `{}` | Exact tool-name → action-copy pools, e.g. `{"my_deploy": ["部署一下", "上线中"]}` |
75
- | `narrate` | `boolean` | `true` | Inject the `⏵` self-narration contract into the system prompt; the line is surfaced live and stripped from the chat body |
76
-
77
- ## Event contract
78
-
79
- `activity/status` is a log-only session event (merge-extensible `SessionEventMap` member, no `surfaceOp`):
80
-
81
- ```ts
82
- {
83
- phase: 'idle' | 'waiting' | 'thinking' | 'tool' | 'done'
84
- line: string // plain-text status line, no ANSI
85
- label?: string // current work label (tool action / stage)
86
- detail?: string // path / command / pattern fragment
87
- phrase?: string // current playful phrase
88
- toolCount: number // tools completed this turn
89
- turnElapsedMs: number // ms since turn start
90
- phaseStartedAt: number // epoch ms the phase started (animation anchor)
91
- }
92
- ```
93
-
94
- Publishing rules: line changes publish immediately; a stable line republishes at most every `publishIntervalMs` so a long tool's elapsed time stays live without flooding the log. All data is lossless JSON; optional fields are omitted when absent.
95
-
96
- ## Export shape
97
-
98
- A function/namespace plugin: `name` / `Config` / `apply`, no default export. The state machine (`ActivityTracker`) and copy pools live in `./status` and `./phrases` (pure, clock-injected, unit-tested). The invariant companion registers under `./invariant`.
99
-
100
- ## Model Experience
101
-
102
- ### Prompt and tool surface
103
-
104
- Nothing. The plugin injects no prompt sections, registers no tools, and appends no surface events. `activity/status` is UI state only: it never enters derived model history, so the model cannot see its own working line.
105
-
106
- ### Token effect
107
-
108
- Zero per request.
109
-
110
- ### KV Cache effect
111
-
112
- No system-prompt contribution, so no cache-stability effect.
113
-
114
- ## Known Limitations and Deferred Work
115
-
116
- - **Single active line**: the plugin keeps one status line per session; the TUI slot shows the most recently active session.
117
- - **Narration is opt-in**: the `⏵` self-narration contract (model writes a short status line at the top of each reply) is injected by default (`narrate: true`); set `narrate: false` for a purely event-derived line.
118
- - **No progress percentages**: DSH has no tool progress events; a long tool shows elapsed time only.
119
- - **No animated frames**: the TUI slot renders a static text fragment; frame animation (moon/comet/braille presets) is deferred until the prompt-slot contract supports a frame callback.
120
- - **Web dock entry duplicates the turn label**: the input-dock `WorkingLine` and the chat `TurnStatus` show the same snapshot; the dock entry exists for session views where the turn label is not visible.
1
+ # dsh-working-activity
2
+
3
+ A live "working line" for DeepSeek Harness: the model's real-time activity — playful thinking copy, the tool actually running, elapsed time, and a turn-end summary — shown while the agent works.
4
+
5
+ ## What it does
6
+
7
+ Folds the durable session stream (`turn/start`, `assistant/chunk`, `tool/call`, `tool/result`, `turn/end`) plus `agent/status` into one status line, refreshed on a render tick:
8
+
9
+ - **Thinking**: short colloquial copy rotates every few seconds (`嗯…让我捋捋`, `盘一下盘一下`, `大脑转起来了`, deadpan `lol` / `hm` / `ok`), tiered when thinking runs long (30s / 1min / 5min), night-owl copy mixed in between 00:00–06:00 local time.
10
+ - **Tool activity**: the running tool renders as `俏皮动词 + 参数细节 + 已耗时` (`跑个命令 npm test · 12s`); failed tools show `翻车了`-style copy in the done line.
11
+ - **Turn summary**: on `turn/end` the line becomes `搞定 ✓ · N 工具 · 想Xs 干Ys` (thinking/tool split), with the last tool's fragment pinned for a few seconds.
12
+ - **Minimal mode**: `phrases: false` renders plain functional labels (`思考中 · 总1m23s`, `bash npm test · 12s`).
13
+
14
+ Two optional sinks, both off by default only when their seam is absent:
15
+
16
+ 1. **TUI prompt slot** — registers the `${activity}` template value on `ctx.tuiPrompt` when the TUI is composed. Add `${activity}` to `theme.leftPrompt` to see it next to `cwd`/`model`/`context`.
17
+ 2. **Session events** — appends log-only `activity/status` events (never surface events: the model never sees them) for Web and other UI consumers; replay ignores them.
18
+
19
+ ## Installation
20
+
21
+ The package is a self-mounting bundle: it declares `dsh.bundle.patch`
22
+ (`cordis.patch.yml`), so the official CLI both installs it and appends it to
23
+ the profile's bundle layer stack:
24
+
25
+ ```sh
26
+ dsh plugin --profile <profile> add dsh-working-activity
27
+ ```
28
+
29
+ At boot, app-boot applies the bundle's patch list over the profile root and
30
+ the package inserts its own `working-activity` row — no manual configuration
31
+ required. To tune a value, override the row's config by id in the profile's
32
+ user layer (`$DSH_HOME/profiles/<profile>/cordis.patch.yml`) instead of
33
+ inserting a second same-id row:
34
+
35
+ ```yaml
36
+ - id: working-activity
37
+ config:
38
+ publishIntervalMs: 500
39
+ ```
40
+
41
+ ## TUI usage
42
+
43
+ Install the plugin into a profile that composes the official `dsh-tui`, then
44
+ add the `${activity}` slot to the left prompt template in the profile's user
45
+ layer (`$DSH_HOME/profiles/<profile>/cordis.patch.yml`):
46
+
47
+ ```yaml
48
+ - id: tui
49
+ config:
50
+ theme:
51
+ leftPrompt: '${cwd}${git/worktree}${activity}${model}${token_meter/cache_hit_rate}${context}'
52
+ ```
53
+
54
+ While a turn runs, the prompt line shows e.g. `dsh main 跑个命令 npm test · 12s deepseek-chat …`; while thinking, `嗯…让我捋捋 · 总1m23s`; after the turn, `搞定 ✓ · 4 工具 · 想12s 干11s` briefly. Without `${activity}` in the template, the plugin is inert in the TUI (the slot is unregistered values are omitted by the template renderer).
55
+
56
+ ## Web usage
57
+
58
+ The Web client renders the live line two ways, both fed by the `activity/status` events:
59
+
60
+ - The turn-level status label (`TurnStatus`, formerly the static "Deep diving...") shows the live line while a turn runs, keeping its sweep animation.
61
+ - A working-line dock entry (`WorkingLine` on `conversation.input.dock`) renders the turn-end statistics (token/elapsed/tool summary) above the composer after a turn settles; live phases stay on the turn label.
62
+
63
+ Both fall back to the previous static label while the plugin is absent, so the Web UI is unaffected by disabling it.
64
+
65
+ ## Configuration
66
+
67
+ | Key | Type | Default | Meaning |
68
+ |---|---|---|---|
69
+ | `phrases` | `boolean` | `true` | Playful copy pool; `false` renders plain functional labels |
70
+ | `publish` | `boolean` | `false` | Append `activity/status` session events for UI consumers. Off by default: appended events currently make session logs unresumable (see note below) |
71
+ | `tickMs` | `number` | `500` | Status render tick interval (100–5000) |
72
+ | `publishIntervalMs` | `number` | `2000` | Minimum interval between published events while the line is stable (500–30000) |
73
+ | `detailLimit` | `number` | `40` | Max displayed detail length (paths/commands/patterns), 8–120 |
74
+ | `customActions` | `object` | `{}` | Exact tool-name → action-copy pools, e.g. `{"my_deploy": ["部署一下", "上线中"]}` |
75
+ | `narrate` | `boolean` | `true` | Inject the `⏵` self-narration contract into the system prompt; the line is surfaced live and stripped from the chat body |
76
+
77
+ ## Event contract
78
+
79
+ `activity/status` is a log-only session event (merge-extensible `SessionEventMap` member, no `surfaceOp`):
80
+
81
+ ```ts
82
+ {
83
+ phase: 'idle' | 'waiting' | 'thinking' | 'tool' | 'done'
84
+ line: string // plain-text status line, no ANSI
85
+ label?: string // current work label (tool action / stage)
86
+ detail?: string // path / command / pattern fragment
87
+ phrase?: string // current playful phrase
88
+ toolCount: number // tools completed this turn
89
+ turnElapsedMs: number // ms since turn start
90
+ phaseStartedAt: number // epoch ms the phase started (animation anchor)
91
+ }
92
+ ```
93
+
94
+ > **Why `publish` is off by default:** `session.append()` cannot mark events ignorable, and the resume read path refuses any log containing unknown non-ignorable event types — so with `publish: true`, every session that rendered a status line fails to resume. Re-enable only for a log-replaying consumer on a harness that supports ignorable appends. The live TUI prompt line is unaffected.
95
+
96
+ Publishing rules: line changes publish immediately; a stable line republishes at most every `publishIntervalMs` so a long tool's elapsed time stays live without flooding the log. All data is lossless JSON; optional fields are omitted when absent.
97
+
98
+ ## Export shape
99
+
100
+ A function/namespace plugin: `name` / `Config` / `apply`, no default export. The state machine (`ActivityTracker`) and copy pools live in `./status` and `./phrases` (pure, clock-injected, unit-tested). The invariant companion registers under `./invariant`.
101
+
102
+ ## Model Experience
103
+
104
+ ### Prompt and tool surface
105
+
106
+ Nothing. The plugin injects no prompt sections, registers no tools, and appends no surface events. `activity/status` is UI state only: it never enters derived model history, so the model cannot see its own working line.
107
+
108
+ ### Token effect
109
+
110
+ Zero per request.
111
+
112
+ ### KV Cache effect
113
+
114
+ No system-prompt contribution, so no cache-stability effect.
115
+
116
+ ## Known Limitations and Deferred Work
117
+
118
+ - **Single active line**: the plugin keeps one status line per session; the TUI slot shows the most recently active session.
119
+ - **Narration is opt-in**: the `⏵` self-narration contract (model writes a short status line at the top of each reply) is injected by default (`narrate: true`); set `narrate: false` for a purely event-derived line.
120
+ - **No progress percentages**: DSH has no tool progress events; a long tool shows elapsed time only.
121
+ - **No animated frames**: the TUI slot renders a static text fragment; frame animation (moon/comet/braille presets) is deferred until the prompt-slot contract supports a frame callback.
122
+ - **Web dock entry duplicates the turn label**: the input-dock `WorkingLine` and the chat `TurnStatus` show the same snapshot; the dock entry exists for session views where the turn label is not visible.
package/README.zh.md CHANGED
@@ -58,7 +58,7 @@ Web 客户端通过 `activity/status` 事件以两种方式渲染实时状态行
58
58
  | 键 | 类型 | 默认值 | 含义 |
59
59
  |---|---|---|---|
60
60
  | `phrases` | `boolean` | `true` | 俏皮文案池;`false` 渲染朴素功能标签 |
61
- | `publish` | `boolean` | `true` | 为 UI 消费者追加 `activity/status` 会话事件 |
61
+ | `publish` | `boolean` | `false` | 为 UI 消费者追加 `activity/status` 会话事件。默认关闭:追加的事件目前会导致会话日志无法 resume(见下方说明) |
62
62
  | `tickMs` | `number` | `500` | 状态渲染 tick 间隔(50–5000) |
63
63
  | `publishIntervalMs` | `number` | `2000` | 状态行稳定时两次发布事件的最小间隔(500–30000) |
64
64
  | `detailLimit` | `number` | `40` | 详情最大展示长度(路径/命令/模式),8–120 |
@@ -82,6 +82,8 @@ Web 客户端通过 `activity/status` 事件以两种方式渲染实时状态行
82
82
  }
83
83
  ```
84
84
 
85
+ > **为什么 `publish` 默认关闭:** `session.append()` 无法把事件标记为 ignorable,而 resume 的读取路径会拒绝包含未知且不可忽略事件类型的日志——开启 `publish` 后,凡是显示过状态行的会话都会 resume 失败。仅在日志重放消费者、且 harness 支持 ignorable append 时再打开。TUI 实时状态行不受影响。
86
+
85
87
  发布规则:状态行变化立即发布;稳定行最多每 `publishIntervalMs` 重发一次,让长工具的已耗时保持实时而不刷爆日志。所有数据都是无损 JSON;可选字段缺省时省略。
86
88
 
87
89
  ## 导出形状
package/cordis.patch.yml CHANGED
@@ -1,19 +1,19 @@
1
- # dsh-working-activity bundle patch: mount the plugin itself into the
2
- # profile composition tree.
3
- #
4
- # `dsh plugin --profile <name> add dsh-working-activity` auto-initializes the
5
- # profile (first layer @deepseek-ai/dsh-base), pnpm-installs this package into
6
- # the profile, and the CLI's reconcile step appends it to the profile's
7
- # dsh.profile.bundles because this package.json declares `dsh.bundle.patch`.
8
- # At boot, app-boot applies every bundle's patch list in bundle order over the
9
- # empty root; this insert list is what actually mounts the working-activity
10
- # row — no manual configuration is needed.
11
- #
12
- # All row config stays at schema defaults (phrases/publish/tickMs/
13
- # publishIntervalMs/detailLimit/customActions/narrate). To tune a value (for
14
- # dsh-cc, set publishIntervalMs to 500), override this row's config by id in
15
- # the profile's own cordis.patch.yml user layer — do NOT insert a second
16
- # same-id row.
17
- - insert:
18
- - id: working-activity
19
- name: 'dsh-working-activity'
1
+ # dsh-working-activity bundle patch: mount the plugin itself into the
2
+ # profile composition tree.
3
+ #
4
+ # `dsh plugin --profile <name> add dsh-working-activity` auto-initializes the
5
+ # profile (first layer @deepseek-ai/dsh-base), pnpm-installs this package into
6
+ # the profile, and the CLI's reconcile step appends it to the profile's
7
+ # dsh.profile.bundles because this package.json declares `dsh.bundle.patch`.
8
+ # At boot, app-boot applies every bundle's patch list in bundle order over the
9
+ # empty root; this insert list is what actually mounts the working-activity
10
+ # row — no manual configuration is needed.
11
+ #
12
+ # All row config stays at schema defaults (phrases/publish/tickMs/
13
+ # publishIntervalMs/detailLimit/customActions/narrate). To tune a value (for
14
+ # dsh-cc, set publishIntervalMs to 500), override this row's config by id in
15
+ # the profile's own cordis.patch.yml user layer — do NOT insert a second
16
+ # same-id row.
17
+ - insert:
18
+ - id: working-activity
19
+ name: 'dsh-working-activity'
package/lib/client.js CHANGED
@@ -5,8 +5,8 @@ window.__ModuleLoader__.load({
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
- //#region \0dsh-css:C:\Users\17481\AppData\Local\Temp\dshwa-scan\packages\activity\working-activity\src\client\WorkingLine.module.css.mjs
9
- const css = ".GDqYEG_line{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width);font-family:var(--dsw-font-family);color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;margin:0 auto;padding:4px 16px 0;font-size:13px;line-height:18px;display:flex}.GDqYEG_marker{background:var(--dsw-alias-label-tertiary);border-radius:50%;flex:none;width:7px;height:7px;animation:1.6s ease-in-out infinite GDqYEG_working-pulse}.GDqYEG_line[data-activity-phase=done] .GDqYEG_marker{background:var(--dsw-alias-state-business-primary);animation:none}.GDqYEG_line[data-activity-phase=tool] .GDqYEG_marker{background:var(--dsw-alias-state-business-primary)}.GDqYEG_line[data-activity-phase=waiting] .GDqYEG_marker{background:var(--dsw-alias-label-tertiary);opacity:.6}.GDqYEG_text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.GDqYEG_tools{background:var(--dsw-alias-surface-tertiary);min-width:18px;color:var(--dsw-alias-label-secondary);text-align:center;border-radius:9px;flex:none;padding:0 5px;font-size:11px;line-height:18px}@keyframes GDqYEG_working-pulse{0%,to{opacity:1}50%{opacity:.35}}";
8
+ //#region \0dsh-css:D:\code\projects\dsh-working-activity\packages\activity\working-activity\src\client\WorkingLine.module.css.mjs
9
+ const css = ".lRI9Pa_line{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width);font-family:var(--dsw-font-family);color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;margin:0 auto;padding:4px 16px 0;font-size:13px;line-height:18px;display:flex}.lRI9Pa_marker{background:var(--dsw-alias-label-tertiary);border-radius:50%;flex:none;width:7px;height:7px;animation:1.6s ease-in-out infinite lRI9Pa_working-pulse}.lRI9Pa_line[data-activity-phase=done] .lRI9Pa_marker{background:var(--dsw-alias-state-business-primary);animation:none}.lRI9Pa_line[data-activity-phase=tool] .lRI9Pa_marker{background:var(--dsw-alias-state-business-primary)}.lRI9Pa_line[data-activity-phase=waiting] .lRI9Pa_marker{background:var(--dsw-alias-label-tertiary);opacity:.6}.lRI9Pa_text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.lRI9Pa_tools{background:var(--dsw-alias-surface-tertiary);min-width:18px;color:var(--dsw-alias-label-secondary);text-align:center;border-radius:9px;flex:none;padding:0 5px;font-size:11px;line-height:18px}@keyframes lRI9Pa_working-pulse{0%,to{opacity:1}50%{opacity:.35}}";
10
10
  const tagId = "dsh-working-activity/WorkingLine.module.css";
11
11
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
12
12
  const tag = document.createElement("style");
@@ -16,11 +16,11 @@ window.__ModuleLoader__.load({
16
16
  document.head.appendChild(tag);
17
17
  }
18
18
  var WorkingLine_module_css_default = {
19
- "line": "GDqYEG_line",
20
- "working-pulse": "GDqYEG_working-pulse",
21
- "tools": "GDqYEG_tools",
22
- "text": "GDqYEG_text",
23
- "marker": "GDqYEG_marker"
19
+ "working-pulse": "lRI9Pa_working-pulse",
20
+ "line": "lRI9Pa_line",
21
+ "marker": "lRI9Pa_marker",
22
+ "text": "lRI9Pa_text",
23
+ "tools": "lRI9Pa_tools"
24
24
  };
25
25
  //#endregion
26
26
  //#region src/client/WorkingLine.tsx
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["css"],"sources":["../src/client/WorkingLine.tsx","../src/client/index.ts"],"sourcesContent":["// Working-line dock entry: one dim full-width row above the composer card\n// showing the live working-activity snapshot — phase-colored breathing\n// marker, the host-composed status line, and the turn's tool count badge.\n// Renders for every live phase (waiting/thinking/tool) and the done summary;\n// hides while idle or before the first publish.\n//\n// The 'conversation.input.dock' SlotMap declaration lives in\n// @deepseek-ai/dsh-client-ui-conversation/client (contract/slots.ts); this\n// entry contributes into it without owning it.\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport css from './WorkingLine.module.css'\n\n/** Full props of the dock entry: the input-zone runtime share (session standard kit). */\nexport type WorkingLineProps = PropsRuntime<'conversation.input.dock'>\n\n/** Tool-count badge copy (no locale seat: the line text itself is host-composed). */\nconst TOOLS_LABEL = 'tools this turn'\n\n/**\n * Working-line dock entry: reads the latest activity snapshot off the\n * conversation snapshot and renders the row, or nothing when idle/absent.\n */\nexport function WorkingLine({ useSession }: WorkingLineProps) {\n const activity = useSession(s => s.activity)\n if (activity === null || activity.phase === 'idle' || activity.line === '') return null\n return (\n <div className={css.line} data-activity-phase={activity.phase}>\n <span className={css.marker} aria-hidden=\"true\" />\n <span className={css.text}>{activity.line}</span>\n {activity.toolCount > 0 && (\n <span className={css.tools} title={`${activity.toolCount} ${TOOLS_LABEL}`}>\n {activity.toolCount}\n </span>\n )}\n </div>\n )\n}\n","/**\n * Working-activity surface plugin, browser half: the working-line entry in\n * the conversation.input.dock strip. This package's node half emits\n * `activity/status` session events; the web runtime patch narrows them into\n * the conversation snapshot's `activity` member, so this dock entry reads\n * the live frame through the standard session kit and owns no store, no\n * refresh chain, and no event listener.\n *\n * Mount contract (see the root README's \"Web UI 集成\" section): the web\n * client's client-modules host scans loader entries for `dsh.client`\n * declarations and serves this package's `./client` bundle at\n * /plugins/dsh-working-activity/client.js. The entry contributes into the\n * input dock — no official-source patch is involved.\n */\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\n// Type-only: pulls the ui-conversation SlotMap merge (the input.dock entry)\n// through the Client assembly boundary.\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { WorkingLine } from './WorkingLine.tsx'\nimport type { ActivityPhase, ActivitySnapshot } from './activity.ts'\n\nexport { WorkingLine, type WorkingLineProps } from './WorkingLine.tsx'\nexport type { ActivityPhase, ActivitySnapshot } from './activity.ts'\n\n/** Required services for the dock registration. */\nexport const inject = ['slots']\n\n/**\n * Client plugin body: the working-line dock entry.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({\n name: 'conversation.input.dock',\n // The pre-slots patch used the same id in ui-conversation; entries with\n // equal order render in registration order, and goal (10) / queue (20)\n // keep their seats — this row sits between them.\n id: 'activity',\n order: 15,\n registrant: 'dsh-working-activity',\n }, WorkingLine))\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBA,MAAM,cAAc;;;;;EAMpB,SAAgB,YAAY,EAAE,cAAgC;GAC5D,MAAM,WAAW,YAAW,MAAK,EAAE,QAAQ;GAC3C,IAAI,aAAa,QAAQ,SAAS,UAAU,UAAU,SAAS,SAAS,IAAI,OAAO;GACnF,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,+BAAI;IAAM,uBAAqB,SAAS;IAAxD,UAAA;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,+BAAI;MAAQ,eAAY;KAAQ,CAAA;KACjD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,+BAAI;MAAO,UAAA,SAAS;KAAW,CAAA;KAC/C,SAAS,YAAY,KACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,+BAAI;MAAO,OAAO,GAAG,SAAS,UAAU,GAAG;MACzD,UAAA,SAAS;KACN,CAAA;IAEL;;EAET;;;;ECXA,MAAa,SAAS,CAAC,OAAO;;;;;EAM9B,SAAgB,MAAM,KAA0B;GAC9C,IAAI,MAAM,OAAO,iCAAiC,IAAI,MAAM,SAAS;IACnE,MAAM;IAIN,IAAI;IACJ,OAAO;IACP,YAAY;GACd,GAAG,WAAW,CAAC;EACjB"}
1
+ {"version":3,"file":"client.js","names":["css"],"sources":["../src/client/WorkingLine.tsx","../src/client/index.ts"],"sourcesContent":["// Working-line dock entry: one dim full-width row above the composer card\r\n// showing the live working-activity snapshot — phase-colored breathing\r\n// marker, the host-composed status line, and the turn's tool count badge.\r\n// Renders for every live phase (waiting/thinking/tool) and the done summary;\r\n// hides while idle or before the first publish.\r\n//\r\n// The 'conversation.input.dock' SlotMap declaration lives in\r\n// @deepseek-ai/dsh-client-ui-conversation/client (contract/slots.ts); this\r\n// entry contributes into it without owning it.\r\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport css from './WorkingLine.module.css'\r\n\r\n/** Full props of the dock entry: the input-zone runtime share (session standard kit). */\r\nexport type WorkingLineProps = PropsRuntime<'conversation.input.dock'>\r\n\r\n/** Tool-count badge copy (no locale seat: the line text itself is host-composed). */\r\nconst TOOLS_LABEL = 'tools this turn'\r\n\r\n/**\r\n * Working-line dock entry: reads the latest activity snapshot off the\r\n * conversation snapshot and renders the row, or nothing when idle/absent.\r\n */\r\nexport function WorkingLine({ useSession }: WorkingLineProps) {\r\n const activity = useSession(s => s.activity)\r\n if (activity === null || activity.phase === 'idle' || activity.line === '') return null\r\n return (\r\n <div className={css.line} data-activity-phase={activity.phase}>\r\n <span className={css.marker} aria-hidden=\"true\" />\r\n <span className={css.text}>{activity.line}</span>\r\n {activity.toolCount > 0 && (\r\n <span className={css.tools} title={`${activity.toolCount} ${TOOLS_LABEL}`}>\r\n {activity.toolCount}\r\n </span>\r\n )}\r\n </div>\r\n )\r\n}\r\n","/**\r\n * Working-activity surface plugin, browser half: the working-line entry in\r\n * the conversation.input.dock strip. This package's node half emits\r\n * `activity/status` session events; the web runtime patch narrows them into\r\n * the conversation snapshot's `activity` member, so this dock entry reads\r\n * the live frame through the standard session kit and owns no store, no\r\n * refresh chain, and no event listener.\r\n *\r\n * Mount contract (see the root README's \"Web UI 集成\" section): the web\r\n * client's client-modules host scans loader entries for `dsh.client`\r\n * declarations and serves this package's `./client` bundle at\r\n * /plugins/dsh-working-activity/client.js. The entry contributes into the\r\n * input dock — no official-source patch is involved.\r\n */\r\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\r\n// Type-only: pulls the ui-conversation SlotMap merge (the input.dock entry)\r\n// through the Client assembly boundary.\r\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\r\nimport { WorkingLine } from './WorkingLine.tsx'\r\nimport type { ActivityPhase, ActivitySnapshot } from './activity.ts'\r\n\r\nexport { WorkingLine, type WorkingLineProps } from './WorkingLine.tsx'\r\nexport type { ActivityPhase, ActivitySnapshot } from './activity.ts'\r\n\r\n/** Required services for the dock registration. */\r\nexport const inject = ['slots']\r\n\r\n/**\r\n * Client plugin body: the working-line dock entry.\r\n * @param ctx - client root context.\r\n */\r\nexport function apply(ctx: ClientContext): void {\r\n ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({\r\n name: 'conversation.input.dock',\r\n // The pre-slots patch used the same id in ui-conversation; entries with\r\n // equal order render in registration order, and goal (10) / queue (20)\r\n // keep their seats — this row sits between them.\r\n id: 'activity',\r\n order: 15,\r\n registrant: 'dsh-working-activity',\r\n }, WorkingLine))\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBA,MAAM,cAAc;;;;;EAMpB,SAAgB,YAAY,EAAE,cAAgC;GAC5D,MAAM,WAAW,YAAW,MAAK,EAAE,QAAQ;GAC3C,IAAI,aAAa,QAAQ,SAAS,UAAU,UAAU,SAAS,SAAS,IAAI,OAAO;GACnF,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,+BAAI;IAAM,uBAAqB,SAAS;IAAxD,UAAA;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,+BAAI;MAAQ,eAAY;KAAQ,CAAA;KACjD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,+BAAI;MAAO,UAAA,SAAS;KAAW,CAAA;KAC/C,SAAS,YAAY,KACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,+BAAI;MAAO,OAAO,GAAG,SAAS,UAAU,GAAG;MACzD,UAAA,SAAS;KACN,CAAA;IAEL;;EAET;;;;ECXA,MAAa,SAAS,CAAC,OAAO;;;;;EAM9B,SAAgB,MAAM,KAA0B;GAC9C,IAAI,MAAM,OAAO,iCAAiC,IAAI,MAAM,SAAS;IACnE,MAAM;IAIN,IAAI;IACJ,OAAO;IACP,YAAY;GACd,GAAG,WAAW,CAAC;EACjB"}
@@ -22,7 +22,13 @@ export declare const name = "working-activity";
22
22
  export type Config = {
23
23
  /** Playful copy pool; false renders plain functional labels. */
24
24
  phrases?: boolean;
25
- /** Append `activity/status` session events for UI consumers. */
25
+ /** Append `activity/status` session events for UI consumers. Default OFF:
26
+ * dsh-session's append() cannot mark events ignorable, and the resume
27
+ * read path refuses logs containing unknown non-ignorable types — every
28
+ * appended snapshot makes the whole session unresumable. Re-enable only
29
+ * for a log-replaying consumer on a harness that supports ignorable
30
+ * appends. The live status line (prompt slot / session events) is
31
+ * unaffected by this flag. */
26
32
  publish?: boolean;
27
33
  /** Status render tick interval in ms. */
28
34
  tickMs?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAWxC,mBAAmB,aAAa,CAAA;AAEhC,eAAO,MAAM,IAAI,qBAAqB,CAAA;AAEtC,wDAAwD;AACxD,MAAM,MAAM,MAAM,GAAG;IACnB,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACxC,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;GAQjB,CAAA;AAyBF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,MAAW,GAAG,IAAI,CAyH7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAWxC,mBAAmB,aAAa,CAAA;AAEhC,eAAO,MAAM,IAAI,qBAAqB,CAAA;AAEtC,wDAAwD;AACxD,MAAM,MAAM,MAAM,GAAG;IACnB,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;;;mCAM+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACxC,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;GAQjB,CAAA;AAyBF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,MAAW,GAAG,IAAI,CAyH7D"}
@@ -19,7 +19,7 @@ import { ActivityTracker } from './status.js';
19
19
  export const name = 'working-activity';
20
20
  export const Config = z.object({
21
21
  phrases: z.boolean().default(true),
22
- publish: z.boolean().default(true),
22
+ publish: z.boolean().default(false),
23
23
  tickMs: z.number().step(50).min(100).max(5000).default(500),
24
24
  publishIntervalMs: z.number().step(500).min(500).max(30_000).default(2000),
25
25
  detailLimit: z.number().step(1).min(8).max(120).default(40),
@@ -36,7 +36,7 @@ const NARRATE_INSTRUCTION = '[状态栏] 你有一个状态栏展示给用户。
36
36
  export function apply(ctx, config = {}) {
37
37
  const resolved = {
38
38
  phrases: config.phrases ?? true,
39
- publish: config.publish ?? true,
39
+ publish: config.publish ?? false,
40
40
  tickMs: config.tickMs ?? 500,
41
41
  publishIntervalMs: config.publishIntervalMs ?? 2000,
42
42
  detailLimit: config.detailLimit ?? 40,