@ia-ccun/code-agent-cli 0.0.47-beta.2 → 0.0.47-beta.4
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/bin/cli.js +2 -1
- package/config/agent/extensions/aicode-tips.ts +139 -0
- package/config/agent/extensions/bash-check.ts +1 -0
- package/config/agent/extensions/context-monitor.ts +1 -0
- package/config/agent/extensions/context.ts +1 -0
- package/config/agent/extensions/custom-footer.ts +1 -0
- package/config/agent/extensions/custom.ts +12 -39
- package/config/agent/extensions/error-monitor.ts +103 -0
- package/config/agent/extensions/msg-debug.ts +6 -14
- package/config/agent/extensions/review.ts +1 -0
- package/config/agent/extensions/working-msg.ts +1 -0
- package/package.json +1 -1
- package/scripts/postinstall.js +2 -0
package/bin/cli.js
CHANGED
|
@@ -209,7 +209,8 @@ const env = {
|
|
|
209
209
|
AICODE_CLI_NAME: config.name,
|
|
210
210
|
AICODE_CLI_VERSION: localVersion || '',
|
|
211
211
|
AICODE_CLI_VERSION_CACHE: versionCachePath,
|
|
212
|
-
PI_SKIP_VERSION_CHECK: '1'
|
|
212
|
+
PI_SKIP_VERSION_CHECK: '1',
|
|
213
|
+
PI_OFFLINE: '1' // 禁用包更新检查
|
|
213
214
|
};
|
|
214
215
|
|
|
215
216
|
// 传递配置目录给 pi
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author: xujianjiang
|
|
3
|
+
* Aicode Tips Extension — 在边框下方、状态栏上方随机显示使用技巧
|
|
4
|
+
*
|
|
5
|
+
* 显示 25 秒后消失,5 秒后显示下一条
|
|
6
|
+
* 技巧列表包含快捷键、命令使用及联系方式提示
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
|
|
11
|
+
const AICODE_TIPS = [
|
|
12
|
+
"@ 快速搜索项目文件",
|
|
13
|
+
"Ctrl+L 快速切换模型",
|
|
14
|
+
"Ctrl+P/Shift+Ctrl+P 切换模型",
|
|
15
|
+
"Shift+Tab 切换思考级别",
|
|
16
|
+
"Ctrl+O 展开/折叠工具输出",
|
|
17
|
+
"Ctrl+T 展开/折叠思考块",
|
|
18
|
+
"Alt+Enter 队列跟进消息",
|
|
19
|
+
"Ctrl+V 粘贴图片",
|
|
20
|
+
"Shift+Enter 输入多行",
|
|
21
|
+
"/ 查看所有命令",
|
|
22
|
+
"/tree 查看会话历史",
|
|
23
|
+
"/session 查看统计",
|
|
24
|
+
"/settings 自定义设置",
|
|
25
|
+
"/export 导出会话为HTML",
|
|
26
|
+
"/copy 复制最后消息",
|
|
27
|
+
"/name 设置会话名称",
|
|
28
|
+
"/hotkeys 显示所有快捷键",
|
|
29
|
+
"/reload 重载扩展和技能",
|
|
30
|
+
"/new 开始新会话",
|
|
31
|
+
"!cmd 执行 bash",
|
|
32
|
+
"!!cmd 执行bash但不发送给AI",
|
|
33
|
+
"/compact 压缩上下文",
|
|
34
|
+
"/skill:name 调用技能",
|
|
35
|
+
"/resume 恢复会话",
|
|
36
|
+
"/fork 创建新分支",
|
|
37
|
+
"Ctrl+C 清空编辑器",
|
|
38
|
+
"双击Esc 打开树视图",
|
|
39
|
+
"拖拽文件到终端附加",
|
|
40
|
+
// 扩展命令提示
|
|
41
|
+
"/version 查看当前版本和最新版本",
|
|
42
|
+
"/update 更新 aicode-cli",
|
|
43
|
+
"/status 显示会话状态",
|
|
44
|
+
"/clear 清理当前会话上下文",
|
|
45
|
+
"/quit 退出当前会话",
|
|
46
|
+
// 联系方式提示
|
|
47
|
+
"💡 任何疑问或需求可联系 xujianjiang,支持需求对接开发、系统集成与扩展",
|
|
48
|
+
"📖 内网手册参考 UniDoc《2026.03 AICode Agent CLI编码智能体使用手册》",
|
|
49
|
+
"⚠️ LLM API 4xx/5xx 错误时请确认模型配置是否正确,或在企微群咨询 jiangchi、maliang",
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
export default function (pi: ExtensionAPI) {
|
|
53
|
+
let currentTipIndex = -1;
|
|
54
|
+
let autoHideTimeoutId: NodeJS.Timeout | undefined;
|
|
55
|
+
let autoShowTimeoutId: NodeJS.Timeout | undefined;
|
|
56
|
+
let currentCtx: ExtensionContext | undefined;
|
|
57
|
+
let isAutoPlaying = false;
|
|
58
|
+
|
|
59
|
+
const hideTip = () => {
|
|
60
|
+
if (!currentCtx?.hasUI) return;
|
|
61
|
+
currentCtx.ui.setWidget("aicode-tips", [], { placement: "aboveEditor" });
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const clearAllTimers = () => {
|
|
65
|
+
if (autoHideTimeoutId) {
|
|
66
|
+
clearTimeout(autoHideTimeoutId);
|
|
67
|
+
autoHideTimeoutId = undefined;
|
|
68
|
+
}
|
|
69
|
+
if (autoShowTimeoutId) {
|
|
70
|
+
clearTimeout(autoShowTimeoutId);
|
|
71
|
+
autoShowTimeoutId = undefined;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const padRight = (str: string, width: number): string => {
|
|
76
|
+
const chinese = (str.match(/[\u4e00-\u9fff]/g) || []).length;
|
|
77
|
+
const ascii = str.length - chinese;
|
|
78
|
+
const fullWidth = chinese * 2 + ascii;
|
|
79
|
+
const padding = Math.max(0, width - fullWidth);
|
|
80
|
+
return str + " ".repeat(padding);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const showRandomTip = () => {
|
|
84
|
+
if (!currentCtx?.hasUI) return;
|
|
85
|
+
|
|
86
|
+
// 清除之前的定时器
|
|
87
|
+
clearAllTimers();
|
|
88
|
+
|
|
89
|
+
let randomIndex = Math.floor(Math.random() * AICODE_TIPS.length);
|
|
90
|
+
if (randomIndex === currentTipIndex && AICODE_TIPS.length > 1) {
|
|
91
|
+
randomIndex = (randomIndex + 1) % AICODE_TIPS.length;
|
|
92
|
+
}
|
|
93
|
+
currentTipIndex = randomIndex;
|
|
94
|
+
const tip = AICODE_TIPS[randomIndex];
|
|
95
|
+
// 颜色 #9cc8cfc2,右对齐
|
|
96
|
+
const coloredTip = `\x1b[38;2;156;200;207m${padRight("tips: " + tip, 60)}\x1b[0m`;
|
|
97
|
+
currentCtx.ui.setWidget("aicode-tips", [coloredTip], { placement: "aboveEditor" });
|
|
98
|
+
|
|
99
|
+
// 自动轮播:25秒后隐藏,隐藏后5秒显示下一条
|
|
100
|
+
if (isAutoPlaying) {
|
|
101
|
+
autoHideTimeoutId = setTimeout(() => {
|
|
102
|
+
hideTip();
|
|
103
|
+
autoShowTimeoutId = setTimeout(showRandomTip, 5000);
|
|
104
|
+
}, 25000);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const startAutoPlay = () => {
|
|
109
|
+
isAutoPlaying = true;
|
|
110
|
+
showRandomTip();
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const stopAutoPlay = () => {
|
|
114
|
+
isAutoPlaying = false;
|
|
115
|
+
clearAllTimers();
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// 会话开始时启动自动轮播
|
|
119
|
+
pi.on("session_start", (_event, ctx) => {
|
|
120
|
+
currentCtx = ctx;
|
|
121
|
+
startAutoPlay();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// 会话结束时清理
|
|
125
|
+
pi.on("session_shutdown", () => {
|
|
126
|
+
stopAutoPlay();
|
|
127
|
+
currentCtx?.ui.setWidget("aicode-tips", undefined);
|
|
128
|
+
currentCtx = undefined;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// 手动切换技巧
|
|
132
|
+
pi.registerCommand("tip", {
|
|
133
|
+
description: "显示一个新的 aicode 使用技巧",
|
|
134
|
+
handler: async (_args, ctx) => {
|
|
135
|
+
currentCtx = ctx;
|
|
136
|
+
showRandomTip();
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* @author: xujianjiang
|
|
2
3
|
* 自定义扩展示例
|
|
3
4
|
*
|
|
4
5
|
* 放置位置: config/agent/extensions/
|
|
@@ -134,52 +135,24 @@ export default function (pi: ExtensionAPI) {
|
|
|
134
135
|
// === 注册 /update 命令 ===
|
|
135
136
|
|
|
136
137
|
pi.registerCommand("update", {
|
|
137
|
-
description: "更新
|
|
138
|
+
description: "更新 aicode-cli 工具",
|
|
138
139
|
usage: "/update",
|
|
139
140
|
handler: async (_args, ctx) => {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
"更新依赖 agent",
|
|
143
|
-
];
|
|
144
|
-
|
|
145
|
-
// 让用户选择
|
|
146
|
-
const selected = await ctx.ui.select("选择更新内容", options);
|
|
147
|
-
if (!selected) {
|
|
141
|
+
const ok = await ctx.ui.confirm("更新确认", "确定要更新 aicode-cli 吗?");
|
|
142
|
+
if (!ok) {
|
|
148
143
|
ctx.ui.notify("已取消", "info");
|
|
149
144
|
return;
|
|
150
145
|
}
|
|
151
146
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const { exec } = await import("child_process");
|
|
160
|
-
exec("npm install -g @ia-ccun/code-agent-cli", (error, stdout, stderr) => {
|
|
161
|
-
if (error) {
|
|
162
|
-
ctx.ui.notify(`❌ 更新失败: ${error.message},请重试`, "error");
|
|
163
|
-
} else {
|
|
164
|
-
ctx.ui.notify("✅ aicode-cli 更新成功!", "success");
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
} else if (selected.includes("agent")) {
|
|
168
|
-
const ok = await ctx.ui.confirm("更新确认", "确定要更新依赖的agent 吗?");
|
|
169
|
-
if (!ok) {
|
|
170
|
-
ctx.ui.notify("已取消", "info");
|
|
171
|
-
return;
|
|
147
|
+
ctx.ui.notify("🔄 正在更新 aicode-cli...", "info");
|
|
148
|
+
const { exec } = await import("child_process");
|
|
149
|
+
exec("npm install -g @ia-ccun/code-agent-cli", (error, stdout, stderr) => {
|
|
150
|
+
if (error) {
|
|
151
|
+
ctx.ui.notify(`❌ 更新失败: ${error.message},请重试`, "error");
|
|
152
|
+
} else {
|
|
153
|
+
ctx.ui.notify("✅ aicode-cli 更新成功!请重启 CLI", "success");
|
|
172
154
|
}
|
|
173
|
-
|
|
174
|
-
const { exec } = await import("child_process");
|
|
175
|
-
exec("npm install -g @mariozechner/pi-coding-agent", (error, stdout, stderr) => {
|
|
176
|
-
if (error) {
|
|
177
|
-
ctx.ui.notify(`❌ 更新失败: ${error.message},请重试`, "error");
|
|
178
|
-
} else {
|
|
179
|
-
ctx.ui.notify("✅ 依赖的 agent 更新成功!", "success");
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
}
|
|
155
|
+
});
|
|
183
156
|
},
|
|
184
157
|
});
|
|
185
158
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Monitor Extension
|
|
3
|
+
*
|
|
4
|
+
* @author: xujianjiang
|
|
5
|
+
*
|
|
6
|
+
* Logs errors to ./.aicode-cli/debug-logs/aicode-error.log
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
|
|
13
|
+
// Error log file configuration
|
|
14
|
+
const ERROR_LOG_DIR = path.resolve(process.cwd(), "./.aicode-cli/debug-logs");
|
|
15
|
+
const ERROR_LOG_FILE = path.join(ERROR_LOG_DIR, "aicode-error.log");
|
|
16
|
+
|
|
17
|
+
// Ensure log directory exists
|
|
18
|
+
function ensureLogDir(): void {
|
|
19
|
+
if (!fs.existsSync(ERROR_LOG_DIR)) {
|
|
20
|
+
fs.mkdirSync(ERROR_LOG_DIR, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @author: xujianjiang
|
|
26
|
+
* Append error message to log file
|
|
27
|
+
*/
|
|
28
|
+
function appendToErrorLog(message: string, context?: Record<string, unknown>): void {
|
|
29
|
+
ensureLogDir();
|
|
30
|
+
const timestamp = new Date().toISOString();
|
|
31
|
+
let logEntry = `[${timestamp}] ${message}`;
|
|
32
|
+
if (context && Object.keys(context).length > 0) {
|
|
33
|
+
logEntry += `\nContext: ${JSON.stringify(context, null, 2)}`;
|
|
34
|
+
}
|
|
35
|
+
logEntry += "\n---\n";
|
|
36
|
+
fs.appendFileSync(ERROR_LOG_FILE, logEntry);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default function (pi: ExtensionAPI) {
|
|
40
|
+
// Counter for error tracking
|
|
41
|
+
let toolErrorCount = 0;
|
|
42
|
+
let bashErrorCount = 0;
|
|
43
|
+
const startTime = Date.now();
|
|
44
|
+
|
|
45
|
+
// Monitor tool execution end for errors
|
|
46
|
+
pi.on("tool_execution_end", (event) => {
|
|
47
|
+
const { toolCallId, toolName, result, isError } = event;
|
|
48
|
+
|
|
49
|
+
if (isError) {
|
|
50
|
+
toolErrorCount++;
|
|
51
|
+
const errorMsg = typeof result === "string" ? result : JSON.stringify(result);
|
|
52
|
+
|
|
53
|
+
// Append to error log file
|
|
54
|
+
appendToErrorLog(
|
|
55
|
+
`Tool Execution Failed: ${toolName}`,
|
|
56
|
+
{
|
|
57
|
+
toolCallId,
|
|
58
|
+
toolName,
|
|
59
|
+
errorMessage: errorMsg?.substring(0, 500),
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Monitor user bash events for command failures
|
|
66
|
+
pi.on("user_bash", (event) => {
|
|
67
|
+
const { command, result } = event;
|
|
68
|
+
|
|
69
|
+
if (result?.exitCode !== 0) {
|
|
70
|
+
bashErrorCount++;
|
|
71
|
+
|
|
72
|
+
// Append to error log file
|
|
73
|
+
appendToErrorLog(
|
|
74
|
+
`Bash Command Failed: ${command} - exit code ${result?.exitCode}`,
|
|
75
|
+
{
|
|
76
|
+
command,
|
|
77
|
+
exitCode: result?.exitCode,
|
|
78
|
+
stderr: result?.stderr?.substring(0, 500),
|
|
79
|
+
stdout: result?.stdout?.substring(0, 500),
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Summary on session shutdown
|
|
86
|
+
pi.on("session_shutdown", () => {
|
|
87
|
+
const uptime = Math.round((Date.now() - startTime) / 1000);
|
|
88
|
+
const totalErrors = toolErrorCount + bashErrorCount;
|
|
89
|
+
|
|
90
|
+
if (totalErrors > 0) {
|
|
91
|
+
console.log(`
|
|
92
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
93
|
+
📊 Error Monitor 会话统计
|
|
94
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
95
|
+
总错误数: ${totalErrors}
|
|
96
|
+
工具错误数: ${toolErrorCount}
|
|
97
|
+
Bash 错误数: ${bashErrorCount}
|
|
98
|
+
运行时长: ${uptime}秒
|
|
99
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
100
|
+
`);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* @author: xujianjiang
|
|
2
3
|
* Msg Debug Extension - Log LLM request/response messages to file
|
|
3
4
|
*
|
|
4
5
|
* This extension logs all requests and responses sent to/from the LLM provider
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
* - Logs before_provider_request: messages, parameters, raw payload
|
|
9
10
|
* - Logs after_provider_response: usage stats, response content, stop reason
|
|
10
11
|
* - Logs errors with context
|
|
11
|
-
* - Console output
|
|
12
|
+
* - Console output removed (logs to file only)
|
|
12
13
|
* - Session-based log files (one file per session)
|
|
13
14
|
*/
|
|
14
15
|
|
|
@@ -105,10 +106,7 @@ ${JSON.stringify({ ...payload, messages: filteredMessages }, null, 2)}
|
|
|
105
106
|
================================================================================
|
|
106
107
|
`;
|
|
107
108
|
|
|
108
|
-
//
|
|
109
|
-
console.log(logEntry);
|
|
110
|
-
|
|
111
|
-
// Also save to file
|
|
109
|
+
// Save to file
|
|
112
110
|
appendFileSync(logFile, logEntry, "utf8");
|
|
113
111
|
});
|
|
114
112
|
|
|
@@ -146,10 +144,7 @@ ${JSON.stringify(response, null, 2)}
|
|
|
146
144
|
|
|
147
145
|
`;
|
|
148
146
|
|
|
149
|
-
//
|
|
150
|
-
console.log(logEntry);
|
|
151
|
-
|
|
152
|
-
// Also save to file
|
|
147
|
+
// Save to file
|
|
153
148
|
appendFileSync(logFile, logEntry, "utf8");
|
|
154
149
|
});
|
|
155
150
|
|
|
@@ -172,12 +167,9 @@ ${JSON.stringify(context, null, 2)}
|
|
|
172
167
|
|
|
173
168
|
`;
|
|
174
169
|
|
|
175
|
-
//
|
|
176
|
-
console.error(logEntry);
|
|
177
|
-
|
|
178
|
-
// Also save to file
|
|
170
|
+
// Save to file
|
|
179
171
|
appendFileSync(logFile, logEntry, "utf8");
|
|
180
172
|
});
|
|
181
173
|
|
|
182
|
-
|
|
174
|
+
// Extension enabled silently (logs to file only, no console output)
|
|
183
175
|
}
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -170,10 +170,12 @@ const FORCE_OVERWRITE_LIST = [
|
|
|
170
170
|
'APPEND_SYSTEM.md',
|
|
171
171
|
'SYSTEM.md',
|
|
172
172
|
'dangerous-patterns.json',
|
|
173
|
+
'settings.json',
|
|
173
174
|
'extensions/working-msg.ts',
|
|
174
175
|
'extensions/custom-footer.ts',
|
|
175
176
|
'extensions/custom.ts',
|
|
176
177
|
'extensions/bash-check.ts',
|
|
178
|
+
'extensions/aicode-tips.ts',
|
|
177
179
|
// Force overwrite all prompts .md files
|
|
178
180
|
'prompts/*.md',
|
|
179
181
|
// Force overwrite all skills SKILL.md files
|