dsh-next-actions 0.1.0 → 0.1.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # 版本记录
2
2
 
3
+ ## 0.1.1 — 2026-11-11
4
+
5
+ 修复 DSH 升级后引导提示丢失:`AgentRegistry.roots()` 在 DSH 0.2.1-rc.3 起被移除,
6
+ 原来的根 agent 判定抛错后被静默忽略,常驻提示语因此从未注册,模型只看到单独的工具描述。
7
+
8
+ - 改用会话 header 的 `origin: 'subagent'` 区分普通会话与子代理;子代理仍不注册工具与提示。
9
+ - 静默降级改为可诊断:引导安装失败、既有 agent 列表不可读、会话 header 无法判定都写 Host 日志;
10
+ Host logger 缺失时回退 `console.warn`。
11
+ - 引导语明确说明工程/代码工作同样适用:卡片在回答下方,不把回答变成 UI 回答。
12
+ - 工具描述自述触发时机,即使提示语丢失也能说明用途。
13
+ - 客户端光标插入被拒绝或抛错时回退为追加,并写 `console.warn` 说明降级。
14
+ - 测试改用当前 `AgentRegistry.list()` 接口,并覆盖子代理排除、各静默降级的告警。
15
+
3
16
  ## 0.1.0 — 2026-11-11
4
17
 
5
18
  首个公开发布。
package/DESIGN.md CHANGED
@@ -60,7 +60,7 @@
60
60
 
61
61
  | 部分 | 文件 | 职责 |
62
62
  | --- | --- | --- |
63
- | Host | `index.js` | 为根 agent 注册 `suggest_next_actions` 与一段常驻提示;子代理不注册;`enabled:false` 时什么都不注册 |
63
+ | Host | `index.js` | 为根 agent 注册 `suggest_next_actions` 与一段常驻提示;子代理不注册(按会话 header 的 `origin` 区分);安装与判定失败写日志;`enabled:false` 时什么都不注册 |
64
64
  | 规范化 | `lib/normalize.js` | 参数 → `{ shown, context, suggestions[≤3] }`:折叠空白、截断、按指令去重、推荐至多一条且置顶;危险标记来自模型字段或命令形状模式。结果作为 `tool/result.meta` 写入会话日志 |
65
65
  | Client | `client.js`(手写单文件,含 CSS) | 两个 Conversation Definition:`next-actions` 把本工具结果上的 meta(native 与 PTC `run_code` 两条通路)发布为该轮卡片;`next-actions-sent` 把用户在该轮发出的第一条 `user/message` 发布为 `sent` 文本。`conversation.chat.turnTail` 渲染卡片;`tool.call.toolview` 渲染过程行 |
66
66
 
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > Suggested next actions under DeepSeek Harness replies — clicking one fills the input, never sends.
4
4
  > DSH Web/Desktop 插件:在回复下方显示 1–3 条「下一步建议」,点击只填入输入框。
5
5
 
6
- **状态:v0.1.0,已发布到 npm。** 设计与理念见 [`DESIGN.md`](DESIGN.md),版本记录见 [`CHANGELOG.md`](CHANGELOG.md)。
6
+ **状态:v0.1.1(npm 包:[dsh-next-actions](https://www.npmjs.com/package/dsh-next-actions))。** 设计与理念见 [`DESIGN.md`](DESIGN.md),版本记录见 [`CHANGELOG.md`](CHANGELOG.md)。
7
7
 
8
8
  ## 安装
9
9
 
@@ -38,6 +38,7 @@ lib/normalize.js 参数规范化,结果写入 tool/result.meta
38
38
  client.js Client(手写单文件):Definition、卡片、过程行与 CSS
39
39
  cordis.patch.yml 插件行 patch
40
40
  test/ node --test
41
+ assets/promo/ 宣传短片:源文件、封面与渲染脚本(成片不入库,不随 npm 发布)
41
42
  ```
42
43
 
43
44
  ## 开发
@@ -50,6 +51,21 @@ npm pack --dry-run # 打包检查
50
51
  安装/卸载用 `plugin_manager` 的 `install_bundle` / `remove_bundle`;验证使用假 `DSH_HOME`。
51
52
  Host 改动需重启 DSH,Client 改动需刷新页面。
52
53
 
54
+ ## 发布
55
+
56
+ 改 `package.json` 版本与 `CHANGELOG.md` 后:
57
+
58
+ ```sh
59
+ node --test
60
+ npm pack --dry-run
61
+ git tag -a v<version> -m "v<version>"
62
+ git push origin main --tags
63
+ npm publish --access public
64
+ npm view dsh-next-actions version # 确认 latest 指向新版本
65
+ ```
66
+
67
+ 发布后用假 `DSH_HOME` 从 registry 装一次;本机 `link:` 安装不需要切换。
68
+
53
69
  关闭功能:在 profile 的 `cordis.patch.yml` 写
54
70
 
55
71
  ```yaml
package/client.js CHANGED
@@ -277,8 +277,12 @@ window.__ModuleLoader__.load({
277
277
  next = null
278
278
  try {
279
279
  // One editor edit at the caret: keeps @ references, undoable with ⌘Z.
280
- if (actions.insertText(`\n\n${prompt}`, actions.captureInsertion()) !== true) next = `${draft.trimEnd()}\n\n${prompt}`
281
- } catch {
280
+ if (actions.insertText(`\n\n${prompt}`, actions.captureInsertion()) !== true) {
281
+ console.warn('[dsh-next-actions] insertText declined; appending the action instead')
282
+ next = `${draft.trimEnd()}\n\n${prompt}`
283
+ }
284
+ } catch (error) {
285
+ console.warn('[dsh-next-actions] insert at caret failed; appending the action instead', error)
282
286
  next = `${draft.trimEnd()}\n\n${prompt}`
283
287
  }
284
288
  }
package/index.js CHANGED
@@ -18,6 +18,7 @@ const GUIDANCE = [
18
18
  'Before your final answer, call suggest_next_actions once when this turn leaves real follow-up work:',
19
19
  'a task finished or advanced, tools ran, files changed, review or approval is due,',
20
20
  'or you were about to end with a list of next actions.',
21
+ 'Use it for code and engineering work too; the card sits under the reply and the reply keeps its normal plain-text format.',
21
22
  'Put those actions only in the card; the reply gets at most one lead-in sentence and never numbers or bullets them.',
22
23
  'Skip greetings, acknowledgements, pure knowledge answers, repeated cards, and turns that already asked a structured question.',
23
24
  ].join(' ')
@@ -28,7 +29,8 @@ const TOOL = {
28
29
  name: TOOL_NAME,
29
30
  description: [
30
31
  'Show 1–3 clickable next actions as a card under your reply; clicking one fills the message input, never sends.',
31
- "Write them in the user's language and never repeat them in your prose.",
32
+ 'Call it once before the final answer when this turn leaves real follow-up work.',
33
+ "Write the actions in the user's language and never repeat them in your prose.",
32
34
  ].join(' '),
33
35
  parameters: {
34
36
  type: 'object',
@@ -83,12 +85,18 @@ export function normalizeConfig(raw) {
83
85
  return { enabled: !(raw !== null && typeof raw === 'object' && raw.enabled === false) }
84
86
  }
85
87
 
86
- /** Root agents only; fail open so a Harness change never silently hides the tool. */
87
- function isRoot(ctx, agent) {
88
+ /**
89
+ * Ordinary session agents only. Delegated agents carry the durable
90
+ * `origin: 'subagent'` header; `AgentRegistry.roots()` no longer exists since
91
+ * DSH 0.2.1-rc.3, so the header is the supported discriminator. Fail open so a
92
+ * Harness change never silently hides the tool, and report the drift once.
93
+ */
94
+ function isRoot(agent, onUnreadable) {
88
95
  if (agent === undefined || agent === null) return true
89
96
  try {
90
- return ctx.agents.roots().includes(agent)
91
- } catch {
97
+ return agent.session.header.origin !== 'subagent'
98
+ } catch (error) {
99
+ onUnreadable?.(error)
92
100
  return true
93
101
  }
94
102
  }
@@ -96,17 +104,38 @@ function isRoot(ctx, agent) {
96
104
  export function apply(ctx, config) {
97
105
  if (!normalizeConfig(config).enabled) return
98
106
 
107
+ /** Host log, with a console fallback so a missing logger cannot hide the report. */
108
+ const warn = (message) => {
109
+ const line = `dsh-next-actions: ${message}`
110
+ try {
111
+ if (typeof ctx.logger?.warn === 'function') {
112
+ ctx.logger.warn(line)
113
+ return
114
+ }
115
+ } catch {
116
+ // Fall through: the warning must not depend on a working logger.
117
+ }
118
+ console.warn(line)
119
+ }
120
+
121
+ /** Report a header-shape change once; `when` runs on every tool resolution. */
122
+ let headerFailureReported = false
123
+ const isRootAgent = (agent) => isRoot(agent, (error) => {
124
+ if (headerFailureReported) return
125
+ headerFailureReported = true
126
+ warn(`agent session header unreadable; treating the agent as a root: ${String(error)}`)
127
+ })
128
+
99
129
  ctx.effect(
100
- () => ctx.tools.register(TOOL, { when: ({ agent }) => isRoot(ctx, agent) }),
130
+ () => ctx.tools.register(TOOL, { when: ({ agent }) => isRootAgent(agent) }),
101
131
  'dsh-next-actions: tool',
102
132
  )
103
133
 
104
134
  /** agent → disposer of its prompt section. */
105
135
  const installed = new Map()
106
136
  const install = (agent) => {
107
- if (installed.has(agent)) return
137
+ if (installed.has(agent) || !isRootAgent(agent)) return
108
138
  try {
109
- if (!ctx.agents.roots().includes(agent)) return
110
139
  const prompt = agent.ctx.systemPrompt
111
140
  const base = prompt.getSectionOrder?.('TOOL_REPORT')
112
141
  installed.set(agent, agent.ctx.effect(() => prompt.section({
@@ -114,8 +143,10 @@ export function apply(ctx, config) {
114
143
  order: typeof base === 'number' ? base + 50 : 2950,
115
144
  text: GUIDANCE,
116
145
  }), 'dsh-next-actions: guidance'))
117
- } catch {
118
- // The guidance is an enhancement; the tool stays registered.
146
+ } catch (error) {
147
+ // The tool still works without the guidance; surface the degradation
148
+ // instead of silently losing the standing instruction.
149
+ warn(`guidance not installed: ${String(error)}`)
119
150
  }
120
151
  }
121
152
 
@@ -123,9 +154,11 @@ export function apply(ctx, config) {
123
154
  const offCreated = ctx.on('agent/created', ({ agent }) => install(agent))
124
155
  const offDisposed = ctx.on('agent/disposed', ({ agent }) => installed.delete(agent))
125
156
  try {
126
- for (const agent of ctx.agents.roots()) install(agent)
127
- } catch {
128
- // Agents created later still arrive through agent/created.
157
+ for (const agent of ctx.agents.list()) install(agent)
158
+ } catch (error) {
159
+ // Agents created later still arrive through agent/created, but agents
160
+ // that were already live at apply time keep missing the guidance.
161
+ warn(`could not install guidance on existing agents: ${String(error)}`)
129
162
  }
130
163
  return () => {
131
164
  offCreated()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-next-actions",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "license": "MIT",
5
5
  "description": "Shows 1–3 clickable next actions under replies; clicking one fills the input draft, never sends.",
6
6
  "icon": "./icon.svg",