@ai-zen/cli 0.9.0 → 1.0.0-alpha.10

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 (314) hide show
  1. package/CHANGELOG.md +199 -1
  2. package/README.md +115 -62
  3. package/README.zh.md +115 -62
  4. package/dist/agent-creator.d.ts +18 -1
  5. package/dist/agent-creator.d.ts.map +1 -1
  6. package/dist/agent-creator.js +36 -12
  7. package/dist/agent-creator.js.map +1 -1
  8. package/dist/agents-store.d.ts +33 -0
  9. package/dist/agents-store.d.ts.map +1 -0
  10. package/dist/agents-store.js +50 -0
  11. package/dist/agents-store.js.map +1 -0
  12. package/dist/auto-migrate-confirm.d.ts +43 -0
  13. package/dist/auto-migrate-confirm.d.ts.map +1 -0
  14. package/dist/auto-migrate-confirm.js +46 -0
  15. package/dist/auto-migrate-confirm.js.map +1 -0
  16. package/dist/config-editor.d.ts +201 -0
  17. package/dist/config-editor.d.ts.map +1 -0
  18. package/dist/config-editor.js +511 -0
  19. package/dist/config-editor.js.map +1 -0
  20. package/dist/config.d.ts +55 -16
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +46 -29
  23. package/dist/config.js.map +1 -1
  24. package/dist/conversation-commands/registry.d.ts +4 -5
  25. package/dist/conversation-commands/registry.d.ts.map +1 -1
  26. package/dist/conversation-commands/registry.js +11 -7
  27. package/dist/conversation-commands/registry.js.map +1 -1
  28. package/dist/conversation-persist-plugin.d.ts +25 -0
  29. package/dist/conversation-persist-plugin.d.ts.map +1 -0
  30. package/dist/conversation-persist-plugin.js +44 -0
  31. package/dist/conversation-persist-plugin.js.map +1 -0
  32. package/dist/conversation-repository.d.ts +19 -2
  33. package/dist/conversation-repository.d.ts.map +1 -1
  34. package/dist/conversation-repository.js +48 -5
  35. package/dist/conversation-repository.js.map +1 -1
  36. package/dist/format-time.d.ts +2 -2
  37. package/dist/format-time.js +2 -2
  38. package/dist/handoff-service.d.ts +19 -0
  39. package/dist/handoff-service.d.ts.map +1 -0
  40. package/dist/handoff-service.js +87 -0
  41. package/dist/handoff-service.js.map +1 -0
  42. package/dist/hook.d.ts.map +1 -1
  43. package/dist/hook.js +58 -46
  44. package/dist/hook.js.map +1 -1
  45. package/dist/index.js +82 -35
  46. package/dist/index.js.map +1 -1
  47. package/dist/mode.d.ts +56 -0
  48. package/dist/mode.d.ts.map +1 -0
  49. package/dist/mode.js +83 -0
  50. package/dist/mode.js.map +1 -0
  51. package/dist/session-pointer.d.ts +35 -0
  52. package/dist/session-pointer.d.ts.map +1 -0
  53. package/dist/session-pointer.js +81 -0
  54. package/dist/session-pointer.js.map +1 -0
  55. package/dist/stdio-runner.d.ts +34 -0
  56. package/dist/stdio-runner.d.ts.map +1 -0
  57. package/dist/stdio-runner.js +161 -0
  58. package/dist/stdio-runner.js.map +1 -0
  59. package/dist/tui/chat-session.d.ts +106 -0
  60. package/dist/tui/chat-session.d.ts.map +1 -0
  61. package/dist/tui/chat-session.js +299 -0
  62. package/dist/tui/chat-session.js.map +1 -0
  63. package/dist/tui/components.d.ts +47 -0
  64. package/dist/tui/components.d.ts.map +1 -0
  65. package/dist/tui/components.js +62 -0
  66. package/dist/tui/components.js.map +1 -0
  67. package/dist/tui/config-wizard/detail.d.ts +51 -0
  68. package/dist/tui/config-wizard/detail.d.ts.map +1 -0
  69. package/dist/tui/config-wizard/detail.js +273 -0
  70. package/dist/tui/config-wizard/detail.js.map +1 -0
  71. package/dist/tui/config-wizard/engine.d.ts +36 -0
  72. package/dist/tui/config-wizard/engine.d.ts.map +1 -0
  73. package/dist/tui/config-wizard/engine.js +187 -0
  74. package/dist/tui/config-wizard/engine.js.map +1 -0
  75. package/dist/tui/config-wizard/fields.d.ts +24 -0
  76. package/dist/tui/config-wizard/fields.d.ts.map +1 -0
  77. package/dist/tui/config-wizard/fields.js +411 -0
  78. package/dist/tui/config-wizard/fields.js.map +1 -0
  79. package/dist/tui/config-wizard/frame.d.ts +27 -0
  80. package/dist/tui/config-wizard/frame.d.ts.map +1 -0
  81. package/dist/tui/config-wizard/frame.js +28 -0
  82. package/dist/tui/config-wizard/frame.js.map +1 -0
  83. package/dist/tui/config-wizard/index.d.ts +6 -0
  84. package/dist/tui/config-wizard/index.d.ts.map +1 -0
  85. package/dist/tui/config-wizard/index.js +7 -0
  86. package/dist/tui/config-wizard/index.js.map +1 -0
  87. package/dist/tui/config-wizard/kv-editor.d.ts +18 -0
  88. package/dist/tui/config-wizard/kv-editor.d.ts.map +1 -0
  89. package/dist/tui/config-wizard/kv-editor.js +116 -0
  90. package/dist/tui/config-wizard/kv-editor.js.map +1 -0
  91. package/dist/tui/config-wizard/list.d.ts +13 -0
  92. package/dist/tui/config-wizard/list.d.ts.map +1 -0
  93. package/dist/tui/config-wizard/list.js +29 -0
  94. package/dist/tui/config-wizard/list.js.map +1 -0
  95. package/dist/tui/config-wizard/mcp-helpers.d.ts +9 -0
  96. package/dist/tui/config-wizard/mcp-helpers.d.ts.map +1 -0
  97. package/dist/tui/config-wizard/mcp-helpers.js +19 -0
  98. package/dist/tui/config-wizard/mcp-helpers.js.map +1 -0
  99. package/dist/tui/config-wizard/menu.d.ts +18 -0
  100. package/dist/tui/config-wizard/menu.d.ts.map +1 -0
  101. package/dist/tui/config-wizard/menu.js +70 -0
  102. package/dist/tui/config-wizard/menu.js.map +1 -0
  103. package/dist/tui/config-wizard/prompt-editor.d.ts +24 -0
  104. package/dist/tui/config-wizard/prompt-editor.d.ts.map +1 -0
  105. package/dist/tui/config-wizard/prompt-editor.js +83 -0
  106. package/dist/tui/config-wizard/prompt-editor.js.map +1 -0
  107. package/dist/tui/config-wizard/prompt.d.ts +57 -0
  108. package/dist/tui/config-wizard/prompt.d.ts.map +1 -0
  109. package/dist/tui/config-wizard/prompt.js +130 -0
  110. package/dist/tui/config-wizard/prompt.js.map +1 -0
  111. package/dist/tui/config-wizard/step-agents.d.ts +4 -0
  112. package/dist/tui/config-wizard/step-agents.d.ts.map +1 -0
  113. package/dist/tui/config-wizard/step-agents.js +110 -0
  114. package/dist/tui/config-wizard/step-agents.js.map +1 -0
  115. package/dist/tui/config-wizard/step-defaults.d.ts +4 -0
  116. package/dist/tui/config-wizard/step-defaults.d.ts.map +1 -0
  117. package/dist/tui/config-wizard/step-defaults.js +76 -0
  118. package/dist/tui/config-wizard/step-defaults.js.map +1 -0
  119. package/dist/tui/config-wizard/step-endpoints.d.ts +4 -0
  120. package/dist/tui/config-wizard/step-endpoints.d.ts.map +1 -0
  121. package/dist/tui/config-wizard/step-endpoints.js +43 -0
  122. package/dist/tui/config-wizard/step-endpoints.js.map +1 -0
  123. package/dist/tui/config-wizard/step-mcp.d.ts +4 -0
  124. package/dist/tui/config-wizard/step-mcp.d.ts.map +1 -0
  125. package/dist/tui/config-wizard/step-mcp.js +97 -0
  126. package/dist/tui/config-wizard/step-mcp.js.map +1 -0
  127. package/dist/tui/config-wizard/step-menu.d.ts +4 -0
  128. package/dist/tui/config-wizard/step-menu.d.ts.map +1 -0
  129. package/dist/tui/config-wizard/step-menu.js +28 -0
  130. package/dist/tui/config-wizard/step-menu.js.map +1 -0
  131. package/dist/tui/config-wizard/step-models.d.ts +4 -0
  132. package/dist/tui/config-wizard/step-models.d.ts.map +1 -0
  133. package/dist/tui/config-wizard/step-models.js +114 -0
  134. package/dist/tui/config-wizard/step-models.js.map +1 -0
  135. package/dist/tui/config-wizard/step-new-endpoint.d.ts +4 -0
  136. package/dist/tui/config-wizard/step-new-endpoint.d.ts.map +1 -0
  137. package/dist/tui/config-wizard/step-new-endpoint.js +54 -0
  138. package/dist/tui/config-wizard/step-new-endpoint.js.map +1 -0
  139. package/dist/tui/config-wizard/step-simple.d.ts +4 -0
  140. package/dist/tui/config-wizard/step-simple.d.ts.map +1 -0
  141. package/dist/tui/config-wizard/step-simple.js +55 -0
  142. package/dist/tui/config-wizard/step-simple.js.map +1 -0
  143. package/dist/tui/config-wizard/types.d.ts +147 -0
  144. package/dist/tui/config-wizard/types.d.ts.map +1 -0
  145. package/dist/tui/config-wizard/types.js +12 -0
  146. package/dist/tui/config-wizard/types.js.map +1 -0
  147. package/dist/tui/config-wizard/wizard.d.ts +9 -0
  148. package/dist/tui/config-wizard/wizard.d.ts.map +1 -0
  149. package/dist/tui/config-wizard/wizard.js +34 -0
  150. package/dist/tui/config-wizard/wizard.js.map +1 -0
  151. package/dist/tui/highlight.d.ts +35 -0
  152. package/dist/tui/highlight.d.ts.map +1 -0
  153. package/dist/tui/highlight.js +117 -0
  154. package/dist/tui/highlight.js.map +1 -0
  155. package/dist/tui/index.d.ts +34 -0
  156. package/dist/tui/index.d.ts.map +1 -0
  157. package/dist/tui/index.js +265 -0
  158. package/dist/tui/index.js.map +1 -0
  159. package/dist/tui/screens/chat-commands.d.ts +35 -0
  160. package/dist/tui/screens/chat-commands.d.ts.map +1 -0
  161. package/dist/tui/screens/chat-commands.js +214 -0
  162. package/dist/tui/screens/chat-commands.js.map +1 -0
  163. package/dist/tui/screens/chat.d.ts +21 -0
  164. package/dist/tui/screens/chat.d.ts.map +1 -0
  165. package/dist/tui/screens/chat.js +563 -0
  166. package/dist/tui/screens/chat.js.map +1 -0
  167. package/dist/tui/screens/frame-buffer.d.ts +47 -0
  168. package/dist/tui/screens/frame-buffer.d.ts.map +1 -0
  169. package/dist/tui/screens/frame-buffer.js +78 -0
  170. package/dist/tui/screens/frame-buffer.js.map +1 -0
  171. package/dist/tui/screens/index.d.ts +13 -0
  172. package/dist/tui/screens/index.d.ts.map +1 -0
  173. package/dist/tui/screens/index.js +14 -0
  174. package/dist/tui/screens/index.js.map +1 -0
  175. package/dist/tui/screens/input.d.ts +29 -0
  176. package/dist/tui/screens/input.d.ts.map +1 -0
  177. package/dist/tui/screens/input.js +54 -0
  178. package/dist/tui/screens/input.js.map +1 -0
  179. package/dist/tui/screens/layout.d.ts +44 -0
  180. package/dist/tui/screens/layout.d.ts.map +1 -0
  181. package/dist/tui/screens/layout.js +40 -0
  182. package/dist/tui/screens/layout.js.map +1 -0
  183. package/dist/tui/screens/lines.d.ts +42 -0
  184. package/dist/tui/screens/lines.d.ts.map +1 -0
  185. package/dist/tui/screens/lines.js +190 -0
  186. package/dist/tui/screens/lines.js.map +1 -0
  187. package/dist/tui/screens/messages-view.d.ts +10 -0
  188. package/dist/tui/screens/messages-view.d.ts.map +1 -0
  189. package/dist/tui/screens/messages-view.js +115 -0
  190. package/dist/tui/screens/messages-view.js.map +1 -0
  191. package/dist/tui/screens/notice.d.ts +32 -0
  192. package/dist/tui/screens/notice.d.ts.map +1 -0
  193. package/dist/tui/screens/notice.js +46 -0
  194. package/dist/tui/screens/notice.js.map +1 -0
  195. package/dist/tui/screens/overlays.d.ts +12 -0
  196. package/dist/tui/screens/overlays.d.ts.map +1 -0
  197. package/dist/tui/screens/overlays.js +34 -0
  198. package/dist/tui/screens/overlays.js.map +1 -0
  199. package/dist/tui/screens/render.d.ts +7 -0
  200. package/dist/tui/screens/render.d.ts.map +1 -0
  201. package/dist/tui/screens/render.js +61 -0
  202. package/dist/tui/screens/render.js.map +1 -0
  203. package/dist/tui/screens/splash.d.ts +5 -0
  204. package/dist/tui/screens/splash.d.ts.map +1 -0
  205. package/dist/tui/screens/splash.js +51 -0
  206. package/dist/tui/screens/splash.js.map +1 -0
  207. package/dist/tui/text.d.ts +76 -0
  208. package/dist/tui/text.d.ts.map +1 -0
  209. package/dist/tui/text.js +198 -0
  210. package/dist/tui/text.js.map +1 -0
  211. package/dist/tui/theme.d.ts +68 -0
  212. package/dist/tui/theme.d.ts.map +1 -0
  213. package/dist/tui/theme.js +132 -0
  214. package/dist/tui/theme.js.map +1 -0
  215. package/dist/types.d.ts +7 -5
  216. package/dist/types.d.ts.map +1 -1
  217. package/dist/types.js +1 -1
  218. package/package.json +12 -7
  219. package/dist/auto-migrate-confirm-plugin.d.ts +0 -58
  220. package/dist/auto-migrate-confirm-plugin.d.ts.map +0 -1
  221. package/dist/auto-migrate-confirm-plugin.js +0 -79
  222. package/dist/auto-migrate-confirm-plugin.js.map +0 -1
  223. package/dist/config-wizard.d.ts +0 -6
  224. package/dist/config-wizard.d.ts.map +0 -1
  225. package/dist/config-wizard.js +0 -46
  226. package/dist/config-wizard.js.map +0 -1
  227. package/dist/conversation-commands/back.d.ts +0 -3
  228. package/dist/conversation-commands/back.d.ts.map +0 -1
  229. package/dist/conversation-commands/back.js +0 -144
  230. package/dist/conversation-commands/back.js.map +0 -1
  231. package/dist/conversation-commands/clear.d.ts +0 -3
  232. package/dist/conversation-commands/clear.d.ts.map +0 -1
  233. package/dist/conversation-commands/clear.js +0 -8
  234. package/dist/conversation-commands/clear.js.map +0 -1
  235. package/dist/conversation-commands/editor.d.ts +0 -3
  236. package/dist/conversation-commands/editor.d.ts.map +0 -1
  237. package/dist/conversation-commands/editor.js +0 -15
  238. package/dist/conversation-commands/editor.js.map +0 -1
  239. package/dist/conversation-commands/exit.d.ts +0 -3
  240. package/dist/conversation-commands/exit.d.ts.map +0 -1
  241. package/dist/conversation-commands/exit.js +0 -37
  242. package/dist/conversation-commands/exit.js.map +0 -1
  243. package/dist/conversation-commands/help.d.ts +0 -3
  244. package/dist/conversation-commands/help.d.ts.map +0 -1
  245. package/dist/conversation-commands/help.js +0 -10
  246. package/dist/conversation-commands/help.js.map +0 -1
  247. package/dist/conversation-commands/index.d.ts +0 -13
  248. package/dist/conversation-commands/index.d.ts.map +0 -1
  249. package/dist/conversation-commands/index.js +0 -66
  250. package/dist/conversation-commands/index.js.map +0 -1
  251. package/dist/conversation-commands/migrate.d.ts +0 -12
  252. package/dist/conversation-commands/migrate.d.ts.map +0 -1
  253. package/dist/conversation-commands/migrate.js +0 -56
  254. package/dist/conversation-commands/migrate.js.map +0 -1
  255. package/dist/conversation-commands/new.d.ts +0 -3
  256. package/dist/conversation-commands/new.d.ts.map +0 -1
  257. package/dist/conversation-commands/new.js +0 -45
  258. package/dist/conversation-commands/new.js.map +0 -1
  259. package/dist/conversation-commands/save.d.ts +0 -3
  260. package/dist/conversation-commands/save.d.ts.map +0 -1
  261. package/dist/conversation-commands/save.js +0 -32
  262. package/dist/conversation-commands/save.js.map +0 -1
  263. package/dist/conversation-runner.d.ts +0 -17
  264. package/dist/conversation-runner.d.ts.map +0 -1
  265. package/dist/conversation-runner.js +0 -176
  266. package/dist/conversation-runner.js.map +0 -1
  267. package/dist/delta-renderer.d.ts +0 -33
  268. package/dist/delta-renderer.d.ts.map +0 -1
  269. package/dist/delta-renderer.js +0 -120
  270. package/dist/delta-renderer.js.map +0 -1
  271. package/dist/draft-plugin.d.ts +0 -19
  272. package/dist/draft-plugin.d.ts.map +0 -1
  273. package/dist/draft-plugin.js +0 -30
  274. package/dist/draft-plugin.js.map +0 -1
  275. package/dist/draft-repository.d.ts +0 -34
  276. package/dist/draft-repository.d.ts.map +0 -1
  277. package/dist/draft-repository.js +0 -64
  278. package/dist/draft-repository.js.map +0 -1
  279. package/dist/menus/agents.d.ts +0 -5
  280. package/dist/menus/agents.d.ts.map +0 -1
  281. package/dist/menus/agents.js +0 -219
  282. package/dist/menus/agents.js.map +0 -1
  283. package/dist/menus/common.d.ts +0 -41
  284. package/dist/menus/common.d.ts.map +0 -1
  285. package/dist/menus/common.js +0 -104
  286. package/dist/menus/common.js.map +0 -1
  287. package/dist/menus/config-display.d.ts +0 -2
  288. package/dist/menus/config-display.d.ts.map +0 -1
  289. package/dist/menus/config-display.js +0 -82
  290. package/dist/menus/config-display.js.map +0 -1
  291. package/dist/menus/config.d.ts +0 -8
  292. package/dist/menus/config.d.ts.map +0 -1
  293. package/dist/menus/config.js +0 -407
  294. package/dist/menus/config.js.map +0 -1
  295. package/dist/menus/conversations.d.ts +0 -20
  296. package/dist/menus/conversations.d.ts.map +0 -1
  297. package/dist/menus/conversations.js +0 -83
  298. package/dist/menus/conversations.js.map +0 -1
  299. package/dist/menus/index.d.ts +0 -5
  300. package/dist/menus/index.d.ts.map +0 -1
  301. package/dist/menus/index.js +0 -59
  302. package/dist/menus/index.js.map +0 -1
  303. package/dist/menus/start-conversation.d.ts +0 -16
  304. package/dist/menus/start-conversation.d.ts.map +0 -1
  305. package/dist/menus/start-conversation.js +0 -176
  306. package/dist/menus/start-conversation.js.map +0 -1
  307. package/dist/migration-service.d.ts +0 -13
  308. package/dist/migration-service.d.ts.map +0 -1
  309. package/dist/migration-service.js +0 -56
  310. package/dist/migration-service.js.map +0 -1
  311. package/dist/slash-hint-prompt.d.ts +0 -41
  312. package/dist/slash-hint-prompt.d.ts.map +0 -1
  313. package/dist/slash-hint-prompt.js +0 -92
  314. package/dist/slash-hint-prompt.js.map +0 -1
package/dist/hook.js CHANGED
@@ -1,8 +1,13 @@
1
1
  import { homedir } from "node:os";
2
2
  import { join } from "node:path";
3
3
  import { promises as fs } from "node:fs";
4
- const MARKER_START = "# === aiz hook (开始) ===";
5
- const MARKER_END = "# === aiz hook (结束) ===";
4
+ /** 当前标记(ai hook 时代) */
5
+ const MARKER_START = "# === ai hook (开始) ===";
6
+ const MARKER_END = "# === ai hook (结束) ===";
7
+ /** 历史标记(aiz hook 时代,用于平滑迁移) */
8
+ const LEGACY_BLOCKS = [
9
+ { start: "# === aiz hook (开始) ===", end: "# === aiz hook (结束) ===" },
10
+ ];
6
11
  function detectShell() {
7
12
  const shell = process.env.SHELL || "";
8
13
  const home = homedir();
@@ -15,25 +20,35 @@ function detectShell() {
15
20
  return null;
16
21
  }
17
22
  function hookCode(hookFn) {
18
- return [
19
- "",
20
- MARKER_START,
21
- `${hookFn}() {`,
22
- ' aiz "$@"',
23
- "}",
24
- MARKER_END,
25
- "",
26
- ].join("\n");
23
+ return ["", MARKER_START, `${hookFn}() {`, ' ai "$@"', "}", MARKER_END, ""].join("\n");
27
24
  }
28
- async function isInstalled(rcFile) {
29
- try {
30
- await fs.access(rcFile);
31
- }
32
- catch {
33
- return false;
25
+ /**
26
+ * 移除文件中所有 hook 代码块(含历史 aiz 标记),返回清理后的内容;
27
+ * `removed` 表示是否确有块被移除。
28
+ */
29
+ function stripHookBlocks(content) {
30
+ const blocks = [{ start: MARKER_START, end: MARKER_END }, ...LEGACY_BLOCKS];
31
+ const lines = content.split("\n");
32
+ const kept = [];
33
+ let skipping = false;
34
+ let removed = false;
35
+ let matchedAny = false;
36
+ for (const line of lines) {
37
+ const trimmed = line.trim();
38
+ if (!skipping && blocks.some((b) => b.start === trimmed)) {
39
+ skipping = true;
40
+ removed = true;
41
+ matchedAny = true;
42
+ continue;
43
+ }
44
+ if (skipping && blocks.some((b) => b.end === trimmed)) {
45
+ skipping = false;
46
+ continue;
47
+ }
48
+ if (!skipping)
49
+ kept.push(line);
34
50
  }
35
- const content = await fs.readFile(rcFile, "utf-8");
36
- return content.includes(MARKER_START);
51
+ return { content: kept.join("\n"), removed: matchedAny };
37
52
  }
38
53
  export async function installHook() {
39
54
  const shell = detectShell();
@@ -41,12 +56,24 @@ export async function installHook() {
41
56
  console.error("❌ 不支持的 shell(仅支持 bash / zsh)");
42
57
  process.exit(1);
43
58
  }
44
- if (await isInstalled(shell.rcFile)) {
45
- console.log("ℹ️ aiz hook 已安装,无需重复操作");
59
+ let current = "";
60
+ try {
61
+ current = await fs.readFile(shell.rcFile, "utf-8");
62
+ }
63
+ catch {
64
+ // 文件不存在:视为空内容
65
+ }
66
+ if (current.includes(MARKER_START)) {
67
+ console.log("ℹ️ ai hook 已安装,无需重复操作");
46
68
  return;
47
69
  }
48
- await fs.appendFile(shell.rcFile, hookCode(shell.hookFn), "utf-8");
49
- console.log(`✅ aiz hook 已安装到 ${shell.rcFile}`);
70
+ // 迁移:先移除历史 aiz 块,再写入新块
71
+ const { content: cleaned, removed } = stripHookBlocks(current);
72
+ const base = cleaned.replace(/\n+$/, "");
73
+ await fs.writeFile(shell.rcFile, base + "\n" + hookCode(shell.hookFn), "utf-8");
74
+ console.log(`✅ ai hook 已安装到 ${shell.rcFile}`);
75
+ if (removed)
76
+ console.log(" (已自动升级旧版 aiz hook)");
50
77
  console.log(` 重启终端或执行 source ${shell.rcFile} 即可生效`);
51
78
  console.log(` 之后输入不存在的命令会自动转发给 AI 处理`);
52
79
  }
@@ -56,35 +83,20 @@ export async function uninstallHook() {
56
83
  console.error("❌ 不支持的 shell(仅支持 bash / zsh)");
57
84
  process.exit(1);
58
85
  }
86
+ let content;
59
87
  try {
60
- await fs.access(shell.rcFile);
88
+ content = await fs.readFile(shell.rcFile, "utf-8");
61
89
  }
62
90
  catch {
63
- console.log("ℹ️ aiz hook 未安装(文件不存在)");
91
+ console.log("ℹ️ ai hook 未安装(文件不存在)");
64
92
  return;
65
93
  }
66
- const content = await fs.readFile(shell.rcFile, "utf-8");
67
- if (!content.includes(MARKER_START)) {
68
- console.log("ℹ️ aiz hook 未安装");
94
+ const { content: cleaned, removed } = stripHookBlocks(content);
95
+ if (!removed) {
96
+ console.log("ℹ️ ai hook 未安装");
69
97
  return;
70
98
  }
71
- const lines = content.split("\n");
72
- const newLines = [];
73
- let skipping = false;
74
- for (const line of lines) {
75
- if (line.trim() === MARKER_START) {
76
- skipping = true;
77
- continue;
78
- }
79
- if (line.trim() === MARKER_END) {
80
- skipping = false;
81
- continue;
82
- }
83
- if (!skipping) {
84
- newLines.push(line);
85
- }
86
- }
87
- await fs.writeFile(shell.rcFile, newLines.join("\n"), "utf-8");
88
- console.log(`✅ aiz hook 已从 ${shell.rcFile} 卸载`);
99
+ await fs.writeFile(shell.rcFile, cleaned, "utf-8");
100
+ console.log(`✅ ai hook 已从 ${shell.rcFile} 卸载`);
89
101
  }
90
102
  //# sourceMappingURL=hook.js.map
package/dist/hook.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,47 +1,94 @@
1
1
  #!/usr/bin/env node
2
- import chalk from "chalk";
3
- import { showMainMenu } from "./menus/index.js";
4
- import { startNewConversation } from "./menus/start-conversation.js";
5
2
  import { installHook, uninstallHook } from "./hook.js";
3
+ import { resolveInvocation } from "./mode.js";
4
+ import { runStdio } from "./stdio-runner.js";
5
+ import { CLI_VERSION } from "./version.js";
6
+ // ⚠️ 必须在加载 React/Ink 之前把 NODE_ENV 定为 production。
7
+ //
8
+ // 背景(OOM 根因):Node 官方分发版没有内置“production” React,react/react-reconciler
9
+ // 的入口用 `process.env.NODE_ENV !== "production"` 决定引用哪个构建。若此变量为空,
10
+ // 就会加载 *development* 版 reconciler —— 它每次渲染都会调用 `performance.measure()`
11
+ // (User Timing API),而 Node 的 performance 条目缓冲**无界且从不逐出**。长时间流式
12
+ // TUI 会话下条目数持续增长,约 55 分钟即把堆顶到 heap_size_limit(本机 ~1GB)触发 OOM。
13
+ //
14
+ // ESM 的静态 `import` 会被提升到模块体之前执行,若此处仍静态 `import "./tui/index.js"`,
15
+ // 则 React 会在本行之前就被求值成 DEV 版。因此对 TUI 入口改用动态 import(见下方 tui 分支)。
16
+ // 用 `||=` 而非 `??=`:空的 NODE_ENV 同样会被 React 视为非 production,需一并纠正。
17
+ process.env.NODE_ENV ||= "production";
6
18
  /**
7
- * CLI 入口
19
+ * CLI 入口 —— 双模式路由
8
20
  *
9
- * aiz → 进入交互式主菜单
10
- * aiz <消息内容> → 直接进入对话
11
- * aiz hook install → 安装 shell 兜底钩子
12
- * aiz hook uninstall → 卸载 shell 兜底钩子
21
+ * ai → TUI(仅当无参数且 stdin/stdout 均为 TTY)
22
+ * ai <提示词> → 纯 stdio:结果写 stdout,日志写 stderr
23
+ * cat 文件 | ai "总结" → 纯 stdio:stdin 为内容
24
+ * ai hook install → 安装 shell 兜底钩子
25
+ * ai hook uninstall → 卸载 shell 兜底钩子
26
+ * ai --help / --version → 帮助 / 版本
27
+ *
28
+ * 模式判定与参数解析集中在 ./mode.ts(纯函数,单测覆盖),本文件只做分发。
13
29
  */
30
+ const HELP_TEXT = `ai — AI-Zen CLI v${CLI_VERSION}
31
+
32
+ 用法:
33
+ ai 进入交互式界面(TUI,需 stdin/stdout 为 TTY)
34
+ ai <提示词> 以纯 stdio 模式提问,结果写入 stdout
35
+ cat 文件 | ai "总结要点" 通过管道传入内容,参数作为指令
36
+ ai hook install 安装 shell 兜底钩子(命令不存在时转发给 AI)
37
+ ai hook uninstall 卸载 shell 兜底钩子
38
+
39
+ 选项:
40
+ --save 保存本次对话到存档(默认不落盘)
41
+ -h, --help 显示本帮助
42
+ -v, --version 显示版本号
43
+
44
+ 说明:
45
+ stdio 模式无任何交互,结果走 stdout、日志走 stderr,成功退出码 0。
46
+ `;
14
47
  async function main() {
15
- const args = process.argv.slice(2);
16
- if (args.length === 0) {
17
- // 无参数:进入交互式主菜单(循环)
18
- while (true) {
19
- await showMainMenu();
20
- }
21
- return;
22
- }
23
- // 处理 hook 命令
24
- if (args[0] === "hook") {
25
- const action = args[1];
26
- if (action === "install") {
27
- installHook();
28
- }
29
- else if (action === "uninstall") {
30
- uninstallHook();
31
- }
32
- else {
33
- console.error("❌ 用法: aiz hook install|uninstall");
34
- process.exit(1);
48
+ const tty = {
49
+ stdinIsTTY: Boolean(process.stdin.isTTY),
50
+ stdoutIsTTY: Boolean(process.stdout.isTTY),
51
+ };
52
+ const invocation = resolveInvocation(process.argv.slice(2), tty);
53
+ switch (invocation.kind) {
54
+ case "help":
55
+ process.stdout.write(HELP_TEXT);
56
+ return;
57
+ case "version":
58
+ process.stdout.write(`${CLI_VERSION}\n`);
59
+ return;
60
+ case "hook":
61
+ if (invocation.action === "install")
62
+ await installHook();
63
+ else if (invocation.action === "uninstall")
64
+ await uninstallHook();
65
+ else {
66
+ process.stderr.write("用法: ai hook install|uninstall\n");
67
+ process.exitCode = 1;
68
+ }
69
+ return;
70
+ case "stdio":
71
+ process.exitCode = await runStdio({
72
+ instruction: invocation.instruction,
73
+ save: invocation.save,
74
+ });
75
+ return;
76
+ case "tui": {
77
+ // 无参数且均为 TTY:进入全屏交互界面(Ink)。
78
+ // 流式统一走 Ink —— 由 `RENDER_OPTIONS.incrementalRendering`(只重绘变化的行)
79
+ // 压低输出量,SSH / 弱网下实测稳定。
80
+ //
81
+ // 动态 import:确保 React/Ink 的求值发生在上方 `process.env.NODE_ENV ||= "production"`
82
+ // 之后,从而加载 production 版 reconciler(避免 DEV 版 performance.measure 缓冲撑爆堆)。
83
+ const { runTui } = await import("./tui/index.js");
84
+ await runTui();
85
+ return;
35
86
  }
36
- return;
37
87
  }
38
- // 有参数且不是 hook 命令:直接进入对话(参数作为初始消息)
39
- const message = args.join(" ");
40
- console.log(chalk.blue.bold(`\n🤖 快速开始: "${message}"\n`));
41
- await startNewConversation(message);
42
88
  }
43
89
  main().catch((error) => {
44
- console.error(chalk.red(`\n❌ 意外错误: ${error.message}\n`));
45
- process.exit(1);
90
+ const message = error instanceof Error ? error.message : String(error);
91
+ process.stderr.write(`\n❌ 意外错误: ${message}\n`);
92
+ process.exitCode = 1;
46
93
  });
47
94
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEvD;;;;;;;GAOG;AAEH,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,mBAAmB;QACnB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,YAAY,EAAE,CAAC;QACvB,CAAC;QACD,OAAO;IACT,CAAC;IAED,aAAa;IACb,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,WAAW,EAAE,CAAC;QAChB,CAAC;aAAM,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,aAAa,EAAE,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO;IACT,CAAC;IAED,kCAAkC;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,OAAO,KAAK,CAAC,CAAC,CAAC;IAC1D,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,iDAAiD;AACjD,EAAE;AACF,qEAAqE;AACrE,gEAAgE;AAChE,uEAAuE;AACvE,+DAA+D;AAC/D,8DAA8D;AAC9D,EAAE;AACF,kEAAkE;AAClE,+DAA+D;AAC/D,gEAAgE;AAChE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;AAEtC;;;;;;;;;;;GAWG;AAEH,MAAM,SAAS,GAAG,oBAAoB,WAAW;;;;;;;;;;;;;;;;CAgBhD,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG;QACV,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;QACxC,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;KAC3C,CAAC;IACF,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAEjE,QAAQ,UAAU,CAAC,IAAI,EAAE,CAAC;QACxB,KAAK,MAAM;YACT,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAChC,OAAO;QAET,KAAK,SAAS;YACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,IAAI,CAAC,CAAC;YACzC,OAAO;QAET,KAAK,MAAM;YACT,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM,WAAW,EAAE,CAAC;iBACpD,IAAI,UAAU,CAAC,MAAM,KAAK,WAAW;gBAAE,MAAM,aAAa,EAAE,CAAC;iBAC7D,CAAC;gBACJ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;gBACxD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACvB,CAAC;YACD,OAAO;QAET,KAAK,OAAO;YACV,OAAO,CAAC,QAAQ,GAAG,MAAM,QAAQ,CAAC;gBAChC,WAAW,EAAE,UAAU,CAAC,WAAW;gBACnC,IAAI,EAAE,UAAU,CAAC,IAAI;aACtB,CAAC,CAAC;YACH,OAAO;QAET,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,4BAA4B;YAC5B,gEAAgE;YAChE,uBAAuB;YACvB,EAAE;YACF,0EAA0E;YAC1E,uEAAuE;YACvE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;YAClD,MAAM,MAAM,EAAE,CAAC;YACf,OAAO;QACT,CAAC;IACH,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,OAAO,IAAI,CAAC,CAAC;IAC/C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
package/dist/mode.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ /**
2
+ * 运行模式判定与启动参数解析 —— 双模式改造的决策核心
3
+ *
4
+ * 最终形态为两种**互不混合**的运行模式(见 TODO §0):
5
+ *
6
+ * | 模式 | 触发条件 | 面向对象 |
7
+ * |-------------|--------------------------------------------|------------------------|
8
+ * | 纯 stdio | 带位置参数,或 stdin/stdout 非 TTY | 脚本、管道、shell 钩子 |
9
+ * | TUI | 无参数且 stdin/stdout 均为 TTY | 人类用户 |
10
+ *
11
+ * 本模块为纯函数与纯数据,不触碰 stdin/stdout、不 import chalk 等 UI 依赖,
12
+ * 便于单测(模式判定与路由是改造中风险最高的逻辑,必须被测覆盖)。
13
+ */
14
+ /** 运行模式 */
15
+ export type RunMode = "stdio" | "tui";
16
+ /** 终端能力快照(由入口注入,便于测试) */
17
+ export interface TtyState {
18
+ stdinIsTTY: boolean;
19
+ stdoutIsTTY: boolean;
20
+ }
21
+ /**
22
+ * 一次启动要执行的动作(路由结果)。
23
+ *
24
+ * 子命令(hook/help/version)与运行模式正交:命中子命令时短路模式判定,
25
+ * 不进入 stdio/TUI 任一路径。
26
+ */
27
+ export type Invocation = {
28
+ kind: "hook";
29
+ action: "install" | "uninstall" | "usage";
30
+ } | {
31
+ kind: "help";
32
+ } | {
33
+ kind: "version";
34
+ } | {
35
+ kind: "stdio";
36
+ instruction: string;
37
+ save: boolean;
38
+ } | {
39
+ kind: "tui";
40
+ };
41
+ /**
42
+ * 模式判定(纯函数)。
43
+ *
44
+ * - 有位置参数 → stdio(脚本/管道优先,绝不进 TUI)
45
+ * - 无参数但 stdin 或 stdout 非 TTY → stdio(管道、重定向、CI)
46
+ * - 无参数且 stdin/stdout 均为 TTY → TUI
47
+ */
48
+ export declare function decideMode(tty: TtyState, hasArgs: boolean): RunMode;
49
+ /**
50
+ * 解析 argv 并路由为 `Invocation`。
51
+ *
52
+ * 选项在遇到 `--` 之后一律视为位置参数(便于传入以 `-` 开头的提示词)。
53
+ * 未知的 `-x` 选项不报错,按位置参数处理,避免误伤以 `-` 开头的正常提问。
54
+ */
55
+ export declare function resolveInvocation(argv: string[], tty: TtyState): Invocation;
56
+ //# sourceMappingURL=mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode.d.ts","sourceRoot":"","sources":["../src/mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,WAAW;AACX,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;AAEtC,yBAAyB;AACzB,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAKpB;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAInE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,GAAG,UAAU,CA8C3E"}
package/dist/mode.js ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * 运行模式判定与启动参数解析 —— 双模式改造的决策核心
3
+ *
4
+ * 最终形态为两种**互不混合**的运行模式(见 TODO §0):
5
+ *
6
+ * | 模式 | 触发条件 | 面向对象 |
7
+ * |-------------|--------------------------------------------|------------------------|
8
+ * | 纯 stdio | 带位置参数,或 stdin/stdout 非 TTY | 脚本、管道、shell 钩子 |
9
+ * | TUI | 无参数且 stdin/stdout 均为 TTY | 人类用户 |
10
+ *
11
+ * 本模块为纯函数与纯数据,不触碰 stdin/stdout、不 import chalk 等 UI 依赖,
12
+ * 便于单测(模式判定与路由是改造中风险最高的逻辑,必须被测覆盖)。
13
+ */
14
+ /** shell 兜底钩子的子动作 */
15
+ const HOOK_ACTIONS = new Set(["install", "uninstall"]);
16
+ /**
17
+ * 模式判定(纯函数)。
18
+ *
19
+ * - 有位置参数 → stdio(脚本/管道优先,绝不进 TUI)
20
+ * - 无参数但 stdin 或 stdout 非 TTY → stdio(管道、重定向、CI)
21
+ * - 无参数且 stdin/stdout 均为 TTY → TUI
22
+ */
23
+ export function decideMode(tty, hasArgs) {
24
+ if (hasArgs)
25
+ return "stdio";
26
+ if (!tty.stdinIsTTY || !tty.stdoutIsTTY)
27
+ return "stdio";
28
+ return "tui";
29
+ }
30
+ /**
31
+ * 解析 argv 并路由为 `Invocation`。
32
+ *
33
+ * 选项在遇到 `--` 之后一律视为位置参数(便于传入以 `-` 开头的提示词)。
34
+ * 未知的 `-x` 选项不报错,按位置参数处理,避免误伤以 `-` 开头的正常提问。
35
+ */
36
+ export function resolveInvocation(argv, tty) {
37
+ const positional = [];
38
+ let save = false;
39
+ let wantHelp = false;
40
+ let wantVersion = false;
41
+ let passthrough = false;
42
+ for (const arg of argv) {
43
+ if (passthrough) {
44
+ positional.push(arg);
45
+ continue;
46
+ }
47
+ if (arg === "--") {
48
+ passthrough = true;
49
+ continue;
50
+ }
51
+ if (arg === "--save") {
52
+ save = true;
53
+ continue;
54
+ }
55
+ if (arg === "--help" || arg === "-h") {
56
+ wantHelp = true;
57
+ continue;
58
+ }
59
+ if (arg === "--version" || arg === "-v") {
60
+ wantVersion = true;
61
+ continue;
62
+ }
63
+ positional.push(arg);
64
+ }
65
+ // 子命令短路(与运行模式无关的管理动作)
66
+ if (positional[0] === "hook") {
67
+ const action = positional[1];
68
+ return {
69
+ kind: "hook",
70
+ action: action && HOOK_ACTIONS.has(action) ? action : "usage",
71
+ };
72
+ }
73
+ if (wantHelp)
74
+ return { kind: "help" };
75
+ if (wantVersion)
76
+ return { kind: "version" };
77
+ const instruction = positional.join(" ").trim();
78
+ const mode = decideMode(tty, positional.length > 0);
79
+ if (mode === "tui")
80
+ return { kind: "tui" };
81
+ return { kind: "stdio", instruction, save };
82
+ }
83
+ //# sourceMappingURL=mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode.js","sourceRoot":"","sources":["../src/mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAwBH,qBAAqB;AACrB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,GAAa,EAAE,OAAgB;IACxD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,WAAW;QAAE,OAAO,OAAO,CAAC;IACxD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAc,EAAE,GAAa;IAC7D,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,WAAW,GAAG,KAAK,CAAC;IAExB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,WAAW,EAAE,CAAC;YAChB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,WAAW,GAAG,IAAI,CAAC;YACnB,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrB,IAAI,GAAG,IAAI,CAAC;YACZ,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACrC,QAAQ,GAAG,IAAI,CAAC;YAChB,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACxC,WAAW,GAAG,IAAI,CAAC;YACnB,SAAS;QACX,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,sBAAsB;IACtB,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC7B,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,MAAM,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,MAAkC,CAAC,CAAC,CAAC,OAAO;SAC3F,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACtC,IAAI,WAAW;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAE5C,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAChD,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpD,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC3C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CLI 会话指针 — 按「工作目录(cwd)」记录各自的「上一轮会话 id」。
3
+ *
4
+ * 取代原草稿机制:不再维护单独的单文件草稿(`drafts/_current.json`),
5
+ * 而是让每个会话直接落盘为 `conversations/<id>.json`,再用本指针记住
6
+ * 「每个目录最近活动的会话 id」,供下次在该目录启动时自动续接。
7
+ *
8
+ * 存储位置:`$AI_ZEN_DIR/cli/last-session.json`,结构为 cwd → 续接记录的 map:
9
+ *
10
+ * {
11
+ * "version": 1,
12
+ * "sessions": {
13
+ * "/abs/path/to/proj-a": { "id": "对话_...", "updatedAt": "..." },
14
+ * "/abs/path/to/proj-b": { "id": "对话_...", "updatedAt": "..." }
15
+ * }
16
+ * }
17
+ *
18
+ * 以 `process.cwd()` 的**精确字符串**为键:不同目录各记各的,互不干扰。
19
+ * 旧版单指针文件(顶层 `{ id, updatedAt }`)无法归属到具体目录,一律视为
20
+ * 「无记录」——宁可丢一次续接,也不把别的目录的历史错认到当前目录。
21
+ */
22
+ /** 单个工作目录的续接记录 */
23
+ export interface SessionPointer {
24
+ /** 上一轮(最近活动)会话 id */
25
+ id: string;
26
+ /** 最后活动时间(ISO 字符串) */
27
+ updatedAt: string;
28
+ }
29
+ /** 读取指定工作目录的「上一轮会话 id」;无记录时返回 null */
30
+ export declare function readLastSession(cwd: string): Promise<SessionPointer | null>;
31
+ /** 更新指定工作目录的「上一轮会话 id」(保留其它目录的记录,原子写) */
32
+ export declare function writeLastSession(cwd: string, id: string): Promise<void>;
33
+ /** 清除指定工作目录的指针(会话被删除等场景使用) */
34
+ export declare function clearLastSession(cwd: string): Promise<void>;
35
+ //# sourceMappingURL=session-pointer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-pointer.d.ts","sourceRoot":"","sources":["../src/session-pointer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AASH,kBAAkB;AAClB,MAAM,WAAW,cAAc;IAC7B,qBAAqB;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AA2CD,sCAAsC;AACtC,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAGjF;AAED,yCAAyC;AACzC,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7E;AAED,8BAA8B;AAC9B,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKjE"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * CLI 会话指针 — 按「工作目录(cwd)」记录各自的「上一轮会话 id」。
3
+ *
4
+ * 取代原草稿机制:不再维护单独的单文件草稿(`drafts/_current.json`),
5
+ * 而是让每个会话直接落盘为 `conversations/<id>.json`,再用本指针记住
6
+ * 「每个目录最近活动的会话 id」,供下次在该目录启动时自动续接。
7
+ *
8
+ * 存储位置:`$AI_ZEN_DIR/cli/last-session.json`,结构为 cwd → 续接记录的 map:
9
+ *
10
+ * {
11
+ * "version": 1,
12
+ * "sessions": {
13
+ * "/abs/path/to/proj-a": { "id": "对话_...", "updatedAt": "..." },
14
+ * "/abs/path/to/proj-b": { "id": "对话_...", "updatedAt": "..." }
15
+ * }
16
+ * }
17
+ *
18
+ * 以 `process.cwd()` 的**精确字符串**为键:不同目录各记各的,互不干扰。
19
+ * 旧版单指针文件(顶层 `{ id, updatedAt }`)无法归属到具体目录,一律视为
20
+ * 「无记录」——宁可丢一次续接,也不把别的目录的历史错认到当前目录。
21
+ */
22
+ import { promises as fs } from "node:fs";
23
+ import { join } from "node:path";
24
+ import { CLI_DIR } from "./config.js";
25
+ const POINTER_FILE = join(CLI_DIR, "last-session.json");
26
+ const FILE_VERSION = 1;
27
+ /** 读取整份指针文件;不存在 / 损坏 / 旧版格式时返回空结构 */
28
+ async function readPointerFile() {
29
+ const empty = { version: FILE_VERSION, sessions: {} };
30
+ let parsed;
31
+ try {
32
+ parsed = JSON.parse(await fs.readFile(POINTER_FILE, "utf-8"));
33
+ }
34
+ catch {
35
+ return empty;
36
+ }
37
+ // 仅接受新版 map 结构;旧版单指针(顶层 id)或其它形状一律视为空。
38
+ if (!parsed || typeof parsed !== "object" || typeof parsed.sessions !== "object" || parsed.sessions === null) {
39
+ return empty;
40
+ }
41
+ const sessions = {};
42
+ for (const [cwd, entry] of Object.entries(parsed.sessions)) {
43
+ const e = entry;
44
+ if (e && typeof e === "object" && typeof e.id === "string" && e.id) {
45
+ sessions[cwd] = { id: e.id, updatedAt: typeof e.updatedAt === "string" ? e.updatedAt : "" };
46
+ }
47
+ }
48
+ return { version: FILE_VERSION, sessions };
49
+ }
50
+ /** 原子写入整份指针文件(必要时创建目录,tmp + rename 避免半截文件) */
51
+ async function writePointerFile(file) {
52
+ try {
53
+ await fs.access(CLI_DIR);
54
+ }
55
+ catch {
56
+ await fs.mkdir(CLI_DIR, { recursive: true });
57
+ }
58
+ const tmp = `${POINTER_FILE}.tmp`;
59
+ await fs.writeFile(tmp, JSON.stringify(file, null, 2), "utf-8");
60
+ await fs.rename(tmp, POINTER_FILE);
61
+ }
62
+ /** 读取指定工作目录的「上一轮会话 id」;无记录时返回 null */
63
+ export async function readLastSession(cwd) {
64
+ const file = await readPointerFile();
65
+ return file.sessions[cwd] ?? null;
66
+ }
67
+ /** 更新指定工作目录的「上一轮会话 id」(保留其它目录的记录,原子写) */
68
+ export async function writeLastSession(cwd, id) {
69
+ const file = await readPointerFile();
70
+ file.sessions[cwd] = { id, updatedAt: new Date().toISOString() };
71
+ await writePointerFile(file);
72
+ }
73
+ /** 清除指定工作目录的指针(会话被删除等场景使用) */
74
+ export async function clearLastSession(cwd) {
75
+ const file = await readPointerFile();
76
+ if (!(cwd in file.sessions))
77
+ return;
78
+ delete file.sessions[cwd];
79
+ await writePointerFile(file);
80
+ }
81
+ //# sourceMappingURL=session-pointer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-pointer.js","sourceRoot":"","sources":["../src/session-pointer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 纯 stdio 模式运行器
3
+ *
4
+ * 约定(见 TODO §1):
5
+ * - 不进入交互循环、不显示横幅、不等待任何按键;
6
+ * - 仅把**最终 assistant 文本**写入 stdout(零 ANSI、零 emoji 前缀、零 spinner);
7
+ * - 日志 / 进度 / SDK 输出一律走 stderr;
8
+ * - 成功退出码 0,失败非 0。
9
+ *
10
+ * 该模式不落盘(不写草稿 / 对话存档),仅当显式 `--save` 时保存对话存档。
11
+ */
12
+ import { AgentNS } from "@ai-zen/agents-core";
13
+ export interface StdioRunOptions {
14
+ /** 位置参数拼接而成的指令(可空,此时全部内容来自 stdin) */
15
+ instruction: string;
16
+ /** 是否保存对话存档(默认 false,不落盘) */
17
+ save: boolean;
18
+ }
19
+ /**
20
+ * 读取全部 stdin 文本。
21
+ * stdin 为 TTY(无管道)或读取失败时返回空串。
22
+ */
23
+ export declare function readStdin(): Promise<string>;
24
+ /**
25
+ * 合并「指令 + stdin 内容」(见 TODO §5 开放问题 2:参数为指令、stdin 为内容)。
26
+ * - 两者都有:`指令\n\n内容`
27
+ * - 仅其一:取该者
28
+ */
29
+ export declare function mergePrompt(instruction: string, stdin: string): string;
30
+ /** 从内容块中提取纯文本;非文本块(图片/文件)以占位文本表示 */
31
+ export declare function extractText(content: AgentNS.MessageContent | undefined): string;
32
+ /** 运行一次纯 stdio 对话,返回进程退出码 */
33
+ export declare function runStdio(options: StdioRunOptions): Promise<number>;
34
+ //# sourceMappingURL=stdio-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-runner.d.ts","sourceRoot":"","sources":["../src/stdio-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAa9C,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,IAAI,EAAE,OAAO,CAAC;CACf;AAOD;;;GAGG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAWjD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED,oCAAoC;AACpC,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,GAAG,SAAS,GAAG,MAAM,CAY/E;AAoCD,6BAA6B;AAC7B,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAuExE"}