@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 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
  * Bash 命令危险检测扩展
3
4
  *
4
5
  * 放置位置: config/agent/extensions/
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * @author: xujianjiang
2
3
  * Context Monitor Extension — 自动检测上下文大小并在接近阈值时警告
3
4
  *
4
5
  * 功能:
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * @author: xujianjiang
2
3
  * /context
3
4
  *
4
5
  * Small TUI view showing what's loaded/available:
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * @author: xujianjiang
2
3
  * Custom Footer Extension — Single-line compact powerline style
3
4
  *
4
5
  * ~/path (branch) │ ↑in ↓out $cost │ 42%/200k │ ⚡ model • thinking
@@ -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: "更新 CLI 工具",
138
+ description: "更新 aicode-cli 工具",
138
139
  usage: "/update",
139
140
  handler: async (_args, ctx) => {
140
- const options = [
141
- "更新自己 (aicode-cli)",
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
- if (selected.includes("aicode-cli")) {
153
- const ok = await ctx.ui.confirm("更新确认", "确定要更新 aicode-cli 吗?");
154
- if (!ok) {
155
- ctx.ui.notify("已取消", "info");
156
- return;
157
- }
158
- ctx.ui.notify("🔄 正在更新 aicode-cli...", "info");
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
- ctx.ui.notify("🔄 正在更新 ...", "info");
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 for real-time monitoring
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
- // Print to console
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
- // Print to console
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
- // Print to console (errors in red)
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
- console.log(`[msg-debug] Debug logging enabled. Logs will be saved to: ${logFile}`);
174
+ // Extension enabled silently (logs to file only, no console output)
183
175
  }
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * @author: xujianjiang
2
3
  * Code Review Extension (inspired by Codex's review feature)
3
4
  *
4
5
  * Provides a `/review` command that prompts the agent to review code changes.
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * @author: xujianjiang
2
3
  * working-message
3
4
  *
4
5
  * 自定义工作消息,格式类似 Claude Code: ✶ xxx… (时间 · tokens)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ia-ccun/code-agent-cli",
3
- "version": "0.0.47-beta.2",
3
+ "version": "0.0.47-beta.4",
4
4
  "description": "AI Coding Agent CLI - 基于OpenClaw🦞底层Agent(pi)原理封装的编码智能体(供学习使用)。",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -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