@jingyi0605/codingns4dsh 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.
Files changed (216) hide show
  1. package/README.en.md +306 -0
  2. package/README.md +190 -993
  3. package/data/build/dist/client/account-bar.d.ts +2 -2
  4. package/data/build/dist/client/account-bar.js +96 -39
  5. package/data/build/dist/client/bundle.js +13722 -3611
  6. package/data/build/dist/client/cli-catalog.js +20 -3
  7. package/data/build/dist/client/cli-slots.d.ts +5 -0
  8. package/data/build/dist/client/cli-slots.js +57 -7
  9. package/data/build/dist/client/debug/ui.d.ts +1 -1
  10. package/data/build/dist/client/debug/ui.js +62 -32
  11. package/data/build/dist/client/dsh-runtime-version.d.ts +9 -2
  12. package/data/build/dist/client/dsh-runtime-version.js +24 -2
  13. package/data/build/dist/client/features/cli-adapters.d.ts +1 -1
  14. package/data/build/dist/client/features/cli-adapters.js +19 -16
  15. package/data/build/dist/client/features/debug.js +2 -2
  16. package/data/build/dist/client/features/index.d.ts +2 -1
  17. package/data/build/dist/client/features/index.js +3 -1
  18. package/data/build/dist/client/features/lan-access-panel.d.ts +1 -1
  19. package/data/build/dist/client/features/lan-access-panel.js +8 -10
  20. package/data/build/dist/client/features/lan-access.js +1 -1
  21. package/data/build/dist/client/features/login-protection-panel.d.ts +1 -1
  22. package/data/build/dist/client/features/login-protection-panel.js +7 -9
  23. package/data/build/dist/client/features/reverse-proxy-panel.d.ts +1 -1
  24. package/data/build/dist/client/features/reverse-proxy-panel.js +99 -11
  25. package/data/build/dist/client/features/reverse-proxy.d.ts +1 -1
  26. package/data/build/dist/client/features/reverse-proxy.js +19 -18
  27. package/data/build/dist/client/features/terminal-enhancement-panel.d.ts +1 -1
  28. package/data/build/dist/client/features/terminal-enhancement-panel.js +62 -55
  29. package/data/build/dist/client/features/terminal-enhancement.d.ts +1 -1
  30. package/data/build/dist/client/features/terminal-enhancement.js +3 -3
  31. package/data/build/dist/client/features/types.d.ts +14 -3
  32. package/data/build/dist/client/features/workspace-session-enhancement-panel.d.ts +1 -1
  33. package/data/build/dist/client/features/workspace-session-enhancement-panel.js +31 -9
  34. package/data/build/dist/client/features/workspace-session-enhancement.js +72 -11
  35. package/data/build/dist/client/git-management.d.ts +16 -0
  36. package/data/build/dist/client/git-management.js +757 -0
  37. package/data/build/dist/client/index.d.ts +3 -2
  38. package/data/build/dist/client/index.js +152 -27
  39. package/data/build/dist/client/locale.js +91 -29
  40. package/data/build/dist/client/quick-phrase-layout.d.ts +49 -0
  41. package/data/build/dist/client/quick-phrase-layout.js +95 -0
  42. package/data/build/dist/client/quick-phrase-slot.d.ts +7 -0
  43. package/data/build/dist/client/quick-phrase-slot.js +370 -0
  44. package/data/build/dist/client/remote-web-context.js +1 -1
  45. package/data/build/dist/client/settings-bridge.d.ts +9 -6
  46. package/data/build/dist/client/settings-bridge.js +51 -27
  47. package/data/build/dist/client/settings-section.d.ts +3 -2
  48. package/data/build/dist/client/settings-section.js +33 -19
  49. package/data/build/dist/client/subscription-slot.d.ts +3 -0
  50. package/data/build/dist/client/subscription-slot.js +108 -16
  51. package/data/build/dist/client/terminal/model.d.ts +14 -2
  52. package/data/build/dist/client/terminal/model.js +109 -21
  53. package/data/build/dist/client/terminal/recovery.d.ts +50 -0
  54. package/data/build/dist/client/terminal/recovery.js +101 -0
  55. package/data/build/dist/client/terminal/ui.d.ts +2 -2
  56. package/data/build/dist/client/terminal/ui.js +49 -11
  57. package/data/build/dist/client/terminal/xterm-view.d.ts +2 -2
  58. package/data/build/dist/client/terminal/xterm-view.js +2 -1
  59. package/data/build/dist/client/theme.d.ts +6 -1
  60. package/data/build/dist/client/theme.js +32 -1
  61. package/data/build/dist/client/workspace-session-archive-dom.d.ts +12 -0
  62. package/data/build/dist/client/workspace-session-archive-dom.js +27 -5
  63. package/data/build/dist/client/workspace-session-visibility-dom.d.ts +30 -0
  64. package/data/build/dist/client/workspace-session-visibility-dom.js +604 -0
  65. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.d.ts +50 -0
  66. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js +139 -0
  67. package/data/build/dist/dsh-capabilities/client/conversation-adapter.d.ts +7 -0
  68. package/data/build/dist/dsh-capabilities/client/conversation-adapter.js +6 -0
  69. package/data/build/dist/dsh-capabilities/client/locale-adapter.d.ts +9 -0
  70. package/data/build/dist/dsh-capabilities/client/locale-adapter.js +4 -0
  71. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +10 -0
  72. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +14 -0
  73. package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.d.ts +8 -0
  74. package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.js +16 -0
  75. package/data/build/dist/dsh-capabilities/client/sidebar-adapter.d.ts +7 -0
  76. package/data/build/dist/dsh-capabilities/client/sidebar-adapter.js +5 -0
  77. package/data/build/dist/dsh-capabilities/client/theme-adapter.d.ts +6 -0
  78. package/data/build/dist/dsh-capabilities/client/theme-adapter.js +4 -0
  79. package/data/build/dist/dsh-capabilities/client/typert-adapter.d.ts +5 -0
  80. package/data/build/dist/dsh-capabilities/client/typert-adapter.js +4 -0
  81. package/data/build/dist/dsh-capabilities/host/config-forms-adapter.d.ts +19 -0
  82. package/data/build/dist/dsh-capabilities/host/config-forms-adapter.js +45 -0
  83. package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.d.ts +19 -0
  84. package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.js +13 -0
  85. package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.d.ts +8 -0
  86. package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.js +47 -0
  87. package/data/build/dist/dsh-capabilities/host/typert-adapter.d.ts +6 -0
  88. package/data/build/dist/dsh-capabilities/host/typert-adapter.js +4 -0
  89. package/data/build/dist/dsh-capabilities/index.d.ts +6 -0
  90. package/data/build/dist/dsh-capabilities/index.js +6 -0
  91. package/data/build/dist/dsh-capabilities/matrix.d.ts +15 -0
  92. package/data/build/dist/dsh-capabilities/matrix.js +32 -0
  93. package/data/build/dist/dsh-capabilities/registry.d.ts +22 -0
  94. package/data/build/dist/dsh-capabilities/registry.js +196 -0
  95. package/data/build/dist/dsh-capabilities/routes.d.ts +10 -0
  96. package/data/build/dist/dsh-capabilities/routes.js +34 -0
  97. package/data/build/dist/dsh-capabilities/settings-store.d.ts +29 -0
  98. package/data/build/dist/dsh-capabilities/settings-store.js +5 -0
  99. package/data/build/dist/dsh-capabilities/types.d.ts +50 -0
  100. package/data/build/dist/dsh-capabilities/types.js +23 -0
  101. package/data/build/dist/features/registry.d.ts +8 -2
  102. package/data/build/dist/features/registry.js +104 -1
  103. package/data/build/dist/host/auth-session.d.ts +8 -1
  104. package/data/build/dist/host/auth-session.js +28 -6
  105. package/data/build/dist/host/cli-adapters/claude-driver.d.ts +2 -0
  106. package/data/build/dist/host/cli-adapters/claude-driver.js +19 -4
  107. package/data/build/dist/host/cli-adapters/claude-model-options.d.ts +14 -0
  108. package/data/build/dist/host/cli-adapters/claude-model-options.js +157 -0
  109. package/data/build/dist/host/cli-adapters/codex-driver.d.ts +11 -0
  110. package/data/build/dist/host/cli-adapters/codex-driver.js +166 -14
  111. package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
  112. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +15 -0
  113. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +120 -29
  114. package/data/build/dist/host/cli-adapters/dsh-tool-history.d.ts +4 -1
  115. package/data/build/dist/host/cli-adapters/dsh-tool-history.js +25 -7
  116. package/data/build/dist/host/cli-adapters/feature.js +74 -8
  117. package/data/build/dist/host/cli-adapters/gemini-driver.js +2 -2
  118. package/data/build/dist/host/cli-adapters/grok-driver.js +2 -2
  119. package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +4 -2
  120. package/data/build/dist/host/cli-adapters/json-rpc-process.js +8 -9
  121. package/data/build/dist/host/cli-adapters/kimi-driver.js +1 -1
  122. package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts +17 -0
  123. package/data/build/dist/host/cli-adapters/legacy-session-adapter.js +88 -0
  124. package/data/build/dist/host/cli-adapters/legacy-session-settings.d.ts +24 -0
  125. package/data/build/dist/host/cli-adapters/legacy-session-settings.js +162 -0
  126. package/data/build/dist/host/cli-adapters/official-provider-subscription.d.ts +29 -0
  127. package/data/build/dist/host/cli-adapters/official-provider-subscription.js +361 -0
  128. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +2 -0
  129. package/data/build/dist/host/cli-adapters/opencode-driver.js +97 -12
  130. package/data/build/dist/host/cli-adapters/pi-driver.js +69 -23
  131. package/data/build/dist/host/cli-adapters/provider-registry.d.ts +33 -0
  132. package/data/build/dist/host/cli-adapters/provider-registry.js +83 -0
  133. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +25 -3
  134. package/data/build/dist/host/cli-adapters/provider-subscription.js +346 -30
  135. package/data/build/dist/host/cli-adapters/registry.d.ts +6 -0
  136. package/data/build/dist/host/cli-adapters/registry.js +170 -13
  137. package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +10 -0
  138. package/data/build/dist/host/cli-adapters/session-store.d.ts +7 -0
  139. package/data/build/dist/host/cli-adapters/session-store.js +39 -1
  140. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +3 -0
  141. package/data/build/dist/host/cli-adapters/stream-normalizer.d.ts +3 -0
  142. package/data/build/dist/host/cli-adapters/stream-normalizer.js +22 -2
  143. package/data/build/dist/host/control-api-client.d.ts +3 -3
  144. package/data/build/dist/host/control-api-client.js +2 -1
  145. package/data/build/dist/host/credential-store.js +11 -1
  146. package/data/build/dist/host/dsh-device-runtime.d.ts +4 -0
  147. package/data/build/dist/host/dsh-device-runtime.js +20 -9
  148. package/data/build/dist/host/dsh-runtime-version.d.ts +3 -2
  149. package/data/build/dist/host/dsh-runtime-version.js +71 -2
  150. package/data/build/dist/host/features/auth.js +8 -5
  151. package/data/build/dist/host/features/debug.js +1 -1
  152. package/data/build/dist/host/features/git-management.d.ts +5 -0
  153. package/data/build/dist/host/features/git-management.js +290 -0
  154. package/data/build/dist/host/features/host-status.js +1 -1
  155. package/data/build/dist/host/features/index.d.ts +1 -0
  156. package/data/build/dist/host/features/index.js +3 -0
  157. package/data/build/dist/host/features/terminal-process.js +1 -1
  158. package/data/build/dist/host/features/terminal-status.d.ts +3 -1
  159. package/data/build/dist/host/features/terminal-status.js +3 -1
  160. package/data/build/dist/host/index.d.ts +7 -3
  161. package/data/build/dist/host/index.js +79 -15
  162. package/data/build/dist/host/lan-access-dsh.js +18 -5
  163. package/data/build/dist/host/native-session-bridge.d.ts +23 -1
  164. package/data/build/dist/host/native-session-bridge.js +157 -10
  165. package/data/build/dist/host/rpc-table.d.ts +1 -1
  166. package/data/build/dist/host/rpc.js +60 -10
  167. package/data/build/dist/host/session-migration-repair.d.ts +19 -0
  168. package/data/build/dist/host/session-migration-repair.js +395 -0
  169. package/data/build/dist/host/settings.d.ts +8 -1
  170. package/data/build/dist/host/settings.js +94 -3
  171. package/data/build/dist/host/terminal/backends/tmux-backend.d.ts +1 -0
  172. package/data/build/dist/host/terminal/backends/tmux-backend.js +4 -2
  173. package/data/build/dist/host/terminal/controller-factory.d.ts +4 -0
  174. package/data/build/dist/host/terminal/controller-factory.js +26 -7
  175. package/data/build/dist/host/terminal/runtime-manager.d.ts +2 -1
  176. package/data/build/dist/host/terminal/runtime-manager.js +3 -0
  177. package/data/build/dist/host/terminal/startup.d.ts +2 -0
  178. package/data/build/dist/host/terminal/startup.js +2 -1
  179. package/data/build/dist/host/terminal/terminal-controller.d.ts +10 -3
  180. package/data/build/dist/host/terminal/terminal-controller.js +101 -15
  181. package/data/build/dist/host/terminal/terminal-process-service.js +3 -1
  182. package/data/build/dist/host/terminal/terminal-service.d.ts +2 -0
  183. package/data/build/dist/host/terminal/terminal-service.js +10 -0
  184. package/data/build/dist/index.d.ts +6 -2
  185. package/data/build/dist/index.js +8 -2
  186. package/data/build/dist/shared/contracts/cli-adapter.d.ts +14 -0
  187. package/data/build/dist/shared/contracts/config.d.ts +31 -1
  188. package/data/build/dist/shared/contracts/config.js +25 -0
  189. package/data/build/dist/shared/contracts/dsh-device.d.ts +13 -1
  190. package/data/build/dist/shared/contracts/errors.d.ts +1 -1
  191. package/data/build/dist/shared/contracts/feature.d.ts +6 -0
  192. package/data/build/dist/shared/contracts/git.d.ts +82 -0
  193. package/data/build/dist/shared/contracts/git.js +3 -0
  194. package/data/build/dist/shared/contracts/subscription.d.ts +46 -0
  195. package/data/build/dist/shared/contracts/terminal.d.ts +4 -1
  196. package/data/build/dist/shared/contracts/version.d.ts +2 -2
  197. package/data/build/dist/shared/contracts/version.js +4 -6
  198. package/data/build/dist/shared/debug.d.ts +14 -0
  199. package/data/build/dist/shared/debug.js +53 -0
  200. package/data/build/dist/shared/index.d.ts +7 -4
  201. package/data/build/dist/shared/index.js +2 -1
  202. package/data/build/dist/transport/debug.d.ts +1 -1
  203. package/data/build/dist/transport/debug.js +3 -30
  204. package/data/build/dist/transport/dsh-session.js +3 -3
  205. package/data/build/dist/typert.host.d.ts +1 -1
  206. package/data/build/dist/typert.host.js +6 -3
  207. package/data/build/dist/typert.remote-client.d.ts +11 -0
  208. package/data/build/dist/typert.remote-client.js +7 -0
  209. package/dsh.bundle.patch +1 -1
  210. package/package.json +13 -5
  211. package/profile/README.md +4 -4
  212. package/profile/package.json +6 -4
  213. package/profile/scripts/check-dsh-install.mjs +2 -2
  214. package/profile/version.json +2 -2
  215. package/scripts/check-dsh-install.mjs +2 -2
  216. package/version.json +2 -2
@@ -10,10 +10,15 @@ export class CodingNsDshMessageProjector {
10
10
  options;
11
11
  normalizer = new CodingNsAgentEventNormalizer();
12
12
  toolHistory;
13
+ reasoningIndex = 0;
14
+ textIndex = 1;
15
+ nextBlockIndex = 2;
16
+ reasoningText = '';
17
+ textText = '';
13
18
  finished = false;
14
19
  constructor(options) {
15
20
  this.options = options;
16
- this.toolHistory = new CodingNsDshToolHistoryProjector(options.nativeSessions, options.sessionId);
21
+ this.toolHistory = new CodingNsDshToolHistoryProjector(options.nativeSessions, options.sessionId, options.adapterId);
17
22
  }
18
23
  get isFinished() {
19
24
  return this.finished;
@@ -21,6 +26,8 @@ export class CodingNsDshMessageProjector {
21
26
  async push(event) {
22
27
  if (this.finished)
23
28
  return [];
29
+ if (event.type === 'usage')
30
+ this.recordUsageSample(event);
24
31
  const projected = [];
25
32
  for (const normalized of this.normalizer.push(event)) {
26
33
  projected.push(...await this.project(normalized));
@@ -44,7 +51,7 @@ export class CodingNsDshMessageProjector {
44
51
  const projected = await this.flushUsage();
45
52
  const reason = cancelled ? 'cancel' : 'error';
46
53
  if (!cancelled) {
47
- projected.push({ type: 'text-delta', index: 1, text: formatExecutionFailure(this.options.adapterId, message) });
54
+ projected.push(...await this.project({ type: 'text-delta', text: formatExecutionFailure(this.options.adapterId, message) }));
48
55
  }
49
56
  projected.push(...await this.project({ type: 'finish', reason }, message));
50
57
  return projected;
@@ -55,14 +62,55 @@ export class CodingNsDshMessageProjector {
55
62
  projected.push(...await this.project(event));
56
63
  return projected;
57
64
  }
65
+ /** Provider 的 usage 到达时立即给 token-meter 一个非 surface 采样点。
66
+ *
67
+ * DSH 规范要求正式 usage 仍随 assistant/message 在 finish 前结算,因此这里不
68
+ * 提前向 LLM 流发送第二个 usage,只写入 assistant/attempt 供上下文计量投影使用。
69
+ */
70
+ recordUsageSample(event) {
71
+ const usage = {
72
+ inputTokens: event.inputTokens,
73
+ outputTokens: event.outputTokens,
74
+ ...(event.cacheReadTokens === undefined ? {} : { cacheReadTokens: event.cacheReadTokens }),
75
+ ...(event.cacheWriteTokens === undefined ? {} : { cacheWriteTokens: event.cacheWriteTokens }),
76
+ ...(event.uncachedInputTokens === undefined ? {} : { uncachedInputTokens: event.uncachedInputTokens }),
77
+ ...(event.totalTokens === undefined ? {} : { totalTokens: event.totalTokens }),
78
+ ...(event.cacheHitRate === undefined ? {} : { cacheHitRate: event.cacheHitRate }),
79
+ ...(event.contextWindow === undefined ? {} : { contextWindow: event.contextWindow }),
80
+ ...(event.contextTokens === undefined ? {} : { contextTokens: event.contextTokens }),
81
+ ...(event.contextUsageRatio === undefined ? {} : { contextUsageRatio: event.contextUsageRatio }),
82
+ };
83
+ if (event.contextWindow !== undefined) {
84
+ this.options.nativeSessions?.appendRequestContext?.(this.options.sessionId, {
85
+ provider: this.options.adapterId,
86
+ model: this.options.modelId ?? this.options.adapterId,
87
+ contextWindow: event.contextWindow,
88
+ });
89
+ }
90
+ this.options.nativeSessions?.appendUsageSample?.(this.options.sessionId, usage);
91
+ }
58
92
  async project(event, failureMessage) {
59
93
  switch (event.type) {
60
94
  case 'reasoning-delta':
61
- return event.text === '' ? [] : [{ type: 'reasoning-delta', index: 0, text: event.text }];
95
+ if (event.text === '')
96
+ return [];
97
+ return this.appendDelta('reasoning', event.text);
62
98
  case 'text-delta':
63
- return event.text === '' ? [] : [{ type: 'text-delta', index: 1, text: event.text }];
99
+ if (event.text === '')
100
+ return [];
101
+ return this.appendDelta('text', event.text);
102
+ case 'message-boundary':
103
+ return this.closeMessageBlock(event.channel);
104
+ case 'step-boundary':
105
+ // DSH 0.1.7 的 Chat 分组器会把同一 Turn 中没有可见 assistant
106
+ // 回复的连续工具节点合并到一个 process group。Codex 的工具已经
107
+ // 在外部进程完成,分段之间没有 DSH 原生 assistant 文本可供分组器
108
+ // 识别,因此写入一个 Markdown 引用定义作为不可见的回复边界。
109
+ // 必须从新行开始;DSH UI 会忽略 definition 节点,而不是把 HTML 当注释解析。
110
+ // 该内容不会显示给用户,也不会改变工具的原生 step 坐标。
111
+ return this.appendDelta('text', '\n\n[//]: # (codingns-step-boundary)');
64
112
  case 'tool-event':
65
- return externalToolChunk(this.toolHistory.observe(event));
113
+ return this.externalToolChunk(this.toolHistory.observe(event));
66
114
  case 'permission-request':
67
115
  await this.requestPermission(event);
68
116
  return [];
@@ -70,13 +118,6 @@ export class CodingNsDshMessageProjector {
70
118
  await this.requestQuestions(event);
71
119
  return [];
72
120
  case 'usage':
73
- if (event.contextWindow !== undefined) {
74
- this.options.nativeSessions?.appendRequestContext?.(this.options.sessionId, {
75
- provider: this.options.adapterId,
76
- model: this.options.modelId ?? this.options.adapterId,
77
- contextWindow: event.contextWindow,
78
- });
79
- }
80
121
  return [{
81
122
  type: 'usage',
82
123
  usage: {
@@ -95,11 +136,77 @@ export class CodingNsDshMessageProjector {
95
136
  case 'session-binding':
96
137
  return [];
97
138
  case 'finish':
139
+ const closed = [
140
+ ...this.closeMessageBlock('reasoning'),
141
+ ...this.closeMessageBlock('text'),
142
+ ];
98
143
  this.finished = true;
99
144
  this.toolHistory.finalize(event.reason, failureMessage);
100
- return [{ type: 'finish', reason: toDshFinishReason(event.reason, failureMessage) }];
145
+ closed.push({ type: 'finish', reason: toDshFinishReason(event.reason, failureMessage) });
146
+ return closed;
101
147
  }
102
148
  }
149
+ appendDelta(channel, text) {
150
+ const opened = channel === 'reasoning' ? this.reasoningText === '' : this.textText === '';
151
+ const index = this.openBlock(channel);
152
+ if (channel === 'reasoning')
153
+ this.reasoningText += text;
154
+ else
155
+ this.textText += text;
156
+ const delta = { type: `${channel}-delta`, index, text };
157
+ return opened ? [{ type: 'block-start', index, blockType: channel }, delta] : [delta];
158
+ }
159
+ openBlock(channel) {
160
+ const current = channel === 'reasoning' ? this.reasoningIndex : this.textIndex;
161
+ if (current !== undefined)
162
+ return current;
163
+ const index = this.nextBlockIndex;
164
+ this.nextBlockIndex += 1;
165
+ if (channel === 'reasoning')
166
+ this.reasoningIndex = index;
167
+ else
168
+ this.textIndex = index;
169
+ return index;
170
+ }
171
+ closeMessageBlock(channel) {
172
+ if (channel === 'reasoning') {
173
+ if (this.reasoningText === '')
174
+ return [];
175
+ const index = this.reasoningIndex;
176
+ if (index === undefined)
177
+ return [];
178
+ const chunk = { type: 'block-end', index, block: { type: 'reasoning', text: this.reasoningText } };
179
+ this.reasoningText = '';
180
+ this.reasoningIndex = undefined;
181
+ return [chunk];
182
+ }
183
+ if (this.textText === '')
184
+ return [];
185
+ const index = this.textIndex;
186
+ if (index === undefined)
187
+ return [];
188
+ const chunk = { type: 'block-end', index, block: { type: 'text', text: this.textText } };
189
+ this.textText = '';
190
+ this.textIndex = undefined;
191
+ return [chunk];
192
+ }
193
+ externalToolChunk(marker) {
194
+ if (marker === null)
195
+ return [];
196
+ const index = this.nextBlockIndex;
197
+ this.nextBlockIndex += 1;
198
+ return [
199
+ { type: 'block-start', index, blockType: 'reasoning' },
200
+ {
201
+ type: 'reasoning-delta',
202
+ index,
203
+ // 空 delta 会被 DSH 的流式聚合器丢弃,空格能保留 live-chunk 但不会显示思考正文。
204
+ text: ' ',
205
+ codingnsExternalTool: marker,
206
+ },
207
+ { type: 'block-end', index, block: { type: 'reasoning', text: ' ' } },
208
+ ];
209
+ }
103
210
  async requestPermission(event) {
104
211
  const responder = this.options.respondPermission;
105
212
  if (responder === undefined)
@@ -129,22 +236,6 @@ export class CodingNsDshMessageProjector {
129
236
  await responder(response);
130
237
  }
131
238
  }
132
- /**
133
- * 没有 DSH 原生 Session 时的工具展示回退:使用空白 reasoning chunk 携带私有标记,
134
- * 只让 Client 的实时 Conversation 投影读取,不会再次执行工具。完整 Host 直接使用
135
- * 原生 tool/call 与 tool/result,不经过这里。
136
- */
137
- function externalToolChunk(marker) {
138
- if (marker === null)
139
- return [];
140
- return [{
141
- type: 'reasoning-delta',
142
- index: 0,
143
- // 空 delta 会被 DSH 的流式聚合器丢弃,空格能保留 live-chunk 但不会显示思考正文。
144
- text: ' ',
145
- codingnsExternalTool: marker,
146
- }];
147
- }
148
239
  function toDshFinishReason(reason, failureMessage) {
149
240
  if (reason === 'cancel') {
150
241
  return { kind: 'aborted', failure: { message: failureMessage ?? '外部 Agent 执行已取消', code: 'ABORTED' } };
@@ -10,6 +10,7 @@ export interface CodingNsDshExternalToolMarker {
10
10
  readonly status: 'running' | 'completed' | 'failed';
11
11
  readonly output?: string;
12
12
  readonly error?: string;
13
+ readonly adapterId?: string;
13
14
  }
14
15
  /**
15
16
  * 所有外部 Agent 共用的 DSH 工具历史投影器。
@@ -20,6 +21,7 @@ export interface CodingNsDshExternalToolMarker {
20
21
  export declare class CodingNsDshToolHistoryProjector {
21
22
  private readonly nativeSessions;
22
23
  private readonly sessionId;
24
+ private readonly adapterId?;
23
25
  private readonly records;
24
26
  private readonly deferNativeAppend;
25
27
  private readonly removeNativeEventListener;
@@ -28,7 +30,7 @@ export declare class CodingNsDshToolHistoryProjector {
28
30
  private observedCalls;
29
31
  private finalized;
30
32
  private flushScheduled;
31
- constructor(nativeSessions: CodingNsNativeSessionBridge | undefined, sessionId: string);
33
+ constructor(nativeSessions: CodingNsNativeSessionBridge | undefined, sessionId: string, adapterId?: string | undefined);
32
34
  observe(event: CodingNsAgentToolEvent): CodingNsDshExternalToolMarker | null;
33
35
  /** 流结束时补齐 Provider 遗漏的终态,避免原生组件永久停留在运行中。 */
34
36
  finalize(reason: 'stop' | 'cancel' | 'error', failure?: string): void;
@@ -36,6 +38,7 @@ export declare class CodingNsDshToolHistoryProjector {
36
38
  private settle;
37
39
  /** 按 Provider 到达顺序把工具调用和结果写入当前 DSH step。 */
38
40
  private flushNativeRecords;
41
+ private hasPendingNativeRecords;
39
42
  private persistNativeRecord;
40
43
  private scheduleFlush;
41
44
  /** 活动 step 晚于首个工具通知时,补写尚未进入 Session 的工具标记。 */
@@ -12,6 +12,7 @@ const TRUNCATION_MARKER = '\n...[内容因长度限制已截断]';
12
12
  export class CodingNsDshToolHistoryProjector {
13
13
  nativeSessions;
14
14
  sessionId;
15
+ adapterId;
15
16
  records = new Map();
16
17
  deferNativeAppend;
17
18
  removeNativeEventListener;
@@ -20,12 +21,13 @@ export class CodingNsDshToolHistoryProjector {
20
21
  observedCalls = 0;
21
22
  finalized = false;
22
23
  flushScheduled = false;
23
- constructor(nativeSessions, sessionId) {
24
+ constructor(nativeSessions, sessionId, adapterId) {
24
25
  this.nativeSessions = nativeSessions;
25
26
  this.sessionId = sessionId;
26
- // 工具事件必须尽早进入当前 step。新桥接优先写入原生 tool/call 与 tool/result;
27
- // 自定义标记只负责把这次通知立即送进实时 Conversation。不能把工具伪装成
28
- // assistant/attempt,因为 DSH 会把后者当成模型结算,天然排到正文之后。
27
+ this.adapterId = adapterId;
28
+ // 工具通知必须在当前 llm/stream 结束前写入原生时间线。若把它延迟到
29
+ // assistant/message 结算之后,最后一条事件会变成带 tool-call 的合成 assistant,
30
+ // DSH 会把整步判定为 process,最终正文也会被收进折叠按钮。
29
31
  const subscribe = nativeSessions?.supportsEvents === true ? nativeSessions.subscribe : undefined;
30
32
  this.deferNativeAppend = nativeSessions?.appendToolCall === undefined && nativeSessions?.appendExternalToolEvent === undefined && subscribe !== undefined;
31
33
  this.removeNativeEventListener = subscribe?.call(nativeSessions, {
@@ -93,6 +95,7 @@ export class CodingNsDshToolHistoryProjector {
93
95
  name: normalized.name,
94
96
  arguments: normalized.arguments,
95
97
  status,
98
+ ...(this.adapterId === undefined ? {} : { adapterId: this.adapterId }),
96
99
  ...(record.output === undefined ? {} : { output: record.output }),
97
100
  ...(record.error === undefined ? {} : { error: record.error }),
98
101
  };
@@ -125,7 +128,6 @@ export class CodingNsDshToolHistoryProjector {
125
128
  }
126
129
  if (this.nativeSessions?.appendToolCall !== undefined) {
127
130
  this.flushNativeRecords();
128
- this.removeNativeEventListener?.();
129
131
  }
130
132
  else if (this.nativeSessions?.appendExternalToolEvent !== undefined) {
131
133
  this.flushExternalMarkers();
@@ -160,9 +162,16 @@ export class CodingNsDshToolHistoryProjector {
160
162
  return;
161
163
  for (const record of this.records.values())
162
164
  this.persistNativeRecord(record);
163
- if (this.finalized)
165
+ if (this.finalized && !this.hasPendingNativeRecords())
164
166
  this.removeNativeEventListener?.();
165
167
  }
168
+ hasPendingNativeRecords() {
169
+ for (const record of this.records.values()) {
170
+ if (record.handle === null || record.settled && !record.resultAppended)
171
+ return true;
172
+ }
173
+ return false;
174
+ }
166
175
  persistNativeRecord(record) {
167
176
  const append = this.nativeSessions?.appendToolCall;
168
177
  if (append === undefined || this.sessionId.trim() === '')
@@ -221,7 +230,15 @@ export class CodingNsDshToolHistoryProjector {
221
230
  if (!record.externalPersisted) {
222
231
  const start = marker.phase === 'start'
223
232
  ? marker
224
- : { source: marker.source, phase: 'start', callId: marker.callId, name: marker.name, arguments: marker.arguments, status: 'running' };
233
+ : {
234
+ source: marker.source,
235
+ phase: 'start',
236
+ callId: marker.callId,
237
+ name: marker.name,
238
+ arguments: marker.arguments,
239
+ status: 'running',
240
+ ...(this.adapterId === undefined ? {} : { adapterId: this.adapterId }),
241
+ };
225
242
  try {
226
243
  if (!append.call(this.nativeSessions, this.sessionId, start))
227
244
  return false;
@@ -250,6 +267,7 @@ export class CodingNsDshToolHistoryProjector {
250
267
  callId: record.callId,
251
268
  name: normalized.name,
252
269
  arguments: normalized.arguments,
270
+ ...(this.adapterId === undefined ? {} : { adapterId: this.adapterId }),
253
271
  });
254
272
  }
255
273
  catch {
@@ -15,7 +15,7 @@ export function createCliAdaptersFeature(options = {}) {
15
15
  return {
16
16
  descriptor: {
17
17
  name: 'cliAdapters',
18
- version: '0.1.0',
18
+ version: '0.1.1',
19
19
  enabledByDefault: true,
20
20
  dependencies: [],
21
21
  runtime: 'host',
@@ -24,6 +24,13 @@ export function createCliAdaptersFeature(options = {}) {
24
24
  const commandCodeSubscription = new CommandCodeSubscriptionService();
25
25
  const subscriptions = new ProviderSubscriptionService({ commandCode: commandCodeSubscription });
26
26
  const sessionStore = new CodingNsCliSessionStore(context.services.settings === undefined ? {} : { settings: context.services.settings });
27
+ const nativeSessions = context.services.nativeSessions;
28
+ if (nativeSessions !== undefined) {
29
+ const migration = sessionStore.migrateLegacySessions(nativeSessions.list());
30
+ if (migration.migrated > 0 || migration.unresolved > 0) {
31
+ console.info('codingns4dsh: 旧外部会话适配器迁移完成', migration);
32
+ }
33
+ }
27
34
  const registry = options.registry ?? new CodingNsCliAdapterRegistry([
28
35
  new CommandCodeDriver(),
29
36
  new ClaudeCodeDriver(),
@@ -40,7 +47,6 @@ export function createCliAdaptersFeature(options = {}) {
40
47
  });
41
48
  registry.applyEnabledSettings(context.services.settings?.get().agentAdapters);
42
49
  registry.warmCatalog();
43
- const nativeSessions = context.services.nativeSessions;
44
50
  if (nativeSessions !== undefined) {
45
51
  const disposeNativeEvents = nativeSessions.subscribe({
46
52
  onEvent: (session, event) => {
@@ -48,6 +54,10 @@ export function createCliAdaptersFeature(options = {}) {
48
54
  const eventType = nativeEventType(event);
49
55
  if (sessionId === undefined || eventType === undefined)
50
56
  return;
57
+ // 旧会话可能不在启动时的 SessionStore.list() 中,直到用户点击
58
+ // 侧栏才加载。加载事件本身携带完整快照,此时补做一次迁移。
59
+ if (sessionStore.get(sessionId) === undefined)
60
+ sessionStore.migrateLegacySessions([session]);
51
61
  const current = sessionStore.get(sessionId);
52
62
  if (current === undefined || current.status === 'archived')
53
63
  return;
@@ -69,12 +79,20 @@ export function createCliAdaptersFeature(options = {}) {
69
79
  case 'session/get': return registry.getSession(readSessionId(payload));
70
80
  case 'session/set': return registry.setSession(readSessionId(payload), readSessionConfig(payload));
71
81
  case 'session/list': return registry.listSessions(readSessionListOptions(payload));
72
- case 'session/adapter-map': return sessionStore.adapterBindings();
82
+ case 'session/adapter-map':
83
+ // DSH 历史会话的 seed 事件不会发布 session/event;每次读取映射时
84
+ // 重新检查当前已加载对象,覆盖“用户刚点击打开旧会话”的路径。
85
+ if (nativeSessions !== undefined)
86
+ sessionStore.migrateLegacySessions(nativeSessions.list());
87
+ return sessionStore.adapterBindings();
73
88
  case 'session/archive': return registry.archiveSession(readSessionId(payload));
74
89
  case 'session/steer': return registry.steer(readSessionId(payload), readPrompt(payload), false);
75
90
  case 'session/follow-up': return registry.steer(readSessionId(payload), readPrompt(payload), true);
76
91
  case 'session/interrupt': return registry.interrupt(readSessionId(payload));
77
- case 'subscription': return subscriptions.read(readSubscriptionAdapterId(payload));
92
+ case 'subscription': {
93
+ const subscription = readSubscriptionRequest(payload);
94
+ return subscriptions.read(subscription.adapterId, subscription.providerId);
95
+ }
78
96
  default: throw new Error(`未知 CLI RPC: cli/${action}`);
79
97
  }
80
98
  }));
@@ -106,6 +124,9 @@ export function createCliAdaptersFeature(options = {}) {
106
124
  }
107
125
  const messages = Array.isArray(value?.messages) ? value.messages.filter(isMessage) : [];
108
126
  const cwd = resolveSessionCwd(context.services.nativeSessions, sessionId, value);
127
+ // 只有 Provider 驱动明确维护了稳定的 turn 分段,才把工具边界映射为 DSH step。
128
+ // OpenCode、Command Code 会在同一轮连续产出工具和 usage,强行切 step 会让
129
+ // token-meter 在下一条 usage 到达前失去投影,表现为上下文组件反复卸载。
109
130
  const input = {
110
131
  sessionId,
111
132
  messages,
@@ -116,6 +137,13 @@ export function createCliAdaptersFeature(options = {}) {
116
137
  ...(config.rawStoreRef ? { rawStoreRef: config.rawStoreRef } : {}),
117
138
  ...(cwd === undefined ? {} : { cwd }),
118
139
  ...(isAbortSignal(value?.signal) ? { signal: value.signal } : {}),
140
+ ...(registry.supportsSegmentedTurns(config.adapterId)
141
+ && nativeSessions?.available === true
142
+ && nativeSessions.injectNextStep !== undefined
143
+ && (nativeSessions.canInjectNextStep === undefined
144
+ || nativeSessions.canInjectNextStep(sessionId))
145
+ ? { splitToolSteps: true }
146
+ : {}),
119
147
  };
120
148
  const projector = new CodingNsDshMessageProjector({
121
149
  adapterId: config.adapterId,
@@ -126,8 +154,25 @@ export function createCliAdaptersFeature(options = {}) {
126
154
  respondPermission: (response) => registry.respondPermission(sessionId, response),
127
155
  respondQuestion: (response) => registry.respondQuestion(sessionId, response),
128
156
  });
157
+ const discardSuspendedTurn = () => registry.discardSegmentedTurn(sessionId);
158
+ input.signal?.addEventListener('abort', discardSuspendedTurn, { once: true });
159
+ if (input.signal?.aborted)
160
+ discardSuspendedTurn();
129
161
  try {
130
162
  for await (const chunk of registry.execute({ ...input, adapterId: config.adapterId })) {
163
+ if (chunk.type === 'step-boundary') {
164
+ // Agent Loop 会在本次 llm/stream 返回后关闭当前 step,并在返回前
165
+ // 检查 next-step inbox。必须先注入,再发送 finish,不能等 complete()
166
+ // 之后再写入,否则 DSH 已经把整个 turn 结算完了。
167
+ const injected = nativeSessions?.available === true
168
+ ? nativeSessions.injectNextStep?.(sessionId) ?? false
169
+ : false;
170
+ if (!injected)
171
+ discardSuspendedTurn();
172
+ for (const dshChunk of await projector.push(chunk))
173
+ yield dshChunk;
174
+ continue;
175
+ }
131
176
  for (const dshChunk of await projector.push(chunk))
132
177
  yield dshChunk;
133
178
  // DSH 要求 finish 是唯一且最后一个 chunk。这里 return 也会关闭上游迭代器。
@@ -143,6 +188,9 @@ export function createCliAdaptersFeature(options = {}) {
143
188
  for (const dshChunk of await projector.fail(message, input.signal?.aborted ?? false))
144
189
  yield dshChunk;
145
190
  }
191
+ finally {
192
+ input.signal?.removeEventListener('abort', discardSuspendedTurn);
193
+ }
146
194
  });
147
195
  if (typeof dispose === 'function')
148
196
  context.resources.add(() => { dispose(); });
@@ -157,11 +205,15 @@ function readAdapterId(value) {
157
205
  throw new Error('adapterId 不能为空');
158
206
  return record.adapterId.trim();
159
207
  }
160
- function readSubscriptionAdapterId(value) {
208
+ function readSubscriptionRequest(value) {
161
209
  const record = asRecord(value);
162
210
  if (record === null || record.adapterId === undefined)
163
- return 'command-code';
164
- return readAdapterId(value);
211
+ return { adapterId: 'command-code' };
212
+ const adapterId = readAdapterId(value);
213
+ return {
214
+ adapterId,
215
+ ...(typeof record.providerId === 'string' && record.providerId.trim() !== '' ? { providerId: record.providerId.trim() } : {}),
216
+ };
165
217
  }
166
218
  function readSessionId(value) {
167
219
  const record = asRecord(value);
@@ -176,6 +228,7 @@ function readSessionConfig(value) {
176
228
  adapterId,
177
229
  ...(typeof record?.modelId === 'string' && record.modelId.trim() ? { modelId: record.modelId.trim() } : {}),
178
230
  ...(typeof record?.effortId === 'string' && record.effortId.trim() ? { effortId: record.effortId.trim() } : {}),
231
+ ...(typeof record?.providerId === 'string' && record.providerId.trim() ? { providerId: record.providerId.trim() } : {}),
179
232
  ...(typeof record?.providerSessionId === 'string' && record.providerSessionId.trim() ? { providerSessionId: record.providerSessionId.trim() } : {}),
180
233
  };
181
234
  }
@@ -215,15 +268,17 @@ function readDshSelection(value) {
215
268
  };
216
269
  const modelId = read(['model', 'modelId']);
217
270
  const effortId = read(['reasoningEffort', 'effortId', 'thinking']);
271
+ const providerId = read(['provider', 'providerId', 'providerName']);
218
272
  return {
219
273
  ...(modelId === undefined ? {} : { modelId }),
220
274
  ...(effortId === undefined ? {} : { effortId }),
275
+ ...(providerId === undefined ? {} : { providerId }),
221
276
  };
222
277
  }
223
278
  /** DSH Session 快照把最近选择放在 modelSelection.lastUsed/next。 */
224
279
  function readModelSelectionCandidates(value) {
225
280
  const result = [];
226
- for (const candidate of [value, asRecord(value?.request), asRecord(value?.config), asRecord(value?.header)]) {
281
+ for (const candidate of [value, asRecord(value?.request), asRecord(value?.config), asRecord(value?.header), asRecord(asRecord(value?.record)?.rows)]) {
227
282
  const selection = asRecord(candidate?.modelSelection);
228
283
  const lastUsed = asRecord(selection?.lastUsed);
229
284
  const next = asRecord(selection?.next);
@@ -247,11 +302,22 @@ async function setAdapterEnabled(settings, registry, value) {
247
302
  function extractPrompt(messages) {
248
303
  for (let index = messages.length - 1; index >= 0; index -= 1) {
249
304
  const message = messages[index];
305
+ if (message !== undefined && isInjectedStepNotice(message))
306
+ return extractText(message.content);
250
307
  if (message !== undefined && isHumanUserMessage(message))
251
308
  return extractText(message.content);
252
309
  }
253
310
  return '';
254
311
  }
312
+ /** DSH 为工具分段注入的继续提示必须成为下一次 Provider 请求的 prompt。 */
313
+ function isInjectedStepNotice(message) {
314
+ if (message.role !== 'user' || !isRecord(message.source))
315
+ return false;
316
+ if (message.source.form !== 'notice')
317
+ return false;
318
+ return message.source.kind === 'model-selection'
319
+ || message.source.kind === 'plugin' && message.source.plugin === 'codingns4dsh';
320
+ }
255
321
  function isHumanUserMessage(message) {
256
322
  if (message.role !== 'user')
257
323
  return false;
@@ -25,7 +25,7 @@ export class GeminiCliDriver extends StandardStreamDriver {
25
25
  try {
26
26
  await rpc.request('initialize', {
27
27
  protocolVersion: 1,
28
- clientInfo: { name: 'codingns4dsh', version: '0.1.0' },
28
+ clientInfo: { name: 'codingns4dsh', version: '0.1.1' },
29
29
  clientCapabilities: {},
30
30
  }, { signal: controller.signal });
31
31
  const session = await rpc.request('session/new', {
@@ -128,7 +128,7 @@ export class GeminiCliDriver extends StandardStreamDriver {
128
128
  try {
129
129
  await rpc.request('initialize', {
130
130
  protocolVersion: 1,
131
- clientInfo: { name: 'codingns4dsh', version: '0.1.0' },
131
+ clientInfo: { name: 'codingns4dsh', version: '0.1.1' },
132
132
  clientCapabilities: {},
133
133
  }, { signal: input.signal });
134
134
  rpc.notify('initialized', {});
@@ -34,7 +34,7 @@ export class GrokBuildDriver {
34
34
  return emptyCatalog();
35
35
  const rpc = new JsonRpcProcess({ command, args: ['agent', '--no-leader', 'stdio'], spawn: this.runSpawn });
36
36
  try {
37
- await rpc.request('initialize', { protocolVersion: 1, clientInfo: { name: 'codingns4dsh', version: '0.1.0' }, capabilities: {} });
37
+ await rpc.request('initialize', { protocolVersion: 1, clientInfo: { name: 'codingns4dsh', version: '0.1.1' }, capabilities: {} });
38
38
  rpc.notify('initialized', {});
39
39
  const session = await rpc.request('session/new', { cwd: process.cwd(), mcpServers: [] });
40
40
  const parsed = parseGrokCatalog(session);
@@ -126,7 +126,7 @@ export class GrokBuildDriver {
126
126
  const state = { rpc, cwd: input.cwd, providerSessionId: '', requests: new Map() };
127
127
  await rpc.request('initialize', {
128
128
  protocolVersion: 1,
129
- clientInfo: { name: 'codingns4dsh', version: '0.1.0' },
129
+ clientInfo: { name: 'codingns4dsh', version: '0.1.1' },
130
130
  capabilities: {},
131
131
  });
132
132
  rpc.notify('initialized', {});
@@ -25,6 +25,8 @@ export interface JsonRpcRequestOptions {
25
25
  readonly onNotification?: (message: JsonRpcMessage) => void;
26
26
  /** 取消本次请求时是否同时终止整个 Agent 进程;长期会话应关闭此项。 */
27
27
  readonly killOnAbort?: boolean;
28
+ /** Pi 使用 type/data 顶层命令,不是 JSON-RPC method/params。 */
29
+ readonly wireFormat?: 'jsonrpc' | 'pi';
28
30
  }
29
31
  /**
30
32
  * 统一管理 stdio JSON-RPC 子进程:请求编号、逐行解码、取消和退出清理都在这里完成。
@@ -43,8 +45,8 @@ export declare class JsonRpcProcess {
43
45
  private serverRequestHandler;
44
46
  constructor(options: JsonRpcProcessOptions);
45
47
  request(method: string, params?: unknown, options?: JsonRpcRequestOptions): Promise<unknown>;
46
- /** 发送无需响应的 JSON-RPC 通知,例如 initialized 或 cancel。 */
47
- notify(method: string, params?: unknown): void;
48
+ /** 发送无需响应的协议通知,例如 initialized 或 cancel。 */
49
+ notify(method: string, params?: unknown, wireFormat?: 'jsonrpc' | 'pi'): void;
48
50
  /** 注册 Agent 发起的 JSON-RPC 服务端请求处理器,例如 Codex 权限审批。 */
49
51
  setServerRequestHandler(handler: ((message: JsonRpcMessage) => unknown | Promise<unknown>) | undefined): void;
50
52
  /** 为一段流式请求注册独立监听器,响应先到时也不会提前移除。 */
@@ -40,14 +40,10 @@ export class JsonRpcProcess {
40
40
  else
41
41
  options.signal?.addEventListener('abort', onAbort, { once: true });
42
42
  try {
43
- // Pi 的模型探测命令是自定义 RPC:请求体使用 `type`,不能包成 JSON-RPC
44
- // method,否则 Pi 会回报 “Unknown command: undefined”。其余适配器仍走标准 JSON-RPC。
45
- if (method === 'get_available_models') {
43
+ if (options.wireFormat === 'pi')
46
44
  this.write({ id, type: method, ...(isRecord(params) ? params : {}) });
47
- }
48
- else {
45
+ else
49
46
  this.write({ jsonrpc: '2.0', id, method, params });
50
- }
51
47
  const result = await promise;
52
48
  if (options.signal?.aborted)
53
49
  throw new Error('请求已取消');
@@ -60,10 +56,13 @@ export class JsonRpcProcess {
60
56
  this.pending.delete(id);
61
57
  }
62
58
  }
63
- /** 发送无需响应的 JSON-RPC 通知,例如 initialized 或 cancel。 */
64
- notify(method, params = {}) {
59
+ /** 发送无需响应的协议通知,例如 initialized 或 cancel。 */
60
+ notify(method, params = {}, wireFormat = 'jsonrpc') {
65
61
  this.ensureStarted();
66
- this.write({ jsonrpc: '2.0', method, params });
62
+ if (wireFormat === 'pi')
63
+ this.write({ type: method, ...(isRecord(params) ? params : {}) });
64
+ else
65
+ this.write({ jsonrpc: '2.0', method, params });
67
66
  }
68
67
  /** 注册 Agent 发起的 JSON-RPC 服务端请求处理器,例如 Codex 权限审批。 */
69
68
  setServerRequestHandler(handler) {
@@ -137,7 +137,7 @@ export class KimiCliDriver extends StandardStreamDriver {
137
137
  method: 'initialize',
138
138
  params: {
139
139
  protocol_version: '1.10',
140
- client: { name: 'codingns4dsh', version: '0.1.0' },
140
+ client: { name: 'codingns4dsh', version: '0.1.1' },
141
141
  capabilities: { supports_question: true },
142
142
  },
143
143
  })}\n`);
@@ -0,0 +1,17 @@
1
+ import type { CodingNsCliAdapterId } from '../../shared/contracts/cli-adapter.js';
2
+ /** 当前插件注册的适配器;旧日志只能从这些稳定 ID 中选择,不能猜测任意品牌。 */
3
+ export declare const KNOWN_CLI_ADAPTER_IDS: Set<string>;
4
+ export interface LegacySessionAdapterEvidence {
5
+ readonly sessionId: string;
6
+ readonly adapterId?: CodingNsCliAdapterId;
7
+ readonly cwd?: string;
8
+ readonly createdAt?: string;
9
+ readonly external: boolean;
10
+ }
11
+ /**
12
+ * 从 DSH 原生会话快照读取旧版外部 Agent 的适配器证据。
13
+ * `codingns-external` 只能证明消息来自外部 Agent;只有 source/provider 或
14
+ * request/context 中出现当前已知适配器 ID 时才回填,避免把 DSH 模型提供方误认成 CLI。
15
+ */
16
+ export declare function inspectLegacySessionAdapter(value: unknown): LegacySessionAdapterEvidence | undefined;
17
+ //# sourceMappingURL=legacy-session-adapter.d.ts.map