@gird/ccli 2.5.1 → 2.7.0

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 (59) hide show
  1. package/README.md +4 -1
  2. package/dist/agent/ai.js +19 -6
  3. package/dist/agent/ai.js.map +1 -1
  4. package/dist/cli/{args.js → args/index.js} +1 -1
  5. package/dist/cli/args/index.js.map +1 -0
  6. package/dist/cli/file-reference.js +91 -0
  7. package/dist/cli/file-reference.js.map +1 -0
  8. package/dist/cli/repl/history.js.map +1 -0
  9. package/dist/cli/{repl.js → repl/index.js} +35 -14
  10. package/dist/cli/repl/index.js.map +1 -0
  11. package/dist/cli/repl/input.js.map +1 -0
  12. package/dist/cli/{run.js → run/index.js} +16 -7
  13. package/dist/cli/run/index.js.map +1 -0
  14. package/dist/cli/{session.js → session/index.js} +22 -1
  15. package/dist/cli/session/index.js.map +1 -0
  16. package/dist/cli/slash/config/model.js +51 -0
  17. package/dist/cli/slash/config/model.js.map +1 -0
  18. package/dist/cli/slash/config/role.js +23 -0
  19. package/dist/cli/slash/config/role.js.map +1 -0
  20. package/dist/cli/slash/context.js +2 -0
  21. package/dist/cli/slash/context.js.map +1 -0
  22. package/dist/cli/slash/index.js +123 -0
  23. package/dist/cli/slash/index.js.map +1 -0
  24. package/dist/cli/slash/mcp/mcp.js +133 -0
  25. package/dist/cli/slash/mcp/mcp.js.map +1 -0
  26. package/dist/cli/slash/session/load.js +69 -0
  27. package/dist/cli/slash/session/load.js.map +1 -0
  28. package/dist/cli/slash/session/resume.js +18 -0
  29. package/dist/cli/slash/session/resume.js.map +1 -0
  30. package/dist/cli/slash/session/save.js +12 -0
  31. package/dist/cli/slash/session/save.js.map +1 -0
  32. package/dist/cli/slash/session/sessions.js +15 -0
  33. package/dist/cli/slash/session/sessions.js.map +1 -0
  34. package/dist/cli/slash/system/agent.js +189 -0
  35. package/dist/cli/slash/system/agent.js.map +1 -0
  36. package/dist/cli/slash/system/delete.js +24 -0
  37. package/dist/cli/slash/system/delete.js.map +1 -0
  38. package/dist/cli/slash/system/help.js +25 -0
  39. package/dist/cli/slash/system/help.js.map +1 -0
  40. package/dist/cli/slash/system/stats.js +6 -0
  41. package/dist/cli/slash/system/stats.js.map +1 -0
  42. package/dist/cli/slash/system/undo.js +39 -0
  43. package/dist/cli/slash/system/undo.js.map +1 -0
  44. package/dist/cli/{stats.js → stats/index.js} +1 -1
  45. package/dist/cli/stats/index.js.map +1 -0
  46. package/dist/index.js +5 -4
  47. package/dist/index.js.map +1 -1
  48. package/package.json +1 -1
  49. package/dist/cli/args.js.map +0 -1
  50. package/dist/cli/history.js.map +0 -1
  51. package/dist/cli/input.js.map +0 -1
  52. package/dist/cli/repl.js.map +0 -1
  53. package/dist/cli/run.js.map +0 -1
  54. package/dist/cli/session.js.map +0 -1
  55. package/dist/cli/slash.js +0 -416
  56. package/dist/cli/slash.js.map +0 -1
  57. package/dist/cli/stats.js.map +0 -1
  58. /package/dist/cli/{history.js → repl/history.js} +0 -0
  59. /package/dist/cli/{input.js → repl/input.js} +0 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * 斜杠命令入口。
3
+ *
4
+ * REPL 里凡是以 `/` 开头的输入都交给这里处理,不会发给 AI。
5
+ * 具体命令实现拆到同目录下的子模块中。
6
+ */
7
+ import { listSessions } from '../session/index.js';
8
+ import { resetStats } from '../stats/index.js';
9
+ import { COMMANDS, printHelp } from './system/help.js';
10
+ export { COMMANDS, printHelp };
11
+ import { handleUndo } from './system/undo.js';
12
+ import { handleModel } from './config/model.js';
13
+ import { handleSave } from './session/save.js';
14
+ import { handleLoad } from './session/load.js';
15
+ import { handleSessions } from './session/sessions.js';
16
+ import { handleStats } from './system/stats.js';
17
+ import { handleDelete } from './system/delete.js';
18
+ import { handleAgent } from './system/agent.js';
19
+ import { handleResume } from './session/resume.js';
20
+ import { handleRole } from './config/role.js';
21
+ import { handleMcp, reloadMcpServers } from './mcp/mcp.js';
22
+ /**
23
+ * readline 的 Tab 补全函数。
24
+ * 对斜杠命令和 /load 的会话名提供补全提示。
25
+ */
26
+ export function slashCompleter(line) {
27
+ // /load <name> 的会话名补全:子串匹配,最近修改的排在前面
28
+ const loadPrefix = '/load ';
29
+ if (line.startsWith(loadPrefix)) {
30
+ const keyword = line.slice(loadPrefix.length).toLowerCase();
31
+ const sessions = listSessions()
32
+ .filter((s) => s.name.toLowerCase().includes(keyword))
33
+ .map((s) => `${loadPrefix}${s.name}`);
34
+ return [sessions, line];
35
+ }
36
+ // 其他斜杠命令补全
37
+ if (line.startsWith('/')) {
38
+ const hits = COMMANDS.filter(([cmd]) => cmd.startsWith(line))
39
+ .flatMap(([cmd]) => cmd
40
+ .split(' ')[0]
41
+ .split(',')
42
+ .map((c) => c.trim()))
43
+ .filter((c) => c.startsWith('/'));
44
+ return [hits, line];
45
+ }
46
+ return [[], line];
47
+ }
48
+ /**
49
+ * 处理一条斜杠命令。
50
+ * @returns true 表示已作为命令处理(不应再发给 AI)
51
+ */
52
+ export async function handleSlash(input, ctx) {
53
+ // 去掉开头的 '/',按空白拆成命令名 + 参数
54
+ const [name, ...rest] = input.slice(1).split(/\s+/);
55
+ const arg = rest.join(' ').trim();
56
+ switch (name) {
57
+ case 'help':
58
+ printHelp();
59
+ return true;
60
+ case 'clear':
61
+ // 保留第 0 条 system 提示,清掉其余历史
62
+ ctx.history.length = 1;
63
+ resetStats(ctx.stats);
64
+ console.log('(已清空对话历史和 token 统计)');
65
+ return true;
66
+ case 'undo':
67
+ handleUndo(arg, ctx);
68
+ return true;
69
+ case 'model':
70
+ await handleModel(arg, ctx);
71
+ return true;
72
+ case 'save':
73
+ handleSave(arg, ctx);
74
+ return true;
75
+ case 'load':
76
+ await handleLoad(arg, ctx);
77
+ return true;
78
+ case 'sessions':
79
+ handleSessions();
80
+ return true;
81
+ case 'delete':
82
+ await handleDelete(arg, ctx);
83
+ return true;
84
+ case 'agent':
85
+ await handleAgent(arg, ctx);
86
+ return true;
87
+ case 'stats':
88
+ handleStats(ctx);
89
+ return true;
90
+ case 'resume':
91
+ handleResume(ctx);
92
+ return true;
93
+ case 'reload':
94
+ await handleReload(ctx);
95
+ return true;
96
+ case 'mcp':
97
+ await handleMcp(arg, ctx);
98
+ return true;
99
+ case 'role':
100
+ handleRole(arg, ctx);
101
+ return true;
102
+ case 'exit':
103
+ case 'quit':
104
+ ctx.requestExit();
105
+ return true;
106
+ default:
107
+ console.log(`未知命令:/${name},输入 /help 查看可用命令。`);
108
+ return true;
109
+ }
110
+ }
111
+ /** /reload:重新加载配置文件并刷新 MCP server。 */
112
+ async function handleReload(ctx) {
113
+ const result = ctx.reloadConfig();
114
+ if (!result.ok) {
115
+ console.log(`配置重载失败:${result.message}`);
116
+ return;
117
+ }
118
+ console.log('配置已重新加载。');
119
+ if (ctx.mcpManager) {
120
+ await reloadMcpServers(ctx.mcpManager, result.config.mcpServers ?? {});
121
+ }
122
+ }
123
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/slash/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ import { McpClientManager } from '../../../agent/mcp.js';
2
+ import { saveMcpServers, } from '../../../config/config.js';
3
+ import { registerMcpTools, unregisterAllMcpTools, unregisterMcpServerTools, } from '../../../tools/index.js';
4
+ /** /mcp:管理 MCP server。 */
5
+ export async function handleMcp(arg, ctx) {
6
+ if (!ctx.mcpManager) {
7
+ console.log('当前没有可用的 MCP manager。');
8
+ return;
9
+ }
10
+ const parts = arg.trim().split(/\s+/);
11
+ const sub = parts[0]?.toLowerCase();
12
+ switch (sub) {
13
+ case 'list':
14
+ await mcpList(ctx);
15
+ return;
16
+ case 'add':
17
+ await mcpAdd(parts.slice(1), ctx);
18
+ return;
19
+ case 'remove':
20
+ await mcpRemove(parts.slice(1), ctx);
21
+ return;
22
+ case 'reload':
23
+ await mcpReload(ctx);
24
+ return;
25
+ default:
26
+ console.log('用法:/mcp list | add <name> <command> [args...] | remove <name> | reload');
27
+ }
28
+ }
29
+ async function mcpList(ctx) {
30
+ const servers = ctx.mcpManager.getServerNames();
31
+ if (servers.length === 0) {
32
+ console.log('没有已连接的 MCP server。');
33
+ return;
34
+ }
35
+ console.log('已连接的 MCP server:');
36
+ const tools = await ctx.mcpManager.listTools();
37
+ for (const name of servers) {
38
+ const serverTools = tools
39
+ .filter((t) => t.serverName === name)
40
+ .map((t) => t.originalName);
41
+ console.log(` ${name}`);
42
+ for (const t of serverTools) {
43
+ console.log(` - ${t}`);
44
+ }
45
+ }
46
+ }
47
+ async function mcpAdd(parts, ctx) {
48
+ if (parts.length < 2) {
49
+ console.log('用法:/mcp add <name> <command> [args...]');
50
+ return;
51
+ }
52
+ const [name, command, ...args] = parts;
53
+ const cfg = { command, args };
54
+ // 先临时连一下测试是否可用
55
+ const testManager = new McpClientManager({ [name]: cfg }, { name: 'ccli', version: '0.0.0' });
56
+ const testErrors = await testManager.connectAll();
57
+ if (testErrors.length > 0) {
58
+ console.log(`连接失败:${testErrors[0]}`);
59
+ await testManager.closeAll();
60
+ return;
61
+ }
62
+ // 把新 server 加到现有 manager
63
+ const currentConfig = ctx.mcpManager.getServersConfig();
64
+ const newConfig = { ...currentConfig, [name]: cfg };
65
+ // 持久化
66
+ const saved = saveMcpServers(ctx.cwd, newConfig);
67
+ if (!saved.ok) {
68
+ console.log(saved.message);
69
+ await testManager.closeAll();
70
+ return;
71
+ }
72
+ // 更新 manager 配置并注册 tools
73
+ Object.assign(currentConfig, { [name]: cfg });
74
+ unregisterMcpServerTools(name);
75
+ await registerMcpTools(testManager);
76
+ console.log(`已添加 MCP server:${name}(配置已保存到 ${saved.path})`);
77
+ }
78
+ async function mcpRemove(parts, ctx) {
79
+ const name = parts[0];
80
+ if (!name) {
81
+ console.log('用法:/mcp remove <name>');
82
+ return;
83
+ }
84
+ const removed = await ctx.mcpManager.removeServer(name);
85
+ if (!removed) {
86
+ console.log(`未找到 MCP server:${name}`);
87
+ return;
88
+ }
89
+ unregisterMcpServerTools(name);
90
+ const currentConfig = ctx.mcpManager.getServersConfig();
91
+ const newConfig = { ...currentConfig };
92
+ delete newConfig[name];
93
+ Object.assign(currentConfig, newConfig);
94
+ const saved = saveMcpServers(ctx.cwd, newConfig);
95
+ if (saved.ok) {
96
+ console.log(`已移除 MCP server:${name}(配置已保存到 ${saved.path})`);
97
+ }
98
+ else {
99
+ console.log(`已移除 MCP server:${name},但保存配置失败:${saved.message}`);
100
+ }
101
+ }
102
+ async function mcpReload(ctx) {
103
+ const result = ctx.reloadConfig();
104
+ if (!result.ok) {
105
+ console.log(`配置重载失败:${result.message}`);
106
+ return;
107
+ }
108
+ console.log('配置已重新加载。');
109
+ await reloadMcpServers(ctx.mcpManager, result.config.mcpServers ?? {});
110
+ }
111
+ /**
112
+ * 根据最新配置刷新 MCP server:
113
+ * 关闭现有连接,用新配置重新连接并注册 tools。
114
+ */
115
+ export async function reloadMcpServers(manager, mcpServers) {
116
+ await manager.closeAll();
117
+ unregisterAllMcpTools();
118
+ // 直接替换 manager 内部的 serversConfig 对象内容
119
+ const currentConfig = manager.getServersConfig();
120
+ for (const key of Object.keys(currentConfig)) {
121
+ delete currentConfig[key];
122
+ }
123
+ Object.assign(currentConfig, mcpServers);
124
+ const errors = await manager.connectAll();
125
+ if (errors.length > 0) {
126
+ console.error('部分 MCP server 连接失败:');
127
+ for (const e of errors)
128
+ console.error(` ${e}`);
129
+ }
130
+ await registerMcpTools(manager);
131
+ console.log('MCP server 已重新加载。');
132
+ }
133
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../../src/cli/slash/mcp/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { listSessions, loadSession, searchSessions, } from '../../session/index.js';
2
+ /** /load:精确匹配时直接加载;否则按关键词列出候选并支持交互式选择。 */
3
+ export async function handleLoad(arg, ctx) {
4
+ if (!arg) {
5
+ console.log('用法:/load <会话名>');
6
+ return;
7
+ }
8
+ // 精确匹配 → 直接加载
9
+ const exact = listSessions().find((s) => s.name === arg);
10
+ if (exact) {
11
+ const result = loadSession(arg);
12
+ if (result.ok) {
13
+ ctx.history.length = 0;
14
+ ctx.history.push(...result.history);
15
+ console.log(`已加载会话:${result.name}(${result.history.length} 条消息)`);
16
+ }
17
+ else {
18
+ console.log(result.message);
19
+ }
20
+ return;
21
+ }
22
+ // 否则按关键词搜索
23
+ const matches = searchSessions(arg);
24
+ if (matches.length === 0) {
25
+ console.log(`找不到包含 "${arg}" 的会话。`);
26
+ return;
27
+ }
28
+ // 只有一个候选 → 直接加载,不用输全名
29
+ if (matches.length === 1) {
30
+ const name = matches[0].name;
31
+ const result = loadSession(name);
32
+ if (result.ok) {
33
+ ctx.history.length = 0;
34
+ ctx.history.push(...result.history);
35
+ console.log(`已加载会话:${result.name}(${result.history.length} 条消息)`);
36
+ }
37
+ else {
38
+ console.log(result.message);
39
+ }
40
+ return;
41
+ }
42
+ // 多个候选 → 列出让用户选
43
+ console.log(`未精确匹配 "${arg}",以下 ${matches.length} 个可选:`);
44
+ for (let i = 0; i < matches.length; i++) {
45
+ const s = matches[i];
46
+ console.log(` ${i + 1}. ${s.name}`);
47
+ }
48
+ const answer = (await ctx.ask('选择序号加载(直接回车取消):')).trim();
49
+ if (answer === '') {
50
+ console.log('已取消。');
51
+ return;
52
+ }
53
+ const idx = Number.parseInt(answer, 10);
54
+ if (Number.isNaN(idx) || idx <= 0 || idx > matches.length) {
55
+ console.log('无效选择。');
56
+ return;
57
+ }
58
+ const name = matches[idx - 1].name;
59
+ const result = loadSession(name);
60
+ if (result.ok) {
61
+ ctx.history.length = 0;
62
+ ctx.history.push(...result.history);
63
+ console.log(`已加载会话:${result.name}(${result.history.length} 条消息)`);
64
+ }
65
+ else {
66
+ console.log(result.message);
67
+ }
68
+ }
69
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../../../src/cli/slash/session/load.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { hasLastSession, loadLastSession } from '../../session/index.js';
2
+ /** /resume:手动恢复上次自动保存的会话。 */
3
+ export function handleResume(ctx) {
4
+ if (!hasLastSession()) {
5
+ console.log('没有可恢复的 last 会话。');
6
+ return;
7
+ }
8
+ const loaded = loadLastSession();
9
+ if (loaded.ok) {
10
+ ctx.history.length = 0;
11
+ ctx.history.push(...loaded.history);
12
+ console.log(`已恢复上次会话(${loaded.history.length} 条消息)。`);
13
+ }
14
+ else {
15
+ console.log(`恢复失败:${loaded.message}`);
16
+ }
17
+ }
18
+ //# sourceMappingURL=resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../../src/cli/slash/session/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzE,6BAA6B;AAC7B,MAAM,UAAU,YAAY,CAAC,GAAiB;IAC1C,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC/B,OAAO;IACX,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACZ,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACvB,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,MAAM,QAAQ,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1C,CAAC;AACL,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { saveSession } from '../../session/index.js';
2
+ /** /save:把当前历史落盘。 */
3
+ export function handleSave(arg, ctx) {
4
+ const result = saveSession(ctx.history, arg);
5
+ if (result.ok) {
6
+ console.log(`已保存会话:${result.name}`);
7
+ }
8
+ else {
9
+ console.log(result.message);
10
+ }
11
+ }
12
+ //# sourceMappingURL=save.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save.js","sourceRoot":"","sources":["../../../../src/cli/slash/session/save.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGrD,qBAAqB;AACrB,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,GAAiB;IACrD,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;AACL,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { listSessions } from '../../session/index.js';
2
+ /** /sessions:列出所有保存的会话。 */
3
+ export function handleSessions() {
4
+ const sessions = listSessions();
5
+ if (sessions.length === 0) {
6
+ console.log('没有已保存的会话。');
7
+ return;
8
+ }
9
+ console.log('已保存的会话:');
10
+ for (const s of sessions) {
11
+ const time = s.updatedAt.toLocaleString();
12
+ console.log(` ${s.name.padEnd(30)} ${s.messageCount} 条 ${time}`);
13
+ }
14
+ }
15
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../../src/cli/slash/session/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,2BAA2B;AAC3B,MAAM,UAAU,cAAc;IAC1B,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACzB,OAAO;IACX,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,YAAY,OAAO,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;AACL,CAAC"}
@@ -0,0 +1,189 @@
1
+ import { runAgentTurn } from '../../run/index.js';
2
+ import { getTool } from '../../../tools/index.js';
3
+ /** 规划阶段的系统提示:只输出计划,不调用工具。 */
4
+ const PLANNING_SYSTEM_PROMPT = `你是 CCLI 的 Agent 规划助手。
5
+
6
+ 用户的任务会由另一个 Agent 来执行。你的工作是先制定一个清晰、可执行的计划。
7
+
8
+ 可用工具包括:
9
+ - read_file:读取文件内容
10
+ - list_dir:列出目录内容
11
+ - grep:在文件中搜索文本
12
+ - write_file:创建或覆盖文件
13
+ - edit_file:编辑文件的特定部分
14
+ - bash:执行 shell 命令
15
+
16
+ 要求:
17
+ 1. 只输出计划,不要调用任何工具。
18
+ 2. 计划用编号列表,每一步说明要做什么、准备调用哪个工具。
19
+ 3. 计划要简洁,不要包含大段代码或文件内容。
20
+ 4. 如果任务明显无法完成,直接说明原因。`;
21
+ /** 执行阶段的系统提示:让模型按计划调用工具并完成任务。 */
22
+ const EXECUTION_SYSTEM_PROMPT = `你是 CCLI 的 Agent 执行助手。
23
+
24
+ 你的工作方式是:
25
+ 1. 调用可用工具收集信息或执行操作。
26
+ 2. 根据工具返回结果继续下一步。
27
+ 3. 任务完成后,给出清晰简洁的最终总结。
28
+
29
+ 注意:
30
+ - 对于写文件、编辑文件、执行 shell 等破坏性操作,系统会先向用户确认。
31
+ - 保持回复简洁,重点放在行动和结果上。
32
+ - 如果某一步失败,尝试用其他方式完成,或说明无法完成的原因。`;
33
+ /** 从计划文本中解析编号步骤。 */
34
+ export function parsePlanSteps(plan) {
35
+ return plan
36
+ .split('\n')
37
+ .map((line) => line.trim())
38
+ .filter((line) => /^\d+[.、.\)\]]\s*/.test(line))
39
+ .map((line) => line.replace(/^\d+[.、.\)\]]\s*/, '').trim());
40
+ }
41
+ /** 计划进度跟踪器:负责打印带状态标记的计划。 */
42
+ export class PlanTracker {
43
+ steps;
44
+ completed = 0;
45
+ constructor(plan) {
46
+ this.steps = parsePlanSteps(plan);
47
+ }
48
+ hasSteps() {
49
+ return this.steps.length > 0;
50
+ }
51
+ total() {
52
+ return this.steps.length;
53
+ }
54
+ /** 打印当前步骤(执行中)。 */
55
+ printCurrent() {
56
+ const idx = Math.min(this.completed, this.steps.length - 1);
57
+ const text = this.steps[idx] ?? '继续执行';
58
+ console.log(`\n[→] 步骤 ${idx + 1}/${this.steps.length}:${text}`);
59
+ }
60
+ /** 打印刚完成的步骤。 */
61
+ printDone() {
62
+ const idx = this.completed;
63
+ if (idx >= 0 && idx < this.steps.length) {
64
+ console.log(`[✓] 步骤 ${idx + 1}/${this.steps.length} 完成`);
65
+ }
66
+ }
67
+ /** 打印完整计划状态。 */
68
+ printState() {
69
+ if (this.steps.length === 0)
70
+ return;
71
+ console.log('[Agent] 当前计划状态:');
72
+ for (let i = 0; i < this.steps.length; i++) {
73
+ let marker;
74
+ if (i < this.completed) {
75
+ marker = '[✓]';
76
+ }
77
+ else if (i === this.completed) {
78
+ marker = '[→]';
79
+ }
80
+ else {
81
+ marker = '[ ]';
82
+ }
83
+ console.log(`${marker} ${i + 1}. ${this.steps[i]}`);
84
+ }
85
+ }
86
+ /** 标记当前步骤已完成。 */
87
+ advance() {
88
+ if (this.completed < this.steps.length) {
89
+ this.completed++;
90
+ }
91
+ }
92
+ }
93
+ /** 截断过长的工具结果,便于在终端阅读。 */
94
+ function truncateResult(result, max = 300) {
95
+ if (result.length <= max)
96
+ return result;
97
+ return result.slice(0, max) + '\n...(结果已截断)';
98
+ }
99
+ /** 把工具调用格式化成易读的摘要。 */
100
+ function formatToolCall(tc) {
101
+ const tool = getTool(tc.name);
102
+ if (tool?.preview) {
103
+ try {
104
+ return tool.preview(JSON.parse(tc.arguments || '{}'));
105
+ }
106
+ catch {
107
+ // 预览解析失败时降级为原始参数
108
+ }
109
+ }
110
+ return `${tc.name}(${tc.arguments})`;
111
+ }
112
+ /** 向 AI 请求制定计划,返回计划文本。 */
113
+ async function buildPlan(task, ctx) {
114
+ const planningHistory = [
115
+ { role: 'system', content: PLANNING_SYSTEM_PROMPT },
116
+ { role: 'user', content: task },
117
+ ];
118
+ let plan = '';
119
+ const turn = await ctx.ai.chat(planningHistory, (delta) => {
120
+ plan += delta;
121
+ process.stdout.write(delta);
122
+ }, { disableTools: true });
123
+ plan = turn.content || plan;
124
+ return plan.trim();
125
+ }
126
+ /** 使用 ask 包装确认函数。 */
127
+ function makeConfirm(ctx) {
128
+ return async (preview) => {
129
+ console.log('\n' + preview);
130
+ const answer = (await ctx.ask('确认执行?(y/N) ')).trim().toLowerCase();
131
+ return answer === 'y' || answer === 'yes';
132
+ };
133
+ }
134
+ /** /agent:先制定计划,确认后自动执行。 */
135
+ export async function handleAgent(arg, ctx) {
136
+ const task = arg.trim();
137
+ if (task.length === 0) {
138
+ console.log('用法:/agent <任务描述>');
139
+ return;
140
+ }
141
+ console.log(`[Agent] 开始为任务制定计划:${task}\n`);
142
+ const plan = await buildPlan(task, ctx);
143
+ if (!plan) {
144
+ console.log('\n[Agent] 未能生成计划。');
145
+ return;
146
+ }
147
+ console.log('\n\n[Agent] 计划如下:');
148
+ console.log(plan);
149
+ const answer = (await ctx.ask('\n是否按此计划执行?(y/N) '))
150
+ .trim()
151
+ .toLowerCase();
152
+ if (answer !== 'y' && answer !== 'yes') {
153
+ console.log('[Agent] 已取消执行。');
154
+ return;
155
+ }
156
+ console.log('\n[Agent] 开始执行计划...');
157
+ const tracker = new PlanTracker(plan);
158
+ if (tracker.hasSteps()) {
159
+ tracker.printState();
160
+ }
161
+ // 切换为执行系统提示,并注入已批准的计划
162
+ ctx.history[0].content = `${EXECUTION_SYSTEM_PROMPT}\n\n已批准的计划:\n${plan}`;
163
+ ctx.history.push({ role: 'user', content: task });
164
+ await runAgentTurn({
165
+ ai: ctx.ai,
166
+ history: ctx.history,
167
+ confirm: makeConfirm(ctx),
168
+ stats: ctx.stats,
169
+ maxRounds: 30,
170
+ requireToolsFirstRound: true,
171
+ onToolCall: (tc) => {
172
+ if (tracker.hasSteps()) {
173
+ tracker.printCurrent();
174
+ }
175
+ console.log(`\n[Agent] 调用 ${tc.name}`);
176
+ console.log(formatToolCall(tc));
177
+ },
178
+ onToolResult: (tc, result) => {
179
+ console.log(`\n[Agent] ${tc.name} 结果:`);
180
+ console.log(truncateResult(result));
181
+ if (tracker.hasSteps()) {
182
+ tracker.advance();
183
+ tracker.printState();
184
+ }
185
+ },
186
+ });
187
+ console.log('\n[Agent] 任务执行结束');
188
+ }
189
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../../src/cli/slash/system/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { deleteSession } from '../../session/index.js';
2
+ /** /delete:删除指定已保存会话,执行前需要用户确认。 */
3
+ export async function handleDelete(arg, ctx) {
4
+ const name = arg.trim();
5
+ if (name.length === 0) {
6
+ console.log('用法:/delete <会话名>');
7
+ return;
8
+ }
9
+ const answer = (await ctx.ask(`确认删除会话 "${name}"?(y/N) `))
10
+ .trim()
11
+ .toLowerCase();
12
+ if (answer !== 'y' && answer !== 'yes') {
13
+ console.log('已取消。');
14
+ return;
15
+ }
16
+ const result = deleteSession(name);
17
+ if (result.ok) {
18
+ console.log(`已删除会话:${result.name}`);
19
+ }
20
+ else {
21
+ console.log(result.message);
22
+ }
23
+ }
24
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../../src/cli/slash/system/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,mCAAmC;AACnC,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,GAAW,EACX,GAAiB;IAEjB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,OAAO;IACX,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,UAAU,CAAC,CAAC;SACpD,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IACnB,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,OAAO;IACX,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;AACL,CAAC"}