@ai-zen/cli 1.0.0-alpha.20 → 1.0.0-alpha.23

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 (261) hide show
  1. package/CHANGELOG.md +205 -0
  2. package/README.md +45 -17
  3. package/README.zh.md +45 -17
  4. package/dist/agent-creator.d.ts.map +1 -1
  5. package/dist/agent-creator.js +32 -10
  6. package/dist/agent-creator.js.map +1 -1
  7. package/dist/agent-switch.d.ts +61 -0
  8. package/dist/agent-switch.d.ts.map +1 -0
  9. package/dist/agent-switch.js +83 -0
  10. package/dist/agent-switch.js.map +1 -0
  11. package/dist/agents-store.d.ts +6 -1
  12. package/dist/agents-store.d.ts.map +1 -1
  13. package/dist/agents-store.js +6 -1
  14. package/dist/agents-store.js.map +1 -1
  15. package/dist/auto-migrate-confirm.d.ts.map +1 -1
  16. package/dist/auto-migrate-confirm.js +2 -1
  17. package/dist/auto-migrate-confirm.js.map +1 -1
  18. package/dist/config-editor.d.ts +9 -1
  19. package/dist/config-editor.d.ts.map +1 -1
  20. package/dist/config-editor.js +30 -19
  21. package/dist/config-editor.js.map +1 -1
  22. package/dist/config.d.ts +1 -1
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +29 -13
  25. package/dist/config.js.map +1 -1
  26. package/dist/conversation-commands/registry.d.ts +123 -4
  27. package/dist/conversation-commands/registry.d.ts.map +1 -1
  28. package/dist/conversation-commands/registry.js +92 -17
  29. package/dist/conversation-commands/registry.js.map +1 -1
  30. package/dist/conversation-persist-plugin.d.ts.map +1 -1
  31. package/dist/conversation-persist-plugin.js +6 -14
  32. package/dist/conversation-persist-plugin.js.map +1 -1
  33. package/dist/conversation-repository.d.ts +68 -14
  34. package/dist/conversation-repository.d.ts.map +1 -1
  35. package/dist/conversation-repository.js +81 -23
  36. package/dist/conversation-repository.js.map +1 -1
  37. package/dist/cwd-tracker-plugin.d.ts.map +1 -1
  38. package/dist/cwd-tracker-plugin.js +6 -2
  39. package/dist/cwd-tracker-plugin.js.map +1 -1
  40. package/dist/format-time.d.ts +17 -6
  41. package/dist/format-time.d.ts.map +1 -1
  42. package/dist/format-time.js +32 -14
  43. package/dist/format-time.js.map +1 -1
  44. package/dist/handoff-service.d.ts.map +1 -1
  45. package/dist/handoff-service.js +22 -19
  46. package/dist/handoff-service.js.map +1 -1
  47. package/dist/hook.d.ts.map +1 -1
  48. package/dist/hook.js +69 -15
  49. package/dist/hook.js.map +1 -1
  50. package/dist/i18n/en-wizard.d.ts +8 -0
  51. package/dist/i18n/en-wizard.d.ts.map +1 -0
  52. package/dist/i18n/en-wizard.js +290 -0
  53. package/dist/i18n/en-wizard.js.map +1 -0
  54. package/dist/i18n/en.d.ts +7 -0
  55. package/dist/i18n/en.d.ts.map +1 -0
  56. package/dist/i18n/en.js +223 -0
  57. package/dist/i18n/en.js.map +1 -0
  58. package/dist/i18n/index.d.ts +57 -0
  59. package/dist/i18n/index.d.ts.map +1 -0
  60. package/dist/i18n/index.js +109 -0
  61. package/dist/i18n/index.js.map +1 -0
  62. package/dist/i18n/preferences.d.ts +34 -0
  63. package/dist/i18n/preferences.d.ts.map +1 -0
  64. package/dist/i18n/preferences.js +69 -0
  65. package/dist/i18n/preferences.js.map +1 -0
  66. package/dist/i18n/zh-wizard.d.ts +11 -0
  67. package/dist/i18n/zh-wizard.d.ts.map +1 -0
  68. package/dist/i18n/zh-wizard.js +293 -0
  69. package/dist/i18n/zh-wizard.js.map +1 -0
  70. package/dist/i18n/zh.d.ts +10 -0
  71. package/dist/i18n/zh.d.ts.map +1 -0
  72. package/dist/i18n/zh.js +227 -0
  73. package/dist/i18n/zh.js.map +1 -0
  74. package/dist/index.js +41 -23
  75. package/dist/index.js.map +1 -1
  76. package/dist/mcp-command.d.ts +32 -0
  77. package/dist/mcp-command.d.ts.map +1 -0
  78. package/dist/mcp-command.js +37 -0
  79. package/dist/mcp-command.js.map +1 -0
  80. package/dist/mode.d.ts +31 -4
  81. package/dist/mode.d.ts.map +1 -1
  82. package/dist/mode.js +42 -7
  83. package/dist/mode.js.map +1 -1
  84. package/dist/model-switch.d.ts.map +1 -1
  85. package/dist/model-switch.js +5 -4
  86. package/dist/model-switch.js.map +1 -1
  87. package/dist/reasoning-effort.d.ts +23 -4
  88. package/dist/reasoning-effort.d.ts.map +1 -1
  89. package/dist/reasoning-effort.js +51 -24
  90. package/dist/reasoning-effort.js.map +1 -1
  91. package/dist/sdk-log.d.ts +23 -16
  92. package/dist/sdk-log.d.ts.map +1 -1
  93. package/dist/sdk-log.js +43 -19
  94. package/dist/sdk-log.js.map +1 -1
  95. package/dist/stdio-runner.d.ts.map +1 -1
  96. package/dist/stdio-runner.js +19 -19
  97. package/dist/stdio-runner.js.map +1 -1
  98. package/dist/sub-agent-guard-plugin.d.ts +5 -2
  99. package/dist/sub-agent-guard-plugin.d.ts.map +1 -1
  100. package/dist/sub-agent-guard-plugin.js +5 -2
  101. package/dist/sub-agent-guard-plugin.js.map +1 -1
  102. package/dist/tui/chat-session.d.ts +73 -0
  103. package/dist/tui/chat-session.d.ts.map +1 -1
  104. package/dist/tui/chat-session.js +167 -33
  105. package/dist/tui/chat-session.js.map +1 -1
  106. package/dist/tui/components.d.ts +43 -2
  107. package/dist/tui/components.d.ts.map +1 -1
  108. package/dist/tui/components.js +97 -4
  109. package/dist/tui/components.js.map +1 -1
  110. package/dist/tui/config-wizard/detail.d.ts +12 -6
  111. package/dist/tui/config-wizard/detail.d.ts.map +1 -1
  112. package/dist/tui/config-wizard/detail.js +33 -32
  113. package/dist/tui/config-wizard/detail.js.map +1 -1
  114. package/dist/tui/config-wizard/engine.d.ts.map +1 -1
  115. package/dist/tui/config-wizard/engine.js +26 -20
  116. package/dist/tui/config-wizard/engine.js.map +1 -1
  117. package/dist/tui/config-wizard/fields.d.ts.map +1 -1
  118. package/dist/tui/config-wizard/fields.js +176 -164
  119. package/dist/tui/config-wizard/fields.js.map +1 -1
  120. package/dist/tui/config-wizard/kv-editor.d.ts.map +1 -1
  121. package/dist/tui/config-wizard/kv-editor.js +9 -5
  122. package/dist/tui/config-wizard/kv-editor.js.map +1 -1
  123. package/dist/tui/config-wizard/list.d.ts.map +1 -1
  124. package/dist/tui/config-wizard/list.js +2 -1
  125. package/dist/tui/config-wizard/list.js.map +1 -1
  126. package/dist/tui/config-wizard/mcp-helpers.d.ts.map +1 -1
  127. package/dist/tui/config-wizard/mcp-helpers.js +4 -3
  128. package/dist/tui/config-wizard/mcp-helpers.js.map +1 -1
  129. package/dist/tui/config-wizard/menu.d.ts.map +1 -1
  130. package/dist/tui/config-wizard/menu.js +32 -19
  131. package/dist/tui/config-wizard/menu.js.map +1 -1
  132. package/dist/tui/config-wizard/prompt-editor.d.ts.map +1 -1
  133. package/dist/tui/config-wizard/prompt-editor.js +4 -3
  134. package/dist/tui/config-wizard/prompt-editor.js.map +1 -1
  135. package/dist/tui/config-wizard/prompt.d.ts.map +1 -1
  136. package/dist/tui/config-wizard/prompt.js +8 -7
  137. package/dist/tui/config-wizard/prompt.js.map +1 -1
  138. package/dist/tui/config-wizard/step-agents.d.ts.map +1 -1
  139. package/dist/tui/config-wizard/step-agents.js +29 -20
  140. package/dist/tui/config-wizard/step-agents.js.map +1 -1
  141. package/dist/tui/config-wizard/step-defaults.d.ts.map +1 -1
  142. package/dist/tui/config-wizard/step-defaults.js +21 -17
  143. package/dist/tui/config-wizard/step-defaults.js.map +1 -1
  144. package/dist/tui/config-wizard/step-endpoints.d.ts.map +1 -1
  145. package/dist/tui/config-wizard/step-endpoints.js +16 -6
  146. package/dist/tui/config-wizard/step-endpoints.js.map +1 -1
  147. package/dist/tui/config-wizard/step-mcp.d.ts.map +1 -1
  148. package/dist/tui/config-wizard/step-mcp.js +17 -19
  149. package/dist/tui/config-wizard/step-mcp.js.map +1 -1
  150. package/dist/tui/config-wizard/step-models.d.ts.map +1 -1
  151. package/dist/tui/config-wizard/step-models.js +41 -26
  152. package/dist/tui/config-wizard/step-models.js.map +1 -1
  153. package/dist/tui/config-wizard/step-new-endpoint.d.ts.map +1 -1
  154. package/dist/tui/config-wizard/step-new-endpoint.js +16 -12
  155. package/dist/tui/config-wizard/step-new-endpoint.js.map +1 -1
  156. package/dist/tui/config-wizard/step-simple.d.ts.map +1 -1
  157. package/dist/tui/config-wizard/step-simple.js +18 -17
  158. package/dist/tui/config-wizard/step-simple.js.map +1 -1
  159. package/dist/tui/index.d.ts +17 -1
  160. package/dist/tui/index.d.ts.map +1 -1
  161. package/dist/tui/index.js +25 -14
  162. package/dist/tui/index.js.map +1 -1
  163. package/dist/tui/input-editing.d.ts +4 -1
  164. package/dist/tui/input-editing.d.ts.map +1 -1
  165. package/dist/tui/input-editing.js +7 -3
  166. package/dist/tui/input-editing.js.map +1 -1
  167. package/dist/tui/phase.d.ts +64 -0
  168. package/dist/tui/phase.d.ts.map +1 -0
  169. package/dist/tui/phase.js +112 -0
  170. package/dist/tui/phase.js.map +1 -0
  171. package/dist/tui/screens/agent-tabs.d.ts +53 -0
  172. package/dist/tui/screens/agent-tabs.d.ts.map +1 -0
  173. package/dist/tui/screens/agent-tabs.js +81 -0
  174. package/dist/tui/screens/agent-tabs.js.map +1 -0
  175. package/dist/tui/screens/chat-commands.d.ts +54 -3
  176. package/dist/tui/screens/chat-commands.d.ts.map +1 -1
  177. package/dist/tui/screens/chat-commands.js +469 -330
  178. package/dist/tui/screens/chat-commands.js.map +1 -1
  179. package/dist/tui/screens/chat.d.ts +8 -0
  180. package/dist/tui/screens/chat.d.ts.map +1 -1
  181. package/dist/tui/screens/chat.js +263 -406
  182. package/dist/tui/screens/chat.js.map +1 -1
  183. package/dist/tui/screens/common-keys.d.ts +36 -0
  184. package/dist/tui/screens/common-keys.d.ts.map +1 -0
  185. package/dist/tui/screens/common-keys.js +67 -0
  186. package/dist/tui/screens/common-keys.js.map +1 -0
  187. package/dist/tui/screens/handoff-choice.d.ts.map +1 -1
  188. package/dist/tui/screens/handoff-choice.js +4 -3
  189. package/dist/tui/screens/handoff-choice.js.map +1 -1
  190. package/dist/tui/screens/index.d.ts +3 -1
  191. package/dist/tui/screens/index.d.ts.map +1 -1
  192. package/dist/tui/screens/index.js +2 -1
  193. package/dist/tui/screens/index.js.map +1 -1
  194. package/dist/tui/screens/input-row.d.ts +64 -0
  195. package/dist/tui/screens/input-row.d.ts.map +1 -0
  196. package/dist/tui/screens/input-row.js +67 -0
  197. package/dist/tui/screens/input-row.js.map +1 -0
  198. package/dist/tui/screens/input.d.ts +13 -1
  199. package/dist/tui/screens/input.d.ts.map +1 -1
  200. package/dist/tui/screens/input.js +26 -12
  201. package/dist/tui/screens/input.js.map +1 -1
  202. package/dist/tui/screens/layout.d.ts +15 -0
  203. package/dist/tui/screens/layout.d.ts.map +1 -1
  204. package/dist/tui/screens/layout.js +14 -2
  205. package/dist/tui/screens/layout.js.map +1 -1
  206. package/dist/tui/screens/lines.d.ts.map +1 -1
  207. package/dist/tui/screens/lines.js +6 -6
  208. package/dist/tui/screens/lines.js.map +1 -1
  209. package/dist/tui/screens/messages-view.d.ts.map +1 -1
  210. package/dist/tui/screens/messages-view.js +5 -4
  211. package/dist/tui/screens/messages-view.js.map +1 -1
  212. package/dist/tui/screens/notice-bar.d.ts +5 -0
  213. package/dist/tui/screens/notice-bar.d.ts.map +1 -0
  214. package/dist/tui/screens/notice-bar.js +15 -0
  215. package/dist/tui/screens/notice-bar.js.map +1 -0
  216. package/dist/tui/screens/notice.d.ts +40 -8
  217. package/dist/tui/screens/notice.d.ts.map +1 -1
  218. package/dist/tui/screens/notice.js +75 -15
  219. package/dist/tui/screens/notice.js.map +1 -1
  220. package/dist/tui/screens/overlays.d.ts.map +1 -1
  221. package/dist/tui/screens/overlays.js +3 -2
  222. package/dist/tui/screens/overlays.js.map +1 -1
  223. package/dist/tui/screens/splash.d.ts +1 -1
  224. package/dist/tui/screens/splash.d.ts.map +1 -1
  225. package/dist/tui/screens/splash.js +5 -2
  226. package/dist/tui/screens/splash.js.map +1 -1
  227. package/dist/tui/screens/use-chat-viewport.d.ts +22 -0
  228. package/dist/tui/screens/use-chat-viewport.d.ts.map +1 -0
  229. package/dist/tui/screens/use-chat-viewport.js +50 -0
  230. package/dist/tui/screens/use-chat-viewport.js.map +1 -0
  231. package/dist/tui/screens/use-input-editing.d.ts +44 -0
  232. package/dist/tui/screens/use-input-editing.d.ts.map +1 -0
  233. package/dist/tui/screens/use-input-editing.js +192 -0
  234. package/dist/tui/screens/use-input-editing.js.map +1 -0
  235. package/dist/tui/screens/use-overlays.d.ts +25 -0
  236. package/dist/tui/screens/use-overlays.d.ts.map +1 -0
  237. package/dist/tui/screens/use-overlays.js +32 -0
  238. package/dist/tui/screens/use-overlays.js.map +1 -0
  239. package/dist/tui/screens/use-wizard-host.d.ts +35 -0
  240. package/dist/tui/screens/use-wizard-host.d.ts.map +1 -0
  241. package/dist/tui/screens/use-wizard-host.js +103 -0
  242. package/dist/tui/screens/use-wizard-host.js.map +1 -0
  243. package/dist/tui/status-segments.d.ts +37 -0
  244. package/dist/tui/status-segments.d.ts.map +1 -0
  245. package/dist/tui/status-segments.js +166 -0
  246. package/dist/tui/status-segments.js.map +1 -0
  247. package/dist/tui/text.d.ts +8 -5
  248. package/dist/tui/text.d.ts.map +1 -1
  249. package/dist/tui/text.js +95 -35
  250. package/dist/tui/text.js.map +1 -1
  251. package/dist/tui/theme.d.ts +2 -0
  252. package/dist/tui/theme.d.ts.map +1 -1
  253. package/dist/tui/theme.js +2 -0
  254. package/dist/tui/theme.js.map +1 -1
  255. package/dist/tui/token-rate.d.ts +83 -0
  256. package/dist/tui/token-rate.d.ts.map +1 -0
  257. package/dist/tui/token-rate.js +195 -0
  258. package/dist/tui/token-rate.js.map +1 -0
  259. package/dist/types.d.ts +0 -3
  260. package/dist/types.d.ts.map +1 -1
  261. package/package.json +4 -3
package/dist/config.js CHANGED
@@ -47,7 +47,8 @@
47
47
  */
48
48
  import { promises as fs } from "fs";
49
49
  import { dirname, join } from "path";
50
- import { ConfigManager as SdkConfigManager } from "@ai-zen/agents-sdk";
50
+ import { ConfigManager as SdkConfigManager, getLogger } from "@ai-zen/agents-sdk";
51
+ import { t } from "./i18n/index.js";
51
52
  // ==================== 根目录 ====================
52
53
  export const AI_ZEN_DIR = process.env.AI_ZEN_DIR || join(process.env.HOME || process.env.USERPROFILE || "", ".ai-zen");
53
54
  // ==================== CLI 运行时目录 ====================
@@ -86,28 +87,43 @@ export const SHARED_MCP_CONFIG_FILE = join(process.cwd(), ".mcp.json");
86
87
  const sdkConfigMgr = new SdkConfigManager(CONFIG_FILE);
87
88
  // ==================== 目录初始化 ====================
88
89
  /**
89
- * 确保配置目录和默认文件存在。
90
+ * 一次性初始化的 Promise(进程生命周期内只跑一次)。
91
+ *
92
+ * 为什么必须缓存 **Promise** 而不是「已初始化」布尔:`readConfig()` 内部就会调它,而
93
+ * `readConfig()` 被 TUI 的 effect、命令层、`createAgent()`、`getScope()` 反复调用 ——
94
+ * 等于每次读配置都重跑一遍全量初始化(bootstrap + 多次 stat/mkdir)。而布尔判据在
95
+ * `await` 窗口期内不成立,并发调用会一起穿透、重复 bootstrap。
96
+ */
97
+ let initPromise = null;
98
+ /**
99
+ * 确保配置目录和默认文件存在(进程内只真正执行一次)。
90
100
  *
91
101
  * 共享实体(Agent、SubAgent、Skill 目录等)委托给 SDK 的 ConfigManager.bootstrap()。
92
102
  * CLI 自身的运行时目录(conversations/)由本函数额外创建。
93
103
  * SDK 的出厂默认配置会自动写入 config.json(如果不存在)。
94
104
  */
95
105
  export async function ensureConfigDir() {
106
+ if (!initPromise) {
107
+ initPromise = initOnce().catch((error) => {
108
+ // 失败不缓存:否则一次瞬时故障(如磁盘短暂只读)会让整个进程永久失能
109
+ initPromise = null;
110
+ throw error;
111
+ });
112
+ }
113
+ return initPromise;
114
+ }
115
+ async function initOnce() {
96
116
  // SDK bootstrap:目录 + config.json + default Agent + default SubAgent + 出厂思考策略表
97
117
  await sdkConfigMgr.bootstrap();
98
- // CLI 运行时目录
99
- const cliDirs = [CLI_DIR, CONVERSATIONS_DIR];
100
- for (const dir of cliDirs) {
118
+ // CLI 运行时目录(recursive 模式已存在时不报错,无需先 access 探测)
119
+ for (const dir of [CLI_DIR, CONVERSATIONS_DIR]) {
101
120
  try {
102
- await fs.access(dir);
121
+ await fs.mkdir(dir, { recursive: true });
103
122
  }
104
- catch {
105
- try {
106
- await fs.mkdir(dir, { recursive: true });
107
- }
108
- catch {
109
- console.warn(`⚠️ 无法创建目录: ${dir}`);
110
- }
123
+ catch (error) {
124
+ // 走统一日志出口:TUI 下已改道落盘、stdio 下走 stderr。
125
+ // 这里不能用 console.warn —— 那会绕过日志系统,界面里看不见、日志文件里也查不到。
126
+ getLogger().warn(t("app.mkdirFailed", { dir, error: error?.message ?? error }));
111
127
  }
112
128
  }
113
129
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -13,12 +13,130 @@ export interface CommandMeta {
13
13
  /** 主命令名(不含 `/` 前缀),同时是处理函数表的键 */
14
14
  name: string;
15
15
  /** 等价别名(不含 `/` 前缀) */
16
- aliases?: string[];
17
- /** 一句话说明 */
18
- description: string;
16
+ aliases?: readonly string[];
17
+ /**
18
+ * 一句话说明的 i18n key。
19
+ *
20
+ * 这里存 **key 而不是文案**:本模块是纯数据,加载时机靠前(甚至早于语言初始化),
21
+ * 存成文案就定死了「加载那一刻的语言」。渲染时由 `getCommandHints()` 用 `t()` 现取。
22
+ */
23
+ descriptionKey: string;
24
+ /**
25
+ * 执行期间会调用模型(较慢,几十秒)。
26
+ *
27
+ * 宿主据此**拦住输入框**:否则用户以为没反应、继续打字,按键会被静默吞进隐藏的
28
+ * 输入缓冲,等命令结束后才突然冒出来(迁移过程中出现过这个 bug)。
29
+ * 这是命令的属性而不是宿主的白名单 —— 新增命令只改本文件,宿主自动跟上。
30
+ */
31
+ blocksInput?: boolean;
19
32
  }
20
- /** 命令元数据表(数组顺序即展示顺序) */
33
+ /**
34
+ * 命令元数据表(数组顺序即展示顺序)。
35
+ *
36
+ * 用 `as const` 声明以保留命令名的字面量类型,从而派生出 `CommandName`:
37
+ * 命令处理器表以 `Record<CommandName, …>` 声明,于是「新增命令但忘了写处理器」是
38
+ * **编译错误**,而不是运行时静默落到「未知命令」。
39
+ *
40
+ * 但 `as const` 的代价是联合类型里**没有别名的条目压根没有 `aliases` 字段**,
41
+ * 遍历时访问会报错。所以这里只把它作为内部字面量,对外导出的
42
+ * {@link COMMAND_REGISTRY} 放宽成 `readonly CommandMeta[]` —— 类型保护一分不少,
43
+ * 而所有遍历点都能直接读 `command.aliases`,不需要额外的取值 helper。
44
+ */
45
+ declare const REGISTRY_ENTRIES: readonly [{
46
+ readonly name: "save";
47
+ readonly descriptionKey: "cmd.save.desc";
48
+ }, {
49
+ readonly name: "load";
50
+ readonly descriptionKey: "cmd.load.desc";
51
+ }, {
52
+ readonly name: "new";
53
+ readonly descriptionKey: "cmd.new.desc";
54
+ }, {
55
+ readonly name: "back";
56
+ readonly descriptionKey: "cmd.back.desc";
57
+ }, {
58
+ readonly name: "editor";
59
+ readonly descriptionKey: "cmd.editor.desc";
60
+ }, {
61
+ readonly name: "clear";
62
+ readonly descriptionKey: "cmd.clear.desc";
63
+ }, {
64
+ readonly name: "config";
65
+ readonly descriptionKey: "cmd.config.desc";
66
+ }, {
67
+ readonly name: "model";
68
+ readonly descriptionKey: "cmd.model.desc";
69
+ }, {
70
+ readonly name: "agent";
71
+ readonly descriptionKey: "cmd.agent.desc";
72
+ }, {
73
+ readonly name: "reload";
74
+ readonly descriptionKey: "cmd.reload.desc";
75
+ }, {
76
+ readonly name: "mcp";
77
+ readonly descriptionKey: "cmd.mcp.desc";
78
+ }, {
79
+ readonly name: "lang";
80
+ readonly descriptionKey: "cmd.lang.desc";
81
+ }, {
82
+ readonly name: "think";
83
+ readonly aliases: readonly ["effort"];
84
+ readonly descriptionKey: "cmd.think.desc";
85
+ }, {
86
+ readonly name: "key";
87
+ readonly descriptionKey: "cmd.key.desc";
88
+ }, {
89
+ readonly name: "handoff";
90
+ readonly descriptionKey: "cmd.handoff.desc";
91
+ readonly blocksInput: true;
92
+ }, {
93
+ readonly name: "migrate";
94
+ readonly descriptionKey: "cmd.migrate.desc";
95
+ readonly blocksInput: true;
96
+ }, {
97
+ readonly name: "help";
98
+ readonly descriptionKey: "cmd.help.desc";
99
+ }, {
100
+ readonly name: "exit";
101
+ readonly aliases: readonly ["quit"];
102
+ readonly descriptionKey: "cmd.exit.desc";
103
+ }];
104
+ /** 命令主名的字面量联合(别名已归一到主名) */
105
+ export type CommandName = (typeof REGISTRY_ENTRIES)[number]["name"];
106
+ /** 命令元数据表:值来自上面的字面量,类型放宽到 `readonly CommandMeta[]` 便于遍历 */
21
107
  export declare const COMMAND_REGISTRY: readonly CommandMeta[];
108
+ /**
109
+ * 把命令名(含别名)归一到主名;未知命令返回 `undefined`。
110
+ *
111
+ * `/think` 与 `/effort` 是同一条命令的两种写法,处理器只按主名注册一份。
112
+ */
113
+ export declare function canonicalCommandName(name: string): CommandName | undefined;
114
+ /** 命中命令的元数据(别名可查) */
115
+ export declare function findCommand(name: string): CommandMeta | undefined;
116
+ /** 该命令执行期间是否应拦住输入框(见 {@link CommandMeta.blocksInput}) */
117
+ export declare function commandBlocksInput(name: string): boolean;
118
+ /**
119
+ * 从原始输入里取命令参数(首个 token 之后的全部 token)。
120
+ *
121
+ * 与 {@link parseCommandInput} 共用 {@link splitCommandInput},保证「命令名边界」与
122
+ * 「参数边界」用的是同一把尺子。
123
+ */
124
+ export declare function parseCommandArgs(text: string): string[];
125
+ /**
126
+ * 解析斜杠输入:`/migrate summary` → `{ name: "migrate", args: ["summary"] }`。
127
+ *
128
+ * 命令名的解析**只有这一处**:此前宿主自己也 `slice(1).split(/\s+/)[0]` 了一遍,
129
+ * 于是「命令名怎么算」在命令层与宿主层各有一份实现。
130
+ *
131
+ * 注意「只打了个 `/`」也算命令(`name` 为空串):宿主按斜杠前缀分流,空命令名
132
+ * 落到「未知命令」——与拆出本函数之前的行为一致。
133
+ *
134
+ * @returns 非斜杠输入返回 `null`
135
+ */
136
+ export declare function parseCommandInput(text: string): {
137
+ name: string;
138
+ args: string[];
139
+ } | null;
22
140
  /** 命令展示条目:等价写法(如 `/exit` `/quit`)折叠为一条 */
23
141
  export interface CommandHint {
24
142
  /** 全部等价写法(不含 `/` 前缀),首个为主命令名 */
@@ -42,4 +160,5 @@ export declare const COMMAND_LABEL_WIDTH: number;
42
160
  export declare function matchCommandHints(keyword: string): CommandHint[];
43
161
  /** 全部命令名(含别名,升序),供启动横幅等场景展示 */
44
162
  export declare function getCommandNames(): string[];
163
+ export {};
45
164
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,iBAAiB;AACjB,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAwB;AACxB,eAAO,MAAM,gBAAgB,EAAE,SAAS,WAAW,EAgBlD,CAAC;AAEF,0CAA0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAwB;AACxB,wBAAgB,eAAe,IAAI,WAAW,EAAE,CAS/C;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QACqC,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAOhE;AAED,+BAA+B;AAC/B,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAM1C"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,iBAAiB;AACjB,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoBqB,CAAC;AAE5C,2BAA2B;AAC3B,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,2DAA2D;AAC3D,eAAO,MAAM,gBAAgB,EAAE,SAAS,WAAW,EAAqB,CAAC;AAEzE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAO1E;AAED,qBAAqB;AACrB,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAGjE;AAED,yDAAyD;AACzD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAcD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAIvF;AAED,0CAA0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAwB;AACxB,wBAAgB,eAAe,IAAI,WAAW,EAAE,CAS/C;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QACqC,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAOhE;AAED,+BAA+B;AAC/B,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAM1C"}
@@ -8,24 +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: "model", description: "切换当前会话使用的模型(写入配置)" },
21
- { name: "think", aliases: ["effort"], description: "切换思考强度(写入模型配置)" },
22
- { name: "key", description: "设置当前端点的 API Key" },
23
- { name: "handoff", description: "编写任务交接文档(不切换会话)" },
24
- { name: "migrate", aliases: ["migration"], description: "交接并开启新会话(生成交接文档)" },
25
- { 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" },
26
42
  // exit 置于末尾:斜杠菜单回车执行高亮项,避免「只输入 / 就回车」直接退出
27
- { name: "exit", aliases: ["quit"], description: "退出对话(会提示是否保存)" },
43
+ { name: "exit", aliases: ["quit"], descriptionKey: "cmd.exit.desc" },
28
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
+ }
29
104
  /** 展开全部命令为展示条目(别名折叠) */
30
105
  export function getCommandHints() {
31
106
  return COMMAND_REGISTRY.map((command) => {
@@ -33,7 +108,7 @@ export function getCommandHints() {
33
108
  return {
34
109
  names,
35
110
  label: names.map((name) => `/${name}`).join(" "),
36
- description: command.description,
111
+ description: t(command.descriptionKey),
37
112
  };
38
113
  });
39
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"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"}
@@ -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,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;CAwBtD"}
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,8 +8,8 @@
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) {
@@ -23,20 +23,12 @@ export class ConversationPersistPlugin {
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
- messages,
32
- cwd,
33
- createdAt: existing?.createdAt ?? now,
34
- updatedAt: now,
35
- });
36
- await writeLastSession(cwd ?? process.cwd(), id);
26
+ // 每轮自动落盘也算「本目录的上一轮会话」—— 下次在该目录启动时续接它。
27
+ // `SendContext.cwd` 是 SDK 的可选字段,这里(调用点)是**唯一**需要兜底的地方。
28
+ await persistConversation({ id, agentId, messages, cwd: cwd ?? process.cwd() });
37
29
  }
38
30
  catch (err) {
39
- onError?.(`⚠️ 会话落盘失败:${err?.message ?? err}`);
31
+ onError?.(t("chat.persistFailed", { error: err?.message ?? err }));
40
32
  }
41
33
  }
42
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;AAWxD,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,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,QAAQ;gBACR,GAAG;gBACH,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,GAAG;gBACrC,SAAS,EAAE,GAAG;aACf,CAAC,CAAC;YACH,MAAM,gBAAgB,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QACnD,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,14 +7,14 @@
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
15
  /**
16
- * @deprecated 已不再读写。模型真相源是 `AgentDefinition.modelId`。
17
- * 保留字段仅为了不破坏旧存档的反序列化,读取时一律忽略。
16
+ * @deprecated 已不再读**也不写**(收敛前 stdio 的 `--save` 曾写入它)。
17
+ * 模型真相源是 `AgentDefinition.modelId`;保留字段仅为兼容旧存档的反序列化。
18
18
  */
19
19
  modelId?: string;
20
20
  messages: AgentNS.Message[];
@@ -23,26 +23,80 @@ export interface Conversation {
23
23
  createdAt: string;
24
24
  updatedAt: string;
25
25
  }
26
- /** 会话仓储:每个会话一个 JSON 文件(${conversationsDir}/${id}.json) */
27
- export declare const conversationRepository: EntityRepository<Conversation>;
28
26
  /**
29
- * 生成文件名安全的会话 id(语义化中文时间戳,天然不含非法字符)。
30
- * 形如 `对话_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`。
31
43
  */
32
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
+ }
33
63
  /**
34
- * 保存当前对话到 conversations 目录,并更新「上一轮会话 id」指针。
35
- * 迁移前落盘旧会话(onBeforeMigrate)、手动 /save 等场景共同调用,保证 id 计算一致。
64
+ * 落盘一份会话 —— **唯一的写入入口**。
65
+ *
66
+ * 此前「读旧记录拿 createdAt → 写 → 更新指针」这段在 5 个地方各写了一遍,并且已经
67
+ * 漂移:`saveConversation()` 漏写 `cwd`、stdio 的 `--save` 不更新指针、还写了一个已
68
+ * 废弃的 `modelId`。收敛到这里后,各处差异只剩「是否更新指针」一个显式开关。
36
69
  */
37
- export declare function saveConversation(ctx: ConversationContext): Promise<string>;
70
+ export declare function persistConversation(input: PersistConversationInput): Promise<string>;
38
71
  /**
39
- * 列出已保存的会话(仅读文件名与 mtime,不解析 JSON 内容,快),按更新时间倒序。
40
- * 供对话内 `/load` 选择器使用。
72
+ * 保存当前对话(交接前落盘旧会话时用):以 `ctx` 为真相源,走统一的写入入口。
41
73
  */
42
- export declare function listConversations(): Promise<Array<{
74
+ export declare function saveConversation(ctx: ConversationContext): Promise<string>;
75
+ /** `/load` 选择器的一行 */
76
+ export interface ConversationSummary {
43
77
  id: string;
78
+ /** 文件名(= id),无摘要时的回退显示 */
44
79
  name: string;
80
+ /** 首条用户消息的第一行(截断);读不到时为空串 */
81
+ preview: string;
45
82
  updatedAt: string;
46
83
  size: number;
47
- }>>;
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 {};
48
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;;;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,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,CAahF;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"}