@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.
- package/CHANGELOG.md +199 -1
- package/README.md +115 -62
- package/README.zh.md +115 -62
- package/dist/agent-creator.d.ts +18 -1
- package/dist/agent-creator.d.ts.map +1 -1
- package/dist/agent-creator.js +36 -12
- package/dist/agent-creator.js.map +1 -1
- package/dist/agents-store.d.ts +33 -0
- package/dist/agents-store.d.ts.map +1 -0
- package/dist/agents-store.js +50 -0
- package/dist/agents-store.js.map +1 -0
- package/dist/auto-migrate-confirm.d.ts +43 -0
- package/dist/auto-migrate-confirm.d.ts.map +1 -0
- package/dist/auto-migrate-confirm.js +46 -0
- package/dist/auto-migrate-confirm.js.map +1 -0
- package/dist/config-editor.d.ts +201 -0
- package/dist/config-editor.d.ts.map +1 -0
- package/dist/config-editor.js +511 -0
- package/dist/config-editor.js.map +1 -0
- package/dist/config.d.ts +55 -16
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +46 -29
- package/dist/config.js.map +1 -1
- package/dist/conversation-commands/registry.d.ts +4 -5
- package/dist/conversation-commands/registry.d.ts.map +1 -1
- package/dist/conversation-commands/registry.js +11 -7
- package/dist/conversation-commands/registry.js.map +1 -1
- package/dist/conversation-persist-plugin.d.ts +25 -0
- package/dist/conversation-persist-plugin.d.ts.map +1 -0
- package/dist/conversation-persist-plugin.js +44 -0
- package/dist/conversation-persist-plugin.js.map +1 -0
- package/dist/conversation-repository.d.ts +19 -2
- package/dist/conversation-repository.d.ts.map +1 -1
- package/dist/conversation-repository.js +48 -5
- package/dist/conversation-repository.js.map +1 -1
- package/dist/format-time.d.ts +2 -2
- package/dist/format-time.js +2 -2
- package/dist/handoff-service.d.ts +19 -0
- package/dist/handoff-service.d.ts.map +1 -0
- package/dist/handoff-service.js +87 -0
- package/dist/handoff-service.js.map +1 -0
- package/dist/hook.d.ts.map +1 -1
- package/dist/hook.js +58 -46
- package/dist/hook.js.map +1 -1
- package/dist/index.js +82 -35
- package/dist/index.js.map +1 -1
- package/dist/mode.d.ts +56 -0
- package/dist/mode.d.ts.map +1 -0
- package/dist/mode.js +83 -0
- package/dist/mode.js.map +1 -0
- package/dist/session-pointer.d.ts +35 -0
- package/dist/session-pointer.d.ts.map +1 -0
- package/dist/session-pointer.js +81 -0
- package/dist/session-pointer.js.map +1 -0
- package/dist/stdio-runner.d.ts +34 -0
- package/dist/stdio-runner.d.ts.map +1 -0
- package/dist/stdio-runner.js +161 -0
- package/dist/stdio-runner.js.map +1 -0
- package/dist/tui/chat-session.d.ts +106 -0
- package/dist/tui/chat-session.d.ts.map +1 -0
- package/dist/tui/chat-session.js +299 -0
- package/dist/tui/chat-session.js.map +1 -0
- package/dist/tui/components.d.ts +47 -0
- package/dist/tui/components.d.ts.map +1 -0
- package/dist/tui/components.js +62 -0
- package/dist/tui/components.js.map +1 -0
- package/dist/tui/config-wizard/detail.d.ts +51 -0
- package/dist/tui/config-wizard/detail.d.ts.map +1 -0
- package/dist/tui/config-wizard/detail.js +273 -0
- package/dist/tui/config-wizard/detail.js.map +1 -0
- package/dist/tui/config-wizard/engine.d.ts +36 -0
- package/dist/tui/config-wizard/engine.d.ts.map +1 -0
- package/dist/tui/config-wizard/engine.js +187 -0
- package/dist/tui/config-wizard/engine.js.map +1 -0
- package/dist/tui/config-wizard/fields.d.ts +24 -0
- package/dist/tui/config-wizard/fields.d.ts.map +1 -0
- package/dist/tui/config-wizard/fields.js +411 -0
- package/dist/tui/config-wizard/fields.js.map +1 -0
- package/dist/tui/config-wizard/frame.d.ts +27 -0
- package/dist/tui/config-wizard/frame.d.ts.map +1 -0
- package/dist/tui/config-wizard/frame.js +28 -0
- package/dist/tui/config-wizard/frame.js.map +1 -0
- package/dist/tui/config-wizard/index.d.ts +6 -0
- package/dist/tui/config-wizard/index.d.ts.map +1 -0
- package/dist/tui/config-wizard/index.js +7 -0
- package/dist/tui/config-wizard/index.js.map +1 -0
- package/dist/tui/config-wizard/kv-editor.d.ts +18 -0
- package/dist/tui/config-wizard/kv-editor.d.ts.map +1 -0
- package/dist/tui/config-wizard/kv-editor.js +116 -0
- package/dist/tui/config-wizard/kv-editor.js.map +1 -0
- package/dist/tui/config-wizard/list.d.ts +13 -0
- package/dist/tui/config-wizard/list.d.ts.map +1 -0
- package/dist/tui/config-wizard/list.js +29 -0
- package/dist/tui/config-wizard/list.js.map +1 -0
- package/dist/tui/config-wizard/mcp-helpers.d.ts +9 -0
- package/dist/tui/config-wizard/mcp-helpers.d.ts.map +1 -0
- package/dist/tui/config-wizard/mcp-helpers.js +19 -0
- package/dist/tui/config-wizard/mcp-helpers.js.map +1 -0
- package/dist/tui/config-wizard/menu.d.ts +18 -0
- package/dist/tui/config-wizard/menu.d.ts.map +1 -0
- package/dist/tui/config-wizard/menu.js +70 -0
- package/dist/tui/config-wizard/menu.js.map +1 -0
- package/dist/tui/config-wizard/prompt-editor.d.ts +24 -0
- package/dist/tui/config-wizard/prompt-editor.d.ts.map +1 -0
- package/dist/tui/config-wizard/prompt-editor.js +83 -0
- package/dist/tui/config-wizard/prompt-editor.js.map +1 -0
- package/dist/tui/config-wizard/prompt.d.ts +57 -0
- package/dist/tui/config-wizard/prompt.d.ts.map +1 -0
- package/dist/tui/config-wizard/prompt.js +130 -0
- package/dist/tui/config-wizard/prompt.js.map +1 -0
- package/dist/tui/config-wizard/step-agents.d.ts +4 -0
- package/dist/tui/config-wizard/step-agents.d.ts.map +1 -0
- package/dist/tui/config-wizard/step-agents.js +110 -0
- package/dist/tui/config-wizard/step-agents.js.map +1 -0
- package/dist/tui/config-wizard/step-defaults.d.ts +4 -0
- package/dist/tui/config-wizard/step-defaults.d.ts.map +1 -0
- package/dist/tui/config-wizard/step-defaults.js +76 -0
- package/dist/tui/config-wizard/step-defaults.js.map +1 -0
- package/dist/tui/config-wizard/step-endpoints.d.ts +4 -0
- package/dist/tui/config-wizard/step-endpoints.d.ts.map +1 -0
- package/dist/tui/config-wizard/step-endpoints.js +43 -0
- package/dist/tui/config-wizard/step-endpoints.js.map +1 -0
- package/dist/tui/config-wizard/step-mcp.d.ts +4 -0
- package/dist/tui/config-wizard/step-mcp.d.ts.map +1 -0
- package/dist/tui/config-wizard/step-mcp.js +97 -0
- package/dist/tui/config-wizard/step-mcp.js.map +1 -0
- package/dist/tui/config-wizard/step-menu.d.ts +4 -0
- package/dist/tui/config-wizard/step-menu.d.ts.map +1 -0
- package/dist/tui/config-wizard/step-menu.js +28 -0
- package/dist/tui/config-wizard/step-menu.js.map +1 -0
- package/dist/tui/config-wizard/step-models.d.ts +4 -0
- package/dist/tui/config-wizard/step-models.d.ts.map +1 -0
- package/dist/tui/config-wizard/step-models.js +114 -0
- package/dist/tui/config-wizard/step-models.js.map +1 -0
- package/dist/tui/config-wizard/step-new-endpoint.d.ts +4 -0
- package/dist/tui/config-wizard/step-new-endpoint.d.ts.map +1 -0
- package/dist/tui/config-wizard/step-new-endpoint.js +54 -0
- package/dist/tui/config-wizard/step-new-endpoint.js.map +1 -0
- package/dist/tui/config-wizard/step-simple.d.ts +4 -0
- package/dist/tui/config-wizard/step-simple.d.ts.map +1 -0
- package/dist/tui/config-wizard/step-simple.js +55 -0
- package/dist/tui/config-wizard/step-simple.js.map +1 -0
- package/dist/tui/config-wizard/types.d.ts +147 -0
- package/dist/tui/config-wizard/types.d.ts.map +1 -0
- package/dist/tui/config-wizard/types.js +12 -0
- package/dist/tui/config-wizard/types.js.map +1 -0
- package/dist/tui/config-wizard/wizard.d.ts +9 -0
- package/dist/tui/config-wizard/wizard.d.ts.map +1 -0
- package/dist/tui/config-wizard/wizard.js +34 -0
- package/dist/tui/config-wizard/wizard.js.map +1 -0
- package/dist/tui/highlight.d.ts +35 -0
- package/dist/tui/highlight.d.ts.map +1 -0
- package/dist/tui/highlight.js +117 -0
- package/dist/tui/highlight.js.map +1 -0
- package/dist/tui/index.d.ts +34 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +265 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/screens/chat-commands.d.ts +35 -0
- package/dist/tui/screens/chat-commands.d.ts.map +1 -0
- package/dist/tui/screens/chat-commands.js +214 -0
- package/dist/tui/screens/chat-commands.js.map +1 -0
- package/dist/tui/screens/chat.d.ts +21 -0
- package/dist/tui/screens/chat.d.ts.map +1 -0
- package/dist/tui/screens/chat.js +563 -0
- package/dist/tui/screens/chat.js.map +1 -0
- package/dist/tui/screens/frame-buffer.d.ts +47 -0
- package/dist/tui/screens/frame-buffer.d.ts.map +1 -0
- package/dist/tui/screens/frame-buffer.js +78 -0
- package/dist/tui/screens/frame-buffer.js.map +1 -0
- package/dist/tui/screens/index.d.ts +13 -0
- package/dist/tui/screens/index.d.ts.map +1 -0
- package/dist/tui/screens/index.js +14 -0
- package/dist/tui/screens/index.js.map +1 -0
- package/dist/tui/screens/input.d.ts +29 -0
- package/dist/tui/screens/input.d.ts.map +1 -0
- package/dist/tui/screens/input.js +54 -0
- package/dist/tui/screens/input.js.map +1 -0
- package/dist/tui/screens/layout.d.ts +44 -0
- package/dist/tui/screens/layout.d.ts.map +1 -0
- package/dist/tui/screens/layout.js +40 -0
- package/dist/tui/screens/layout.js.map +1 -0
- package/dist/tui/screens/lines.d.ts +42 -0
- package/dist/tui/screens/lines.d.ts.map +1 -0
- package/dist/tui/screens/lines.js +190 -0
- package/dist/tui/screens/lines.js.map +1 -0
- package/dist/tui/screens/messages-view.d.ts +10 -0
- package/dist/tui/screens/messages-view.d.ts.map +1 -0
- package/dist/tui/screens/messages-view.js +115 -0
- package/dist/tui/screens/messages-view.js.map +1 -0
- package/dist/tui/screens/notice.d.ts +32 -0
- package/dist/tui/screens/notice.d.ts.map +1 -0
- package/dist/tui/screens/notice.js +46 -0
- package/dist/tui/screens/notice.js.map +1 -0
- package/dist/tui/screens/overlays.d.ts +12 -0
- package/dist/tui/screens/overlays.d.ts.map +1 -0
- package/dist/tui/screens/overlays.js +34 -0
- package/dist/tui/screens/overlays.js.map +1 -0
- package/dist/tui/screens/render.d.ts +7 -0
- package/dist/tui/screens/render.d.ts.map +1 -0
- package/dist/tui/screens/render.js +61 -0
- package/dist/tui/screens/render.js.map +1 -0
- package/dist/tui/screens/splash.d.ts +5 -0
- package/dist/tui/screens/splash.d.ts.map +1 -0
- package/dist/tui/screens/splash.js +51 -0
- package/dist/tui/screens/splash.js.map +1 -0
- package/dist/tui/text.d.ts +76 -0
- package/dist/tui/text.d.ts.map +1 -0
- package/dist/tui/text.js +198 -0
- package/dist/tui/text.js.map +1 -0
- package/dist/tui/theme.d.ts +68 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +132 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/types.d.ts +7 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/package.json +12 -7
- package/dist/auto-migrate-confirm-plugin.d.ts +0 -58
- package/dist/auto-migrate-confirm-plugin.d.ts.map +0 -1
- package/dist/auto-migrate-confirm-plugin.js +0 -79
- package/dist/auto-migrate-confirm-plugin.js.map +0 -1
- package/dist/config-wizard.d.ts +0 -6
- package/dist/config-wizard.d.ts.map +0 -1
- package/dist/config-wizard.js +0 -46
- package/dist/config-wizard.js.map +0 -1
- package/dist/conversation-commands/back.d.ts +0 -3
- package/dist/conversation-commands/back.d.ts.map +0 -1
- package/dist/conversation-commands/back.js +0 -144
- package/dist/conversation-commands/back.js.map +0 -1
- package/dist/conversation-commands/clear.d.ts +0 -3
- package/dist/conversation-commands/clear.d.ts.map +0 -1
- package/dist/conversation-commands/clear.js +0 -8
- package/dist/conversation-commands/clear.js.map +0 -1
- package/dist/conversation-commands/editor.d.ts +0 -3
- package/dist/conversation-commands/editor.d.ts.map +0 -1
- package/dist/conversation-commands/editor.js +0 -15
- package/dist/conversation-commands/editor.js.map +0 -1
- package/dist/conversation-commands/exit.d.ts +0 -3
- package/dist/conversation-commands/exit.d.ts.map +0 -1
- package/dist/conversation-commands/exit.js +0 -37
- package/dist/conversation-commands/exit.js.map +0 -1
- package/dist/conversation-commands/help.d.ts +0 -3
- package/dist/conversation-commands/help.d.ts.map +0 -1
- package/dist/conversation-commands/help.js +0 -10
- package/dist/conversation-commands/help.js.map +0 -1
- package/dist/conversation-commands/index.d.ts +0 -13
- package/dist/conversation-commands/index.d.ts.map +0 -1
- package/dist/conversation-commands/index.js +0 -66
- package/dist/conversation-commands/index.js.map +0 -1
- package/dist/conversation-commands/migrate.d.ts +0 -12
- package/dist/conversation-commands/migrate.d.ts.map +0 -1
- package/dist/conversation-commands/migrate.js +0 -56
- package/dist/conversation-commands/migrate.js.map +0 -1
- package/dist/conversation-commands/new.d.ts +0 -3
- package/dist/conversation-commands/new.d.ts.map +0 -1
- package/dist/conversation-commands/new.js +0 -45
- package/dist/conversation-commands/new.js.map +0 -1
- package/dist/conversation-commands/save.d.ts +0 -3
- package/dist/conversation-commands/save.d.ts.map +0 -1
- package/dist/conversation-commands/save.js +0 -32
- package/dist/conversation-commands/save.js.map +0 -1
- package/dist/conversation-runner.d.ts +0 -17
- package/dist/conversation-runner.d.ts.map +0 -1
- package/dist/conversation-runner.js +0 -176
- package/dist/conversation-runner.js.map +0 -1
- package/dist/delta-renderer.d.ts +0 -33
- package/dist/delta-renderer.d.ts.map +0 -1
- package/dist/delta-renderer.js +0 -120
- package/dist/delta-renderer.js.map +0 -1
- package/dist/draft-plugin.d.ts +0 -19
- package/dist/draft-plugin.d.ts.map +0 -1
- package/dist/draft-plugin.js +0 -30
- package/dist/draft-plugin.js.map +0 -1
- package/dist/draft-repository.d.ts +0 -34
- package/dist/draft-repository.d.ts.map +0 -1
- package/dist/draft-repository.js +0 -64
- package/dist/draft-repository.js.map +0 -1
- package/dist/menus/agents.d.ts +0 -5
- package/dist/menus/agents.d.ts.map +0 -1
- package/dist/menus/agents.js +0 -219
- package/dist/menus/agents.js.map +0 -1
- package/dist/menus/common.d.ts +0 -41
- package/dist/menus/common.d.ts.map +0 -1
- package/dist/menus/common.js +0 -104
- package/dist/menus/common.js.map +0 -1
- package/dist/menus/config-display.d.ts +0 -2
- package/dist/menus/config-display.d.ts.map +0 -1
- package/dist/menus/config-display.js +0 -82
- package/dist/menus/config-display.js.map +0 -1
- package/dist/menus/config.d.ts +0 -8
- package/dist/menus/config.d.ts.map +0 -1
- package/dist/menus/config.js +0 -407
- package/dist/menus/config.js.map +0 -1
- package/dist/menus/conversations.d.ts +0 -20
- package/dist/menus/conversations.d.ts.map +0 -1
- package/dist/menus/conversations.js +0 -83
- package/dist/menus/conversations.js.map +0 -1
- package/dist/menus/index.d.ts +0 -5
- package/dist/menus/index.d.ts.map +0 -1
- package/dist/menus/index.js +0 -59
- package/dist/menus/index.js.map +0 -1
- package/dist/menus/start-conversation.d.ts +0 -16
- package/dist/menus/start-conversation.d.ts.map +0 -1
- package/dist/menus/start-conversation.js +0 -176
- package/dist/menus/start-conversation.js.map +0 -1
- package/dist/migration-service.d.ts +0 -13
- package/dist/migration-service.d.ts.map +0 -1
- package/dist/migration-service.js +0 -56
- package/dist/migration-service.js.map +0 -1
- package/dist/slash-hint-prompt.d.ts +0 -41
- package/dist/slash-hint-prompt.d.ts.map +0 -1
- package/dist/slash-hint-prompt.js +0 -92
- package/dist/slash-hint-prompt.js.map +0 -1
package/dist/config.js
CHANGED
|
@@ -15,7 +15,14 @@
|
|
|
15
15
|
* ├── mcp-oauth/ ← MCP OAuth token(共享)
|
|
16
16
|
* └── cli/ ← CLI 运行时数据
|
|
17
17
|
* ├── conversations/ ← 对话记录
|
|
18
|
-
* └──
|
|
18
|
+
* └── last-session.json ← 「各 cwd 上一轮会话 id」指针(cwd → id)
|
|
19
|
+
*
|
|
20
|
+
* 项目/.ai-zen/ ← 项目级配置与产物
|
|
21
|
+
* ├── skills/ ← 项目级 Skill
|
|
22
|
+
* ├── tools/ ← 项目级工具
|
|
23
|
+
* ├── sub-agents/ ← 项目级子 Agent
|
|
24
|
+
* ├── mcp.json ← 项目级 MCP 配置
|
|
25
|
+
* └── handoffs/ ← 交接文档(任务交接的落盘产物)
|
|
19
26
|
*
|
|
20
27
|
* ~/.agents/ ← 业界通用规范(如 Cursor、Windsurf、Cline)
|
|
21
28
|
* ├── skills/ ← 用户级 Skill
|
|
@@ -39,8 +46,7 @@
|
|
|
39
46
|
* 4. ~/.agents/skills/
|
|
40
47
|
*/
|
|
41
48
|
import { promises as fs } from "fs";
|
|
42
|
-
import { join } from "path";
|
|
43
|
-
import chalk from "chalk";
|
|
49
|
+
import { dirname, join } from "path";
|
|
44
50
|
import { ConfigManager as SdkConfigManager } from "@ai-zen/agents-sdk";
|
|
45
51
|
// ==================== 根目录 ====================
|
|
46
52
|
export const AI_ZEN_DIR = process.env.AI_ZEN_DIR || join(process.env.HOME || process.env.USERPROFILE || "", ".ai-zen");
|
|
@@ -48,7 +54,6 @@ export const AI_ZEN_DIR = process.env.AI_ZEN_DIR || join(process.env.HOME || pro
|
|
|
48
54
|
export const CLI_DIR = join(AI_ZEN_DIR, "cli");
|
|
49
55
|
export const CONFIG_FILE = join(AI_ZEN_DIR, "config.json");
|
|
50
56
|
export const CONVERSATIONS_DIR = join(CLI_DIR, "conversations");
|
|
51
|
-
export const DRAFTS_DIR = join(CLI_DIR, "drafts");
|
|
52
57
|
// ==================== 共享目录 ====================
|
|
53
58
|
export const AGENTS_DIR = join(AI_ZEN_DIR, "agents");
|
|
54
59
|
export const SUB_AGENTS_DIR = join(AI_ZEN_DIR, "sub-agents");
|
|
@@ -58,6 +63,13 @@ export const TOOLS_DIR = join(AI_ZEN_DIR, "tools");
|
|
|
58
63
|
export const PROJECT_SUB_AGENTS_DIR = join(process.cwd(), ".ai-zen", "sub-agents");
|
|
59
64
|
export const PROJECT_SKILLS_DIR = join(process.cwd(), ".ai-zen", "skills");
|
|
60
65
|
export const PROJECT_TOOLS_DIR = join(process.cwd(), ".ai-zen", "tools");
|
|
66
|
+
/**
|
|
67
|
+
* 交接文档目录(项目级):`<cwd>/.ai-zen/handoffs/`。
|
|
68
|
+
*
|
|
69
|
+
* 交接文档是「人也能直接读」的产物,放在项目内便于随仓库共享/评审;
|
|
70
|
+
* 目录由交接时的 write 工具或服务落盘时自动创建,无需预先建立。
|
|
71
|
+
*/
|
|
72
|
+
export const PROJECT_HANDOFFS_DIR = join(process.cwd(), ".ai-zen", "handoffs");
|
|
61
73
|
// ==================== 业界通用规范 ~/.agents/ 目录 ====================
|
|
62
74
|
const USER_AGENTS_DIR = join(process.env.HOME || process.env.USERPROFILE || "", ".agents");
|
|
63
75
|
export const USER_AGENTS_SKILLS_DIR = join(USER_AGENTS_DIR, "skills");
|
|
@@ -77,14 +89,14 @@ const sdkConfigMgr = new SdkConfigManager(CONFIG_FILE);
|
|
|
77
89
|
* 确保配置目录和默认文件存在。
|
|
78
90
|
*
|
|
79
91
|
* 共享实体(Agent、SubAgent、Skill 目录等)委托给 SDK 的 ConfigManager.bootstrap()。
|
|
80
|
-
* CLI 自身的运行时目录(conversations
|
|
92
|
+
* CLI 自身的运行时目录(conversations/)由本函数额外创建。
|
|
81
93
|
* SDK 的出厂默认配置会自动写入 config.json(如果不存在)。
|
|
82
94
|
*/
|
|
83
95
|
export async function ensureConfigDir() {
|
|
84
96
|
// SDK bootstrap:目录 + config.json + default Agent + default SubAgent
|
|
85
97
|
await sdkConfigMgr.bootstrap();
|
|
86
98
|
// CLI 运行时目录
|
|
87
|
-
const cliDirs = [CLI_DIR, CONVERSATIONS_DIR
|
|
99
|
+
const cliDirs = [CLI_DIR, CONVERSATIONS_DIR];
|
|
88
100
|
for (const dir of cliDirs) {
|
|
89
101
|
try {
|
|
90
102
|
await fs.access(dir);
|
|
@@ -94,7 +106,7 @@ export async function ensureConfigDir() {
|
|
|
94
106
|
await fs.mkdir(dir, { recursive: true });
|
|
95
107
|
}
|
|
96
108
|
catch {
|
|
97
|
-
console.warn(
|
|
109
|
+
console.warn(`⚠️ 无法创建目录: ${dir}`);
|
|
98
110
|
}
|
|
99
111
|
}
|
|
100
112
|
}
|
|
@@ -108,19 +120,23 @@ export async function saveConfig(config) {
|
|
|
108
120
|
await ensureConfigDir();
|
|
109
121
|
await sdkConfigMgr.write(config);
|
|
110
122
|
}
|
|
123
|
+
/** 作用域对应的 mcp.json 路径 */
|
|
124
|
+
export function mcpConfigPath(scope) {
|
|
125
|
+
return scope === "project" ? PROJECT_MCP_CONFIG_FILE : MCP_CONFIG_FILE;
|
|
126
|
+
}
|
|
111
127
|
/**
|
|
112
|
-
*
|
|
128
|
+
* 读取指定路径的 mcp.json,不存在 / 解析失败时返回空结构。
|
|
113
129
|
* 采用业界标准 `mcpServers` 顶层字段(与 SDK discoverMcpServers 一致)。
|
|
114
130
|
*/
|
|
115
|
-
export async function
|
|
131
|
+
export async function readMcpConfigAt(path) {
|
|
116
132
|
try {
|
|
117
|
-
await fs.access(
|
|
133
|
+
await fs.access(path);
|
|
118
134
|
}
|
|
119
135
|
catch {
|
|
120
136
|
return { mcpServers: {} };
|
|
121
137
|
}
|
|
122
138
|
try {
|
|
123
|
-
const raw = JSON.parse(await fs.readFile(
|
|
139
|
+
const raw = JSON.parse(await fs.readFile(path, "utf-8"));
|
|
124
140
|
// 兼容并归一:以 mcpServers 为准,缺失时回退到空的 mcpServers
|
|
125
141
|
return { mcpServers: raw.mcpServers ?? {} };
|
|
126
142
|
}
|
|
@@ -129,27 +145,28 @@ export async function readMcpConfig() {
|
|
|
129
145
|
}
|
|
130
146
|
}
|
|
131
147
|
/**
|
|
132
|
-
*
|
|
148
|
+
* 原子写入指定路径的 mcp.json(必要时创建父目录)。
|
|
133
149
|
*/
|
|
134
|
-
export async function
|
|
135
|
-
|
|
150
|
+
export async function writeMcpConfigAt(path, mcpConfig) {
|
|
151
|
+
await fs.mkdir(dirname(path), { recursive: true });
|
|
152
|
+
const tmp = path + ".tmp";
|
|
136
153
|
await fs.writeFile(tmp, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
137
|
-
await fs.rename(tmp,
|
|
154
|
+
await fs.rename(tmp, path);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 读取某个作用域的 mcp.json(默认全局 ~/.ai-zen/mcp.json)。
|
|
158
|
+
*/
|
|
159
|
+
export async function readMcpConfig(scope = "global") {
|
|
160
|
+
return readMcpConfigAt(mcpConfigPath(scope));
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 原子写入某个作用域的 mcp.json(默认全局 ~/.ai-zen/mcp.json)。
|
|
164
|
+
*/
|
|
165
|
+
export async function writeMcpConfig(mcpConfig, scope = "global") {
|
|
166
|
+
await writeMcpConfigAt(mcpConfigPath(scope), mcpConfig);
|
|
138
167
|
}
|
|
168
|
+
/** 读取项目级 <cwd>/.ai-zen/mcp.json(等价于 readMcpConfig("project")) */
|
|
139
169
|
export async function readProjectMcpConfig() {
|
|
140
|
-
|
|
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
|
-
}
|
|
170
|
+
return readMcpConfigAt(PROJECT_MCP_CONFIG_FILE);
|
|
154
171
|
}
|
|
155
172
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
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
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* - 提示:`../slash-hint-prompt.ts` 渲染输入 `/` 时的实时候选提示
|
|
4
|
+
* 命令名、别名与说明集中声明于此,由 TUI 层复用:
|
|
5
|
+
* - 提示/补全:`src/tui/screens.tsx` 渲染输入 `/` 时的实时候选菜单
|
|
6
|
+
* - 帮助:`/help` 命令按本清单渲染
|
|
8
7
|
*
|
|
9
8
|
* 新增、改名或调整说明只需改动本文件。本模块为纯数据与纯函数,
|
|
10
|
-
* 不依赖
|
|
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
|
|
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,EAclD,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,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 对话命令元数据 — 对话命令清单的唯一来源
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* - 提示:`../slash-hint-prompt.ts` 渲染输入 `/` 时的实时候选提示
|
|
4
|
+
* 命令名、别名与说明集中声明于此,由 TUI 层复用:
|
|
5
|
+
* - 提示/补全:`src/tui/screens.tsx` 渲染输入 `/` 时的实时候选菜单
|
|
6
|
+
* - 帮助:`/help` 命令按本清单渲染
|
|
8
7
|
*
|
|
9
8
|
* 新增、改名或调整说明只需改动本文件。本模块为纯数据与纯函数,
|
|
10
|
-
* 不依赖
|
|
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: "清屏" },
|
|
20
|
-
{ name: "
|
|
19
|
+
{ name: "config", description: "打开配置中心(默认模型 / 端点管理)" },
|
|
20
|
+
{ name: "key", description: "设置当前端点的 API Key" },
|
|
21
|
+
{ name: "handoff", description: "编写任务交接文档(不切换会话)" },
|
|
22
|
+
{ name: "migrate", aliases: ["migration"], description: "交接并开启新会话(生成交接文档)" },
|
|
21
23
|
{ name: "help", description: "显示此帮助" },
|
|
24
|
+
// exit 置于末尾:斜杠菜单回车执行高亮项,避免「只输入 / 就回车」直接退出
|
|
25
|
+
{ name: "exit", aliases: ["quit"], description: "退出对话(会提示是否保存)" },
|
|
22
26
|
];
|
|
23
27
|
/** 展开全部命令为展示条目(别名折叠) */
|
|
24
28
|
export function getCommandHints() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/conversation-commands/registry.ts"],"names":[],"mappings":"AAAA
|
|
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,iBAAiB,EAAE;IACnD,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,kBAAkB,EAAE;IAC5E,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(cwd ?? process.cwd(), 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,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"}
|
|
@@ -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
|
-
*
|
|
24
|
-
*
|
|
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
|
|
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
|
-
*
|
|
13
|
-
*
|
|
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 ||
|
|
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:
|
|
23
|
-
updatedAt:
|
|
37
|
+
createdAt: existing?.createdAt ?? now,
|
|
38
|
+
updatedAt: now,
|
|
24
39
|
});
|
|
40
|
+
await writeLastSession(process.cwd(), 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
|
|
1
|
+
{"version":3,"file":"conversation-repository.js","sourceRoot":"","sources":["../src/conversation-repository.ts"],"names":[],"mappings":"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"}
|
package/dist/format-time.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 统一时间格式化工具
|
|
3
3
|
*
|
|
4
4
|
* 所有用户可见的时间文案统一使用 dayjs + zh-cn locale,
|
|
5
|
-
*
|
|
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;
|
package/dist/format-time.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 统一时间格式化工具
|
|
3
3
|
*
|
|
4
4
|
* 所有用户可见的时间文案统一使用 dayjs + zh-cn locale,
|
|
5
|
-
*
|
|
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) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { HandoffService, type HandoffMode } from "@ai-zen/agents-sdk";
|
|
2
|
+
import type { ConversationContext } from "./types.js";
|
|
3
|
+
/** 执行者的中文名(供提示文案使用) */
|
|
4
|
+
export declare function describeMode(mode: HandoffMode): string;
|
|
5
|
+
/**
|
|
6
|
+
* 创建 CLI 交接服务实例(自动迁移与 `/migrate` / `/handoff` 共用同一个实例)。
|
|
7
|
+
*
|
|
8
|
+
* 分工:
|
|
9
|
+
* - **SDK**:`handoff()`(停工 → 写文档 → 校验 → 失败降级)与 `migrate()`(+ 清历史、注入断点);
|
|
10
|
+
* - **CLI(本函数)**:只补产品侧副作用——进度提示、旧会话存档、新会话落盘与指针更新。
|
|
11
|
+
*
|
|
12
|
+
* @param ctx 当前会话上下文(先建后回填 handoffService;钩子直接引用该对象)
|
|
13
|
+
*/
|
|
14
|
+
export declare function createHandoffService(ctx: ConversationContext, options?: {
|
|
15
|
+
log?: (text: string) => void;
|
|
16
|
+
/** 交接文档目录;默认项目级 `<cwd>/.ai-zen/handoffs`(测试/多工作区可覆盖) */
|
|
17
|
+
handoffDir?: string;
|
|
18
|
+
}): HandoffService;
|
|
19
|
+
//# sourceMappingURL=handoff-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-service.d.ts","sourceRoot":"","sources":["../src/handoff-service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAEd,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAS5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,uBAAuB;AACvB,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CAChB,GACL,cAAc,CAwEhB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { HandoffService, } from "@ai-zen/agents-sdk";
|
|
2
|
+
import { saveConversation, conversationRepository, generateConversationId, } from "./conversation-repository.js";
|
|
3
|
+
import { writeLastSession } from "./session-pointer.js";
|
|
4
|
+
import { PROJECT_HANDOFFS_DIR } from "./config.js";
|
|
5
|
+
import { listSkillDirs } from "./agent-creator.js";
|
|
6
|
+
/** 执行者的中文名(供提示文案使用) */
|
|
7
|
+
export function describeMode(mode) {
|
|
8
|
+
return mode === "self" ? "原 agent 自交接" : "独立摘要";
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 创建 CLI 交接服务实例(自动迁移与 `/migrate` / `/handoff` 共用同一个实例)。
|
|
12
|
+
*
|
|
13
|
+
* 分工:
|
|
14
|
+
* - **SDK**:`handoff()`(停工 → 写文档 → 校验 → 失败降级)与 `migrate()`(+ 清历史、注入断点);
|
|
15
|
+
* - **CLI(本函数)**:只补产品侧副作用——进度提示、旧会话存档、新会话落盘与指针更新。
|
|
16
|
+
*
|
|
17
|
+
* @param ctx 当前会话上下文(先建后回填 handoffService;钩子直接引用该对象)
|
|
18
|
+
*/
|
|
19
|
+
export function createHandoffService(ctx, options = {}) {
|
|
20
|
+
// 进度/结果一律经 `log` 上报(TUI 走 Ink notice 块),不直接 console.log 污染画面
|
|
21
|
+
const log = options.log ?? (() => { });
|
|
22
|
+
return new HandoffService({
|
|
23
|
+
// 交接文档落在项目内,便于随仓库共享与评审
|
|
24
|
+
handoffDir: options.handoffDir ?? PROJECT_HANDOFFS_DIR,
|
|
25
|
+
// CLI 采用物理剔除模式:迁移后不保留历史消息,仅保留系统提示 + 交接断点
|
|
26
|
+
strategy: "prune",
|
|
27
|
+
// 交接模板的唯一真相源:磁盘上的 handoff Skill(出厂随 SDK 释放,可被项目级覆盖)
|
|
28
|
+
skillDirs: listSkillDirs(),
|
|
29
|
+
onBeforeHandoff: (hctx) => {
|
|
30
|
+
const isAuto = hctx.promptTokens != null && hctx.maxTokens != null;
|
|
31
|
+
if (isAuto) {
|
|
32
|
+
log(`📋 检测到上下文即将超限(${hctx.promptTokens}/${hctx.maxTokens} tokens),正在交接(${describeMode(hctx.requestedMode)})…`);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
log(`📋 正在编写任务交接文档(${describeMode(hctx.requestedMode)})…`);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
onHandoff: async (hctx) => {
|
|
39
|
+
// 降级时告知用户:请求的执行者与实际执行者不一致
|
|
40
|
+
if (hctx.mode !== hctx.requestedMode) {
|
|
41
|
+
log(`⚠️ ${describeMode(hctx.requestedMode)}未能产出文档,已降级为${describeMode(hctx.mode)}`);
|
|
42
|
+
}
|
|
43
|
+
log(`📄 交接文档:${hctx.handoffPath}`);
|
|
44
|
+
// 迁移前(历史尚未剔除)保存旧对话:此时已包含交接回合,可完整审计
|
|
45
|
+
if (hctx.migrating) {
|
|
46
|
+
await saveConversation(ctx);
|
|
47
|
+
log(`✅ 原对话已保存:${ctx.currentName}`);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
onMigrated: async (hctx) => {
|
|
51
|
+
// 清空「最近一次用量」:prune 已把上下文物理重置(仅留系统提示 + 交接断点),
|
|
52
|
+
// 但 lastUsage 仍是迁移前/交接回合的 prompt_tokens。若不清理,下一次发送时
|
|
53
|
+
// ContextGuardPlugin(`onInnerLoopStart` 以 maxTokens × ratio 为硬上限)会拿这个
|
|
54
|
+
// 陈旧值判定,立即抛出「上下文严重超限」而中断——用户表现为「迁移完成后第一条
|
|
55
|
+
// 消息就被总上下文保护插件拦截」。置空后护栏首轮无据可查而放行,待下一次响应
|
|
56
|
+
// 以真实(已大幅缩小的)用量回填。
|
|
57
|
+
hctx.agent.lastUsage = undefined;
|
|
58
|
+
// 迁移开启新会话:分配新的会话 id 与名称
|
|
59
|
+
const id = generateConversationId();
|
|
60
|
+
ctx.currentId = id;
|
|
61
|
+
ctx.currentName = id;
|
|
62
|
+
log(`🚀 任务迁移完成,已开启新会话(共 ${hctx.agent.messages.length} 条消息)`);
|
|
63
|
+
log("💡 新助手会先读取交接文档,随后即可继续推进任务。");
|
|
64
|
+
// 迁移后立即把新开场白落盘为独立会话文件,并更新「上一轮会话 id」指针,
|
|
65
|
+
// 避免迁移发生在 onAfterSend(ConversationPersistPlugin 的 onInnerLoopEnd
|
|
66
|
+
// 已不再触发)导致迁移后的新对话未被及时落盘、用户中途退出时丢失。
|
|
67
|
+
try {
|
|
68
|
+
const existing = await conversationRepository.read(id);
|
|
69
|
+
const now = new Date().toISOString();
|
|
70
|
+
await conversationRepository.write({
|
|
71
|
+
id,
|
|
72
|
+
agentId: ctx.agentId || "default",
|
|
73
|
+
modelId: ctx.modelId,
|
|
74
|
+
messages: hctx.agent.messages,
|
|
75
|
+
cwd: process.cwd(),
|
|
76
|
+
createdAt: existing?.createdAt ?? now,
|
|
77
|
+
updatedAt: now,
|
|
78
|
+
});
|
|
79
|
+
await writeLastSession(process.cwd(), id);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
log(`⚠️ 迁移后会话落盘失败:${err?.message ?? err}`);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=handoff-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-service.js","sourceRoot":"","sources":["../src/handoff-service.ts"],"names":[],"mappings":"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"}
|
package/dist/hook.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"
|
|
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"}
|