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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +94 -40
  3. package/README.zh.md +94 -40
  4. package/dist/agent-creator.d.ts +7 -1
  5. package/dist/agent-creator.d.ts.map +1 -1
  6. package/dist/agent-creator.js +16 -1
  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-plugin.d.ts +7 -7
  13. package/dist/auto-migrate-confirm-plugin.d.ts.map +1 -1
  14. package/dist/auto-migrate-confirm-plugin.js +3 -21
  15. package/dist/auto-migrate-confirm-plugin.js.map +1 -1
  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 +41 -16
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +32 -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 +9 -6
  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/hook.d.ts.map +1 -1
  39. package/dist/hook.js +58 -46
  40. package/dist/hook.js.map +1 -1
  41. package/dist/index.js +65 -36
  42. package/dist/index.js.map +1 -1
  43. package/dist/migration-service.d.ts +3 -1
  44. package/dist/migration-service.d.ts.map +1 -1
  45. package/dist/migration-service.js +26 -23
  46. package/dist/migration-service.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 +22 -0
  52. package/dist/session-pointer.d.ts.map +1 -0
  53. package/dist/session-pointer.js +49 -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 +100 -0
  60. package/dist/tui/chat-session.d.ts.map +1 -0
  61. package/dist/tui/chat-session.js +263 -0
  62. package/dist/tui/chat-session.js.map +1 -0
  63. package/dist/tui/components.d.ts +44 -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 +138 -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 +33 -0
  150. package/dist/tui/config-wizard/wizard.js.map +1 -0
  151. package/dist/tui/highlight.d.ts +34 -0
  152. package/dist/tui/highlight.d.ts.map +1 -0
  153. package/dist/tui/highlight.js +116 -0
  154. package/dist/tui/highlight.js.map +1 -0
  155. package/dist/tui/index.d.ts +33 -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 +27 -0
  160. package/dist/tui/screens/chat-commands.d.ts.map +1 -0
  161. package/dist/tui/screens/chat-commands.js +176 -0
  162. package/dist/tui/screens/chat-commands.js.map +1 -0
  163. package/dist/tui/screens/chat.d.ts +25 -0
  164. package/dist/tui/screens/chat.d.ts.map +1 -0
  165. package/dist/tui/screens/chat.js +494 -0
  166. package/dist/tui/screens/chat.js.map +1 -0
  167. package/dist/tui/screens/index.d.ts +13 -0
  168. package/dist/tui/screens/index.d.ts.map +1 -0
  169. package/dist/tui/screens/index.js +14 -0
  170. package/dist/tui/screens/index.js.map +1 -0
  171. package/dist/tui/screens/input.d.ts +29 -0
  172. package/dist/tui/screens/input.d.ts.map +1 -0
  173. package/dist/tui/screens/input.js +54 -0
  174. package/dist/tui/screens/input.js.map +1 -0
  175. package/dist/tui/screens/layout.d.ts +42 -0
  176. package/dist/tui/screens/layout.d.ts.map +1 -0
  177. package/dist/tui/screens/layout.js +45 -0
  178. package/dist/tui/screens/layout.js.map +1 -0
  179. package/dist/tui/screens/lines.d.ts +71 -0
  180. package/dist/tui/screens/lines.d.ts.map +1 -0
  181. package/dist/tui/screens/lines.js +198 -0
  182. package/dist/tui/screens/lines.js.map +1 -0
  183. package/dist/tui/screens/overlays.d.ts +12 -0
  184. package/dist/tui/screens/overlays.d.ts.map +1 -0
  185. package/dist/tui/screens/overlays.js +34 -0
  186. package/dist/tui/screens/overlays.js.map +1 -0
  187. package/dist/tui/screens/render.d.ts +9 -0
  188. package/dist/tui/screens/render.d.ts.map +1 -0
  189. package/dist/tui/screens/render.js +97 -0
  190. package/dist/tui/screens/render.js.map +1 -0
  191. package/dist/tui/screens/splash.d.ts +5 -0
  192. package/dist/tui/screens/splash.d.ts.map +1 -0
  193. package/dist/tui/screens/splash.js +51 -0
  194. package/dist/tui/screens/splash.js.map +1 -0
  195. package/dist/tui/screens/state.d.ts +13 -0
  196. package/dist/tui/screens/state.d.ts.map +1 -0
  197. package/dist/tui/screens/state.js +75 -0
  198. package/dist/tui/screens/state.js.map +1 -0
  199. package/dist/tui/text.d.ts +71 -0
  200. package/dist/tui/text.d.ts.map +1 -0
  201. package/dist/tui/text.js +191 -0
  202. package/dist/tui/text.js.map +1 -0
  203. package/dist/tui/theme.d.ts +62 -0
  204. package/dist/tui/theme.d.ts.map +1 -0
  205. package/dist/tui/theme.js +120 -0
  206. package/dist/tui/theme.js.map +1 -0
  207. package/dist/types.d.ts +1 -2
  208. package/dist/types.d.ts.map +1 -1
  209. package/dist/types.js +1 -1
  210. package/package.json +11 -6
  211. package/dist/config-wizard.d.ts +0 -6
  212. package/dist/config-wizard.d.ts.map +0 -1
  213. package/dist/config-wizard.js +0 -46
  214. package/dist/config-wizard.js.map +0 -1
  215. package/dist/conversation-commands/back.d.ts +0 -3
  216. package/dist/conversation-commands/back.d.ts.map +0 -1
  217. package/dist/conversation-commands/back.js +0 -144
  218. package/dist/conversation-commands/back.js.map +0 -1
  219. package/dist/conversation-commands/clear.d.ts +0 -3
  220. package/dist/conversation-commands/clear.d.ts.map +0 -1
  221. package/dist/conversation-commands/clear.js +0 -8
  222. package/dist/conversation-commands/clear.js.map +0 -1
  223. package/dist/conversation-commands/editor.d.ts +0 -3
  224. package/dist/conversation-commands/editor.d.ts.map +0 -1
  225. package/dist/conversation-commands/editor.js +0 -15
  226. package/dist/conversation-commands/editor.js.map +0 -1
  227. package/dist/conversation-commands/exit.d.ts +0 -3
  228. package/dist/conversation-commands/exit.d.ts.map +0 -1
  229. package/dist/conversation-commands/exit.js +0 -37
  230. package/dist/conversation-commands/exit.js.map +0 -1
  231. package/dist/conversation-commands/help.d.ts +0 -3
  232. package/dist/conversation-commands/help.d.ts.map +0 -1
  233. package/dist/conversation-commands/help.js +0 -10
  234. package/dist/conversation-commands/help.js.map +0 -1
  235. package/dist/conversation-commands/index.d.ts +0 -13
  236. package/dist/conversation-commands/index.d.ts.map +0 -1
  237. package/dist/conversation-commands/index.js +0 -66
  238. package/dist/conversation-commands/index.js.map +0 -1
  239. package/dist/conversation-commands/migrate.d.ts +0 -12
  240. package/dist/conversation-commands/migrate.d.ts.map +0 -1
  241. package/dist/conversation-commands/migrate.js +0 -56
  242. package/dist/conversation-commands/migrate.js.map +0 -1
  243. package/dist/conversation-commands/new.d.ts +0 -3
  244. package/dist/conversation-commands/new.d.ts.map +0 -1
  245. package/dist/conversation-commands/new.js +0 -45
  246. package/dist/conversation-commands/new.js.map +0 -1
  247. package/dist/conversation-commands/save.d.ts +0 -3
  248. package/dist/conversation-commands/save.d.ts.map +0 -1
  249. package/dist/conversation-commands/save.js +0 -32
  250. package/dist/conversation-commands/save.js.map +0 -1
  251. package/dist/conversation-runner.d.ts +0 -17
  252. package/dist/conversation-runner.d.ts.map +0 -1
  253. package/dist/conversation-runner.js +0 -176
  254. package/dist/conversation-runner.js.map +0 -1
  255. package/dist/delta-renderer.d.ts +0 -33
  256. package/dist/delta-renderer.d.ts.map +0 -1
  257. package/dist/delta-renderer.js +0 -120
  258. package/dist/delta-renderer.js.map +0 -1
  259. package/dist/draft-plugin.d.ts +0 -19
  260. package/dist/draft-plugin.d.ts.map +0 -1
  261. package/dist/draft-plugin.js +0 -30
  262. package/dist/draft-plugin.js.map +0 -1
  263. package/dist/draft-repository.d.ts +0 -34
  264. package/dist/draft-repository.d.ts.map +0 -1
  265. package/dist/draft-repository.js +0 -64
  266. package/dist/draft-repository.js.map +0 -1
  267. package/dist/menus/agents.d.ts +0 -5
  268. package/dist/menus/agents.d.ts.map +0 -1
  269. package/dist/menus/agents.js +0 -219
  270. package/dist/menus/agents.js.map +0 -1
  271. package/dist/menus/common.d.ts +0 -41
  272. package/dist/menus/common.d.ts.map +0 -1
  273. package/dist/menus/common.js +0 -104
  274. package/dist/menus/common.js.map +0 -1
  275. package/dist/menus/config-display.d.ts +0 -2
  276. package/dist/menus/config-display.d.ts.map +0 -1
  277. package/dist/menus/config-display.js +0 -82
  278. package/dist/menus/config-display.js.map +0 -1
  279. package/dist/menus/config.d.ts +0 -8
  280. package/dist/menus/config.d.ts.map +0 -1
  281. package/dist/menus/config.js +0 -407
  282. package/dist/menus/config.js.map +0 -1
  283. package/dist/menus/conversations.d.ts +0 -20
  284. package/dist/menus/conversations.d.ts.map +0 -1
  285. package/dist/menus/conversations.js +0 -83
  286. package/dist/menus/conversations.js.map +0 -1
  287. package/dist/menus/index.d.ts +0 -5
  288. package/dist/menus/index.d.ts.map +0 -1
  289. package/dist/menus/index.js +0 -59
  290. package/dist/menus/index.js.map +0 -1
  291. package/dist/menus/start-conversation.d.ts +0 -16
  292. package/dist/menus/start-conversation.d.ts.map +0 -1
  293. package/dist/menus/start-conversation.js +0 -176
  294. package/dist/menus/start-conversation.js.map +0 -1
  295. package/dist/slash-hint-prompt.d.ts +0 -41
  296. package/dist/slash-hint-prompt.d.ts.map +0 -1
  297. package/dist/slash-hint-prompt.js +0 -92
  298. package/dist/slash-hint-prompt.js.map +0 -1
package/dist/config.js CHANGED
@@ -15,7 +15,7 @@
15
15
  * ├── mcp-oauth/ ← MCP OAuth token(共享)
16
16
  * └── cli/ ← CLI 运行时数据
17
17
  * ├── conversations/ ← 对话记录
18
- * └── drafts/ ← 草稿
18
+ * └── last-session.json ← 「上一轮会话 id」指针
19
19
  *
20
20
  * ~/.agents/ ← 业界通用规范(如 Cursor、Windsurf、Cline)
21
21
  * ├── skills/ ← 用户级 Skill
@@ -39,8 +39,7 @@
39
39
  * 4. ~/.agents/skills/
40
40
  */
41
41
  import { promises as fs } from "fs";
42
- import { join } from "path";
43
- import chalk from "chalk";
42
+ import { dirname, join } from "path";
44
43
  import { ConfigManager as SdkConfigManager } from "@ai-zen/agents-sdk";
45
44
  // ==================== 根目录 ====================
46
45
  export const AI_ZEN_DIR = process.env.AI_ZEN_DIR || join(process.env.HOME || process.env.USERPROFILE || "", ".ai-zen");
@@ -48,7 +47,6 @@ export const AI_ZEN_DIR = process.env.AI_ZEN_DIR || join(process.env.HOME || pro
48
47
  export const CLI_DIR = join(AI_ZEN_DIR, "cli");
49
48
  export const CONFIG_FILE = join(AI_ZEN_DIR, "config.json");
50
49
  export const CONVERSATIONS_DIR = join(CLI_DIR, "conversations");
51
- export const DRAFTS_DIR = join(CLI_DIR, "drafts");
52
50
  // ==================== 共享目录 ====================
53
51
  export const AGENTS_DIR = join(AI_ZEN_DIR, "agents");
54
52
  export const SUB_AGENTS_DIR = join(AI_ZEN_DIR, "sub-agents");
@@ -77,14 +75,14 @@ const sdkConfigMgr = new SdkConfigManager(CONFIG_FILE);
77
75
  * 确保配置目录和默认文件存在。
78
76
  *
79
77
  * 共享实体(Agent、SubAgent、Skill 目录等)委托给 SDK 的 ConfigManager.bootstrap()。
80
- * CLI 自身的运行时目录(conversations/、drafts/)由本函数额外创建。
78
+ * CLI 自身的运行时目录(conversations/)由本函数额外创建。
81
79
  * SDK 的出厂默认配置会自动写入 config.json(如果不存在)。
82
80
  */
83
81
  export async function ensureConfigDir() {
84
82
  // SDK bootstrap:目录 + config.json + default Agent + default SubAgent
85
83
  await sdkConfigMgr.bootstrap();
86
84
  // CLI 运行时目录
87
- const cliDirs = [CLI_DIR, CONVERSATIONS_DIR, DRAFTS_DIR];
85
+ const cliDirs = [CLI_DIR, CONVERSATIONS_DIR];
88
86
  for (const dir of cliDirs) {
89
87
  try {
90
88
  await fs.access(dir);
@@ -94,7 +92,7 @@ export async function ensureConfigDir() {
94
92
  await fs.mkdir(dir, { recursive: true });
95
93
  }
96
94
  catch {
97
- console.warn(chalk.yellow(`⚠️ 无法创建目录: ${dir}`));
95
+ console.warn(`⚠️ 无法创建目录: ${dir}`);
98
96
  }
99
97
  }
100
98
  }
@@ -108,19 +106,23 @@ export async function saveConfig(config) {
108
106
  await ensureConfigDir();
109
107
  await sdkConfigMgr.write(config);
110
108
  }
109
+ /** 作用域对应的 mcp.json 路径 */
110
+ export function mcpConfigPath(scope) {
111
+ return scope === "project" ? PROJECT_MCP_CONFIG_FILE : MCP_CONFIG_FILE;
112
+ }
111
113
  /**
112
- * 读取全局 ~/.ai-zen/mcp.json,不存在时返回空结构。
114
+ * 读取指定路径的 mcp.json,不存在 / 解析失败时返回空结构。
113
115
  * 采用业界标准 `mcpServers` 顶层字段(与 SDK discoverMcpServers 一致)。
114
116
  */
115
- export async function readMcpConfig() {
117
+ export async function readMcpConfigAt(path) {
116
118
  try {
117
- await fs.access(MCP_CONFIG_FILE);
119
+ await fs.access(path);
118
120
  }
119
121
  catch {
120
122
  return { mcpServers: {} };
121
123
  }
122
124
  try {
123
- const raw = JSON.parse(await fs.readFile(MCP_CONFIG_FILE, "utf-8"));
125
+ const raw = JSON.parse(await fs.readFile(path, "utf-8"));
124
126
  // 兼容并归一:以 mcpServers 为准,缺失时回退到空的 mcpServers
125
127
  return { mcpServers: raw.mcpServers ?? {} };
126
128
  }
@@ -129,27 +131,28 @@ export async function readMcpConfig() {
129
131
  }
130
132
  }
131
133
  /**
132
- * 原子写入全局 ~/.ai-zen/mcp.json。
134
+ * 原子写入指定路径的 mcp.json(必要时创建父目录)。
133
135
  */
134
- export async function writeMcpConfig(mcpConfig) {
135
- const tmp = MCP_CONFIG_FILE + ".tmp";
136
+ export async function writeMcpConfigAt(path, mcpConfig) {
137
+ await fs.mkdir(dirname(path), { recursive: true });
138
+ const tmp = path + ".tmp";
136
139
  await fs.writeFile(tmp, JSON.stringify(mcpConfig, null, 2), "utf-8");
137
- await fs.rename(tmp, MCP_CONFIG_FILE);
140
+ await fs.rename(tmp, path);
141
+ }
142
+ /**
143
+ * 读取某个作用域的 mcp.json(默认全局 ~/.ai-zen/mcp.json)。
144
+ */
145
+ export async function readMcpConfig(scope = "global") {
146
+ return readMcpConfigAt(mcpConfigPath(scope));
138
147
  }
148
+ /**
149
+ * 原子写入某个作用域的 mcp.json(默认全局 ~/.ai-zen/mcp.json)。
150
+ */
151
+ export async function writeMcpConfig(mcpConfig, scope = "global") {
152
+ await writeMcpConfigAt(mcpConfigPath(scope), mcpConfig);
153
+ }
154
+ /** 读取项目级 <cwd>/.ai-zen/mcp.json(等价于 readMcpConfig("project")) */
139
155
  export async function readProjectMcpConfig() {
140
- const path = PROJECT_MCP_CONFIG_FILE;
141
- try {
142
- await fs.access(path);
143
- }
144
- catch {
145
- return { mcpServers: {} };
146
- }
147
- try {
148
- const raw = JSON.parse(await fs.readFile(path, "utf-8"));
149
- return { mcpServers: raw.mcpServers ?? {} };
150
- }
151
- catch {
152
- return { mcpServers: {} };
153
- }
156
+ return readMcpConfigAt(PROJECT_MCP_CONFIG_FILE);
154
157
  }
155
158
  //# sourceMappingURL=config.js.map
@@ -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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"}
@@ -1,13 +1,12 @@
1
1
  /**
2
2
  * 对话命令元数据 — 对话命令清单的唯一来源
3
3
  *
4
- * 命令名、别名与说明集中声明于此,由三类消费方共用:
5
- * - 分发:`./index.ts` 按主命令名装配处理函数表,并按别名自动展开
6
- * - 帮助:`./help.ts` 渲染 `/help` 输出
7
- * - 提示:`../slash-hint-prompt.ts` 渲染输入 `/` 时的实时候选提示
4
+ * 命令名、别名与说明集中声明于此,由 TUI 层复用:
5
+ * - 提示/补全:`src/tui/screens.tsx` 渲染输入 `/` 时的实时候选菜单
6
+ * - 帮助:`/help` 命令按本清单渲染
8
7
  *
9
8
  * 新增、改名或调整说明只需改动本文件。本模块为纯数据与纯函数,
10
- * 不依赖 inquirer / chalk,可直接单测。
9
+ * 不依赖 chalk / React 等 UI 依赖,可直接单测。
11
10
  */
12
11
  /** 单个对话命令的元数据 */
13
12
  export interface CommandMeta {
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;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,EASlD,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;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,EAalD,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,24 +1,27 @@
1
1
  /**
2
2
  * 对话命令元数据 — 对话命令清单的唯一来源
3
3
  *
4
- * 命令名、别名与说明集中声明于此,由三类消费方共用:
5
- * - 分发:`./index.ts` 按主命令名装配处理函数表,并按别名自动展开
6
- * - 帮助:`./help.ts` 渲染 `/help` 输出
7
- * - 提示:`../slash-hint-prompt.ts` 渲染输入 `/` 时的实时候选提示
4
+ * 命令名、别名与说明集中声明于此,由 TUI 层复用:
5
+ * - 提示/补全:`src/tui/screens.tsx` 渲染输入 `/` 时的实时候选菜单
6
+ * - 帮助:`/help` 命令按本清单渲染
8
7
  *
9
8
  * 新增、改名或调整说明只需改动本文件。本模块为纯数据与纯函数,
10
- * 不依赖 inquirer / chalk,可直接单测。
9
+ * 不依赖 chalk / React 等 UI 依赖,可直接单测。
11
10
  */
12
11
  /** 命令元数据表(数组顺序即展示顺序) */
13
12
  export const COMMAND_REGISTRY = [
14
- { name: "exit", aliases: ["quit"], description: "退出对话(会提示是否保存)" },
15
13
  { name: "save", description: "保存当前对话" },
14
+ { name: "load", description: "加载已保存的对话(替换当前会话)" },
16
15
  { name: "new", description: "重置会话(清空历史)" },
17
16
  { name: "back", description: "撤回消息(可修改后重发)" },
18
17
  { name: "editor", description: "使用系统编辑器输入长消息" },
19
18
  { name: "clear", description: "清屏" },
19
+ { name: "config", description: "打开配置中心(默认模型 / 端点管理)" },
20
+ { name: "key", description: "设置当前端点的 API Key" },
20
21
  { name: "migrate", description: "手动任务迁移(生成交接文档并开启新会话)" },
21
22
  { name: "help", description: "显示此帮助" },
23
+ // exit 置于末尾:斜杠菜单回车执行高亮项,避免「只输入 / 就回车」直接退出
24
+ { name: "exit", aliases: ["quit"], description: "退出对话(会提示是否保存)" },
22
25
  ];
23
26
  /** 展开全部命令为展示条目(别名折叠) */
24
27
  export function getCommandHints() {
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,wBAAwB;AACxB,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE;IACjE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE;IACvC,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,SAAS,EAAE,WAAW,EAAE,sBAAsB,EAAE;IACxD,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE;CACvC,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":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ConversationPersistPlugin — 会话自动落盘插件。
3
+ *
4
+ * 取代原 `DraftPlugin`:不再写单文件草稿,而是每轮内循环结束后把当前
5
+ * 消息写入该会话文件(`conversations/<id>.json`),并更新「上一轮会话 id」指针。
6
+ *
7
+ * 采用「方案 B」:仅在产生实质内容(至少一条用户消息)时落盘,避免留下空会话。
8
+ * 会话 id 通过 `getId()` 动态获取,以便任务迁移切换新会话后依然落盘到正确的文件。
9
+ */
10
+ import type { AgentPlugin, SendContext } from "@ai-zen/agents-sdk";
11
+ export interface ConversationPersistPluginOptions {
12
+ /** 动态返回当前会话 id(迁移切换会话后随之变化) */
13
+ getId: () => string;
14
+ agentId: string;
15
+ modelId: string;
16
+ cwd?: string;
17
+ /** 落盘失败时的上报(TUI 走 Ink notice);默认丢弃 */
18
+ onError?: (text: string) => void;
19
+ }
20
+ export declare class ConversationPersistPlugin implements AgentPlugin {
21
+ private options;
22
+ constructor(options: ConversationPersistPluginOptions);
23
+ onInnerLoopEnd(ctx: SendContext): Promise<void>;
24
+ }
25
+ //# sourceMappingURL=conversation-persist-plugin.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ConversationPersistPlugin — 会话自动落盘插件。
3
+ *
4
+ * 取代原 `DraftPlugin`:不再写单文件草稿,而是每轮内循环结束后把当前
5
+ * 消息写入该会话文件(`conversations/<id>.json`),并更新「上一轮会话 id」指针。
6
+ *
7
+ * 采用「方案 B」:仅在产生实质内容(至少一条用户消息)时落盘,避免留下空会话。
8
+ * 会话 id 通过 `getId()` 动态获取,以便任务迁移切换新会话后依然落盘到正确的文件。
9
+ */
10
+ import { AgentNS } from "@ai-zen/agents-core";
11
+ import { conversationRepository } from "./conversation-repository.js";
12
+ import { writeLastSession } from "./session-pointer.js";
13
+ export class ConversationPersistPlugin {
14
+ options;
15
+ constructor(options) {
16
+ this.options = options;
17
+ }
18
+ async onInnerLoopEnd(ctx) {
19
+ const { getId, agentId, modelId, cwd, onError } = this.options;
20
+ const messages = ctx.agent.messages;
21
+ // 尚无实质内容(没有用户消息)时不落盘,避免产生空会话文件
22
+ if (!messages.some((m) => m.role === AgentNS.Role.User))
23
+ return;
24
+ const id = getId();
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);
38
+ }
39
+ catch (err) {
40
+ onError?.(`⚠️ 会话落盘失败:${err?.message ?? err}`);
41
+ }
42
+ }
43
+ }
44
+ //# sourceMappingURL=conversation-persist-plugin.js.map
@@ -0,0 +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"}
@@ -3,6 +3,8 @@
3
3
  *
4
4
  * 会话是 CLI 的产品数据,由 CLI 自己维护(SDK 只负责驱动与能力)。
5
5
  * 复用 SDK 的 EntityRepository,按 id 一个 JSON 文件(${conversationsDir}/${id}.json)。
6
+ *
7
+ * 「上一轮会话 id」指针(session-pointer.ts)随每次落盘更新,供下次启动续接。
6
8
  */
7
9
  import { EntityRepository } from "@ai-zen/agents-sdk";
8
10
  import type { AgentNS } from "@ai-zen/agents-core";
@@ -20,8 +22,23 @@ export interface Conversation {
20
22
  /** 会话仓储:每个会话一个 JSON 文件(${conversationsDir}/${id}.json) */
21
23
  export declare const conversationRepository: EntityRepository<Conversation>;
22
24
  /**
23
- * 保存当前对话到 conversations 目录。
24
- * 迁移前落盘旧会话(onBeforeMigrate)、错误时自动保存等场景共同调用,保证 id 计算一致。
25
+ * 生成文件名安全的会话 id(语义化中文时间戳,天然不含非法字符)。
26
+ * 形如 `对话_2025年07月01日14时30分00秒`。
27
+ */
28
+ export declare function generateConversationId(date?: Date): string;
29
+ /**
30
+ * 保存当前对话到 conversations 目录,并更新「上一轮会话 id」指针。
31
+ * 迁移前落盘旧会话(onBeforeMigrate)、手动 /save 等场景共同调用,保证 id 计算一致。
25
32
  */
26
33
  export declare function saveConversation(ctx: ConversationContext): Promise<string>;
34
+ /**
35
+ * 列出已保存的会话(仅读文件名与 mtime,不解析 JSON 内容,快),按更新时间倒序。
36
+ * 供对话内 `/load` 选择器使用。
37
+ */
38
+ export declare function listConversations(): Promise<Array<{
39
+ id: string;
40
+ name: string;
41
+ updatedAt: string;
42
+ size: number;
43
+ }>>;
27
44
  //# 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;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,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,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAWhF"}
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"}
@@ -3,25 +3,68 @@
3
3
  *
4
4
  * 会话是 CLI 的产品数据,由 CLI 自己维护(SDK 只负责驱动与能力)。
5
5
  * 复用 SDK 的 EntityRepository,按 id 一个 JSON 文件(${conversationsDir}/${id}.json)。
6
+ *
7
+ * 「上一轮会话 id」指针(session-pointer.ts)随每次落盘更新,供下次启动续接。
6
8
  */
9
+ import { promises as fs } from "node:fs";
10
+ import { join } from "node:path";
7
11
  import { EntityRepository } from "@ai-zen/agents-sdk";
8
12
  import { CONVERSATIONS_DIR } from "./config.js";
13
+ import { formatShortTime } from "./format-time.js";
14
+ import { writeLastSession } from "./session-pointer.js";
9
15
  /** 会话仓储:每个会话一个 JSON 文件(${conversationsDir}/${id}.json) */
10
16
  export const conversationRepository = new EntityRepository(CONVERSATIONS_DIR);
11
17
  /**
12
- * 保存当前对话到 conversations 目录。
13
- * 迁移前落盘旧会话(onBeforeMigrate)、错误时自动保存等场景共同调用,保证 id 计算一致。
18
+ * 生成文件名安全的会话 id(语义化中文时间戳,天然不含非法字符)。
19
+ * 形如 `对话_2025年07月01日14时30分00秒`。
20
+ */
21
+ export function generateConversationId(date = new Date()) {
22
+ return `对话_${formatShortTime(date.toISOString())}`.replace(/[\\/:*?"<>|]/g, "_");
23
+ }
24
+ /**
25
+ * 保存当前对话到 conversations 目录,并更新「上一轮会话 id」指针。
26
+ * 迁移前落盘旧会话(onBeforeMigrate)、手动 /save 等场景共同调用,保证 id 计算一致。
14
27
  */
15
28
  export async function saveConversation(ctx) {
16
- const id = ctx.currentId || ctx.currentName.replace(/[\\/:*?"<>|]/g, "_");
29
+ const id = ctx.currentId || generateConversationId();
30
+ const existing = await conversationRepository.read(id);
31
+ const now = new Date().toISOString();
17
32
  await conversationRepository.write({
18
33
  id,
19
34
  agentId: ctx.agentId || "default",
20
35
  modelId: ctx.modelId,
21
36
  messages: ctx.agent.messages,
22
- createdAt: new Date().toISOString(),
23
- updatedAt: new Date().toISOString(),
37
+ createdAt: existing?.createdAt ?? now,
38
+ updatedAt: now,
24
39
  });
40
+ await writeLastSession(id);
25
41
  return id;
26
42
  }
43
+ /**
44
+ * 列出已保存的会话(仅读文件名与 mtime,不解析 JSON 内容,快),按更新时间倒序。
45
+ * 供对话内 `/load` 选择器使用。
46
+ */
47
+ export async function listConversations() {
48
+ try {
49
+ await fs.access(CONVERSATIONS_DIR);
50
+ }
51
+ catch {
52
+ return [];
53
+ }
54
+ const files = await fs.readdir(CONVERSATIONS_DIR);
55
+ const result = [];
56
+ for (const file of files) {
57
+ if (!file.endsWith(".json"))
58
+ continue;
59
+ const id = file.replace(/\.json$/, "");
60
+ try {
61
+ const st = await fs.stat(join(CONVERSATIONS_DIR, file));
62
+ result.push({ id, name: id, updatedAt: st.mtime.toISOString(), size: st.size });
63
+ }
64
+ catch {
65
+ /* 跳过读取失败的条目 */
66
+ }
67
+ }
68
+ return result.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
69
+ }
27
70
  //# sourceMappingURL=conversation-repository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-repository.js","sourceRoot":"","sources":["../src/conversation-repository.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAchD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,gBAAgB,CAAe,iBAAiB,CAAC,CAAC;AAE5F;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAwB;IAC7D,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;IAC1E,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,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;IACH,OAAO,EAAE,CAAC;AACZ,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,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"}
@@ -2,7 +2,7 @@
2
2
  * 统一时间格式化工具
3
3
  *
4
4
  * 所有用户可见的时间文案统一使用 dayjs + zh-cn locale,
5
- * 确保各种场景(主菜单、对话列表、Agent 列表、草稿保存等)显示一致。
5
+ * 确保各种场景(会话列表、会话标签等)显示一致。
6
6
  */
7
7
  import "dayjs/locale/zh-cn.js";
8
8
  /**
@@ -26,7 +26,7 @@ export declare function formatFullTime(isoString: string): string;
26
26
  */
27
27
  export declare function formatShortTime(isoString: string): string;
28
28
  /**
29
- * 格式化消息数量+时间(用于主菜单草稿提示)
29
+ * 格式化消息数量+时间(用于会话标签;当前暂无调用点,保留供 P1 主菜单复用)
30
30
  * 例:12 条消息, 今天 14:30
31
31
  */
32
32
  export declare function formatMessageTime(messageCount: number, isoString: string): string;
@@ -2,7 +2,7 @@
2
2
  * 统一时间格式化工具
3
3
  *
4
4
  * 所有用户可见的时间文案统一使用 dayjs + zh-cn locale,
5
- * 确保各种场景(主菜单、对话列表、Agent 列表、草稿保存等)显示一致。
5
+ * 确保各种场景(会话列表、会话标签等)显示一致。
6
6
  */
7
7
  import dayjs from "dayjs";
8
8
  import "dayjs/locale/zh-cn.js";
@@ -46,7 +46,7 @@ export function formatShortTime(isoString) {
46
46
  return dayjs(isoString).format("YYYY年MM月DD日HH时mm分ss秒");
47
47
  }
48
48
  /**
49
- * 格式化消息数量+时间(用于主菜单草稿提示)
49
+ * 格式化消息数量+时间(用于会话标签;当前暂无调用点,保留供 P1 主菜单复用)
50
50
  * 例:12 条消息, 今天 14:30
51
51
  */
52
52
  export function formatMessageTime(messageCount, isoString) {
@@ -1 +1 @@
1
- {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"AA0CA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBjD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAuCnD"}
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"AA8DA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA4BjD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAuBnD"}
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