@gird/ccli 2.7.0 → 2.9.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.
- package/README.md +5 -0
- package/dist/cli/confirm-select.js +115 -0
- package/dist/cli/confirm-select.js.map +1 -0
- package/dist/cli/repl/index.js +51 -20
- package/dist/cli/repl/index.js.map +1 -1
- package/dist/cli/run/index.js +3 -2
- package/dist/cli/run/index.js.map +1 -1
- package/dist/cli/slash/index.js +13 -4
- package/dist/cli/slash/index.js.map +1 -1
- package/dist/cli/slash/mcp/mcp.js +20 -19
- package/dist/cli/slash/mcp/mcp.js.map +1 -1
- package/dist/cli/slash/system/agent.js +20 -19
- package/dist/cli/slash/system/agent.js.map +1 -1
- package/dist/cli/slash/system/compact.js +140 -0
- package/dist/cli/slash/system/compact.js.map +1 -0
- package/dist/cli/slash/system/goal.js +160 -0
- package/dist/cli/slash/system/goal.js.map +1 -0
- package/dist/cli/slash/system/help.js +2 -0
- package/dist/cli/slash/system/help.js.map +1 -1
- package/dist/cli/style.js +53 -0
- package/dist/cli/style.js.map +1 -0
- package/dist/config/memory.js +45 -0
- package/dist/config/memory.js.map +1 -0
- package/dist/index.js +10 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { runAgentTurn } from '../../run/index.js';
|
|
2
|
+
import { style } from '../../style.js';
|
|
2
3
|
import { getTool } from '../../../tools/index.js';
|
|
3
4
|
/** 规划阶段的系统提示:只输出计划,不调用工具。 */
|
|
4
5
|
const PLANNING_SYSTEM_PROMPT = `你是 CCLI 的 Agent 规划助手。
|
|
@@ -19,7 +20,7 @@ const PLANNING_SYSTEM_PROMPT = `你是 CCLI 的 Agent 规划助手。
|
|
|
19
20
|
3. 计划要简洁,不要包含大段代码或文件内容。
|
|
20
21
|
4. 如果任务明显无法完成,直接说明原因。`;
|
|
21
22
|
/** 执行阶段的系统提示:让模型按计划调用工具并完成任务。 */
|
|
22
|
-
const EXECUTION_SYSTEM_PROMPT = `你是 CCLI 的 Agent 执行助手。
|
|
23
|
+
export const EXECUTION_SYSTEM_PROMPT = `你是 CCLI 的 Agent 执行助手。
|
|
23
24
|
|
|
24
25
|
你的工作方式是:
|
|
25
26
|
1. 调用可用工具收集信息或执行操作。
|
|
@@ -55,30 +56,30 @@ export class PlanTracker {
|
|
|
55
56
|
printCurrent() {
|
|
56
57
|
const idx = Math.min(this.completed, this.steps.length - 1);
|
|
57
58
|
const text = this.steps[idx] ?? '继续执行';
|
|
58
|
-
console.log(`\n[→] 步骤 ${idx + 1}/${this.steps.length}:${text}`);
|
|
59
|
+
console.log(style.step(`\n[→] 步骤 ${idx + 1}/${this.steps.length}:${text}`));
|
|
59
60
|
}
|
|
60
61
|
/** 打印刚完成的步骤。 */
|
|
61
62
|
printDone() {
|
|
62
63
|
const idx = this.completed;
|
|
63
64
|
if (idx >= 0 && idx < this.steps.length) {
|
|
64
|
-
console.log(`[✓] 步骤 ${idx + 1}/${this.steps.length} 完成`);
|
|
65
|
+
console.log(style.done(`[✓] 步骤 ${idx + 1}/${this.steps.length} 完成`));
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
/** 打印完整计划状态。 */
|
|
68
69
|
printState() {
|
|
69
70
|
if (this.steps.length === 0)
|
|
70
71
|
return;
|
|
71
|
-
console.log('[Agent] 当前计划状态:');
|
|
72
|
+
console.log(style.label('[Agent] 当前计划状态:'));
|
|
72
73
|
for (let i = 0; i < this.steps.length; i++) {
|
|
73
74
|
let marker;
|
|
74
75
|
if (i < this.completed) {
|
|
75
|
-
marker = '[✓]';
|
|
76
|
+
marker = style.done('[✓]');
|
|
76
77
|
}
|
|
77
78
|
else if (i === this.completed) {
|
|
78
|
-
marker = '[→]';
|
|
79
|
+
marker = style.step('[→]');
|
|
79
80
|
}
|
|
80
81
|
else {
|
|
81
|
-
marker = '[ ]';
|
|
82
|
+
marker = style.muted('[ ]');
|
|
82
83
|
}
|
|
83
84
|
console.log(`${marker} ${i + 1}. ${this.steps[i]}`);
|
|
84
85
|
}
|
|
@@ -110,9 +111,9 @@ function formatToolCall(tc) {
|
|
|
110
111
|
return `${tc.name}(${tc.arguments})`;
|
|
111
112
|
}
|
|
112
113
|
/** 向 AI 请求制定计划,返回计划文本。 */
|
|
113
|
-
async function buildPlan(task, ctx) {
|
|
114
|
+
export async function buildPlan(task, ctx, systemPrompt = PLANNING_SYSTEM_PROMPT) {
|
|
114
115
|
const planningHistory = [
|
|
115
|
-
{ role: 'system', content:
|
|
116
|
+
{ role: 'system', content: systemPrompt },
|
|
116
117
|
{ role: 'user', content: task },
|
|
117
118
|
];
|
|
118
119
|
let plan = '';
|
|
@@ -124,7 +125,7 @@ async function buildPlan(task, ctx) {
|
|
|
124
125
|
return plan.trim();
|
|
125
126
|
}
|
|
126
127
|
/** 使用 ask 包装确认函数。 */
|
|
127
|
-
function makeConfirm(ctx) {
|
|
128
|
+
export function makeConfirm(ctx) {
|
|
128
129
|
return async (preview) => {
|
|
129
130
|
console.log('\n' + preview);
|
|
130
131
|
const answer = (await ctx.ask('确认执行?(y/N) ')).trim().toLowerCase();
|
|
@@ -135,25 +136,25 @@ function makeConfirm(ctx) {
|
|
|
135
136
|
export async function handleAgent(arg, ctx) {
|
|
136
137
|
const task = arg.trim();
|
|
137
138
|
if (task.length === 0) {
|
|
138
|
-
console.log('用法:/agent <任务描述>');
|
|
139
|
+
console.log(style.muted('用法:/agent <任务描述>'));
|
|
139
140
|
return;
|
|
140
141
|
}
|
|
141
|
-
console.log(`[Agent] 开始为任务制定计划:${task}\n`);
|
|
142
|
+
console.log(style.label(`[Agent] 开始为任务制定计划:${task}\n`));
|
|
142
143
|
const plan = await buildPlan(task, ctx);
|
|
143
144
|
if (!plan) {
|
|
144
|
-
console.log('\n[Agent] 未能生成计划。');
|
|
145
|
+
console.log(style.warn('\n[Agent] 未能生成计划。'));
|
|
145
146
|
return;
|
|
146
147
|
}
|
|
147
|
-
console.log('\n\n[Agent] 计划如下:');
|
|
148
|
+
console.log(style.label('\n\n[Agent] 计划如下:'));
|
|
148
149
|
console.log(plan);
|
|
149
150
|
const answer = (await ctx.ask('\n是否按此计划执行?(y/N) '))
|
|
150
151
|
.trim()
|
|
151
152
|
.toLowerCase();
|
|
152
153
|
if (answer !== 'y' && answer !== 'yes') {
|
|
153
|
-
console.log('[Agent] 已取消执行。');
|
|
154
|
+
console.log(style.warn('[Agent] 已取消执行。'));
|
|
154
155
|
return;
|
|
155
156
|
}
|
|
156
|
-
console.log('\n[Agent] 开始执行计划...');
|
|
157
|
+
console.log(style.label('\n[Agent] 开始执行计划...'));
|
|
157
158
|
const tracker = new PlanTracker(plan);
|
|
158
159
|
if (tracker.hasSteps()) {
|
|
159
160
|
tracker.printState();
|
|
@@ -172,11 +173,11 @@ export async function handleAgent(arg, ctx) {
|
|
|
172
173
|
if (tracker.hasSteps()) {
|
|
173
174
|
tracker.printCurrent();
|
|
174
175
|
}
|
|
175
|
-
console.log(`\n[Agent] 调用 ${tc.name}`);
|
|
176
|
+
console.log(style.tool(`\n[Agent] 调用 ${tc.name}`));
|
|
176
177
|
console.log(formatToolCall(tc));
|
|
177
178
|
},
|
|
178
179
|
onToolResult: (tc, result) => {
|
|
179
|
-
console.log(`\n[Agent] ${tc.name} 结果:`);
|
|
180
|
+
console.log(style.muted(`\n[Agent] ${tc.name} 结果:`));
|
|
180
181
|
console.log(truncateResult(result));
|
|
181
182
|
if (tracker.hasSteps()) {
|
|
182
183
|
tracker.advance();
|
|
@@ -184,6 +185,6 @@ export async function handleAgent(arg, ctx) {
|
|
|
184
185
|
}
|
|
185
186
|
},
|
|
186
187
|
});
|
|
187
|
-
console.log('\n[Agent] 任务执行结束');
|
|
188
|
+
console.log(style.success('\n[Agent] 任务执行结束'));
|
|
188
189
|
}
|
|
189
190
|
//# sourceMappingURL=agent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../../src/cli/slash/system/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../../src/cli/slash/system/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { estimatePromptTokens, resetStats, getContextLimit, } from '../../stats/index.js';
|
|
2
|
+
import { style } from '../../style.js';
|
|
3
|
+
/** 上下文占比低于此值时,压缩通常没必要,先向用户确认。 */
|
|
4
|
+
const COMPACT_MIN_RATIO = 0.5;
|
|
5
|
+
/** 上下文占比达到此值时,下一轮对话前自动压缩。 */
|
|
6
|
+
const AUTO_COMPACT_RATIO = 0.8;
|
|
7
|
+
/** 摘要请求用的系统提示:要求客观、信息完整、便于据此继续对话。 */
|
|
8
|
+
const SUMMARY_SYSTEM = '你是一个对话摘要助手。请把给定的对话历史压缩成一段简洁但信息完整的摘要,' +
|
|
9
|
+
'用中文、以第三人称客观记录。务必保留:用户的目标与关键决策、已确认的事实、' +
|
|
10
|
+
'涉及的文件/代码/命令、尚未完成的事项、以及任何后续需要的上下文。' +
|
|
11
|
+
'不要遗漏关键信息,也不要编造。只输出摘要本身,不要额外寒暄。';
|
|
12
|
+
/** 把任意消息内容转成纯文本。 */
|
|
13
|
+
function textOf(content) {
|
|
14
|
+
return typeof content === 'string'
|
|
15
|
+
? content
|
|
16
|
+
: JSON.stringify(content ?? '');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 把对话历史(跳过第 0 条 system 提示)序列化成一段可读文本,喂给摘要模型。
|
|
20
|
+
* 导出以便单元测试。
|
|
21
|
+
*/
|
|
22
|
+
export function serializeHistory(history) {
|
|
23
|
+
return history
|
|
24
|
+
.slice(1)
|
|
25
|
+
.map((m) => {
|
|
26
|
+
if (m.role === 'tool') {
|
|
27
|
+
return `[工具结果] ${textOf(m.content)}`;
|
|
28
|
+
}
|
|
29
|
+
const toolCalls = m
|
|
30
|
+
.tool_calls;
|
|
31
|
+
let line = `${m.role}: ${textOf(m.content)}`;
|
|
32
|
+
if (toolCalls?.length) {
|
|
33
|
+
const names = toolCalls.map((t) => t.function.name).join(', ');
|
|
34
|
+
line += ` [调用工具: ${names}]`;
|
|
35
|
+
}
|
|
36
|
+
return line;
|
|
37
|
+
})
|
|
38
|
+
.join('\n');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 压缩核心:把历史压成摘要并原地替换(仅在有收益时)。
|
|
42
|
+
* 不含占比阈值确认、不打印结果——那些由调用方(手动/自动)决定。
|
|
43
|
+
* 被 handleCompact(/compact)与 autoCompactIfNeeded(自动)共用。
|
|
44
|
+
*/
|
|
45
|
+
async function compactHistory(ai, history, stats) {
|
|
46
|
+
if (history.length <= 1)
|
|
47
|
+
return { status: 'empty' };
|
|
48
|
+
const before = estimatePromptTokens(history);
|
|
49
|
+
const convo = serializeHistory(history);
|
|
50
|
+
const summaryMessages = [
|
|
51
|
+
{ role: 'system', content: SUMMARY_SYSTEM },
|
|
52
|
+
{ role: 'user', content: `请压缩以下对话历史:\n\n${convo}` },
|
|
53
|
+
];
|
|
54
|
+
console.log(style.info('正在压缩上下文…\n'));
|
|
55
|
+
let summary;
|
|
56
|
+
try {
|
|
57
|
+
// 压缩时禁用工具,只要文本摘要
|
|
58
|
+
const turn = await ai.chat(summaryMessages, (d) => process.stdout.write(d), { disableTools: true });
|
|
59
|
+
summary = turn.content.trim();
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
return { status: 'failed', message: e?.message ?? String(e) };
|
|
63
|
+
}
|
|
64
|
+
if (!summary) {
|
|
65
|
+
return { status: 'failed', message: '模型未返回摘要' };
|
|
66
|
+
}
|
|
67
|
+
const system = history[0];
|
|
68
|
+
const summaryMessage = {
|
|
69
|
+
role: 'user',
|
|
70
|
+
content: `[以下是此前对话的摘要,请据此继续]\n${summary}`,
|
|
71
|
+
};
|
|
72
|
+
const after = estimatePromptTokens([system, summaryMessage]);
|
|
73
|
+
// 压缩后没有更小(历史本就很短)→ 不替换,避免反而增大上下文
|
|
74
|
+
if (after >= before)
|
|
75
|
+
return { status: 'no-benefit', before };
|
|
76
|
+
history.length = 0;
|
|
77
|
+
history.push(system, summaryMessage);
|
|
78
|
+
resetStats(stats);
|
|
79
|
+
return { status: 'ok', before, after };
|
|
80
|
+
}
|
|
81
|
+
/** 打印压缩结果(成功时报告节省比例)。 */
|
|
82
|
+
function printCompactResult(result) {
|
|
83
|
+
switch (result.status) {
|
|
84
|
+
case 'ok': {
|
|
85
|
+
const saved = Math.round((1 - result.after / result.before) * 100);
|
|
86
|
+
console.log(style.success(`\n\n已压缩上下文:约 ${result.before.toLocaleString()} → ${result.after.toLocaleString()} tokens(节省 ${saved}%)。`));
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case 'no-benefit':
|
|
90
|
+
console.log(style.muted('\n\n当前历史已足够精简,压缩不会减少上下文(历史未改动)。'));
|
|
91
|
+
break;
|
|
92
|
+
case 'failed':
|
|
93
|
+
console.log(style.error(`\n压缩失败:${result.message}(历史未改动)`));
|
|
94
|
+
break;
|
|
95
|
+
case 'empty':
|
|
96
|
+
console.log(style.muted('没有可压缩的对话历史。'));
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* /compact:手动压缩当前对话历史。
|
|
102
|
+
* 占比很低时先确认(压了会白白损失细节),确认后走压缩核心。
|
|
103
|
+
*/
|
|
104
|
+
export async function handleCompact(ctx) {
|
|
105
|
+
if (ctx.history.length <= 1) {
|
|
106
|
+
console.log(style.muted('没有可压缩的对话历史。'));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// 上下文占比很低时,压缩通常没必要且会损失细节 —— 先向用户确认
|
|
110
|
+
const before = estimatePromptTokens(ctx.history);
|
|
111
|
+
const limit = getContextLimit(ctx.ai.getModel());
|
|
112
|
+
const ratio = limit > 0 ? before / limit : 0;
|
|
113
|
+
if (ratio < COMPACT_MIN_RATIO) {
|
|
114
|
+
const pct = (ratio * 100).toFixed(1);
|
|
115
|
+
console.log(style.warn(`当前上下文仅占 ${pct}%(约 ${before.toLocaleString()} / ${limit.toLocaleString()} tokens),` +
|
|
116
|
+
`压缩通常在接近上限时才有必要,且会损失细节。`));
|
|
117
|
+
const ok = await ctx.confirm('仍要压缩?');
|
|
118
|
+
if (!ok) {
|
|
119
|
+
console.log(style.muted('已取消。'));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
printCompactResult(await compactHistory(ctx.ai, ctx.history, ctx.stats));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* 自动压缩:每轮对话后调用。上下文占比达到 AUTO_COMPACT_RATIO 就自动压缩,
|
|
127
|
+
* 只提示、不弹确认(保护性操作;要手动控制用 /compact)。
|
|
128
|
+
*/
|
|
129
|
+
export async function autoCompactIfNeeded(ai, history, stats) {
|
|
130
|
+
if (history.length <= 1)
|
|
131
|
+
return;
|
|
132
|
+
const tokens = estimatePromptTokens(history);
|
|
133
|
+
const limit = getContextLimit(ai.getModel());
|
|
134
|
+
const ratio = limit > 0 ? tokens / limit : 0;
|
|
135
|
+
if (ratio < AUTO_COMPACT_RATIO)
|
|
136
|
+
return;
|
|
137
|
+
console.log(style.warn(`\n⚠ 上下文已达 ${(ratio * 100).toFixed(0)}%(约 ${tokens.toLocaleString()} / ${limit.toLocaleString()} tokens),正在自动压缩…`));
|
|
138
|
+
printCompactResult(await compactHistory(ai, history, stats));
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=compact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compact.js","sourceRoot":"","sources":["../../../../src/cli/slash/system/compact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { runAgentTurn } from '../../run/index.js';
|
|
2
|
+
import { style } from '../../style.js';
|
|
3
|
+
import { getTool } from '../../../tools/index.js';
|
|
4
|
+
import { buildPlan, EXECUTION_SYSTEM_PROMPT, makeConfirm, PlanTracker, } from './agent.js';
|
|
5
|
+
/** 目标未给完成条件时,让规划阶段先补一条可检查条件。 */
|
|
6
|
+
const GOAL_PLANNING_SYSTEM_PROMPT = `你是 CCLI 的 Goal 规划助手。
|
|
7
|
+
|
|
8
|
+
用户会给出一个目标,但不会明确写出完成条件。你需要:
|
|
9
|
+
1. 先补一条明确、可检查的完成条件,写在一行里,格式必须是:完成条件:<内容>。
|
|
10
|
+
2. 再输出编号计划,每一步说明要做什么、准备调用哪个工具。
|
|
11
|
+
3. 只输出完成条件和计划,不要调用任何工具。
|
|
12
|
+
4. 完成条件要可验证,例如“某个文件存在且包含某内容”“某条命令测试通过”。`;
|
|
13
|
+
/** 解析 /goal 参数,格式:`<任务> [| <完成条件>]`。 */
|
|
14
|
+
export function parseGoalArg(arg) {
|
|
15
|
+
const idx = arg.indexOf('|');
|
|
16
|
+
if (idx < 0) {
|
|
17
|
+
const task = arg.trim();
|
|
18
|
+
return task ? { task, done: null } : null;
|
|
19
|
+
}
|
|
20
|
+
const task = arg.slice(0, idx).trim();
|
|
21
|
+
const done = arg.slice(idx + 1).trim();
|
|
22
|
+
if (!task)
|
|
23
|
+
return null;
|
|
24
|
+
return { task, done: done || null };
|
|
25
|
+
}
|
|
26
|
+
/** 从 Goal 规划结果中拆出完成条件和编号计划。 */
|
|
27
|
+
export function parseGoalPlan(plan) {
|
|
28
|
+
const lines = plan.split('\n');
|
|
29
|
+
const rest = [];
|
|
30
|
+
let done = '';
|
|
31
|
+
for (const line of lines) {
|
|
32
|
+
const trimmed = line.trim();
|
|
33
|
+
if (!done && /^完成条件[::]\s*/.test(trimmed)) {
|
|
34
|
+
done = trimmed.replace(/^完成条件[::]\s*/, '').trim();
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
rest.push(line);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
done: done || '完成用户目标,并给出清晰的结果总结。',
|
|
41
|
+
plan: rest.join('\n').trim() || plan.trim(),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** 截断过长的工具结果,便于在终端阅读。 */
|
|
45
|
+
function truncateResult(result, max = 300) {
|
|
46
|
+
if (result.length <= max)
|
|
47
|
+
return result;
|
|
48
|
+
return result.slice(0, max) + '\n...(结果已截断)';
|
|
49
|
+
}
|
|
50
|
+
/** 把工具调用格式化成易读的摘要。 */
|
|
51
|
+
function formatToolCall(tc) {
|
|
52
|
+
const tool = getTool(tc.name);
|
|
53
|
+
if (tool?.preview) {
|
|
54
|
+
try {
|
|
55
|
+
return tool.preview(JSON.parse(tc.arguments || '{}'));
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// 预览解析失败时降级为原始参数
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return `${tc.name}(${tc.arguments})`;
|
|
62
|
+
}
|
|
63
|
+
function buildGoalUserContent(task, done) {
|
|
64
|
+
return `${task}\n\n完成条件:${done}`;
|
|
65
|
+
}
|
|
66
|
+
/** 执行结束后,根据完成条件做一次达成判定。 */
|
|
67
|
+
async function evaluateGoal(task, done, ctx) {
|
|
68
|
+
const prompt = `请基于上面的执行过程与结果,判定目标是否达成。
|
|
69
|
+
|
|
70
|
+
目标:${task}
|
|
71
|
+
完成条件:${done}
|
|
72
|
+
|
|
73
|
+
只输出两行:
|
|
74
|
+
第一行写“达成”或“未达成”;
|
|
75
|
+
第二行写原因和下一步建议。`;
|
|
76
|
+
const evalHistory = [
|
|
77
|
+
...ctx.history,
|
|
78
|
+
{ role: 'user', content: prompt },
|
|
79
|
+
];
|
|
80
|
+
console.log(style.label('\n[Goal] 正在判定完成条件...'));
|
|
81
|
+
let verdict = '';
|
|
82
|
+
const turn = await ctx.ai.chat(evalHistory, (delta) => {
|
|
83
|
+
verdict += delta;
|
|
84
|
+
process.stdout.write(delta);
|
|
85
|
+
}, { disableTools: true });
|
|
86
|
+
verdict = (turn.content || verdict).trim();
|
|
87
|
+
ctx.history.push({ role: 'user', content: prompt });
|
|
88
|
+
ctx.history.push({ role: 'assistant', content: verdict });
|
|
89
|
+
}
|
|
90
|
+
/** /goal:目标执行模式,完成条件可省略。 */
|
|
91
|
+
export async function handleGoal(arg, ctx) {
|
|
92
|
+
const parsed = parseGoalArg(arg);
|
|
93
|
+
if (!parsed) {
|
|
94
|
+
console.log(style.muted('用法:/goal <任务> [| <完成条件>]'));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const { task } = parsed;
|
|
98
|
+
let { done } = parsed;
|
|
99
|
+
console.log(style.label(`[Goal] 目标:${task}`));
|
|
100
|
+
console.log(style.info(`[Goal] 完成条件:${done ?? '待规划阶段补全'}`));
|
|
101
|
+
console.log(style.label('\n[Goal] 开始制定计划...\n'));
|
|
102
|
+
const rawPlan = done
|
|
103
|
+
? await buildPlan(buildGoalUserContent(task, done), ctx)
|
|
104
|
+
: await buildPlan(task, ctx, GOAL_PLANNING_SYSTEM_PROMPT);
|
|
105
|
+
if (!rawPlan) {
|
|
106
|
+
console.log(style.warn('\n[Goal] 未能生成计划。'));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
let plan = rawPlan;
|
|
110
|
+
if (!done) {
|
|
111
|
+
const parsedPlan = parseGoalPlan(rawPlan);
|
|
112
|
+
done = parsedPlan.done;
|
|
113
|
+
plan = parsedPlan.plan;
|
|
114
|
+
}
|
|
115
|
+
const goalContent = buildGoalUserContent(task, done);
|
|
116
|
+
console.log(style.label('\n\n[Goal] 完成条件:'));
|
|
117
|
+
console.log(done);
|
|
118
|
+
console.log(style.label('\n[Goal] 计划如下:'));
|
|
119
|
+
console.log(plan);
|
|
120
|
+
const answer = (await ctx.ask('\n是否按此计划执行?(y/N) '))
|
|
121
|
+
.trim()
|
|
122
|
+
.toLowerCase();
|
|
123
|
+
if (answer !== 'y' && answer !== 'yes') {
|
|
124
|
+
console.log(style.warn('[Goal] 已取消执行。'));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
console.log(style.label('\n[Goal] 开始执行计划...'));
|
|
128
|
+
const tracker = new PlanTracker(plan);
|
|
129
|
+
if (tracker.hasSteps()) {
|
|
130
|
+
tracker.printState();
|
|
131
|
+
}
|
|
132
|
+
ctx.history[0].content = `${EXECUTION_SYSTEM_PROMPT}\n\n目标完成条件:${done}\n\n已批准的计划:\n${plan}`;
|
|
133
|
+
ctx.history.push({ role: 'user', content: goalContent });
|
|
134
|
+
await runAgentTurn({
|
|
135
|
+
ai: ctx.ai,
|
|
136
|
+
history: ctx.history,
|
|
137
|
+
confirm: makeConfirm(ctx),
|
|
138
|
+
stats: ctx.stats,
|
|
139
|
+
maxRounds: 30,
|
|
140
|
+
requireToolsFirstRound: true,
|
|
141
|
+
onToolCall: (tc) => {
|
|
142
|
+
if (tracker.hasSteps()) {
|
|
143
|
+
tracker.printCurrent();
|
|
144
|
+
}
|
|
145
|
+
console.log(style.tool(`\n[Goal] 调用 ${tc.name}`));
|
|
146
|
+
console.log(formatToolCall(tc));
|
|
147
|
+
},
|
|
148
|
+
onToolResult: (tc, result) => {
|
|
149
|
+
console.log(style.muted(`\n[Goal] ${tc.name} 结果:`));
|
|
150
|
+
console.log(truncateResult(result));
|
|
151
|
+
if (tracker.hasSteps()) {
|
|
152
|
+
tracker.advance();
|
|
153
|
+
tracker.printState();
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
await evaluateGoal(task, done, ctx);
|
|
158
|
+
console.log(style.success('\n[Goal] 目标执行结束'));
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=goal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal.js","sourceRoot":"","sources":["../../../../src/cli/slash/system/goal.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,12 +3,14 @@ export const COMMANDS = [
|
|
|
3
3
|
['/help', '列出所有命令'],
|
|
4
4
|
['/clear', '清空对话历史(保留系统提示)'],
|
|
5
5
|
['/undo [n]', '撤销最近 n 轮对话(默认 1)'],
|
|
6
|
+
['/compact', '把对话历史压缩成摘要,释放上下文'],
|
|
6
7
|
['/model [id]', '查看或切换模型'],
|
|
7
8
|
['/save [name]', '保存当前对话(省略名称自动生成)'],
|
|
8
9
|
['/load <name>', '加载会话;不完整时列出候选'],
|
|
9
10
|
['/sessions', '列出已保存的会话'],
|
|
10
11
|
['/delete <name>', '删除指定会话(需确认)'],
|
|
11
12
|
['/agent <task>', '进入自动任务执行模式'],
|
|
13
|
+
['/goal <task> [| <条件>]', '目标执行模式,完成条件可省略'],
|
|
12
14
|
['/stats', '查看本次会话 token 统计'],
|
|
13
15
|
['/resume', '恢复上次自动保存的会话'],
|
|
14
16
|
['/reload', '重新加载 .ccli/config.json 并刷新 MCP server'],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../../src/cli/slash/system/help.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,MAAM,CAAC,MAAM,QAAQ,GAA4B;IAC7C,CAAC,OAAO,EAAE,QAAQ,CAAC;IACnB,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAC5B,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACjC,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,cAAc,EAAE,kBAAkB,CAAC;IACpC,CAAC,cAAc,EAAE,eAAe,CAAC;IACjC,CAAC,WAAW,EAAE,UAAU,CAAC;IACzB,CAAC,gBAAgB,EAAE,aAAa,CAAC;IACjC,CAAC,eAAe,EAAE,YAAY,CAAC;IAC/B,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAC7B,CAAC,SAAS,EAAE,aAAa,CAAC;IAC1B,CAAC,SAAS,EAAE,uCAAuC,CAAC;IACpD,CAAC,mBAAmB,EAAE,uCAAuC,CAAC;IAC9D,CAAC,cAAc,EAAE,cAAc,CAAC;IAChC,CAAC,cAAc,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,UAAU,SAAS;IACrB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../../src/cli/slash/system/help.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,MAAM,CAAC,MAAM,QAAQ,GAA4B;IAC7C,CAAC,OAAO,EAAE,QAAQ,CAAC;IACnB,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAC5B,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACjC,CAAC,UAAU,EAAE,kBAAkB,CAAC;IAChC,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,cAAc,EAAE,kBAAkB,CAAC;IACpC,CAAC,cAAc,EAAE,eAAe,CAAC;IACjC,CAAC,WAAW,EAAE,UAAU,CAAC;IACzB,CAAC,gBAAgB,EAAE,aAAa,CAAC;IACjC,CAAC,eAAe,EAAE,YAAY,CAAC;IAC/B,CAAC,uBAAuB,EAAE,gBAAgB,CAAC;IAC3C,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAC7B,CAAC,SAAS,EAAE,aAAa,CAAC;IAC1B,CAAC,SAAS,EAAE,uCAAuC,CAAC;IACpD,CAAC,mBAAmB,EAAE,uCAAuC,CAAC;IAC9D,CAAC,cAAc,EAAE,cAAc,CAAC;IAChC,CAAC,cAAc,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,UAAU,SAAS;IACrB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 终端输出统一样式。
|
|
3
|
+
*
|
|
4
|
+
* 集中管理 ANSI 颜色与语义样式,避免在各处散落转义码。
|
|
5
|
+
* 默认遵循 NO_COLOR / FORCE_COLOR,非 TTY 环境不输出颜色。
|
|
6
|
+
*/
|
|
7
|
+
const ANSI = {
|
|
8
|
+
reset: '\u001b[0m',
|
|
9
|
+
bold: '\u001b[1m',
|
|
10
|
+
dim: '\u001b[2m',
|
|
11
|
+
black: '\u001b[30m',
|
|
12
|
+
red: '\u001b[31m',
|
|
13
|
+
green: '\u001b[32m',
|
|
14
|
+
yellow: '\u001b[33m',
|
|
15
|
+
blue: '\u001b[34m',
|
|
16
|
+
cyan: '\u001b[36m',
|
|
17
|
+
gray: '\u001b[90m',
|
|
18
|
+
inverse: '\u001b[7m',
|
|
19
|
+
bgCyan: '\u001b[46m',
|
|
20
|
+
};
|
|
21
|
+
/** 判断当前输出是否应该上色。 */
|
|
22
|
+
export function isColorEnabled() {
|
|
23
|
+
if (process.env.NO_COLOR)
|
|
24
|
+
return false;
|
|
25
|
+
if (process.env.FORCE_COLOR && process.env.FORCE_COLOR !== '0') {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return Boolean(process.stdout.isTTY);
|
|
29
|
+
}
|
|
30
|
+
/** 给文本包一个或多个 ANSI 样式;未启用颜色时原样返回。 */
|
|
31
|
+
export function stylize(text, ...styles) {
|
|
32
|
+
if (styles.length === 0 || !isColorEnabled())
|
|
33
|
+
return text;
|
|
34
|
+
const open = styles.map((s) => ANSI[s]).join('');
|
|
35
|
+
return `${open}${text}${ANSI.reset}`;
|
|
36
|
+
}
|
|
37
|
+
/** 语义化样式:业务代码优先用这些,而不是直接写颜色。 */
|
|
38
|
+
export const style = {
|
|
39
|
+
bold: (text) => stylize(text, 'bold'),
|
|
40
|
+
dim: (text) => stylize(text, 'dim'),
|
|
41
|
+
inverse: (text) => stylize(text, 'inverse'),
|
|
42
|
+
selected: (text) => stylize(text, 'bold', 'black', 'bgCyan'),
|
|
43
|
+
label: (text) => stylize(text, 'bold', 'cyan'),
|
|
44
|
+
info: (text) => stylize(text, 'cyan'),
|
|
45
|
+
success: (text) => stylize(text, 'green'),
|
|
46
|
+
warn: (text) => stylize(text, 'yellow'),
|
|
47
|
+
error: (text) => stylize(text, 'bold', 'red'),
|
|
48
|
+
muted: (text) => stylize(text, 'gray'),
|
|
49
|
+
tool: (text) => stylize(text, 'blue'),
|
|
50
|
+
step: (text) => stylize(text, 'yellow'),
|
|
51
|
+
done: (text) => stylize(text, 'green'),
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/cli/style.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,IAAI,GAAG;IACT,KAAK,EAAE,WAAW;IAClB,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,WAAW;IAChB,KAAK,EAAE,YAAY;IACnB,GAAG,EAAE,YAAY;IACjB,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,YAAY;IACpB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,YAAY;CACd,CAAC;AAIX,oBAAoB;AACpB,MAAM,UAAU,cAAc;IAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,GAAG,MAAmB;IACxD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE;QAAE,OAAO,IAAI,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjD,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;AACzC,CAAC;AAED,gCAAgC;AAChC,MAAM,CAAC,MAAM,KAAK,GAAG;IACjB,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;IAC7C,GAAG,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;IAC3C,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;IACnD,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC;IACpE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC;IACtD,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;IAC7C,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;IACjD,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;IAC/C,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC;IACrD,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;IAC9C,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;IAC7C,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;IAC/C,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;CACjD,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 项目记忆(Project Memory)—— 让 CCLI「懂这个项目」。
|
|
3
|
+
*
|
|
4
|
+
* 启动时自动读取项目根目录的记忆文件,把它追加进 system 提示,
|
|
5
|
+
* 这样每次会话都自带项目背景/约定,不用手动 @ 交代。
|
|
6
|
+
*
|
|
7
|
+
* 这是「记忆分层」的第一层:项目记忆。后续可再加全局记忆(~/.ccli/)、
|
|
8
|
+
* 子目录记忆、以及交互中用 # 动态写入。
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { resolve } from 'node:path';
|
|
12
|
+
/** 按优先级尝试的记忆文件名:命中第一个存在且非空的。 */
|
|
13
|
+
const MEMORY_FILES = ['CCLI.md', 'AGENTS.md'];
|
|
14
|
+
/** 记忆内容上限,避免超大文件把上下文撑爆。 */
|
|
15
|
+
const MAX_MEMORY_CHARS = 16_000;
|
|
16
|
+
/** 读取项目根的记忆文件(第一个存在且非空的),没有则返回 null。 */
|
|
17
|
+
export function loadProjectMemory(cwd = process.cwd()) {
|
|
18
|
+
for (const file of MEMORY_FILES) {
|
|
19
|
+
let raw;
|
|
20
|
+
try {
|
|
21
|
+
raw = readFileSync(resolve(cwd, file), 'utf8');
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
continue; // 不存在就试下一个
|
|
25
|
+
}
|
|
26
|
+
const trimmed = raw.trim();
|
|
27
|
+
if (!trimmed)
|
|
28
|
+
continue;
|
|
29
|
+
const content = trimmed.length > MAX_MEMORY_CHARS
|
|
30
|
+
? trimmed.slice(0, MAX_MEMORY_CHARS) + '\n…(记忆文件过长,已截断)'
|
|
31
|
+
: trimmed;
|
|
32
|
+
return { file, content };
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/** 把项目记忆追加到 system 提示后面;无记忆则原样返回。 */
|
|
37
|
+
export function appendProjectMemory(systemPrompt, memory) {
|
|
38
|
+
if (!memory)
|
|
39
|
+
return systemPrompt;
|
|
40
|
+
return (`${systemPrompt}\n\n` +
|
|
41
|
+
`# 项目记忆(来自 ${memory.file})\n` +
|
|
42
|
+
`以下是当前项目的说明与约定,请在本次会话中遵循:\n\n` +
|
|
43
|
+
memory.content);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/config/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,gCAAgC;AAChC,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAE9C,2BAA2B;AAC3B,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAShC,wCAAwC;AACxC,MAAM,UAAU,iBAAiB,CAC7B,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAC9B,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACD,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACL,SAAS,CAAC,WAAW;QACzB,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,MAAM,OAAO,GACT,OAAO,CAAC,MAAM,GAAG,gBAAgB;YAC7B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,iBAAiB;YACxD,CAAC,CAAC,OAAO,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,mBAAmB,CAC/B,YAAoB,EACpB,MAA4B;IAE5B,IAAI,CAAC,MAAM;QAAE,OAAO,YAAY,CAAC;IACjC,OAAO,CACH,GAAG,YAAY,MAAM;QACrB,aAAa,MAAM,CAAC,IAAI,KAAK;QAC7B,8BAA8B;QAC9B,MAAM,CAAC,OAAO,CACjB,CAAC;AACN,CAAC"}
|