@ai-zen/cli 1.0.0-alpha.2 → 1.0.0-alpha.22

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 (311) hide show
  1. package/CHANGELOG.md +514 -0
  2. package/README.md +136 -39
  3. package/README.zh.md +136 -39
  4. package/dist/agent-creator.d.ts +11 -0
  5. package/dist/agent-creator.d.ts.map +1 -1
  6. package/dist/agent-creator.js +52 -21
  7. package/dist/agent-creator.js.map +1 -1
  8. package/dist/agent-switch.d.ts +61 -0
  9. package/dist/agent-switch.d.ts.map +1 -0
  10. package/dist/agent-switch.js +83 -0
  11. package/dist/agent-switch.js.map +1 -0
  12. package/dist/agents-store.d.ts +6 -1
  13. package/dist/agents-store.d.ts.map +1 -1
  14. package/dist/agents-store.js +46 -4
  15. package/dist/agents-store.js.map +1 -1
  16. package/dist/auto-migrate-confirm.d.ts +43 -0
  17. package/dist/auto-migrate-confirm.d.ts.map +1 -0
  18. package/dist/auto-migrate-confirm.js +47 -0
  19. package/dist/auto-migrate-confirm.js.map +1 -0
  20. package/dist/config-editor.d.ts +13 -5
  21. package/dist/config-editor.d.ts.map +1 -1
  22. package/dist/config-editor.js +36 -27
  23. package/dist/config-editor.js.map +1 -1
  24. package/dist/config.d.ts +24 -3
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +55 -15
  27. package/dist/config.js.map +1 -1
  28. package/dist/conversation-commands/registry.d.ts +123 -4
  29. package/dist/conversation-commands/registry.d.ts.map +1 -1
  30. package/dist/conversation-commands/registry.js +92 -14
  31. package/dist/conversation-commands/registry.js.map +1 -1
  32. package/dist/conversation-persist-plugin.d.ts +0 -1
  33. package/dist/conversation-persist-plugin.d.ts.map +1 -1
  34. package/dist/conversation-persist-plugin.js +7 -16
  35. package/dist/conversation-persist-plugin.js.map +1 -1
  36. package/dist/conversation-repository.d.ts +71 -13
  37. package/dist/conversation-repository.d.ts.map +1 -1
  38. package/dist/conversation-repository.js +81 -24
  39. package/dist/conversation-repository.js.map +1 -1
  40. package/dist/cwd-tracker-plugin.d.ts.map +1 -1
  41. package/dist/cwd-tracker-plugin.js +6 -2
  42. package/dist/cwd-tracker-plugin.js.map +1 -1
  43. package/dist/format-time.d.ts +17 -6
  44. package/dist/format-time.d.ts.map +1 -1
  45. package/dist/format-time.js +32 -14
  46. package/dist/format-time.js.map +1 -1
  47. package/dist/handoff-service.d.ts +19 -0
  48. package/dist/handoff-service.d.ts.map +1 -0
  49. package/dist/handoff-service.js +89 -0
  50. package/dist/handoff-service.js.map +1 -0
  51. package/dist/hook.d.ts.map +1 -1
  52. package/dist/hook.js +69 -15
  53. package/dist/hook.js.map +1 -1
  54. package/dist/i18n/en-wizard.d.ts +8 -0
  55. package/dist/i18n/en-wizard.d.ts.map +1 -0
  56. package/dist/i18n/en-wizard.js +290 -0
  57. package/dist/i18n/en-wizard.js.map +1 -0
  58. package/dist/i18n/en.d.ts +7 -0
  59. package/dist/i18n/en.d.ts.map +1 -0
  60. package/dist/i18n/en.js +224 -0
  61. package/dist/i18n/en.js.map +1 -0
  62. package/dist/i18n/index.d.ts +57 -0
  63. package/dist/i18n/index.d.ts.map +1 -0
  64. package/dist/i18n/index.js +109 -0
  65. package/dist/i18n/index.js.map +1 -0
  66. package/dist/i18n/preferences.d.ts +34 -0
  67. package/dist/i18n/preferences.d.ts.map +1 -0
  68. package/dist/i18n/preferences.js +69 -0
  69. package/dist/i18n/preferences.js.map +1 -0
  70. package/dist/i18n/zh-wizard.d.ts +11 -0
  71. package/dist/i18n/zh-wizard.d.ts.map +1 -0
  72. package/dist/i18n/zh-wizard.js +293 -0
  73. package/dist/i18n/zh-wizard.js.map +1 -0
  74. package/dist/i18n/zh.d.ts +10 -0
  75. package/dist/i18n/zh.d.ts.map +1 -0
  76. package/dist/i18n/zh.js +228 -0
  77. package/dist/i18n/zh.js.map +1 -0
  78. package/dist/index.js +61 -25
  79. package/dist/index.js.map +1 -1
  80. package/dist/mcp-command.d.ts +32 -0
  81. package/dist/mcp-command.d.ts.map +1 -0
  82. package/dist/mcp-command.js +37 -0
  83. package/dist/mcp-command.js.map +1 -0
  84. package/dist/mode.d.ts +31 -4
  85. package/dist/mode.d.ts.map +1 -1
  86. package/dist/mode.js +42 -7
  87. package/dist/mode.js.map +1 -1
  88. package/dist/model-switch.d.ts +58 -0
  89. package/dist/model-switch.d.ts.map +1 -0
  90. package/dist/model-switch.js +62 -0
  91. package/dist/model-switch.js.map +1 -0
  92. package/dist/reasoning-effort.d.ts +96 -0
  93. package/dist/reasoning-effort.d.ts.map +1 -0
  94. package/dist/reasoning-effort.js +164 -0
  95. package/dist/reasoning-effort.js.map +1 -0
  96. package/dist/reasoning-presets.d.ts +34 -0
  97. package/dist/reasoning-presets.d.ts.map +1 -0
  98. package/dist/reasoning-presets.js +85 -0
  99. package/dist/reasoning-presets.js.map +1 -0
  100. package/dist/sdk-log.d.ts +55 -0
  101. package/dist/sdk-log.d.ts.map +1 -0
  102. package/dist/sdk-log.js +91 -0
  103. package/dist/sdk-log.js.map +1 -0
  104. package/dist/session-pointer.d.ts +22 -9
  105. package/dist/session-pointer.d.ts.map +1 -1
  106. package/dist/session-pointer.js +55 -23
  107. package/dist/session-pointer.js.map +1 -1
  108. package/dist/stdio-runner.d.ts.map +1 -1
  109. package/dist/stdio-runner.js +32 -30
  110. package/dist/stdio-runner.js.map +1 -1
  111. package/dist/sub-agent-guard-plugin.d.ts +5 -5
  112. package/dist/sub-agent-guard-plugin.d.ts.map +1 -1
  113. package/dist/sub-agent-guard-plugin.js +7 -7
  114. package/dist/sub-agent-guard-plugin.js.map +1 -1
  115. package/dist/tui/chat-session.d.ts +110 -59
  116. package/dist/tui/chat-session.d.ts.map +1 -1
  117. package/dist/tui/chat-session.js +268 -120
  118. package/dist/tui/chat-session.js.map +1 -1
  119. package/dist/tui/components.d.ts +48 -2
  120. package/dist/tui/components.d.ts.map +1 -1
  121. package/dist/tui/components.js +96 -3
  122. package/dist/tui/components.js.map +1 -1
  123. package/dist/tui/config-wizard/detail.d.ts +12 -6
  124. package/dist/tui/config-wizard/detail.d.ts.map +1 -1
  125. package/dist/tui/config-wizard/detail.js +33 -32
  126. package/dist/tui/config-wizard/detail.js.map +1 -1
  127. package/dist/tui/config-wizard/engine.d.ts.map +1 -1
  128. package/dist/tui/config-wizard/engine.js +27 -21
  129. package/dist/tui/config-wizard/engine.js.map +1 -1
  130. package/dist/tui/config-wizard/fields.d.ts +3 -1
  131. package/dist/tui/config-wizard/fields.d.ts.map +1 -1
  132. package/dist/tui/config-wizard/fields.js +216 -152
  133. package/dist/tui/config-wizard/fields.js.map +1 -1
  134. package/dist/tui/config-wizard/kv-editor.d.ts.map +1 -1
  135. package/dist/tui/config-wizard/kv-editor.js +9 -5
  136. package/dist/tui/config-wizard/kv-editor.js.map +1 -1
  137. package/dist/tui/config-wizard/list.d.ts.map +1 -1
  138. package/dist/tui/config-wizard/list.js +2 -1
  139. package/dist/tui/config-wizard/list.js.map +1 -1
  140. package/dist/tui/config-wizard/mcp-helpers.d.ts.map +1 -1
  141. package/dist/tui/config-wizard/mcp-helpers.js +4 -3
  142. package/dist/tui/config-wizard/mcp-helpers.js.map +1 -1
  143. package/dist/tui/config-wizard/menu.d.ts.map +1 -1
  144. package/dist/tui/config-wizard/menu.js +33 -21
  145. package/dist/tui/config-wizard/menu.js.map +1 -1
  146. package/dist/tui/config-wizard/prompt-editor.d.ts.map +1 -1
  147. package/dist/tui/config-wizard/prompt-editor.js +4 -3
  148. package/dist/tui/config-wizard/prompt-editor.js.map +1 -1
  149. package/dist/tui/config-wizard/prompt.d.ts.map +1 -1
  150. package/dist/tui/config-wizard/prompt.js +8 -7
  151. package/dist/tui/config-wizard/prompt.js.map +1 -1
  152. package/dist/tui/config-wizard/step-agents.d.ts.map +1 -1
  153. package/dist/tui/config-wizard/step-agents.js +29 -20
  154. package/dist/tui/config-wizard/step-agents.js.map +1 -1
  155. package/dist/tui/config-wizard/step-defaults.d.ts.map +1 -1
  156. package/dist/tui/config-wizard/step-defaults.js +24 -27
  157. package/dist/tui/config-wizard/step-defaults.js.map +1 -1
  158. package/dist/tui/config-wizard/step-endpoints.d.ts.map +1 -1
  159. package/dist/tui/config-wizard/step-endpoints.js +16 -6
  160. package/dist/tui/config-wizard/step-endpoints.js.map +1 -1
  161. package/dist/tui/config-wizard/step-mcp.d.ts.map +1 -1
  162. package/dist/tui/config-wizard/step-mcp.js +17 -19
  163. package/dist/tui/config-wizard/step-mcp.js.map +1 -1
  164. package/dist/tui/config-wizard/step-models.d.ts.map +1 -1
  165. package/dist/tui/config-wizard/step-models.js +41 -26
  166. package/dist/tui/config-wizard/step-models.js.map +1 -1
  167. package/dist/tui/config-wizard/step-new-endpoint.d.ts.map +1 -1
  168. package/dist/tui/config-wizard/step-new-endpoint.js +16 -12
  169. package/dist/tui/config-wizard/step-new-endpoint.js.map +1 -1
  170. package/dist/tui/config-wizard/step-simple.d.ts.map +1 -1
  171. package/dist/tui/config-wizard/step-simple.js +18 -17
  172. package/dist/tui/config-wizard/step-simple.js.map +1 -1
  173. package/dist/tui/config-wizard/types.d.ts +18 -3
  174. package/dist/tui/config-wizard/types.d.ts.map +1 -1
  175. package/dist/tui/config-wizard/wizard.d.ts.map +1 -1
  176. package/dist/tui/config-wizard/wizard.js +4 -3
  177. package/dist/tui/config-wizard/wizard.js.map +1 -1
  178. package/dist/tui/highlight.d.ts +3 -2
  179. package/dist/tui/highlight.d.ts.map +1 -1
  180. package/dist/tui/highlight.js +3 -2
  181. package/dist/tui/highlight.js.map +1 -1
  182. package/dist/tui/index.d.ts +18 -1
  183. package/dist/tui/index.d.ts.map +1 -1
  184. package/dist/tui/index.js +107 -49
  185. package/dist/tui/index.js.map +1 -1
  186. package/dist/tui/input-editing.d.ts +52 -0
  187. package/dist/tui/input-editing.d.ts.map +1 -0
  188. package/dist/tui/input-editing.js +91 -0
  189. package/dist/tui/input-editing.js.map +1 -0
  190. package/dist/tui/key-debug.d.ts +62 -0
  191. package/dist/tui/key-debug.d.ts.map +1 -0
  192. package/dist/tui/key-debug.js +92 -0
  193. package/dist/tui/key-debug.js.map +1 -0
  194. package/dist/tui/mouse.d.ts +55 -0
  195. package/dist/tui/mouse.d.ts.map +1 -0
  196. package/dist/tui/mouse.js +74 -0
  197. package/dist/tui/mouse.js.map +1 -0
  198. package/dist/tui/phase.d.ts +64 -0
  199. package/dist/tui/phase.d.ts.map +1 -0
  200. package/dist/tui/phase.js +112 -0
  201. package/dist/tui/phase.js.map +1 -0
  202. package/dist/tui/screens/chat-commands.d.ts +64 -3
  203. package/dist/tui/screens/chat-commands.d.ts.map +1 -1
  204. package/dist/tui/screens/chat-commands.js +483 -157
  205. package/dist/tui/screens/chat-commands.js.map +1 -1
  206. package/dist/tui/screens/chat.d.ts +10 -5
  207. package/dist/tui/screens/chat.d.ts.map +1 -1
  208. package/dist/tui/screens/chat.js +464 -301
  209. package/dist/tui/screens/chat.js.map +1 -1
  210. package/dist/tui/screens/common-keys.d.ts +36 -0
  211. package/dist/tui/screens/common-keys.d.ts.map +1 -0
  212. package/dist/tui/screens/common-keys.js +67 -0
  213. package/dist/tui/screens/common-keys.js.map +1 -0
  214. package/dist/tui/screens/frame-buffer.d.ts +47 -0
  215. package/dist/tui/screens/frame-buffer.d.ts.map +1 -0
  216. package/dist/tui/screens/frame-buffer.js +78 -0
  217. package/dist/tui/screens/frame-buffer.js.map +1 -0
  218. package/dist/tui/screens/handoff-choice.d.ts +37 -0
  219. package/dist/tui/screens/handoff-choice.d.ts.map +1 -0
  220. package/dist/tui/screens/handoff-choice.js +42 -0
  221. package/dist/tui/screens/handoff-choice.js.map +1 -0
  222. package/dist/tui/screens/index.d.ts +8 -8
  223. package/dist/tui/screens/index.d.ts.map +1 -1
  224. package/dist/tui/screens/index.js +7 -7
  225. package/dist/tui/screens/index.js.map +1 -1
  226. package/dist/tui/screens/input-row.d.ts +64 -0
  227. package/dist/tui/screens/input-row.d.ts.map +1 -0
  228. package/dist/tui/screens/input-row.js +67 -0
  229. package/dist/tui/screens/input-row.js.map +1 -0
  230. package/dist/tui/screens/input.d.ts +46 -1
  231. package/dist/tui/screens/input.d.ts.map +1 -1
  232. package/dist/tui/screens/input.js +83 -8
  233. package/dist/tui/screens/input.js.map +1 -1
  234. package/dist/tui/screens/layout.d.ts +21 -3
  235. package/dist/tui/screens/layout.d.ts.map +1 -1
  236. package/dist/tui/screens/layout.js +20 -9
  237. package/dist/tui/screens/layout.js.map +1 -1
  238. package/dist/tui/screens/lines.d.ts +12 -41
  239. package/dist/tui/screens/lines.d.ts.map +1 -1
  240. package/dist/tui/screens/lines.js +90 -98
  241. package/dist/tui/screens/lines.js.map +1 -1
  242. package/dist/tui/screens/messages-view.d.ts +10 -0
  243. package/dist/tui/screens/messages-view.d.ts.map +1 -0
  244. package/dist/tui/screens/messages-view.js +116 -0
  245. package/dist/tui/screens/messages-view.js.map +1 -0
  246. package/dist/tui/screens/notice-bar.d.ts +5 -0
  247. package/dist/tui/screens/notice-bar.d.ts.map +1 -0
  248. package/dist/tui/screens/notice-bar.js +15 -0
  249. package/dist/tui/screens/notice-bar.js.map +1 -0
  250. package/dist/tui/screens/notice.d.ts +64 -0
  251. package/dist/tui/screens/notice.d.ts.map +1 -0
  252. package/dist/tui/screens/notice.js +106 -0
  253. package/dist/tui/screens/notice.js.map +1 -0
  254. package/dist/tui/screens/overlays.d.ts.map +1 -1
  255. package/dist/tui/screens/overlays.js +3 -2
  256. package/dist/tui/screens/overlays.js.map +1 -1
  257. package/dist/tui/screens/render.d.ts +2 -4
  258. package/dist/tui/screens/render.d.ts.map +1 -1
  259. package/dist/tui/screens/render.js +7 -43
  260. package/dist/tui/screens/render.js.map +1 -1
  261. package/dist/tui/screens/splash.d.ts +1 -1
  262. package/dist/tui/screens/splash.d.ts.map +1 -1
  263. package/dist/tui/screens/splash.js +12 -3
  264. package/dist/tui/screens/splash.js.map +1 -1
  265. package/dist/tui/screens/use-chat-viewport.d.ts +22 -0
  266. package/dist/tui/screens/use-chat-viewport.d.ts.map +1 -0
  267. package/dist/tui/screens/use-chat-viewport.js +50 -0
  268. package/dist/tui/screens/use-chat-viewport.js.map +1 -0
  269. package/dist/tui/screens/use-input-editing.d.ts +44 -0
  270. package/dist/tui/screens/use-input-editing.d.ts.map +1 -0
  271. package/dist/tui/screens/use-input-editing.js +192 -0
  272. package/dist/tui/screens/use-input-editing.js.map +1 -0
  273. package/dist/tui/screens/use-overlays.d.ts +25 -0
  274. package/dist/tui/screens/use-overlays.d.ts.map +1 -0
  275. package/dist/tui/screens/use-overlays.js +32 -0
  276. package/dist/tui/screens/use-overlays.js.map +1 -0
  277. package/dist/tui/screens/use-wizard-host.d.ts +35 -0
  278. package/dist/tui/screens/use-wizard-host.d.ts.map +1 -0
  279. package/dist/tui/screens/use-wizard-host.js +103 -0
  280. package/dist/tui/screens/use-wizard-host.js.map +1 -0
  281. package/dist/tui/status-segments.d.ts +37 -0
  282. package/dist/tui/status-segments.d.ts.map +1 -0
  283. package/dist/tui/status-segments.js +166 -0
  284. package/dist/tui/status-segments.js.map +1 -0
  285. package/dist/tui/text.d.ts +20 -7
  286. package/dist/tui/text.d.ts.map +1 -1
  287. package/dist/tui/text.js +111 -37
  288. package/dist/tui/text.js.map +1 -1
  289. package/dist/tui/theme.d.ts +7 -1
  290. package/dist/tui/theme.d.ts.map +1 -1
  291. package/dist/tui/theme.js +15 -3
  292. package/dist/tui/theme.js.map +1 -1
  293. package/dist/tui/token-rate.d.ts +83 -0
  294. package/dist/tui/token-rate.d.ts.map +1 -0
  295. package/dist/tui/token-rate.js +195 -0
  296. package/dist/tui/token-rate.js.map +1 -0
  297. package/dist/types.d.ts +7 -8
  298. package/dist/types.d.ts.map +1 -1
  299. package/package.json +4 -3
  300. package/dist/auto-migrate-confirm-plugin.d.ts +0 -58
  301. package/dist/auto-migrate-confirm-plugin.d.ts.map +0 -1
  302. package/dist/auto-migrate-confirm-plugin.js +0 -61
  303. package/dist/auto-migrate-confirm-plugin.js.map +0 -1
  304. package/dist/migration-service.d.ts +0 -15
  305. package/dist/migration-service.d.ts.map +0 -1
  306. package/dist/migration-service.js +0 -59
  307. package/dist/migration-service.js.map +0 -1
  308. package/dist/tui/screens/state.d.ts +0 -13
  309. package/dist/tui/screens/state.d.ts.map +0 -1
  310. package/dist/tui/screens/state.js +0 -75
  311. package/dist/tui/screens/state.js.map +0 -1
@@ -8,21 +8,99 @@
8
8
  * 新增、改名或调整说明只需改动本文件。本模块为纯数据与纯函数,
9
9
  * 不依赖 chalk / React 等 UI 依赖,可直接单测。
10
10
  */
11
- /** 命令元数据表(数组顺序即展示顺序) */
12
- export const COMMAND_REGISTRY = [
13
- { name: "save", description: "保存当前对话" },
14
- { name: "load", description: "加载已保存的对话(替换当前会话)" },
15
- { name: "new", description: "重置会话(清空历史)" },
16
- { name: "back", description: "撤回消息(可修改后重发)" },
17
- { name: "editor", description: "使用系统编辑器输入长消息" },
18
- { name: "clear", description: "清屏" },
19
- { name: "config", description: "打开配置中心(默认模型 / 端点管理)" },
20
- { name: "key", description: "设置当前端点的 API Key" },
21
- { name: "migrate", description: "手动任务迁移(生成交接文档并开启新会话)" },
22
- { name: "help", description: "显示此帮助" },
11
+ import { t } from "../i18n/index.js";
12
+ /**
13
+ * 命令元数据表(数组顺序即展示顺序)。
14
+ *
15
+ * 用 `as const` 声明以保留命令名的字面量类型,从而派生出 `CommandName`:
16
+ * 命令处理器表以 `Record<CommandName, …>` 声明,于是「新增命令但忘了写处理器」是
17
+ * **编译错误**,而不是运行时静默落到「未知命令」。
18
+ *
19
+ * 但 `as const` 的代价是联合类型里**没有别名的条目压根没有 `aliases` 字段**,
20
+ * 遍历时访问会报错。所以这里只把它作为内部字面量,对外导出的
21
+ * {@link COMMAND_REGISTRY} 放宽成 `readonly CommandMeta[]` —— 类型保护一分不少,
22
+ * 而所有遍历点都能直接读 `command.aliases`,不需要额外的取值 helper。
23
+ */
24
+ const REGISTRY_ENTRIES = [
25
+ { name: "save", descriptionKey: "cmd.save.desc" },
26
+ { name: "load", descriptionKey: "cmd.load.desc" },
27
+ { name: "new", descriptionKey: "cmd.new.desc" },
28
+ { name: "back", descriptionKey: "cmd.back.desc" },
29
+ { name: "editor", descriptionKey: "cmd.editor.desc" },
30
+ { name: "clear", descriptionKey: "cmd.clear.desc" },
31
+ { name: "config", descriptionKey: "cmd.config.desc" },
32
+ { name: "model", descriptionKey: "cmd.model.desc" },
33
+ { name: "agent", descriptionKey: "cmd.agent.desc" },
34
+ { name: "reload", descriptionKey: "cmd.reload.desc" },
35
+ { name: "mcp", descriptionKey: "cmd.mcp.desc" },
36
+ { name: "lang", descriptionKey: "cmd.lang.desc" },
37
+ { name: "think", aliases: ["effort"], descriptionKey: "cmd.think.desc" },
38
+ { name: "key", descriptionKey: "cmd.key.desc" },
39
+ { name: "handoff", descriptionKey: "cmd.handoff.desc", blocksInput: true },
40
+ { name: "migrate", descriptionKey: "cmd.migrate.desc", blocksInput: true },
41
+ { name: "help", descriptionKey: "cmd.help.desc" },
23
42
  // exit 置于末尾:斜杠菜单回车执行高亮项,避免「只输入 / 就回车」直接退出
24
- { name: "exit", aliases: ["quit"], description: "退出对话(会提示是否保存)" },
43
+ { name: "exit", aliases: ["quit"], descriptionKey: "cmd.exit.desc" },
25
44
  ];
45
+ /** 命令元数据表:值来自上面的字面量,类型放宽到 `readonly CommandMeta[]` 便于遍历 */
46
+ export const COMMAND_REGISTRY = REGISTRY_ENTRIES;
47
+ /**
48
+ * 把命令名(含别名)归一到主名;未知命令返回 `undefined`。
49
+ *
50
+ * `/think` 与 `/effort` 是同一条命令的两种写法,处理器只按主名注册一份。
51
+ */
52
+ export function canonicalCommandName(name) {
53
+ const normalized = name.trim().toLowerCase();
54
+ // 在放宽类型的表上匹配(可直接读 `aliases`),再用同一下标取回字面量类型
55
+ const index = COMMAND_REGISTRY.findIndex((command) => command.name === normalized || command.aliases?.includes(normalized));
56
+ return index < 0 ? undefined : REGISTRY_ENTRIES[index].name;
57
+ }
58
+ /** 命中命令的元数据(别名可查) */
59
+ export function findCommand(name) {
60
+ const canonical = canonicalCommandName(name);
61
+ return COMMAND_REGISTRY.find((command) => command.name === canonical);
62
+ }
63
+ /** 该命令执行期间是否应拦住输入框(见 {@link CommandMeta.blocksInput}) */
64
+ export function commandBlocksInput(name) {
65
+ return findCommand(name)?.blocksInput ?? false;
66
+ }
67
+ /**
68
+ * 把原始斜杠输入切成「命令名 + 参数」。
69
+ *
70
+ * 两种返回形状共用同一个切分规则(`/migrate self ` → `migrate` + `["self"]`):
71
+ * 命令名由 {@link parseCommandInput} 取,参数由 {@link parseCommandArgs} 取。
72
+ * 以前命令层自己又 `raw.trim().split(/\s+/).slice(1)` 了一遍 —— 命令名收敛了,
73
+ * 参数没有,于是「参数怎么切」仍然有两份实现。
74
+ */
75
+ function splitCommandInput(text) {
76
+ return text.trim().replace(/^\//, "").split(/\s+/);
77
+ }
78
+ /**
79
+ * 从原始输入里取命令参数(首个 token 之后的全部 token)。
80
+ *
81
+ * 与 {@link parseCommandInput} 共用 {@link splitCommandInput},保证「命令名边界」与
82
+ * 「参数边界」用的是同一把尺子。
83
+ */
84
+ export function parseCommandArgs(text) {
85
+ return splitCommandInput(text).slice(1);
86
+ }
87
+ /**
88
+ * 解析斜杠输入:`/migrate summary` → `{ name: "migrate", args: ["summary"] }`。
89
+ *
90
+ * 命令名的解析**只有这一处**:此前宿主自己也 `slice(1).split(/\s+/)[0]` 了一遍,
91
+ * 于是「命令名怎么算」在命令层与宿主层各有一份实现。
92
+ *
93
+ * 注意「只打了个 `/`」也算命令(`name` 为空串):宿主按斜杠前缀分流,空命令名
94
+ * 落到「未知命令」——与拆出本函数之前的行为一致。
95
+ *
96
+ * @returns 非斜杠输入返回 `null`
97
+ */
98
+ export function parseCommandInput(text) {
99
+ if (!text.trim().startsWith("/"))
100
+ return null;
101
+ const [name, ...args] = splitCommandInput(text);
102
+ return { name: name.toLowerCase(), args };
103
+ }
26
104
  /** 展开全部命令为展示条目(别名折叠) */
27
105
  export function getCommandHints() {
28
106
  return COMMAND_REGISTRY.map((command) => {
@@ -30,7 +108,7 @@ export function getCommandHints() {
30
108
  return {
31
109
  names,
32
110
  label: names.map((name) => `/${name}`).join(" "),
33
- description: command.description,
111
+ description: t(command.descriptionKey),
34
112
  };
35
113
  });
36
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH,wBAAwB;AACxB,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE;IACvC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE;IACjD,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE;IAC1C,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE;IAC7C,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE;IAC/C,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE;IACpC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qBAAqB,EAAE;IACtD,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE;IAC/C,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,sBAAsB,EAAE;IACxD,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE;IACtC,0CAA0C;IAC1C,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE;CAClE,CAAC;AAYF,wBAAwB;AACxB,MAAM,UAAU,eAAe;IAC7B,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,OAAO;YACL,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAChD,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC9B,IAAI,CAAC,GAAG,CAAC,GAAG,eAAe,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;AAEtE;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChD,IAAI,CAAC,UAAU;QAAE,OAAO,eAAe,EAAE,CAAC;IAE1C,OAAO,eAAe,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CACvD,CAAC;AACJ,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,EAAE,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,6 @@ export interface ConversationPersistPluginOptions {
12
12
  /** 动态返回当前会话 id(迁移切换会话后随之变化) */
13
13
  getId: () => string;
14
14
  agentId: string;
15
- modelId: string;
16
15
  cwd?: string;
17
16
  /** 落盘失败时的上报(TUI 走 Ink notice);默认丢弃 */
18
17
  onError?: (text: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-persist-plugin.d.ts","sourceRoot":"","sources":["../src/conversation-persist-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKnE,MAAM,WAAW,gCAAgC;IAC/C,+BAA+B;IAC/B,KAAK,EAAE,MAAM,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,yBAA0B,YAAW,WAAW;IAC/C,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,gCAAgC;IAEvD,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAyBtD"}
1
+ {"version":3,"file":"conversation-persist-plugin.d.ts","sourceRoot":"","sources":["../src/conversation-persist-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKnE,MAAM,WAAW,gCAAgC;IAC/C,+BAA+B;IAC/B,KAAK,EAAE,MAAM,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,yBAA0B,YAAW,WAAW;IAC/C,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,gCAAgC;IAEvD,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAgBtD"}
@@ -8,36 +8,27 @@
8
8
  * 会话 id 通过 `getId()` 动态获取,以便任务迁移切换新会话后依然落盘到正确的文件。
9
9
  */
10
10
  import { AgentNS } from "@ai-zen/agents-core";
11
- import { conversationRepository } from "./conversation-repository.js";
12
- import { writeLastSession } from "./session-pointer.js";
11
+ import { persistConversation } from "./conversation-repository.js";
12
+ import { t } from "./i18n/index.js";
13
13
  export class ConversationPersistPlugin {
14
14
  options;
15
15
  constructor(options) {
16
16
  this.options = options;
17
17
  }
18
18
  async onInnerLoopEnd(ctx) {
19
- const { getId, agentId, modelId, cwd, onError } = this.options;
19
+ const { getId, agentId, cwd, onError } = this.options;
20
20
  const messages = ctx.agent.messages;
21
21
  // 尚无实质内容(没有用户消息)时不落盘,避免产生空会话文件
22
22
  if (!messages.some((m) => m.role === AgentNS.Role.User))
23
23
  return;
24
24
  const id = getId();
25
25
  try {
26
- const existing = await conversationRepository.read(id);
27
- const now = new Date().toISOString();
28
- await conversationRepository.write({
29
- id,
30
- agentId,
31
- modelId,
32
- messages,
33
- cwd,
34
- createdAt: existing?.createdAt ?? now,
35
- updatedAt: now,
36
- });
37
- await writeLastSession(id);
26
+ // 每轮自动落盘也算「本目录的上一轮会话」—— 下次在该目录启动时续接它。
27
+ // `SendContext.cwd` 是 SDK 的可选字段,这里(调用点)是**唯一**需要兜底的地方。
28
+ await persistConversation({ id, agentId, messages, cwd: cwd ?? process.cwd() });
38
29
  }
39
30
  catch (err) {
40
- onError?.(`⚠️ 会话落盘失败:${err?.message ?? err}`);
31
+ onError?.(t("chat.persistFailed", { error: err?.message ?? err }));
41
32
  }
42
33
  }
43
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-persist-plugin.js","sourceRoot":"","sources":["../src/conversation-persist-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAYxD,MAAM,OAAO,yBAAyB;IAChB;IAApB,YAAoB,OAAyC;QAAzC,YAAO,GAAP,OAAO,CAAkC;IAAG,CAAC;IAEjE,KAAK,CAAC,cAAc,CAAC,GAAgB;QACnC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAC/D,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;QAEpC,+BAA+B;QAC/B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO;QAEhE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACvD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,sBAAsB,CAAC,KAAK,CAAC;gBACjC,EAAE;gBACF,OAAO;gBACP,OAAO;gBACP,QAAQ;gBACR,GAAG;gBACH,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,GAAG;gBACrC,SAAS,EAAE,GAAG;aACf,CAAC,CAAC;YACH,MAAM,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"conversation-persist-plugin.js","sourceRoot":"","sources":["../src/conversation-persist-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAWpC,MAAM,OAAO,yBAAyB;IAChB;IAApB,YAAoB,OAAyC;QAAzC,YAAO,GAAP,OAAO,CAAkC;IAAG,CAAC;IAEjE,KAAK,CAAC,cAAc,CAAC,GAAgB;QACnC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACtD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;QAEpC,+BAA+B;QAC/B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO;QAEhE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC;YACH,sCAAsC;YACtC,uDAAuD;YACvD,MAAM,mBAAmB,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAClF,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC,CAAC,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;CACF"}
@@ -7,38 +7,96 @@
7
7
  * 「上一轮会话 id」指针(session-pointer.ts)随每次落盘更新,供下次启动续接。
8
8
  */
9
9
  import { EntityRepository } from "@ai-zen/agents-sdk";
10
- import type { AgentNS } from "@ai-zen/agents-core";
10
+ import { AgentNS } from "@ai-zen/agents-core";
11
11
  import type { ConversationContext } from "./types.js";
12
12
  export interface Conversation {
13
13
  id: string;
14
14
  agentId: string;
15
- modelId: string;
15
+ /**
16
+ * @deprecated 已不再读**也不写**(收敛前 stdio 的 `--save` 曾写入它)。
17
+ * 模型真相源是 `AgentDefinition.modelId`;保留字段仅为兼容旧存档的反序列化。
18
+ */
19
+ modelId?: string;
16
20
  messages: AgentNS.Message[];
17
21
  lastPromptTokens?: number;
18
22
  cwd?: string;
19
23
  createdAt: string;
20
24
  updatedAt: string;
21
25
  }
22
- /** 会话仓储:每个会话一个 JSON 文件(${conversationsDir}/${id}.json) */
23
- export declare const conversationRepository: EntityRepository<Conversation>;
24
26
  /**
25
- * 生成文件名安全的会话 id(语义化中文时间戳,天然不含非法字符)。
26
- * 形如 `对话_2025年07月01日14时30分00秒`。
27
+ * 会话仓储:每个会话一个 JSON 文件(${conversationsDir}/${id}.json),**写盘是原子的**。
28
+ *
29
+ * 为什么要覆写 `write()`:SDK 的实现是直接 `fs.writeFile`,进程在写一半时被杀
30
+ * (Ctrl+C、OOM、断电)就留下半截 JSON,`read()` 解析失败返回 null —— 整段历史
31
+ * 就此丢失。会话文件可达数 MB,写入窗口并不小。这里改成「写临时文件 → rename」:
32
+ * 同一文件系统内 rename 是原子操作,任何时刻读到的要么是旧文件、要么是完整新文件。
33
+ *
34
+ * 临时文件名为 `<id>.json.tmp`:`list()` 按 `.json` 后缀过滤,不会把它当成会话。
35
+ */
36
+ declare class AtomicConversationRepository extends EntityRepository<Conversation> {
37
+ write(entity: Conversation): Promise<void>;
38
+ }
39
+ export declare const conversationRepository: AtomicConversationRepository;
40
+ /**
41
+ * 生成文件名安全的会话 id:英文前缀 + 全下划线时间戳,中英一致。
42
+ * 形如 `chat_2026_10_28_00_56_34`。
27
43
  */
28
44
  export declare function generateConversationId(date?: Date): string;
45
+ /** 落盘一份会话所需的全部输入 */
46
+ export interface PersistConversationInput {
47
+ id: string;
48
+ agentId?: string;
49
+ messages: AgentNS.Message[];
50
+ /**
51
+ * 会话所属工作目录。**必填**:调用点都知道自己属于哪个目录,
52
+ * 留成可选只会在入口处多一层 `?? process.cwd()`,与调用点自己的兜底重复。
53
+ */
54
+ cwd: string;
55
+ /**
56
+ * 是否同时把「本目录上一轮会话」指针指向它(默认 true)。
57
+ *
58
+ * stdio 的 `--save` 传 false:那是一次性管道调用的归档,不该让下次 `ai` 续接到它
59
+ * (否则连着跑几条 `cat … | ai --save` 之后,`ai` 会续接到最后一条管道结果上)。
60
+ */
61
+ setAsLastSession?: boolean;
62
+ }
29
63
  /**
30
- * 保存当前对话到 conversations 目录,并更新「上一轮会话 id」指针。
31
- * 迁移前落盘旧会话(onBeforeMigrate)、手动 /save 等场景共同调用,保证 id 计算一致。
64
+ * 落盘一份会话 —— **唯一的写入入口**。
65
+ *
66
+ * 此前「读旧记录拿 createdAt → 写 → 更新指针」这段在 5 个地方各写了一遍,并且已经
67
+ * 漂移:`saveConversation()` 漏写 `cwd`、stdio 的 `--save` 不更新指针、还写了一个已
68
+ * 废弃的 `modelId`。收敛到这里后,各处差异只剩「是否更新指针」一个显式开关。
32
69
  */
33
- export declare function saveConversation(ctx: ConversationContext): Promise<string>;
70
+ export declare function persistConversation(input: PersistConversationInput): Promise<string>;
34
71
  /**
35
- * 列出已保存的会话(仅读文件名与 mtime,不解析 JSON 内容,快),按更新时间倒序。
36
- * 供对话内 `/load` 选择器使用。
72
+ * 保存当前对话(交接前落盘旧会话时用):以 `ctx` 为真相源,走统一的写入入口。
37
73
  */
38
- export declare function listConversations(): Promise<Array<{
74
+ export declare function saveConversation(ctx: ConversationContext): Promise<string>;
75
+ /** `/load` 选择器的一行 */
76
+ export interface ConversationSummary {
39
77
  id: string;
78
+ /** 文件名(= id),无摘要时的回退显示 */
40
79
  name: string;
80
+ /** 首条用户消息的第一行(截断);读不到时为空串 */
81
+ preview: string;
41
82
  updatedAt: string;
42
83
  size: number;
43
- }>>;
84
+ }
85
+ /**
86
+ * 会话摘要:首条用户消息的第一行。
87
+ *
88
+ * 会话 id 是时间戳(`chat_2026_10_28_00_56_34`),直接当标签列出来完全分不清哪条是哪条。
89
+ * 取首行而不是整段:`CwdTrackerPlugin` 会在消息末尾追加工作目录注记,末尾对辨认无意义。
90
+ */
91
+ export declare function conversationPreview(conversation: Conversation | null): string;
92
+ /**
93
+ * 列出已保存的会话,按更新时间倒序。供对话内 `/load` 选择器使用。
94
+ *
95
+ * 先只 stat(快),排序后**只为将要显示的那几条**解析内容取摘要 —— 会话攒到上百条时,
96
+ * 逐个 `JSON.parse` 会明显拖慢 `/load`。
97
+ */
98
+ export declare function listConversations(options: {
99
+ previewLimit: number;
100
+ }): Promise<ConversationSummary[]>;
101
+ export {};
44
102
  //# sourceMappingURL=conversation-repository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-repository.d.ts","sourceRoot":"","sources":["../src/conversation-repository.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAInD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0DAA0D;AAC1D,eAAO,MAAM,sBAAsB,gCAAwD,CAAC;AAE5F;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,GAAE,IAAiB,GAAG,MAAM,CAEtE;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAchF;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAChD,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CACrE,CAmBA"}
1
+ {"version":3,"file":"conversation-repository.d.ts","sourceRoot":"","sources":["../src/conversation-repository.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAI9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,cAAM,4BAA6B,SAAQ,gBAAgB,CAAC,YAAY,CAAC;IACxD,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAO1D;AAED,eAAO,MAAM,sBAAsB,8BAAsD,CAAC;AAE1F;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,GAAE,IAAiB,GAAG,MAAM,CAEtE;AAED,oBAAoB;AACpB,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;IAC5B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAa1F;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAOhF;AAED,qBAAqB;AACrB,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAKD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,GAAG,MAAM,CAK7E;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CA6BzG"}
@@ -7,44 +7,93 @@
7
7
  * 「上一轮会话 id」指针(session-pointer.ts)随每次落盘更新,供下次启动续接。
8
8
  */
9
9
  import { promises as fs } from "node:fs";
10
- import { join } from "node:path";
10
+ import { dirname, join } from "node:path";
11
11
  import { EntityRepository } from "@ai-zen/agents-sdk";
12
+ import { AgentNS } from "@ai-zen/agents-core";
12
13
  import { CONVERSATIONS_DIR } from "./config.js";
13
- import { formatShortTime } from "./format-time.js";
14
+ import { formatFileStamp } from "./format-time.js";
14
15
  import { writeLastSession } from "./session-pointer.js";
15
- /** 会话仓储:每个会话一个 JSON 文件(${conversationsDir}/${id}.json) */
16
- export const conversationRepository = new EntityRepository(CONVERSATIONS_DIR);
17
16
  /**
18
- * 生成文件名安全的会话 id(语义化中文时间戳,天然不含非法字符)。
19
- * 形如 `对话_2025年07月01日14时30分00秒`。
17
+ * 会话仓储:每个会话一个 JSON 文件(${conversationsDir}/${id}.json),**写盘是原子的**。
18
+ *
19
+ * 为什么要覆写 `write()`:SDK 的实现是直接 `fs.writeFile`,进程在写一半时被杀
20
+ * (Ctrl+C、OOM、断电)就留下半截 JSON,`read()` 解析失败返回 null —— 整段历史
21
+ * 就此丢失。会话文件可达数 MB,写入窗口并不小。这里改成「写临时文件 → rename」:
22
+ * 同一文件系统内 rename 是原子操作,任何时刻读到的要么是旧文件、要么是完整新文件。
23
+ *
24
+ * 临时文件名为 `<id>.json.tmp`:`list()` 按 `.json` 后缀过滤,不会把它当成会话。
25
+ */
26
+ class AtomicConversationRepository extends EntityRepository {
27
+ async write(entity) {
28
+ const target = this.path(entity.id);
29
+ const tmp = `${target}.tmp`;
30
+ await fs.mkdir(dirname(target), { recursive: true });
31
+ await fs.writeFile(tmp, JSON.stringify(entity, null, 2), "utf-8");
32
+ await fs.rename(tmp, target);
33
+ }
34
+ }
35
+ export const conversationRepository = new AtomicConversationRepository(CONVERSATIONS_DIR);
36
+ /**
37
+ * 生成文件名安全的会话 id:英文前缀 + 全下划线时间戳,中英一致。
38
+ * 形如 `chat_2026_10_28_00_56_34`。
20
39
  */
21
40
  export function generateConversationId(date = new Date()) {
22
- return `对话_${formatShortTime(date.toISOString())}`.replace(/[\\/:*?"<>|]/g, "_");
41
+ return `chat_${formatFileStamp(date.toISOString())}`;
23
42
  }
24
43
  /**
25
- * 保存当前对话到 conversations 目录,并更新「上一轮会话 id」指针。
26
- * 迁移前落盘旧会话(onBeforeMigrate)、手动 /save 等场景共同调用,保证 id 计算一致。
44
+ * 落盘一份会话 —— **唯一的写入入口**。
45
+ *
46
+ * 此前「读旧记录拿 createdAt → 写 → 更新指针」这段在 5 个地方各写了一遍,并且已经
47
+ * 漂移:`saveConversation()` 漏写 `cwd`、stdio 的 `--save` 不更新指针、还写了一个已
48
+ * 废弃的 `modelId`。收敛到这里后,各处差异只剩「是否更新指针」一个显式开关。
27
49
  */
28
- export async function saveConversation(ctx) {
29
- const id = ctx.currentId || generateConversationId();
30
- const existing = await conversationRepository.read(id);
50
+ export async function persistConversation(input) {
51
+ const existing = await conversationRepository.read(input.id);
31
52
  const now = new Date().toISOString();
32
53
  await conversationRepository.write({
33
- id,
34
- agentId: ctx.agentId || "default",
35
- modelId: ctx.modelId,
36
- messages: ctx.agent.messages,
54
+ id: input.id,
55
+ agentId: input.agentId || "default",
56
+ messages: input.messages,
57
+ cwd: input.cwd,
37
58
  createdAt: existing?.createdAt ?? now,
38
59
  updatedAt: now,
39
60
  });
40
- await writeLastSession(id);
41
- return id;
61
+ if (input.setAsLastSession !== false)
62
+ await writeLastSession(input.cwd, input.id);
63
+ return input.id;
64
+ }
65
+ /**
66
+ * 保存当前对话(交接前落盘旧会话时用):以 `ctx` 为真相源,走统一的写入入口。
67
+ */
68
+ export async function saveConversation(ctx) {
69
+ return persistConversation({
70
+ id: ctx.currentId || generateConversationId(),
71
+ agentId: ctx.agentId,
72
+ messages: ctx.agent.messages,
73
+ cwd: process.cwd(),
74
+ });
42
75
  }
76
+ /** 摘要最大字符数(渲染侧还会按终端宽度再裁一次) */
77
+ const PREVIEW_MAX = 80;
43
78
  /**
44
- * 列出已保存的会话(仅读文件名与 mtime,不解析 JSON 内容,快),按更新时间倒序。
45
- * 供对话内 `/load` 选择器使用。
79
+ * 会话摘要:首条用户消息的第一行。
80
+ *
81
+ * 会话 id 是时间戳(`chat_2026_10_28_00_56_34`),直接当标签列出来完全分不清哪条是哪条。
82
+ * 取首行而不是整段:`CwdTrackerPlugin` 会在消息末尾追加工作目录注记,末尾对辨认无意义。
83
+ */
84
+ export function conversationPreview(conversation) {
85
+ const first = conversation?.messages?.find((m) => m.role === AgentNS.Role.User);
86
+ const content = typeof first?.content === "string" ? first.content : "";
87
+ const line = content.split("\n").find((part) => part.trim()) ?? "";
88
+ return line.trim().slice(0, PREVIEW_MAX);
89
+ }
90
+ /**
91
+ * 列出已保存的会话,按更新时间倒序。供对话内 `/load` 选择器使用。
92
+ *
93
+ * 先只 stat(快),排序后**只为将要显示的那几条**解析内容取摘要 —— 会话攒到上百条时,
94
+ * 逐个 `JSON.parse` 会明显拖慢 `/load`。
46
95
  */
47
- export async function listConversations() {
96
+ export async function listConversations(options) {
48
97
  try {
49
98
  await fs.access(CONVERSATIONS_DIR);
50
99
  }
@@ -52,19 +101,27 @@ export async function listConversations() {
52
101
  return [];
53
102
  }
54
103
  const files = await fs.readdir(CONVERSATIONS_DIR);
55
- const result = [];
104
+ const stats = [];
56
105
  for (const file of files) {
57
106
  if (!file.endsWith(".json"))
58
107
  continue;
59
108
  const id = file.replace(/\.json$/, "");
60
109
  try {
61
110
  const st = await fs.stat(join(CONVERSATIONS_DIR, file));
62
- result.push({ id, name: id, updatedAt: st.mtime.toISOString(), size: st.size });
111
+ stats.push({ id, name: id, updatedAt: st.mtime.toISOString(), size: st.size });
63
112
  }
64
113
  catch {
65
114
  /* 跳过读取失败的条目 */
66
115
  }
67
116
  }
68
- return result.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
117
+ stats.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
118
+ // `previewLimit` 必填:默认 0(=全部无摘要)是个静默陷阱 —— 漏传不会报错,
119
+ // 只会让列表变成一堆谁也分不清的时间戳 id。
120
+ const withPreview = await Promise.all(stats.map(async (item, index) => {
121
+ if (index >= options.previewLimit)
122
+ return { ...item, preview: "" };
123
+ return { ...item, preview: conversationPreview(await conversationRepository.read(item.id)) };
124
+ }));
125
+ return withPreview;
69
126
  }
70
127
  //# sourceMappingURL=conversation-repository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-repository.js","sourceRoot":"","sources":["../src/conversation-repository.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAcxD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,gBAAgB,CAAe,iBAAiB,CAAC,CAAC;AAE5F;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAa,IAAI,IAAI,EAAE;IAC5D,OAAO,MAAM,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;AACnF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAwB;IAC7D,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,IAAI,sBAAsB,EAAE,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,sBAAsB,CAAC,KAAK,CAAC;QACjC,EAAE;QACF,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;QACjC,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ;QAC5B,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,GAAG;QACrC,SAAS,EAAE,GAAG;KACf,CAAC,CAAC;IACH,MAAM,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAC3B,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IAGrC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClD,MAAM,MAAM,GAAyE,EAAE,CAAC;IACxF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAClF,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAClG,CAAC"}
1
+ {"version":3,"file":"conversation-repository.js","sourceRoot":"","sources":["../src/conversation-repository.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAkBxD;;;;;;;;;GASG;AACH,MAAM,4BAA6B,SAAQ,gBAA8B;IAC9D,KAAK,CAAC,KAAK,CAAC,MAAoB;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,MAAM,MAAM,CAAC;QAC5B,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAClE,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,4BAA4B,CAAC,iBAAiB,CAAC,CAAC;AAE1F;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAa,IAAI,IAAI,EAAE;IAC5D,OAAO,QAAQ,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;AACvD,CAAC;AAqBD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAA+B;IACvE,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,sBAAsB,CAAC,KAAK,CAAC;QACjC,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,SAAS;QACnC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,GAAG;QACrC,SAAS,EAAE,GAAG;KACf,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,gBAAgB,KAAK,KAAK;QAAE,MAAM,gBAAgB,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IAClF,OAAO,KAAK,CAAC,EAAE,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAwB;IAC7D,OAAO,mBAAmB,CAAC;QACzB,EAAE,EAAE,GAAG,CAAC,SAAS,IAAI,sBAAsB,EAAE;QAC7C,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ;QAC5B,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;KACnB,CAAC,CAAC;AACL,CAAC;AAaD,8BAA8B;AAC9B,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAAiC;IACnE,MAAM,KAAK,GAAG,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,OAAO,KAAK,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACxE,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IACnE,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAiC;IACvE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClD,MAAM,KAAK,GAAyE,EAAE,CAAC;IACvF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAExF,kDAAkD;IAClD,yBAAyB;IACzB,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CACnC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAgC,EAAE;QAC5D,IAAI,KAAK,IAAI,OAAO,CAAC,YAAY;YAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACnE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,mBAAmB,CAAC,MAAM,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC/F,CAAC,CAAC,CACH,CAAC;IACF,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"cwd-tracker-plugin.d.ts","sourceRoot":"","sources":["../src/cwd-tracker-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEnE,qBAAa,gBAAiB,YAAW,WAAW;IAClD,8BAA8B;IAC9B,OAAO,CAAC,OAAO,CAAuB;IAEhC,gBAAgB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAmBxD"}
1
+ {"version":3,"file":"cwd-tracker-plugin.d.ts","sourceRoot":"","sources":["../src/cwd-tracker-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEnE,qBAAa,gBAAiB,YAAW,WAAW;IAClD,8BAA8B;IAC9B,OAAO,CAAC,OAAO,CAAuB;IAEhC,gBAAgB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAuBxD"}
@@ -45,8 +45,12 @@ export class CwdTrackerPlugin {
45
45
  .find((m) => m.role === AgentNS.Role.User && typeof m.content === "string");
46
46
  if (!lastUserMsg || typeof lastUserMsg.content !== "string")
47
47
  return;
48
- const prefix = isFirstTime ? "" : "\n\n[工作目录变更]";
49
- lastUserMsg.content += `${prefix}\n当前工作目录: ${currentCwd}`;
48
+ // 注入给模型的提示词:用英文,并显式标注「系统注入」—— 翻存档 / 交接文档时
49
+ // 一眼能分辨哪些内容不是用户敲的。(协议内容,不走 i18n)
50
+ const tag = isFirstTime
51
+ ? "[system-injected: current working directory — not written by the user]"
52
+ : "[system-injected: working directory changed — not written by the user]";
53
+ lastUserMsg.content += `\n\n${tag}\nCurrent working directory: ${currentCwd}`;
50
54
  }
51
55
  }
52
56
  //# sourceMappingURL=cwd-tracker-plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cwd-tracker-plugin.js","sourceRoot":"","sources":["../src/cwd-tracker-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAG9C,MAAM,OAAO,gBAAgB;IAC3B,8BAA8B;IACtB,OAAO,GAAkB,IAAI,CAAC;IAEtC,KAAK,CAAC,gBAAgB,CAAC,GAAgB;QACrC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAEjC,gBAAgB;QAChB,IAAI,IAAI,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO;QAExC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC;QAE1B,gCAAgC;QAChC,MAAM,WAAW,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;aACxC,OAAO,EAAE;aACT,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC;QAE9E,IAAI,CAAC,WAAW,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO;QAEpE,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC;QACjD,WAAW,CAAC,OAAO,IAAI,GAAG,MAAM,aAAa,UAAU,EAAE,CAAC;IAC5D,CAAC;CACF"}
1
+ {"version":3,"file":"cwd-tracker-plugin.js","sourceRoot":"","sources":["../src/cwd-tracker-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAG9C,MAAM,OAAO,gBAAgB;IAC3B,8BAA8B;IACtB,OAAO,GAAkB,IAAI,CAAC;IAEtC,KAAK,CAAC,gBAAgB,CAAC,GAAgB;QACrC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAEjC,gBAAgB;QAChB,IAAI,IAAI,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO;QAExC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC;QAE1B,gCAAgC;QAChC,MAAM,WAAW,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;aACxC,OAAO,EAAE;aACT,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC;QAE9E,IAAI,CAAC,WAAW,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO;QAEpE,0CAA0C;QAC1C,iCAAiC;QACjC,MAAM,GAAG,GAAG,WAAW;YACrB,CAAC,CAAC,wEAAwE;YAC1E,CAAC,CAAC,wEAAwE,CAAC;QAC7E,WAAW,CAAC,OAAO,IAAI,OAAO,GAAG,gCAAgC,UAAU,EAAE,CAAC;IAChF,CAAC;CACF"}
@@ -1,8 +1,12 @@
1
1
  /**
2
2
  * 统一时间格式化工具
3
3
  *
4
- * 所有用户可见的时间文案统一使用 dayjs + zh-cn locale,
5
- * 确保各种场景(会话列表、会话标签等)显示一致。
4
+ * 所有用户可见的时间文案统一走本模块,格式随界面语言变化:
5
+ * - 中文:`7月1日 14:30`、`昨天 14:30`
6
+ * - 英文:`Jul 1, 14:30`、`Yesterday 14:30`
7
+ *
8
+ * 语言从 `i18n` 现取(不同模块级常量),因此 `/lang` 切完下一帧就生效。
9
+ * 例外:`formatFileStamp()` 用于**文件名 / 会话 id**,不随语言变(否则新旧文件混排)。
6
10
  */
7
11
  import "dayjs/locale/zh-cn.js";
8
12
  /**
@@ -16,13 +20,20 @@ import "dayjs/locale/zh-cn.js";
16
20
  */
17
21
  export declare function formatRelativeTime(isoString: string): string;
18
22
  /**
19
- * 格式化时间戳为完整中文格式(用于详情展示)
20
- * 例:2025年7月1日 14:30:00
23
+ * 格式化时间戳为完整格式(用于详情展示)
24
+ * 例(中):2025年7月1日 14:30:00 (英):Jul 1, 2025 14:30:00
21
25
  */
22
26
  export declare function formatFullTime(isoString: string): string;
23
27
  /**
24
- * 格式化时间戳为保存名称用的格式,兼容文件名
25
- * 例:2025年07月01日_14时30分00秒
28
+ * 文件名安全的时间戳:全下划线、纯数字,用作会话 id。
29
+ * 例:2026_10_28_00_56_34
30
+ *
31
+ * **刻意不随界面语言变**:它进了文件名与会话 id,跟着语言变会让历史文件与新文件混排。
32
+ */
33
+ export declare function formatFileStamp(isoString: string): string;
34
+ /**
35
+ * 紧凑时间戳(列表/详情提示显示用),随界面语言变:
36
+ * 中文 `2025年07月01日15时30分00秒`,英文 `Jul 1, 2025 15:30:00`。
26
37
  */
27
38
  export declare function formatShortTime(isoString: string): string;
28
39
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"format-time.d.ts","sourceRoot":"","sources":["../src/format-time.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,uBAAuB,CAAC;AAK/B;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAc5D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIpD"}
1
+ {"version":3,"file":"format-time.d.ts","sourceRoot":"","sources":["../src/format-time.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,uBAAuB,CAAC;AAW/B;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAc5D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIpD"}