wave-code 1.0.9 → 1.1.0

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 (244) hide show
  1. package/bin/wave-code.js +8 -2
  2. package/dist/bundle/wave.mjs +3207 -0
  3. package/package.json +24 -25
  4. package/src/commands/update.ts +2 -7
  5. package/src/components/App.tsx +3 -7
  6. package/src/components/BtwDisplay.tsx +10 -1
  7. package/src/components/ChatInterface.tsx +21 -52
  8. package/src/components/ConfirmationDetails.tsx +144 -37
  9. package/src/components/DiffDisplay.tsx +335 -301
  10. package/src/components/InputBox.tsx +3 -1
  11. package/src/components/LoadingIndicator.tsx +16 -2
  12. package/src/components/MessageBlockItem.tsx +2 -4
  13. package/src/components/MessageList.tsx +75 -14
  14. package/src/components/ReasoningDisplay.tsx +2 -4
  15. package/src/components/SessionSelector.tsx +82 -11
  16. package/src/components/StatusCommand.tsx +2 -9
  17. package/src/components/ToolDisplay.tsx +2 -4
  18. package/src/contexts/useChat.tsx +172 -350
  19. package/src/daemon/commands.ts +57 -27
  20. package/src/daemon/jsonRpcClient.ts +1 -1
  21. package/src/daemon/socketClient.ts +2 -2
  22. package/src/hooks/useInputManager.ts +1 -1
  23. package/src/index.ts +57 -10
  24. package/src/managers/inputReducer.ts +186 -104
  25. package/src/print-cli.ts +21 -17
  26. package/src/reducers/selectorReducer.ts +10 -0
  27. package/src/session-selector-cli.tsx +269 -28
  28. package/src/stdio/agentBridge.ts +22 -21
  29. package/src/stdio/daemonServer.ts +3 -1
  30. package/src/stdio/jsonRpcConnection.ts +19 -1
  31. package/src/stdio/stdioServer.ts +17 -0
  32. package/src/utils/clipboard.ts +21 -0
  33. package/src/utils/highlightUtils.ts +46 -1
  34. package/src/utils/readPackageJson.ts +29 -0
  35. package/src/utils/streamingText.ts +11 -0
  36. package/src/utils/worktree.ts +191 -43
  37. package/dist/cli.d.ts +0 -6
  38. package/dist/cli.js +0 -53
  39. package/dist/commands/plugin/disable.d.ts +0 -5
  40. package/dist/commands/plugin/disable.js +0 -15
  41. package/dist/commands/plugin/enable.d.ts +0 -5
  42. package/dist/commands/plugin/enable.js +0 -15
  43. package/dist/commands/plugin/install.d.ts +0 -5
  44. package/dist/commands/plugin/install.js +0 -21
  45. package/dist/commands/plugin/list.d.ts +0 -1
  46. package/dist/commands/plugin/list.js +0 -31
  47. package/dist/commands/plugin/marketplace.d.ts +0 -10
  48. package/dist/commands/plugin/marketplace.js +0 -90
  49. package/dist/commands/plugin/uninstall.d.ts +0 -3
  50. package/dist/commands/plugin/uninstall.js +0 -16
  51. package/dist/commands/plugin/update.d.ts +0 -3
  52. package/dist/commands/plugin/update.js +0 -15
  53. package/dist/commands/update.d.ts +0 -1
  54. package/dist/commands/update.js +0 -97
  55. package/dist/components/AgentsManager.d.ts +0 -7
  56. package/dist/components/AgentsManager.js +0 -109
  57. package/dist/components/App.d.ts +0 -9
  58. package/dist/components/App.js +0 -76
  59. package/dist/components/BackgroundTaskManager.d.ts +0 -5
  60. package/dist/components/BackgroundTaskManager.js +0 -99
  61. package/dist/components/BangDisplay.d.ts +0 -8
  62. package/dist/components/BangDisplay.js +0 -17
  63. package/dist/components/BtwDisplay.d.ts +0 -7
  64. package/dist/components/BtwDisplay.js +0 -19
  65. package/dist/components/ChatInterface.d.ts +0 -2
  66. package/dist/components/ChatInterface.js +0 -61
  67. package/dist/components/CommandSelector.d.ts +0 -10
  68. package/dist/components/CommandSelector.js +0 -66
  69. package/dist/components/CompactDisplay.d.ts +0 -8
  70. package/dist/components/CompactDisplay.js +0 -13
  71. package/dist/components/ConfirmationDetails.d.ts +0 -9
  72. package/dist/components/ConfirmationDetails.js +0 -45
  73. package/dist/components/ConfirmationSelector.d.ts +0 -13
  74. package/dist/components/ConfirmationSelector.js +0 -127
  75. package/dist/components/DiffDisplay.d.ts +0 -8
  76. package/dist/components/DiffDisplay.js +0 -201
  77. package/dist/components/DiscoverView.d.ts +0 -2
  78. package/dist/components/DiscoverView.js +0 -37
  79. package/dist/components/FileSelector.d.ts +0 -11
  80. package/dist/components/FileSelector.js +0 -50
  81. package/dist/components/HelpView.d.ts +0 -7
  82. package/dist/components/HelpView.js +0 -74
  83. package/dist/components/HistorySearch.d.ts +0 -8
  84. package/dist/components/HistorySearch.js +0 -66
  85. package/dist/components/InputBox.d.ts +0 -24
  86. package/dist/components/InputBox.js +0 -149
  87. package/dist/components/InstalledView.d.ts +0 -2
  88. package/dist/components/InstalledView.js +0 -45
  89. package/dist/components/LoadingIndicator.d.ts +0 -10
  90. package/dist/components/LoadingIndicator.js +0 -6
  91. package/dist/components/LoginCommand.d.ts +0 -5
  92. package/dist/components/LoginCommand.js +0 -153
  93. package/dist/components/Markdown.d.ts +0 -5
  94. package/dist/components/Markdown.js +0 -127
  95. package/dist/components/MarketplaceAddForm.d.ts +0 -2
  96. package/dist/components/MarketplaceAddForm.js +0 -55
  97. package/dist/components/MarketplaceDetail.d.ts +0 -2
  98. package/dist/components/MarketplaceDetail.js +0 -74
  99. package/dist/components/MarketplaceList.d.ts +0 -8
  100. package/dist/components/MarketplaceList.js +0 -17
  101. package/dist/components/MarketplaceView.d.ts +0 -2
  102. package/dist/components/MarketplaceView.js +0 -41
  103. package/dist/components/McpManager.d.ts +0 -9
  104. package/dist/components/McpManager.js +0 -88
  105. package/dist/components/MessageBlockItem.d.ts +0 -8
  106. package/dist/components/MessageBlockItem.js +0 -15
  107. package/dist/components/MessageList.d.ts +0 -10
  108. package/dist/components/MessageList.js +0 -80
  109. package/dist/components/ModelSelector.d.ts +0 -8
  110. package/dist/components/ModelSelector.js +0 -45
  111. package/dist/components/Notifications.d.ts +0 -7
  112. package/dist/components/Notifications.js +0 -9
  113. package/dist/components/PlanDisplay.d.ts +0 -7
  114. package/dist/components/PlanDisplay.js +0 -6
  115. package/dist/components/PluginDetail.d.ts +0 -2
  116. package/dist/components/PluginDetail.js +0 -87
  117. package/dist/components/PluginList.d.ts +0 -13
  118. package/dist/components/PluginList.js +0 -15
  119. package/dist/components/PluginManagerShell.d.ts +0 -6
  120. package/dist/components/PluginManagerShell.js +0 -92
  121. package/dist/components/PluginManagerTypes.d.ts +0 -35
  122. package/dist/components/PluginManagerTypes.js +0 -1
  123. package/dist/components/QueuedMessageList.d.ts +0 -2
  124. package/dist/components/QueuedMessageList.js +0 -18
  125. package/dist/components/ReasoningDisplay.d.ts +0 -8
  126. package/dist/components/ReasoningDisplay.js +0 -13
  127. package/dist/components/RewindCommand.d.ts +0 -12
  128. package/dist/components/RewindCommand.js +0 -78
  129. package/dist/components/SessionSelector.d.ts +0 -12
  130. package/dist/components/SessionSelector.js +0 -47
  131. package/dist/components/StatusCommand.d.ts +0 -5
  132. package/dist/components/StatusCommand.js +0 -28
  133. package/dist/components/StatusLine.d.ts +0 -6
  134. package/dist/components/StatusLine.js +0 -9
  135. package/dist/components/TaskList.d.ts +0 -5
  136. package/dist/components/TaskList.js +0 -197
  137. package/dist/components/TaskNotificationMessage.d.ts +0 -5
  138. package/dist/components/TaskNotificationMessage.js +0 -12
  139. package/dist/components/ToolDisplay.d.ts +0 -9
  140. package/dist/components/ToolDisplay.js +0 -55
  141. package/dist/components/WorkflowManager.d.ts +0 -5
  142. package/dist/components/WorkflowManager.js +0 -102
  143. package/dist/components/WorktreeExitPrompt.d.ts +0 -12
  144. package/dist/components/WorktreeExitPrompt.js +0 -35
  145. package/dist/constants/commands.d.ts +0 -2
  146. package/dist/constants/commands.js +0 -92
  147. package/dist/contexts/PluginManagerContext.d.ts +0 -3
  148. package/dist/contexts/PluginManagerContext.js +0 -9
  149. package/dist/contexts/useAppConfig.d.ts +0 -10
  150. package/dist/contexts/useAppConfig.js +0 -13
  151. package/dist/contexts/useChat.d.ts +0 -101
  152. package/dist/contexts/useChat.js +0 -992
  153. package/dist/contracts/status.d.ts +0 -7
  154. package/dist/contracts/status.js +0 -1
  155. package/dist/daemon/commands.d.ts +0 -49
  156. package/dist/daemon/commands.js +0 -341
  157. package/dist/daemon/jsonRpcClient.d.ts +0 -38
  158. package/dist/daemon/jsonRpcClient.js +0 -129
  159. package/dist/daemon/socketClient.d.ts +0 -13
  160. package/dist/daemon/socketClient.js +0 -26
  161. package/dist/daemon-cli.d.ts +0 -10
  162. package/dist/daemon-cli.js +0 -15
  163. package/dist/hooks/useInputManager.d.ts +0 -75
  164. package/dist/hooks/useInputManager.js +0 -583
  165. package/dist/hooks/usePluginManager.d.ts +0 -4
  166. package/dist/hooks/usePluginManager.js +0 -265
  167. package/dist/hooks/useTasks.d.ts +0 -1
  168. package/dist/hooks/useTasks.js +0 -5
  169. package/dist/index.d.ts +0 -4
  170. package/dist/index.js +0 -447
  171. package/dist/managers/inputHandlers.d.ts +0 -30
  172. package/dist/managers/inputHandlers.js +0 -625
  173. package/dist/managers/inputReducer.d.ts +0 -271
  174. package/dist/managers/inputReducer.js +0 -1121
  175. package/dist/plugin-manager-cli.d.ts +0 -5
  176. package/dist/plugin-manager-cli.js +0 -12
  177. package/dist/print-cli.d.ts +0 -10
  178. package/dist/print-cli.js +0 -209
  179. package/dist/reducers/agentsManagerReducer.d.ts +0 -26
  180. package/dist/reducers/agentsManagerReducer.js +0 -54
  181. package/dist/reducers/backgroundTaskManagerReducer.d.ts +0 -62
  182. package/dist/reducers/backgroundTaskManagerReducer.js +0 -106
  183. package/dist/reducers/confirmationReducer.d.ts +0 -37
  184. package/dist/reducers/confirmationReducer.js +0 -193
  185. package/dist/reducers/helpSelectorReducer.d.ts +0 -25
  186. package/dist/reducers/helpSelectorReducer.js +0 -52
  187. package/dist/reducers/marketplaceAddFormReducer.d.ts +0 -24
  188. package/dist/reducers/marketplaceAddFormReducer.js +0 -58
  189. package/dist/reducers/mcpManagerReducer.d.ts +0 -37
  190. package/dist/reducers/mcpManagerReducer.js +0 -74
  191. package/dist/reducers/pluginDetailReducer.d.ts +0 -32
  192. package/dist/reducers/pluginDetailReducer.js +0 -70
  193. package/dist/reducers/questionReducer.d.ts +0 -82
  194. package/dist/reducers/questionReducer.js +0 -375
  195. package/dist/reducers/rewindSelectorReducer.d.ts +0 -21
  196. package/dist/reducers/rewindSelectorReducer.js +0 -37
  197. package/dist/reducers/selectorReducer.d.ts +0 -23
  198. package/dist/reducers/selectorReducer.js +0 -42
  199. package/dist/reducers/workflowManagerReducer.d.ts +0 -40
  200. package/dist/reducers/workflowManagerReducer.js +0 -100
  201. package/dist/session-selector-cli.d.ts +0 -3
  202. package/dist/session-selector-cli.js +0 -25
  203. package/dist/stdio/agentBridge.d.ts +0 -139
  204. package/dist/stdio/agentBridge.js +0 -999
  205. package/dist/stdio/daemonServer.d.ts +0 -67
  206. package/dist/stdio/daemonServer.js +0 -191
  207. package/dist/stdio/index.d.ts +0 -5
  208. package/dist/stdio/index.js +0 -5
  209. package/dist/stdio/jsonRpcConnection.d.ts +0 -30
  210. package/dist/stdio/jsonRpcConnection.js +0 -127
  211. package/dist/stdio/protocol.d.ts +0 -41
  212. package/dist/stdio/protocol.js +0 -26
  213. package/dist/stdio/stdioServer.d.ts +0 -28
  214. package/dist/stdio/stdioServer.js +0 -36
  215. package/dist/stdio-cli.d.ts +0 -8
  216. package/dist/stdio-cli.js +0 -15
  217. package/dist/types.d.ts +0 -20
  218. package/dist/types.js +0 -1
  219. package/dist/utils/bracketedPaste.d.ts +0 -39
  220. package/dist/utils/bracketedPaste.js +0 -122
  221. package/dist/utils/clipboard.d.ts +0 -21
  222. package/dist/utils/clipboard.js +0 -347
  223. package/dist/utils/constants.d.ts +0 -16
  224. package/dist/utils/constants.js +0 -18
  225. package/dist/utils/highlightUtils.d.ts +0 -1
  226. package/dist/utils/highlightUtils.js +0 -93
  227. package/dist/utils/inputUtils.d.ts +0 -17
  228. package/dist/utils/inputUtils.js +0 -67
  229. package/dist/utils/logger.d.ts +0 -71
  230. package/dist/utils/logger.js +0 -259
  231. package/dist/utils/markdownTable.d.ts +0 -34
  232. package/dist/utils/markdownTable.js +0 -302
  233. package/dist/utils/rewindCheckpoints.d.ts +0 -8
  234. package/dist/utils/rewindCheckpoints.js +0 -17
  235. package/dist/utils/throttle.d.ts +0 -14
  236. package/dist/utils/throttle.js +0 -55
  237. package/dist/utils/toolParameterTransforms.d.ts +0 -18
  238. package/dist/utils/toolParameterTransforms.js +0 -73
  239. package/dist/utils/usageSummary.d.ts +0 -28
  240. package/dist/utils/usageSummary.js +0 -121
  241. package/dist/utils/version.d.ts +0 -1
  242. package/dist/utils/version.js +0 -4
  243. package/dist/utils/worktree.d.ts +0 -35
  244. package/dist/utils/worktree.js +0 -219
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * `wave daemon` client subcommands — talk to the wave daemon's unix socket
3
3
  * (JSON-RPC over newline-delimited JSON) to list hosted sessions, inspect
4
- * progress, inject messages and respond to pending permission requests.
4
+ * progress, inject messages, respond to pending permission requests and abort
5
+ * in-flight message generation.
5
6
  *
6
7
  * All subcommands are non-interactive: results go to stdout, diagnostics to
7
8
  * stderr, and every handler calls process.exit() itself (yargs would fall
@@ -68,7 +69,7 @@ async function connectDaemonOrExit(socketPath: string): Promise<SocketClient> {
68
69
  } catch (err) {
69
70
  const code = (err as NodeJS.ErrnoException).code;
70
71
  console.error(
71
- `无法连接 daemon socket ${socketPath}:daemon 未运行?(daemon 空闲 60 秒自动退出)` +
72
+ `Cannot connect to daemon socket ${socketPath}: is the daemon running? (it auto-exits after 60s idle)` +
72
73
  (code ? ` (${code})` : ""),
73
74
  );
74
75
  process.exit(1);
@@ -115,7 +116,7 @@ async function attachSession(
115
116
  // initialize silently started a junk fresh session — remove it from the
116
117
  // registry so the failed attach leaves no trace (spec: 会话不存在错误).
117
118
  await client.request("destroy", undefined, initId).catch(() => {});
118
- fail(`会话不存在或未被该 daemon 托管:${sessionId}`);
119
+ fail(`Session not found or not hosted by this daemon: ${sessionId}`);
119
120
  }
120
121
  throw err;
121
122
  }
@@ -149,7 +150,7 @@ export async function daemonListCommand(socketPath: string): Promise<void> {
149
150
  if (sessions.length > 0) {
150
151
  const rows = sessions.map((s) => ({
151
152
  sessionId: s.sessionId,
152
- status: s.isLoading ? "生成中" : "空闲",
153
+ status: s.isLoading ? "generating" : "idle",
153
154
  messageCount: String(s.messageCount),
154
155
  workingDirectory: s.workingDirectory,
155
156
  }));
@@ -158,7 +159,7 @@ export async function daemonListCommand(socketPath: string): Promise<void> {
158
159
  const pad = (value: string, w: number) => value.padEnd(w);
159
160
 
160
161
  console.log(
161
- `${pad("会话", width("sessionId"))} ${pad("状态", width("status"))} ${pad("消息数", width("messageCount"))} 工作目录`,
162
+ `${pad("Session", width("sessionId"))} ${pad("Status", width("status"))} ${pad("Messages", width("messageCount"))} Working directory`,
162
163
  );
163
164
  for (const r of rows) {
164
165
  console.log(
@@ -167,10 +168,10 @@ export async function daemonListCommand(socketPath: string): Promise<void> {
167
168
  }
168
169
  } else {
169
170
  // Daemon idle-exit is normal — an empty registry is not an error.
170
- console.log("无会话");
171
+ console.log("No sessions");
171
172
  }
172
173
  } catch (err) {
173
- fail(`wave daemon list 失败:${(err as Error).message}`);
174
+ fail(`wave daemon list failed: ${(err as Error).message}`);
174
175
  } finally {
175
176
  await client?.dispose();
176
177
  }
@@ -226,14 +227,18 @@ export async function daemonStatusCommand(
226
227
  };
227
228
 
228
229
  const status =
229
- pending.length > 0 ? "等待审批" : loading ? "生成中" : "空闲";
230
- console.log(`会话: ${initId}`);
231
- console.log(`工作目录: ${init.workingDirectory}`);
232
- console.log(`状态: ${status}`);
230
+ pending.length > 0
231
+ ? "waiting for approval"
232
+ : loading
233
+ ? "generating"
234
+ : "idle";
235
+ console.log(`Session: ${initId}`);
236
+ console.log(`Working directory: ${init.workingDirectory}`);
237
+ console.log(`Status: ${status}`);
233
238
 
234
239
  if (pending.length > 0) {
235
240
  console.log("");
236
- console.log("待审批请求:");
241
+ console.log("Pending approval requests:");
237
242
  for (const r of pending) {
238
243
  const params = summarizeToolInput(r.context);
239
244
  console.log(
@@ -245,7 +250,7 @@ export async function daemonStatusCommand(
245
250
  const recent = messages.messages.slice(-lines);
246
251
  if (recent.length > 0) {
247
252
  console.log("");
248
- console.log(`最近消息 (${recent.length}):`);
253
+ console.log(`Recent messages (${recent.length}):`);
249
254
  for (const m of recent) {
250
255
  const text = getMessageContent(m).replace(/\s+/g, " ").trim();
251
256
  if (!text) continue; // tool-only messages carry no readable text
@@ -253,7 +258,7 @@ export async function daemonStatusCommand(
253
258
  }
254
259
  }
255
260
  } catch (err) {
256
- fail(`wave daemon status 失败:${(err as Error).message}`);
261
+ fail(`wave daemon status failed: ${(err as Error).message}`);
257
262
  } finally {
258
263
  await client?.dispose();
259
264
  }
@@ -311,7 +316,7 @@ export async function daemonSendCommand(
311
316
  await client.request("sendMessage", { text: message }, initId);
312
317
  } catch (err) {
313
318
  client.dispose();
314
- fail(`wave daemon send 失败:${(err as Error).message}`);
319
+ fail(`wave daemon send failed: ${(err as Error).message}`);
315
320
  }
316
321
 
317
322
  // Wait for the reply that corresponds to our message.
@@ -327,13 +332,13 @@ export async function daemonSendCommand(
327
332
  client.dispose();
328
333
  if (pending.length > 0) {
329
334
  fail(
330
- `会话等待权限审批,请通过 \`wave daemon respond ${sessionId} ${pending[0].requestId}\` 处理后重试`,
335
+ `Session is waiting for permission approval; handle it with \`wave daemon respond ${sessionId} ${pending[0].requestId}\` and retry`,
331
336
  );
332
337
  }
333
338
  fail(
334
339
  options.timeout === 0
335
- ? "等待回复超时"
336
- : `等待回复超时(${options.timeout} 秒),未收到助手回复`,
340
+ ? "Timed out waiting for a reply"
341
+ : `Timed out waiting for a reply (${options.timeout}s), no assistant reply received`,
337
342
  );
338
343
  }
339
344
  await sleep(200);
@@ -351,7 +356,7 @@ export async function daemonSendCommand(
351
356
  if (content) console.log(content);
352
357
  }
353
358
  } catch (err) {
354
- fail(`wave daemon send 失败:${(err as Error).message}`);
359
+ fail(`wave daemon send failed: ${(err as Error).message}`);
355
360
  } finally {
356
361
  client.dispose();
357
362
  }
@@ -376,7 +381,7 @@ export async function daemonRespondCommand(
376
381
  options: RespondOptions,
377
382
  ): Promise<void> {
378
383
  if (!!options.allow === !!options.deny) {
379
- fail("请指定 --allow --deny(二选一)");
384
+ fail("Specify either --allow or --deny");
380
385
  }
381
386
  let client: SocketClient | undefined;
382
387
  try {
@@ -387,11 +392,11 @@ export async function daemonRespondCommand(
387
392
  const pending = await listPendingPermissions(client);
388
393
  const req = pending.find((r) => r.requestId === requestId);
389
394
  if (!req) {
390
- fail("该请求不存在或已处理");
395
+ fail("Request not found or already handled");
391
396
  }
392
397
  if (req.sessionId && req.sessionId !== sessionId) {
393
398
  // Cross-check before notifying; never touch another session's request.
394
- fail("会话不存在或未被该 daemon 托管");
399
+ fail("Session not found or not hosted by this daemon");
395
400
  }
396
401
 
397
402
  let decision: PermissionDecision;
@@ -407,13 +412,15 @@ export async function daemonRespondCommand(
407
412
  decision = { behavior: "allow", newPermissionMode: "default" };
408
413
  } else if (toolName === ASK_USER_QUESTION_TOOL_NAME) {
409
414
  if (!options.answer) {
410
- fail("AskUserQuestion 请求需要 --answer 提供答案 JSON");
415
+ fail(
416
+ "AskUserQuestion requests require --answer with the answer JSON",
417
+ );
411
418
  }
412
419
  let answers: unknown;
413
420
  try {
414
421
  answers = JSON.parse(options.answer);
415
422
  } catch {
416
- fail("--answer 不是合法的 JSON");
423
+ fail("--answer is not valid JSON");
417
424
  }
418
425
  decision = { behavior: "allow", message: JSON.stringify(answers) };
419
426
  } else {
@@ -424,7 +431,7 @@ export async function daemonRespondCommand(
424
431
  if (options.mode) {
425
432
  if (!PERMISSION_MODES.includes(options.mode as PermissionMode)) {
426
433
  fail(
427
- `无效的权限模式:${options.mode}(可选:${PERMISSION_MODES.join("")})`,
434
+ `Invalid permission mode: ${options.mode} (options: ${PERMISSION_MODES.join(", ")})`,
428
435
  );
429
436
  }
430
437
  decision.newPermissionMode = options.mode as PermissionMode;
@@ -434,9 +441,32 @@ export async function daemonRespondCommand(
434
441
  // Mirror desktop stdioAgent.sendPermissionResponse: envelope sessionId
435
442
  // present, decision built from the pending request's tool.
436
443
  client.notify("permissionResponse", { requestId, decision }, sessionId);
437
- console.log(`已处理审批请求:${requestId}`);
444
+ console.log(`Handled approval request: ${requestId}`);
445
+ } catch (err) {
446
+ fail(`wave daemon respond failed: ${(err as Error).message}`);
447
+ } finally {
448
+ await client?.dispose();
449
+ }
450
+ process.exit(0);
451
+ }
452
+
453
+ // ── abort ─────────────────────────────────────────────────────
454
+
455
+ export async function daemonAbortCommand(
456
+ socketPath: string,
457
+ sessionId: string,
458
+ ): Promise<void> {
459
+ let client: SocketClient | undefined;
460
+ try {
461
+ client = await connectDaemonOrExit(socketPath);
462
+ const init = await attachSession(client, sessionId);
463
+ // abortMessage is idempotent: a no-op on idle sessions, interrupts
464
+ // in-flight generation (incl. subagents / bash / slash / queued messages)
465
+ // otherwise (spec: 中断幂等,无需先确认是否正在生成).
466
+ await client.request("abortMessage", undefined, init.sessionId);
467
+ console.log(`Aborted session: ${sessionId}`);
438
468
  } catch (err) {
439
- fail(`wave daemon respond 失败:${(err as Error).message}`);
469
+ fail(`wave daemon abort failed: ${(err as Error).message}`);
440
470
  } finally {
441
471
  await client?.dispose();
442
472
  }
@@ -76,7 +76,7 @@ export abstract class JsonRpcClient {
76
76
  ): Promise<unknown> {
77
77
  if (this.closed) {
78
78
  throw new Error(
79
- "连接已断开。wave 进程已退出,请重启编辑器或检查 CLI 安装。",
79
+ "Connection closed. The wave process has exited; restart the editor or check your CLI installation.",
80
80
  );
81
81
  }
82
82
  const id = this.nextId++;
@@ -16,7 +16,7 @@ export class SocketClient extends JsonRpcClient {
16
16
  this.attachReadable(socket);
17
17
 
18
18
  socket.on("close", () => {
19
- this.handleClosed("远端连接已断开。");
19
+ this.handleClosed("Remote connection closed.");
20
20
  });
21
21
  socket.on("error", (err) => {
22
22
  console.error("[wave-daemon] Socket error:", err.message);
@@ -28,7 +28,7 @@ export class SocketClient extends JsonRpcClient {
28
28
  }
29
29
 
30
30
  dispose(): void {
31
- this.handleClosed("远端连接已断开。");
31
+ this.handleClosed("Remote connection closed.");
32
32
  this.socket.destroy();
33
33
  }
34
34
  }
@@ -157,7 +157,7 @@ export const useInputManager = (
157
157
  // Stream partial answers into the overlay so the user sees
158
158
  // the response grow in real time (same visual language as
159
159
  // assistant text / thinking blocks) instead of a static
160
- // "Answering..." indicator.
160
+ // "Answering" indicator.
161
161
  if (!btwDismissedRef.current) {
162
162
  dispatch({
163
163
  type: "SET_BTW_STATE",
package/src/index.ts CHANGED
@@ -9,13 +9,9 @@ import {
9
9
  } from "wave-agent-sdk";
10
10
  import { createWorktree, type WorktreeSession } from "./utils/worktree.js";
11
11
  import path from "path";
12
- import { readFileSync } from "fs";
13
- import { fileURLToPath } from "url";
12
+ import { readNearestPackageJson } from "./utils/readPackageJson.js";
14
13
 
15
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
- const packageJsonPath = path.resolve(__dirname, "../package.json");
17
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
18
- const version = packageJson.version;
14
+ const version = readNearestPackageJson().version;
19
15
 
20
16
  // Export main function for external use
21
17
  export async function main() {
@@ -379,6 +375,24 @@ export async function main() {
379
375
  );
380
376
  },
381
377
  )
378
+ .command(
379
+ "abort <sessionId>",
380
+ "Abort the session's in-flight message generation",
381
+ (yargs) => {
382
+ return yargs.positional("sessionId", {
383
+ describe: "Session ID hosted by the daemon",
384
+ type: "string",
385
+ });
386
+ },
387
+ async (argv) => {
388
+ const { daemonAbortCommand, DEFAULT_DAEMON_SOCKET } =
389
+ await import("./daemon/commands.js");
390
+ await daemonAbortCommand(
391
+ DEFAULT_DAEMON_SOCKET,
392
+ argv.sessionId as string,
393
+ );
394
+ },
395
+ )
382
396
  .demandCommand(1, "Please specify a daemon subcommand");
383
397
  },
384
398
  )
@@ -497,13 +511,29 @@ export async function main() {
497
511
  const { startSessionSelectorCli } = await import(
498
512
  "./session-selector-cli.js"
499
513
  );
500
- const selectedSessionId = await startSessionSelectorCli({ workdir });
501
- if (!selectedSessionId) {
514
+ const { listWorktrees } = await import("./utils/worktree.js");
515
+ const worktreePaths = await listWorktrees(process.cwd());
516
+ const selection = await startSessionSelectorCli({
517
+ workdir,
518
+ worktreePaths,
519
+ });
520
+ if (!selection) {
502
521
  return;
503
522
  }
523
+
524
+ // Resume a session from a sibling worktree of the same repo — chdir into
525
+ // that worktree so the agent's workdir matches the session's origin
526
+ // (mirrors Claude Code's worktree resume; projectRoot is not set, so
527
+ // skills/history stay anchored to the original project).
528
+ let resumeWorkdir = workdir;
529
+ if (selection.resumeWorkdir) {
530
+ resumeWorkdir = selection.resumeWorkdir;
531
+ process.chdir(resumeWorkdir);
532
+ }
533
+
504
534
  // Continue with the selected session
505
535
  return startCli({
506
- restoreSessionId: selectedSessionId,
536
+ restoreSessionId: selection.sessionId,
507
537
  bypassPermissions: argv.dangerouslySkipPermissions as boolean,
508
538
  permissionMode: argv.permissionMode as PermissionMode | undefined,
509
539
  pluginDirs,
@@ -512,7 +542,7 @@ export async function main() {
512
542
  allowedTools,
513
543
  disallowedTools,
514
544
  worktreeSession,
515
- workdir,
545
+ workdir: resumeWorkdir,
516
546
  originalCwd,
517
547
  version,
518
548
  model: argv.model as string | undefined,
@@ -520,6 +550,23 @@ export async function main() {
520
550
  });
521
551
  }
522
552
 
553
+ // Validate an explicitly-specified restore ID before entering the CLI —
554
+ // loadSessionFromJsonl scans every project dir as a fallback, so a miss
555
+ // here means the session truly does not exist. Fail fast with a clear
556
+ // error instead of silently starting a fresh session.
557
+ if (
558
+ typeof argv.restore === "string" &&
559
+ argv.restore !== "" &&
560
+ !argv.print
561
+ ) {
562
+ const { loadSessionFromJsonl } = await import("wave-agent-sdk");
563
+ const exists = await loadSessionFromJsonl(argv.restore, workdir);
564
+ if (!exists) {
565
+ console.error(`Session ${argv.restore} not found on disk.`);
566
+ process.exit(1);
567
+ }
568
+ }
569
+
523
570
  // Handle print mode directly
524
571
  if (argv.print !== undefined) {
525
572
  const { startPrintCli } = await import("./print-cli.js");