@ia-ccun/code-agent-cli 0.0.51 → 0.0.52-beta.1
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 +11 -10
- package/config/agent/extensions/aicode-advisor.ts +707 -0
- package/config/agent/extensions/aicode-btw.ts +2273 -0
- package/config/agent/extensions/aicode-plan.ts +903 -0
- package/config/agent/extensions/aicode-tips.ts +44 -8
- package/config/agent/extensions/bash-check.ts +1 -1
- package/config/agent/extensions/context-monitor.ts +1 -1
- package/config/agent/extensions/context.ts +3 -3
- package/config/agent/extensions/custom-footer.ts +22 -4
- package/config/agent/extensions/custom.ts +118 -84
- package/config/agent/extensions/error-monitor.ts +1 -1
- package/config/agent/extensions/goal.ts +450 -0
- package/config/agent/extensions/msg-debug.ts +49 -10
- package/config/agent/extensions/review.ts +3 -3
- package/config/agent/extensions/working-msg.ts +44 -23
- package/config/agent/help.md +25 -7
- package/config/agent/models.json +7 -7
- package/config/agent/settings.json +0 -2
- package/dist/banner.d.ts +5 -1
- package/dist/banner.d.ts.map +1 -1
- package/dist/banner.js +106 -7
- package/dist/banner.js.map +1 -1
- package/dist/config-loader.d.ts +2 -0
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +81 -7
- package/dist/config-loader.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/security-logger.d.ts +69 -0
- package/dist/security-logger.d.ts.map +1 -0
- package/dist/security-logger.js +178 -0
- package/dist/security-logger.js.map +1 -0
- package/package.json +18 -7
- package/scripts/postinstall.js +130 -50
|
@@ -6,15 +6,17 @@
|
|
|
6
6
|
* 技巧列表包含快捷键、命令使用及联系方式提示
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { ExtensionAPI, ExtensionContext } from "@
|
|
9
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
|
|
11
11
|
const AICODE_TIPS = [
|
|
12
12
|
"@ 快速搜索项目文件",
|
|
13
|
-
"Ctrl+L
|
|
13
|
+
"Ctrl+L 快速切换备选模型,
|
|
14
14
|
"Ctrl+P/Shift+Ctrl+P 切换范围模型",
|
|
15
|
-
"Shift+Tab
|
|
15
|
+
"Shift+Tab 切换思考级别( 需 models.json配置 reasoning 启用)",
|
|
16
16
|
"Ctrl+O 展开/折叠工具输出",
|
|
17
|
-
"Ctrl+
|
|
17
|
+
"Ctrl+U 清空行内光标前的内容",
|
|
18
|
+
"Ctrl+K 清空行内光标后的内容",
|
|
19
|
+
"Ctrl+G 使用高级编辑器进行输入(如vscode), 适合手工输入多行、多段文字的场景",
|
|
18
20
|
"Alt+Enter 队列跟进消息",
|
|
19
21
|
"Shift+Enter 输入多行",
|
|
20
22
|
"/ 查看所有命令",
|
|
@@ -34,6 +36,7 @@ const AICODE_TIPS = [
|
|
|
34
36
|
"/resume 恢复会话",
|
|
35
37
|
"/fork 创建会话新分支",
|
|
36
38
|
"Ctrl+C 清空编辑器",
|
|
39
|
+
"CTRL+ALT+SHIFT+P 开启/关闭 计划模式(只读模式)",
|
|
37
40
|
"双击 Esc 打开树视图",
|
|
38
41
|
"拖拽文件到终端附加",
|
|
39
42
|
// 扩展命令提示
|
|
@@ -43,6 +46,7 @@ const AICODE_TIPS = [
|
|
|
43
46
|
"/clear 清理当前会话",
|
|
44
47
|
"/quit 退出当前会话",
|
|
45
48
|
// 常用 Prompt 提示
|
|
49
|
+
"解读下这个图片内容 /home/user/pic/plan.png",
|
|
46
50
|
"/code-simplifier 自动简化刚修改的代码,提升清晰度和一致性",
|
|
47
51
|
"/feat 新功能开发,支持需求规划→讨论迭代→执行实施完整流程(推荐使用)",
|
|
48
52
|
"/git-commit 分析 Git 改动并生成 Conventional Commits 规范提交信息(推荐使用)",
|
|
@@ -94,24 +98,55 @@ const AICODE_TIPS = [
|
|
|
94
98
|
"/btw 并行侧边对话,可在不中断主流程的情况下进行临时讨论或查询 ",
|
|
95
99
|
"/rewind 回退到任意工具执行前的状态,支持快照恢复和撤销重做 ",
|
|
96
100
|
"/mcp 连接现有的 MCP 服务器 (如 xx 平台、企业微信等等),扩展 AI 能力支持多种外部工具和服务 ",
|
|
101
|
+
// 新增扩展功能提示
|
|
102
|
+
"Alt+/ 或 Ctrl+Alt+W 快速切换到 BTW 侧边对话窗口",
|
|
103
|
+
"BTW 侧边对话:独立上下文,不影响主会话,适合临时查询和讨论",
|
|
104
|
+
"/advisor 可向更强的审查模型征求第二意见,用于复杂决策和方案评估 ",
|
|
105
|
+
"/plan 进入计划模式,强制只读分析流程,生成结构化实施计划(推荐使用)",
|
|
106
|
+
"计划模式禁止写入操作,确保方案经过充分分析后再执行",
|
|
107
|
+
"计划模式自动生成 Todo 列表,跟踪实施步骤和完成进度",
|
|
108
|
+
"/goal 设置长期目标,跟踪进度、时间和 token 消耗",
|
|
109
|
+
"/goal --tokens=50K 设置带 token 预算限制的目标",
|
|
110
|
+
"Goal 扩展支持 paused/resumed 状态,方便暂停和恢复长期任务 (推荐使用)",,
|
|
111
|
+
"Goal 扩展显示实时进度:已完成百分比、已用时间和 token 消耗 (推荐使用)",
|
|
112
|
+
"⚠️ 使用 advisor 获取第二视角评估,避免决策盲点",
|
|
113
|
+
"⚠️ 使用 plan 模式强制分析流程,避免冲动式编码(推荐使用)",
|
|
114
|
+
"⚠️ 使用 goal 跟踪长期任务,避免AI自以为是类的完成,AI若完成必须给出证据",
|
|
115
|
+
"⚠️ BTW 侧边对话适合临时讨论,不会污染主会话上下文",
|
|
116
|
+
// 使用场景和最佳实践
|
|
117
|
+
"💡 大型重构任务:先用 /plan 制定计划,再用 /advisor 评估方案风险",
|
|
118
|
+
"💡 长期开发任务:用 /goal 设置目标并跟踪进度,避免 token 超支",
|
|
119
|
+
"💡 临时查询需求:打开 BTW 侧边对话,不影响主会话",
|
|
120
|
+
"💡 复杂决策场景:用 advisor 工具获取第二视角,避免思维盲点",
|
|
121
|
+
"💡 代码审查流程:用 /skill:code-review + advisor 双重审查确保质量",
|
|
122
|
+
"💡 新功能开发:用 /feat prompt 启动完整需求规划流程",
|
|
123
|
+
"💡 性能优化:用 /skill:audit 全面审计界面质量和性能瓶颈",
|
|
124
|
+
"💡 安全审计:用 /skill:owasp-security 检查 OWASP Top 10 漏洞",
|
|
125
|
+
"💡 文档生成:用 /skill:writing-plans 生成详细实施文档",
|
|
126
|
+
"💡 测试覆盖:用 /skill:test-runner 编写和运行多框架测试",
|
|
127
|
+
"💡 会话整理:用 /clear 清理上下文,用 /compact 压缩历史消息",
|
|
97
128
|
// 消息传递模式提示
|
|
98
129
|
"Enter 插话消息 - 在工具执行后立即发送,中断 AI 思考流程",
|
|
99
|
-
"Alt+Enter 排队消息 - 等待 AI 完全结束后发送,不中断 AI 工作",
|
|
100
130
|
"Escape 中断当前 AI 并恢复编辑器中的排队消息",
|
|
101
|
-
"Alt+Up 查看并编辑所有排队的消息",
|
|
102
131
|
"插话消息会打断 AI 正在执行的工具,等待响应",
|
|
103
132
|
"排队消息静默等待,AI 空闲时自动发送",
|
|
104
133
|
"可在 /settings 中调整消息发送模式和行为偏好",
|
|
105
134
|
// 记忆功能使用技巧
|
|
106
135
|
"💡 记忆功能自动记录会话中的关键经验,下次会话自动应用",
|
|
107
|
-
"💡 使用 /memory 查看当前记忆库中的条目",
|
|
108
136
|
"💡 在对话中说'记住这个'可手动保存经验到记忆库",
|
|
109
137
|
"💡 记忆功能支持选择性注入 (selective),只注入相关记忆避免干扰",
|
|
110
|
-
"💡 说'忘记 XXX'可删除特定记忆条目",
|
|
138
|
+
"💡 说'忘记 XXX '可删除特定记忆条目",
|
|
111
139
|
"💡 记忆会在会话结束时自动整合优化,提炼更有价值的经验",
|
|
112
140
|
"💡 记忆功能示例:记住代码规范后,后续开发自动遵循该规范",
|
|
113
141
|
"💡 记忆功能示例:记录常见错误模式,主动避免重复犯错",
|
|
114
142
|
"💡 记忆功能示例:保存项目特定配置,新会话自动加载上下文",
|
|
143
|
+
// 安全和最佳实践提示
|
|
144
|
+
"⚠️ 目前模型算力有限,部分任务可能存在排队等待的情况,若出现卡顿请稍后重试",
|
|
145
|
+
"⚠️ 执行 shell 命令前会自动检测是否为 safe command,非安全命令需要确认",
|
|
146
|
+
"⚠️ Banner 启动时显示当前版本、模型配置和常用命令,方便快速查看环境",
|
|
147
|
+
"⚠️ 使用 !! 前缀执行 bash 命令不会将输出发送给 AI,适合敏感操作",
|
|
148
|
+
// CodeGraph 使用方法(推荐使用)
|
|
149
|
+
"🔗 创建本地索引目录并构建知识图谱,操作说明 参考 UniDoc《2026.5 aicode+codegraph 安装与使用》 ",
|
|
115
150
|
// Subagent 使用方法
|
|
116
151
|
"🤖 说'使用 subagent 探索当前代码关于权限校验的实现'可快速定位相关代码",
|
|
117
152
|
"🤖 说'使用 subagent 为这个功能制定实施计划'可生成详细的开发步骤",
|
|
@@ -120,6 +155,7 @@ const AICODE_TIPS = [
|
|
|
120
155
|
"🤖 说'使用 subagent 给这个方案提点意见'可获得第二视角的评估建议",
|
|
121
156
|
// 联系方式提示
|
|
122
157
|
"⚠️ 任何疑问或需求可联系 xujianjiang,支持需求对接开发、系统集成与扩展",
|
|
158
|
+
"⚠️ aicode 图像识别参考 UniDoc《2026.03 AICode Agent CLI 编码智能体使用手册》的model.json模型配置",
|
|
123
159
|
"⚠️ 内网手册参考 UniDoc《2026.03 AICode Agent CLI 编码智能体使用手册》",
|
|
124
160
|
"⚠️ LLM API 4xx/5xx 错误时请确认模型配置是否正确,或在企微群咨询 jiangchi、maliang",
|
|
125
161
|
];
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 危险模式配置: config/agent/dangerous-patterns.json
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type { ExtensionAPI } from "@
|
|
13
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
14
14
|
import { readFileSync, existsSync } from "fs";
|
|
15
15
|
import { join } from "path";
|
|
16
16
|
import { homedir } from "os";
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - 100% : 阻止继续并强制提示压缩
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import type { ExtensionAPI, ExtensionContext, ToolResultEvent } from "@
|
|
17
|
+
import type { ExtensionAPI, ExtensionContext, ToolResultEvent } from "@earendil-works/pi-coding-agent";
|
|
18
18
|
|
|
19
19
|
interface ContextThresholds {
|
|
20
20
|
info: number; // 70%
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* - current context window usage + session totals (tokens/cost)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, ToolResultEvent } from "@
|
|
13
|
-
import { DynamicBorder } from "@
|
|
14
|
-
import { Container, Key, Text, matchesKey, type Component, type TUI } from "@
|
|
12
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, ToolResultEvent } from "@earendil-works/pi-coding-agent";
|
|
13
|
+
import { DynamicBorder } from "@earendil-works/pi-coding-agent";
|
|
14
|
+
import { Container, Key, Text, matchesKey, type Component, type TUI } from "@earendil-works/pi-tui";
|
|
15
15
|
import os from "node:os";
|
|
16
16
|
import path from "node:path";
|
|
17
17
|
import fs from "node:fs/promises";
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* [gold] [dim] [dim] [color ctx] [accent]
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { AssistantMessage } from "@
|
|
10
|
-
import type { ExtensionAPI } from "@
|
|
11
|
-
import { truncateToWidth, visibleWidth } from "@
|
|
9
|
+
import type { AssistantMessage } from "@earendil-works/pi-ai";
|
|
10
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
12
12
|
|
|
13
13
|
function fmtTokens(n: number): string {
|
|
14
14
|
if (n < 1000) return n.toString();
|
|
@@ -26,6 +26,16 @@ function getVersion() {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export default function (pi: ExtensionAPI) {
|
|
29
|
+
// Plan 模式状态(由 EventBus 更新)
|
|
30
|
+
let planModeEnabled = false;
|
|
31
|
+
let footerTui: import("@earendil-works/pi-tui").TUI | null = null;
|
|
32
|
+
|
|
33
|
+
// 监听 plan 模式变化事件(全局监听,只注册一次)
|
|
34
|
+
pi.events.on("aicode-plan:mode-changed", (data: any) => {
|
|
35
|
+
planModeEnabled = data.enabled;
|
|
36
|
+
footerTui?.requestRender();
|
|
37
|
+
});
|
|
38
|
+
|
|
29
39
|
pi.on("session_start", async (_event, ctx) => {
|
|
30
40
|
// 检查版本更新并显示通知
|
|
31
41
|
const cachePath = process.env.AICODE_CLI_VERSION_CACHE;
|
|
@@ -47,6 +57,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
ctx.ui.setFooter((tui, theme, footerData) => {
|
|
60
|
+
footerTui = tui;
|
|
50
61
|
const unsub = footerData.onBranchChange(() => tui.requestRender());
|
|
51
62
|
|
|
52
63
|
return {
|
|
@@ -149,7 +160,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
149
160
|
|
|
150
161
|
// quots
|
|
151
162
|
const quotes = [
|
|
152
|
-
"代码是有灵魂的",
|
|
153
163
|
"敬畏生产,双人复核,稳妥变更",
|
|
154
164
|
"让代码更有温度",
|
|
155
165
|
"民生所系,支付所向",
|
|
@@ -184,6 +194,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
184
194
|
if (statsColored) segments.push(statsColored);
|
|
185
195
|
segments.push(ctxColored);
|
|
186
196
|
segments.push(modelColored);
|
|
197
|
+
|
|
198
|
+
// ── Plan mode segment ────────────────────────────────────
|
|
199
|
+
if (planModeEnabled) {
|
|
200
|
+
segments.push(theme.fg("success", "⏸ 计划模式"));
|
|
201
|
+
}else{
|
|
202
|
+
segments.push(theme.fg("error", "▶ 自动模式"));
|
|
203
|
+
}
|
|
204
|
+
|
|
187
205
|
segments.push(theme.fg("muted", quote));
|
|
188
206
|
|
|
189
207
|
// ── Version segment (rightmost) ─────────────────────────
|
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
* @author: xujianjiang
|
|
3
3
|
* 自定义扩展示例
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* 放置位置:config/agent/extensions/
|
|
6
6
|
* 安装后会复制到 ~/.pi/agent/extensions/
|
|
7
7
|
*
|
|
8
8
|
* 可以拦截内置工具、注册自定义工具和命令
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import type { ExtensionAPI } from "@
|
|
12
|
-
import type { AssistantMessage } from "@
|
|
13
|
-
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
11
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
12
|
+
import type { AssistantMessage } from "@earendil-works/pi-ai";
|
|
14
13
|
|
|
15
14
|
export default function (pi: ExtensionAPI) {
|
|
16
15
|
// === 记录开始时间 ===
|
|
@@ -23,40 +22,48 @@ export default function (pi: ExtensionAPI) {
|
|
|
23
22
|
// === 消息完成通知(只在最后一条显示)===
|
|
24
23
|
|
|
25
24
|
pi.on("agent_end", async (event, ctx) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
try {
|
|
26
|
+
// 计算耗时
|
|
27
|
+
const elapsed = Date.now() - agentStartTime;
|
|
28
|
+
let timeStr: string;
|
|
29
|
+
if (elapsed < 1000) {
|
|
30
|
+
timeStr = `${elapsed}ms`;
|
|
31
|
+
} else if (elapsed < 60000) {
|
|
32
|
+
timeStr = `${(elapsed / 1000).toFixed(1)}s`;
|
|
33
|
+
} else {
|
|
34
|
+
const mins = Math.floor(elapsed / 60000);
|
|
35
|
+
const secs = Math.floor((elapsed % 60000) / 1000);
|
|
36
|
+
timeStr = `${mins}m ${secs}s`;
|
|
37
|
+
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
// 格式化完整时间
|
|
40
|
+
const now = new Date();
|
|
41
|
+
const timeStr2 = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// agent_end 表示一轮对话结束,显示完成提示
|
|
44
|
+
ctx.ui.notify(`${timeStr2} | ✨ 消息处理完成 (${timeStr})`, "info");
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// 忽略错误(ctx 可能已过期)
|
|
47
|
+
}
|
|
45
48
|
});
|
|
46
49
|
|
|
47
50
|
// === 拦截工具调用 ===
|
|
48
51
|
|
|
49
52
|
pi.on("tool_call", async (event, ctx) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
try {
|
|
54
|
+
// 拦截 login 工具 - 阻止执行
|
|
55
|
+
if (event.toolName === "login") {
|
|
56
|
+
await ctx.ui.notify("⚠️ login 功能已禁用", "warning");
|
|
57
|
+
return { block: true, reason: "login 功能已禁用" };
|
|
58
|
+
}
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
// 拦截 logout 工具 - 阻止执行
|
|
61
|
+
if (event.toolName === "logout") {
|
|
62
|
+
await ctx.ui.notify("⚠️ logout 功能已禁用", "warning");
|
|
63
|
+
return { block: true, reason: "logout 功能已禁用" };
|
|
64
|
+
}
|
|
65
|
+
} catch (e) {
|
|
66
|
+
// 忽略错误(ctx 可能已过期)
|
|
60
67
|
}
|
|
61
68
|
});
|
|
62
69
|
|
|
@@ -66,22 +73,35 @@ export default function (pi: ExtensionAPI) {
|
|
|
66
73
|
description: "打招呼命令",
|
|
67
74
|
usage: "/hello [名字]",
|
|
68
75
|
handler: async (args, ctx) => {
|
|
69
|
-
|
|
70
|
-
|
|
76
|
+
try {
|
|
77
|
+
const name = args || "大佬,您吃了吗";
|
|
78
|
+
ctx.ui.notify(`你好,${name}!🤝`, "info");
|
|
79
|
+
} catch (e) {
|
|
80
|
+
// 忽略错误
|
|
81
|
+
}
|
|
71
82
|
},
|
|
72
83
|
});
|
|
73
84
|
|
|
74
85
|
pi.registerCommand("status", {
|
|
75
86
|
description: "显示当前会话状态",
|
|
76
87
|
handler: async (_args, ctx) => {
|
|
77
|
-
|
|
88
|
+
try {
|
|
89
|
+
// 保存需要的数据,避免多次触发 getter
|
|
90
|
+
const model = ctx.session.model?.name || "未知";
|
|
91
|
+
const workspace = ctx.session.workspace || "未知";
|
|
92
|
+
const messages = ctx.session.messages?.length || 0;
|
|
93
|
+
|
|
94
|
+
const info = `
|
|
78
95
|
📊 会话状态
|
|
79
96
|
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
97
|
+
- 当前模型:${model}
|
|
98
|
+
- 项目目录:${workspace}
|
|
99
|
+
- 消息数量:${messages}
|
|
83
100
|
`.trim();
|
|
84
|
-
|
|
101
|
+
ctx.ui.notify(info, "info");
|
|
102
|
+
} catch (e) {
|
|
103
|
+
// 忽略错误(ctx 可能已过期)
|
|
104
|
+
}
|
|
85
105
|
},
|
|
86
106
|
});
|
|
87
107
|
|
|
@@ -89,35 +109,33 @@ export default function (pi: ExtensionAPI) {
|
|
|
89
109
|
description: "清理当前会话上下文",
|
|
90
110
|
usage: "/clear",
|
|
91
111
|
handler: async (_args, ctx) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const ok = await ctx.ui.confirm("清理会话", `确定要清理当前会话的所有 ${msgCount} 条消息吗?`);
|
|
103
|
-
if (!ok) {
|
|
104
|
-
ctx.ui.notify("已取消", "info");
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
112
|
+
try {
|
|
113
|
+
// 获取当前会话条目数(在 await 前完成所有 ctx 访问)
|
|
114
|
+
const entries = ctx.sessionManager.getBranch();
|
|
115
|
+
const msgCount = entries.filter(e => e.type === "message").length;
|
|
116
|
+
const uiContext = ctx.ui; // ← 保存 UI context
|
|
117
|
+
|
|
118
|
+
if (msgCount === 0) {
|
|
119
|
+
uiContext.notify("会话已经是空的", "info");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
107
122
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
// 确认清理
|
|
124
|
+
const ok = await uiContext.confirm("清理会话", `确定要清理当前会话的所有 ${msgCount} 条消息吗?`);
|
|
125
|
+
if (!ok) {
|
|
126
|
+
uiContext.notify("已取消", "info");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
114
129
|
|
|
115
|
-
|
|
116
|
-
ctx.
|
|
117
|
-
|
|
130
|
+
// 创建新会话来清空上下文
|
|
131
|
+
await ctx.newSession({
|
|
132
|
+
withSession: async (newCtx) => {
|
|
133
|
+
newCtx.ui.notify(`✅ 已清理 ${msgCount} 条消息,进入新会话`, "success");
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
} catch (e) {
|
|
137
|
+
// 忽略错误(ctx 可能已过期)
|
|
118
138
|
}
|
|
119
|
-
|
|
120
|
-
ctx.ui.notify(`✅ 已清理 ${msgCount} 条消息,进入新会话`, "success");
|
|
121
139
|
},
|
|
122
140
|
});
|
|
123
141
|
|
|
@@ -127,8 +145,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
127
145
|
description: "退出当前会话",
|
|
128
146
|
usage: "/exit",
|
|
129
147
|
handler: async (_args, ctx) => {
|
|
130
|
-
|
|
131
|
-
|
|
148
|
+
try {
|
|
149
|
+
ctx.ui.notify("👋 再见!", "info");
|
|
150
|
+
ctx.shutdown();
|
|
151
|
+
} catch (e) {
|
|
152
|
+
// 忽略错误
|
|
153
|
+
}
|
|
132
154
|
},
|
|
133
155
|
});
|
|
134
156
|
|
|
@@ -138,28 +160,40 @@ export default function (pi: ExtensionAPI) {
|
|
|
138
160
|
description: "更新 aicode-cli 工具",
|
|
139
161
|
usage: "/update",
|
|
140
162
|
handler: async (_args, ctx) => {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
ctx.ui
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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");
|
|
163
|
+
try {
|
|
164
|
+
// ← 在 await 前保存 UI context
|
|
165
|
+
const uiContext = ctx.ui;
|
|
166
|
+
|
|
167
|
+
const ok = await uiContext.confirm("更新确认", "确定要更新 aicode-cli 吗?");
|
|
168
|
+
if (!ok) {
|
|
169
|
+
uiContext.notify("已取消", "info");
|
|
170
|
+
return;
|
|
154
171
|
}
|
|
155
|
-
|
|
172
|
+
|
|
173
|
+
uiContext.notify("🔄 正在更新 aicode-cli...", "info");
|
|
174
|
+
|
|
175
|
+
// 使用 Promise 包装 exec
|
|
176
|
+
const { exec } = await import("child_process");
|
|
177
|
+
await new Promise<void>((resolve) => {
|
|
178
|
+
exec("npm install -g @ia-ccun/code-agent-cli", (error, stdout, stderr) => {
|
|
179
|
+
if (error) {
|
|
180
|
+
uiContext.notify(`❌ 更新失败:${error.message},请重试`, "error");
|
|
181
|
+
} else {
|
|
182
|
+
uiContext.notify("✅ aicode-cli 更新成功!请重启 CLI", "success");
|
|
183
|
+
}
|
|
184
|
+
resolve();
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
} catch (e) {
|
|
188
|
+
// 忽略错误(ctx 可能已过期)
|
|
189
|
+
}
|
|
156
190
|
},
|
|
157
191
|
});
|
|
158
192
|
|
|
159
193
|
// === 注册自定义工具 ===
|
|
160
194
|
|
|
161
|
-
//
|
|
162
|
-
//
|
|
195
|
+
// 注意:注册自定义工具需要更复杂的参数定义
|
|
196
|
+
// 详情请参考:https://github.com/mariozechner/pi-coding-agent/docs/extensions.md
|
|
163
197
|
|
|
164
198
|
// === 注册 /version 命令 ===
|
|
165
199
|
|
|
@@ -200,7 +234,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
200
234
|
(latestParts[0] === localParts[0] && latestParts[1] === localParts[1] && latestParts[2] > localParts[2]);
|
|
201
235
|
|
|
202
236
|
if (needsUpdate) {
|
|
203
|
-
updateMsg = `\n\n⚠️ 发现新版本 v${localVersion} → v${latestVersion}\n
|
|
237
|
+
updateMsg = `\n\n⚠️ 发现新版本 v${localVersion} → v${latestVersion}\n 运行:npm install -g @ia-ccun/code-agent-cli`;
|
|
204
238
|
} else {
|
|
205
239
|
updateMsg = "\n\n✅ 已是最新版本";
|
|
206
240
|
}
|
|
@@ -211,8 +245,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
211
245
|
const info = `
|
|
212
246
|
📦 版本信息
|
|
213
247
|
|
|
214
|
-
|
|
215
|
-
|
|
248
|
+
当前版本:v${localVersion}
|
|
249
|
+
最新版本:v${latestVersion}
|
|
216
250
|
${updateMsg}
|
|
217
251
|
`.trim();
|
|
218
252
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Logs errors to ~/.aicode-cli/logs/aicode-error-YYYY-MM-DD.log
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { ExtensionAPI } from "@
|
|
9
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import fs from "fs";
|
|
11
11
|
import os from "os";
|
|
12
12
|
import path from "path";
|