@ia-ccun/code-agent-cli 0.0.2 → 0.0.4-8.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.
Files changed (189) hide show
  1. package/README.md +92 -11
  2. package/bin/cli.js +212 -59
  3. package/config/agent/APPEND_SYSTEM.md +46 -5
  4. package/config/agent/bin/fd +0 -0
  5. package/config/agent/bin/rg +0 -0
  6. package/config/agent/dangerous-patterns.json +106 -0
  7. package/config/agent/extensions/aicode-tips.ts +191 -0
  8. package/config/agent/extensions/bash-check.ts +227 -0
  9. package/config/agent/extensions/context-monitor.ts +275 -0
  10. package/config/agent/extensions/context.ts +1 -0
  11. package/config/agent/extensions/custom-footer.ts +33 -2
  12. package/config/agent/extensions/custom.ts +24 -91
  13. package/config/agent/extensions/error-monitor.ts +142 -0
  14. package/config/agent/extensions/msg-debug.ts +185 -0
  15. package/config/agent/extensions/review.ts +4 -0
  16. package/config/agent/extensions/working-msg.ts +39 -20
  17. package/config/agent/mcp.json +4 -0
  18. package/config/agent/models.json +16 -43
  19. package/config/agent/prompts/code-simplifier.md +51 -0
  20. package/config/agent/prompts/feat.md +2 -2
  21. package/config/agent/prompts/git-commit.md +9 -15
  22. package/config/agent/prompts/init-project.md +2 -1
  23. package/config/agent/prompts/workflow.md +3 -2
  24. package/config/agent/settings.json +17 -5
  25. package/config/agent/skills/brainstorming/SKILL.md +167 -0
  26. package/config/agent/skills/brainstorming/scripts/frame-template.html +214 -0
  27. package/config/agent/skills/brainstorming/scripts/helper.js +88 -0
  28. package/config/agent/skills/brainstorming/scripts/server.cjs +338 -0
  29. package/config/agent/skills/brainstorming/scripts/start-server.sh +153 -0
  30. package/config/agent/skills/brainstorming/scripts/stop-server.sh +55 -0
  31. package/config/agent/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  32. package/config/agent/skills/brainstorming/visual-companion.md +286 -0
  33. package/config/agent/skills/code-review/SKILL.md +4 -2
  34. package/config/agent/skills/commit/SKILL.md +10 -5
  35. package/config/agent/skills/csv-data-summarizer/SKILL.md +2 -1
  36. package/config/agent/skills/design-md/README.md +34 -0
  37. package/config/agent/skills/design-md/SKILL.md +172 -0
  38. package/config/agent/skills/design-md/examples/DESIGN.md +154 -0
  39. package/config/agent/skills/dispatching-parallel-agents/SKILL.md +185 -0
  40. package/config/agent/skills/executing-plans/SKILL.md +73 -0
  41. package/config/agent/skills/find-skills/SKILL.md +5 -1
  42. package/config/agent/skills/finishing-a-development-branch/SKILL.md +204 -0
  43. package/config/agent/skills/fireworks-tech-graph/LICENSE +21 -0
  44. package/config/agent/skills/fireworks-tech-graph/README.md +528 -0
  45. package/config/agent/skills/fireworks-tech-graph/README.zh.md +499 -0
  46. package/config/agent/skills/fireworks-tech-graph/SKILL.md +537 -0
  47. package/config/agent/skills/fireworks-tech-graph/agentloop-core.svg +101 -0
  48. package/config/agent/skills/fireworks-tech-graph/agents/openai.yaml +4 -0
  49. package/config/agent/skills/fireworks-tech-graph/assets/samples/sample-style1-flat.png +0 -0
  50. package/config/agent/skills/fireworks-tech-graph/assets/samples/sample-style2-dark.png +0 -0
  51. package/config/agent/skills/fireworks-tech-graph/assets/samples/sample-style3-blueprint.png +0 -0
  52. package/config/agent/skills/fireworks-tech-graph/assets/samples/sample-style4-notion.png +0 -0
  53. package/config/agent/skills/fireworks-tech-graph/assets/samples/sample-style5-glass.png +0 -0
  54. package/config/agent/skills/fireworks-tech-graph/assets/samples/sample-style6-claude.png +0 -0
  55. package/config/agent/skills/fireworks-tech-graph/assets/samples/sample-style7-openai.png +0 -0
  56. package/config/agent/skills/fireworks-tech-graph/fixtures/agent-memory-types-style4.json +181 -0
  57. package/config/agent/skills/fireworks-tech-graph/fixtures/api-flow-style7.json +40 -0
  58. package/config/agent/skills/fireworks-tech-graph/fixtures/mem0-style1.json +297 -0
  59. package/config/agent/skills/fireworks-tech-graph/fixtures/microservices-style3.json +64 -0
  60. package/config/agent/skills/fireworks-tech-graph/fixtures/multi-agent-style5.json +45 -0
  61. package/config/agent/skills/fireworks-tech-graph/fixtures/system-architecture-style6.json +48 -0
  62. package/config/agent/skills/fireworks-tech-graph/fixtures/tool-call-style2.json +182 -0
  63. package/config/agent/skills/fireworks-tech-graph/package.json +42 -0
  64. package/config/agent/skills/fireworks-tech-graph/references/icons.md +406 -0
  65. package/config/agent/skills/fireworks-tech-graph/references/style-1-flat-icon.md +108 -0
  66. package/config/agent/skills/fireworks-tech-graph/references/style-2-dark-terminal.md +107 -0
  67. package/config/agent/skills/fireworks-tech-graph/references/style-3-blueprint.md +113 -0
  68. package/config/agent/skills/fireworks-tech-graph/references/style-4-notion-clean.md +94 -0
  69. package/config/agent/skills/fireworks-tech-graph/references/style-5-glassmorphism.md +125 -0
  70. package/config/agent/skills/fireworks-tech-graph/references/style-6-claude-official.md +209 -0
  71. package/config/agent/skills/fireworks-tech-graph/references/style-7-openai.md +215 -0
  72. package/config/agent/skills/fireworks-tech-graph/references/style-diagram-matrix.md +135 -0
  73. package/config/agent/skills/fireworks-tech-graph/references/svg-layout-best-practices.md +100 -0
  74. package/config/agent/skills/fireworks-tech-graph/scripts/README.md +244 -0
  75. package/config/agent/skills/fireworks-tech-graph/scripts/generate-diagram.sh +157 -0
  76. package/config/agent/skills/fireworks-tech-graph/scripts/generate-from-template.py +1556 -0
  77. package/config/agent/skills/fireworks-tech-graph/scripts/test-all-styles.sh +135 -0
  78. package/config/agent/skills/fireworks-tech-graph/scripts/validate-svg.sh +292 -0
  79. package/config/agent/skills/fireworks-tech-graph/templates/agent-architecture.svg +28 -0
  80. package/config/agent/skills/fireworks-tech-graph/templates/architecture.svg +23 -0
  81. package/config/agent/skills/fireworks-tech-graph/templates/comparison-matrix.svg +14 -0
  82. package/config/agent/skills/fireworks-tech-graph/templates/data-flow.svg +28 -0
  83. package/config/agent/skills/fireworks-tech-graph/templates/er-diagram.svg +21 -0
  84. package/config/agent/skills/fireworks-tech-graph/templates/flowchart.svg +21 -0
  85. package/config/agent/skills/fireworks-tech-graph/templates/sequence.svg +20 -0
  86. package/config/agent/skills/fireworks-tech-graph/templates/state-machine.svg +20 -0
  87. package/config/agent/skills/fireworks-tech-graph/templates/timeline.svg +19 -0
  88. package/config/agent/skills/fireworks-tech-graph/templates/use-case.svg +21 -0
  89. package/config/agent/skills/frontend-design/SKILL.md +4 -1
  90. package/config/agent/skills/hello/SKILL.md +5 -2
  91. package/config/agent/skills/impeccable/adapt/SKILL.md +204 -0
  92. package/config/agent/skills/impeccable/animate/SKILL.md +177 -0
  93. package/config/agent/skills/impeccable/arrange/SKILL.md +127 -0
  94. package/config/agent/skills/impeccable/audit/SKILL.md +128 -0
  95. package/config/agent/skills/impeccable/bolder/SKILL.md +119 -0
  96. package/config/agent/skills/impeccable/clarify/SKILL.md +185 -0
  97. package/config/agent/skills/impeccable/colorize/SKILL.md +145 -0
  98. package/config/agent/skills/impeccable/critique/SKILL.md +122 -0
  99. package/config/agent/skills/impeccable/delight/SKILL.md +306 -0
  100. package/config/agent/skills/impeccable/distill/SKILL.md +124 -0
  101. package/config/agent/skills/impeccable/extract/SKILL.md +94 -0
  102. package/config/agent/skills/impeccable/frontend-design/reference/color-and-contrast.md +132 -0
  103. package/config/agent/skills/impeccable/frontend-design/reference/interaction-design.md +123 -0
  104. package/config/agent/skills/impeccable/frontend-design/reference/motion-design.md +99 -0
  105. package/config/agent/skills/impeccable/frontend-design/reference/responsive-design.md +114 -0
  106. package/config/agent/skills/impeccable/frontend-design/reference/spatial-design.md +100 -0
  107. package/config/agent/skills/impeccable/frontend-design/reference/typography.md +133 -0
  108. package/config/agent/skills/impeccable/frontend-design/reference/ux-writing.md +107 -0
  109. package/config/agent/skills/impeccable/harden/SKILL.md +357 -0
  110. package/config/agent/skills/impeccable/normalize/SKILL.md +73 -0
  111. package/config/agent/skills/impeccable/onboard/SKILL.md +248 -0
  112. package/config/agent/skills/impeccable/optimize/SKILL.md +268 -0
  113. package/config/agent/skills/impeccable/overdrive/SKILL.md +144 -0
  114. package/config/agent/skills/impeccable/polish/SKILL.md +205 -0
  115. package/config/agent/skills/impeccable/quieter/SKILL.md +105 -0
  116. package/config/agent/skills/impeccable/teach-impeccable/SKILL.md +71 -0
  117. package/config/agent/skills/impeccable/typeset/SKILL.md +118 -0
  118. package/config/agent/skills/librarian/SKILL.md +5 -1
  119. package/config/agent/skills/markdown-to-html/SKILL.md +5 -2
  120. package/config/agent/skills/owasp-security/SKILL.md +539 -0
  121. package/config/agent/skills/pr/SKILL.md +5 -2
  122. package/config/agent/skills/receiving-code-review/SKILL.md +216 -0
  123. package/config/agent/skills/refactor/SKILL.md +5 -2
  124. package/config/agent/skills/requesting-code-review/SKILL.md +108 -0
  125. package/config/agent/skills/requesting-code-review/code-reviewer.md +146 -0
  126. package/config/agent/skills/session-learning/SKILL.md +185 -0
  127. package/config/agent/skills/skill-creator/SKILL.md +339 -213
  128. package/config/agent/skills/skill-creator/agents/analyzer.md +274 -0
  129. package/config/agent/skills/skill-creator/agents/comparator.md +202 -0
  130. package/config/agent/skills/skill-creator/agents/grader.md +223 -0
  131. package/config/agent/skills/skill-creator/assets/eval_review.html +146 -0
  132. package/config/agent/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  133. package/config/agent/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  134. package/config/agent/skills/skill-creator/references/schemas.md +430 -0
  135. package/config/agent/skills/skill-creator/scripts/__init__.py +0 -0
  136. package/config/agent/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  137. package/config/agent/skills/skill-creator/scripts/generate_report.py +326 -0
  138. package/config/agent/skills/skill-creator/scripts/improve_description.py +248 -0
  139. package/config/agent/skills/skill-creator/scripts/package_skill.py +33 -7
  140. package/config/agent/skills/skill-creator/scripts/quick_validate.py +11 -3
  141. package/config/agent/skills/skill-creator/scripts/run_eval.py +310 -0
  142. package/config/agent/skills/skill-creator/scripts/run_loop.py +332 -0
  143. package/config/agent/skills/skill-creator/scripts/utils.py +47 -0
  144. package/config/agent/skills/subagent-driven-development/SKILL.md +280 -0
  145. package/config/agent/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
  146. package/config/agent/skills/subagent-driven-development/implementer-prompt.md +113 -0
  147. package/config/agent/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  148. package/config/agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
  149. package/config/agent/skills/systematic-debugging/SKILL.md +300 -0
  150. package/config/agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  151. package/config/agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
  152. package/config/agent/skills/systematic-debugging/defense-in-depth.md +122 -0
  153. package/config/agent/skills/systematic-debugging/find-polluter.sh +63 -0
  154. package/config/agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
  155. package/config/agent/skills/systematic-debugging/test-academic.md +14 -0
  156. package/config/agent/skills/systematic-debugging/test-pressure-1.md +58 -0
  157. package/config/agent/skills/systematic-debugging/test-pressure-2.md +68 -0
  158. package/config/agent/skills/systematic-debugging/test-pressure-3.md +69 -0
  159. package/config/agent/skills/test-driven-development/SKILL.md +375 -0
  160. package/config/agent/skills/test-driven-development/testing-anti-patterns.md +299 -0
  161. package/config/agent/skills/ui-ux-pro-max/SKILL.md +4 -1
  162. package/config/agent/skills/unit-test/SKILL.md +4 -2
  163. package/config/agent/skills/using-git-worktrees/SKILL.md +222 -0
  164. package/config/agent/skills/using-superpowers/SKILL.md +118 -0
  165. package/config/agent/skills/using-superpowers/references/codex-tools.md +25 -0
  166. package/config/agent/skills/using-superpowers/references/gemini-tools.md +33 -0
  167. package/config/agent/skills/verification-before-completion/SKILL.md +142 -0
  168. package/config/agent/skills/writing-plans/SKILL.md +148 -0
  169. package/config/agent/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  170. package/config/agent/skills/writing-skills/SKILL.md +669 -0
  171. package/config/agent/skills/writing-skills/anthropic-best-practices.md +1150 -0
  172. package/config/agent/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  173. package/config/agent/skills/writing-skills/graphviz-conventions.dot +172 -0
  174. package/config/agent/skills/writing-skills/persuasion-principles.md +187 -0
  175. package/config/agent/skills/writing-skills/render-graphs.js +168 -0
  176. package/config/agent/skills/writing-skills/testing-skills-with-subagents.md +384 -0
  177. package/config.json +23 -2
  178. package/dist/banner.js +3 -3
  179. package/dist/banner.js.map +1 -1
  180. package/package.json +20 -15
  181. package/scripts/banner.txt +6 -0
  182. package/scripts/postinstall.js +203 -11
  183. package/config/agent/prompts/git-rollback.md +0 -91
  184. package/config/agent/prompts/git-worktree.md +0 -277
  185. package/config/agent/prompts/help.md +0 -10
  186. package/config/agent/skills/github/SKILL.md +0 -47
  187. package/config/agent/skills/skill-creator/references/output-patterns.md +0 -82
  188. package/config/agent/skills/skill-creator/references/workflows.md +0 -28
  189. package/config/agent/skills/skill-creator/scripts/init_skill.py +0 -303
@@ -0,0 +1,191 @@
1
+ /**
2
+ * @author: xujianjiang
3
+ * Aicode Tips Extension — 在边框下方、状态栏上方随机显示使用技巧
4
+ *
5
+ * 显示 10 秒后消失,3 秒后显示下一条
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
+ // 常用Prompt提示
47
+ "/code-simplifier 自动简化刚修改的代码,提升清晰度和一致性",
48
+ "/feat 新功能开发,支持需求规划→讨论迭代→执行实施完整流程(推荐使用)",
49
+ "/git-commit 分析Git改动并生成Conventional Commits规范提交信息(推荐使用)",
50
+ "/init-project 初始化项目AI上下文,生成根级和模块级CLAUDE.md索引",
51
+ "/workflow 专业开发者6阶段结构化工作流(研究→构思→计划→执行→优化→评审)",
52
+ // 常用技能提示
53
+ "/skill:brainstorming 探索用户意图、需求分析和方案设计",
54
+ "/skill:code-review 执行全面的代码质量/安全/性能审查(推荐使用)",
55
+ "/skill:commit 分析代码变更并生成规范的Git提交信息",
56
+ "/skill:frontend-design 创建高质量生产级前端界面(推荐使用)",
57
+ "/skill:owasp-security 遵循OWASP Top 10的安全编码实践(推荐使用)",
58
+ "/skill:receiving-code-review 技术性处理代码评审反馈并验证(推荐使用)",
59
+ "/skill:requesting-code-review 请求代码评审确保满足合并要求",
60
+ "/skill:unit-test 为选定的代码文件生成单元测试",
61
+ "/skill:verification-before-completion 完成前验证实际工作是否完整",
62
+ "/skill:writing-plans 为多步骤任务编写详细的实施计划(推荐使用)",
63
+ "/skill:writing-skills 创建、修改和优化Agent技能并测量性能",
64
+ "/skill:session-learning 总结会话经验并沉淀为可复用的技能",
65
+ "/skill:test-driven-development 先写测试再写实现的TDD开发模式",
66
+ "/skill:subagent-driven-development 通过派发子Agent执行复杂实施计划",
67
+ "/skill:dispatching-parallel-agents 并行分发多个独立任务无共享状态",
68
+ "/skill:csv-data-summarizer 分析CSV文件并生成统计和可视化图表",
69
+ "/skill:executing-plans 执行带有检查点的书面实施计划",
70
+ "/skill:frontend-slides 使用HTML/CSS创建精美的演示幻灯片",
71
+ "/skill:markdown-to-html 将Markdown文档转换为精美的HTML页面",
72
+ "/skill:refactor 重构代码提升可读性和可维护性保持功能不变",
73
+ "/skill:skill-creator 创建、修改和提升技能性能的工具",
74
+ "/skill:ui-ux-pro-max 提供50种设计风格和21种配色方案的设计助手(推荐使用)",
75
+ // 常用技能提示
76
+ "/btw 并行侧边对话,可在不中断主流程的情况下进行临时讨论或查询 ",
77
+ "/rewind 回退到任意工具执行前的状态,支持快照恢复和撤销重做 ",
78
+ "/mcp 连接现有的MCP服务器(如xx平台、企业微信等等),扩展AI能力支持多种外部工具和服务 ",
79
+ // 消息传递模式提示
80
+ "Enter 插话消息 - 在工具执行后立即发送,中断AI思考流程",
81
+ "Alt+Enter 排队消息 - 等待AI完全结束后发送,不中断AI工作",
82
+ "Escape 中断当前AI并恢复编辑器中的排队消息",
83
+ "Alt+Up 查看并编辑所有排队的消息",
84
+ "插话消息会打断AI正在执行的工具,等待响应",
85
+ "排队消息静默等待,AI空闲时自动发送",
86
+ "可在 /settings 中调整消息发送模式和行为偏好",
87
+ // 联系方式提示
88
+ "⚠️ 任何疑问或需求可联系 xujianjiang,支持需求对接开发、系统集成与扩展",
89
+ "⚠️ 内网手册参考 UniDoc《2026.03 AICode Agent CLI编码智能体使用手册》",
90
+ "⚠️ LLM API 4xx/5xx 错误时请确认模型配置是否正确,或在企微群咨询 jiangchi、maliang",
91
+ ];
92
+
93
+ export default function (pi: ExtensionAPI) {
94
+ let currentTipIndex = -1;
95
+ let autoHideTimeoutId: NodeJS.Timeout | undefined;
96
+ let autoShowTimeoutId: NodeJS.Timeout | undefined;
97
+ let currentCtx: ExtensionContext | undefined;
98
+ let isAutoPlaying = false;
99
+
100
+ // 基于 #49bccf (73, 188, 207) 的随机颜色生成
101
+ const getRandomTipColor = (): string => {
102
+ const baseR = 73, baseG = 188, baseB = 207;
103
+ const offset = 20; // 增大偏移范围,透明度降低
104
+ const r = Math.max(0, Math.min(255, baseR + Math.floor(Math.random() * offset * 2 - offset)));
105
+ const g = Math.max(0, Math.min(255, baseG + Math.floor(Math.random() * offset * 2 - offset)));
106
+ const b = Math.max(0, Math.min(255, baseB + Math.floor(Math.random() * offset * 2 - offset)));
107
+ return `\x1b[38;2;${r};${g};${b}m`;
108
+ };
109
+
110
+ const hideTip = () => {
111
+ if (!currentCtx?.hasUI) return;
112
+ currentCtx.ui.setWidget("aicode-tips", [], { placement: "aboveEditor" });
113
+ };
114
+
115
+ const clearAllTimers = () => {
116
+ if (autoHideTimeoutId) {
117
+ clearTimeout(autoHideTimeoutId);
118
+ autoHideTimeoutId = undefined;
119
+ }
120
+ if (autoShowTimeoutId) {
121
+ clearTimeout(autoShowTimeoutId);
122
+ autoShowTimeoutId = undefined;
123
+ }
124
+ };
125
+
126
+ const padRight = (str: string, width: number): string => {
127
+ const chinese = (str.match(/[\u4e00-\u9fff]/g) || []).length;
128
+ const ascii = str.length - chinese;
129
+ const fullWidth = chinese * 2 + ascii;
130
+ const padding = Math.max(0, width - fullWidth);
131
+ return str + " ".repeat(padding);
132
+ };
133
+
134
+ const showRandomTip = () => {
135
+ if (!currentCtx?.hasUI) return;
136
+
137
+ // 清除之前的定时器
138
+ clearAllTimers();
139
+
140
+ let randomIndex = Math.floor(Math.random() * AICODE_TIPS.length);
141
+ if (randomIndex === currentTipIndex && AICODE_TIPS.length > 1) {
142
+ randomIndex = (randomIndex + 1) % AICODE_TIPS.length;
143
+ }
144
+ currentTipIndex = randomIndex;
145
+ const tip = AICODE_TIPS[randomIndex];
146
+ // 使用随机颜色
147
+ const color = getRandomTipColor();
148
+ const coloredTip = `${color}tips: ${tip}\x1b[0m`;
149
+ currentCtx.ui.setWidget("aicode-tips", [coloredTip], { placement: "aboveEditor" });
150
+
151
+ // 自动轮播:10秒后隐藏,隐藏后3秒显示下一条
152
+ if (isAutoPlaying) {
153
+ autoHideTimeoutId = setTimeout(() => {
154
+ hideTip();
155
+ autoShowTimeoutId = setTimeout(showRandomTip, 3000);
156
+ }, 10000);
157
+ }
158
+ };
159
+
160
+ const startAutoPlay = () => {
161
+ isAutoPlaying = true;
162
+ showRandomTip();
163
+ };
164
+
165
+ const stopAutoPlay = () => {
166
+ isAutoPlaying = false;
167
+ clearAllTimers();
168
+ };
169
+
170
+ // 会话开始时启动自动轮播
171
+ pi.on("session_start", (_event, ctx) => {
172
+ currentCtx = ctx;
173
+ startAutoPlay();
174
+ });
175
+
176
+ // 会话结束时清理
177
+ pi.on("session_shutdown", () => {
178
+ stopAutoPlay();
179
+ currentCtx?.ui.setWidget("aicode-tips", undefined);
180
+ currentCtx = undefined;
181
+ });
182
+
183
+ // 手动切换技巧
184
+ pi.registerCommand("tip", {
185
+ description: "显示一个新的 aicode 使用技巧",
186
+ handler: async (_args, ctx) => {
187
+ currentCtx = ctx;
188
+ showRandomTip();
189
+ },
190
+ });
191
+ }
@@ -0,0 +1,227 @@
1
+ /**
2
+ * @author: xujianjiang
3
+ * Bash 命令危险检测扩展
4
+ *
5
+ * 放置位置: config/agent/extensions/
6
+ * 安装后会复制到 ~/.aicode-cli/agent/extensions/
7
+ *
8
+ * 拦截危险 bash 命令,执行前需要用户回答数学题验证
9
+ *
10
+ * 危险模式配置: config/agent/dangerous-patterns.json
11
+ */
12
+
13
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
14
+ import { readFileSync, existsSync } from "fs";
15
+ import { join } from "path";
16
+ import { homedir } from "os";
17
+
18
+ // === 加载 JSON 配置文件 ===
19
+ interface DangerPattern {
20
+ pattern: string;
21
+ commandPrefix: string;
22
+ name: string;
23
+ risk: string;
24
+ description: string;
25
+ impact: string;
26
+ explanation: string;
27
+ }
28
+
29
+ interface DangerPatternsConfig {
30
+ patterns: DangerPattern[];
31
+ }
32
+
33
+ function loadDangerPatterns(): DangerPattern[] {
34
+ const configPath = join(homedir(), ".aicode-cli", "agent", "dangerous-patterns.json");
35
+
36
+ if (existsSync(configPath)) {
37
+ try {
38
+ const content = readFileSync(configPath, "utf-8");
39
+ const config: DangerPatternsConfig = JSON.parse(content);
40
+ return config.patterns || [];
41
+ } catch (e) {
42
+ console.error(`[bash-check] Failed to load config from ${configPath}:`, e);
43
+ }
44
+ }
45
+
46
+ console.warn("[bash-check] No dangerous-patterns.json found, using empty patterns");
47
+ return [];
48
+ }
49
+
50
+ // === 编译危险模式(同步加载)===
51
+ const patterns = loadDangerPatterns();
52
+ const compiledPatterns = patterns.map(p => ({
53
+ ...p,
54
+ compiled: new RegExp(p.pattern, ""),
55
+ }));
56
+
57
+ // === 生成数学验证题目 ===
58
+ function generateMathProblem(): { question: string, answer: number } {
59
+ const operators = ['+', '-'];
60
+ const operator = operators[Math.floor(Math.random() * operators.length)];
61
+ let a = Math.floor(Math.random() * 10) + 1;
62
+ let b = Math.floor(Math.random() * 10) + 1;
63
+
64
+ // 确保减法结果非负
65
+ if (operator === '-' && a < b) {
66
+ [a, b] = [b, a];
67
+ }
68
+
69
+ const question = `${a} ${operator} ${b} = ?`;
70
+ const answer = operator === '+' ? a + b : a - b;
71
+
72
+ return { question, answer };
73
+ }
74
+
75
+ export default function (pi: ExtensionAPI) {
76
+ // === 拦截 bash 工具 - 检查危险操作 ===
77
+ pi.on("tool_call", async (event, ctx) => {
78
+ if (event.toolName !== "bash") return;
79
+
80
+ let command = event.input.command || "";
81
+
82
+ // 过滤掉 git commit -m 后面的 message 内容,只检查实际命令部分
83
+ const commitMsgMatch = command.match(/^(git\s+commit\s+.*?-m\s+)(.*)$/s);
84
+ if (commitMsgMatch) {
85
+ // 只检查 -m 之前的命令部分,忽略 message 内容
86
+ command = commitMsgMatch[1];
87
+ }
88
+
89
+ // 检查是否匹配危险模式
90
+ for (const danger of compiledPatterns) {
91
+ // 1. 首先检查命令是否以指定前缀开头
92
+ const trimmedCmd = command.trim();
93
+ if (!trimmedCmd.startsWith(danger.commandPrefix)) continue;
94
+
95
+ // 2. 然后检查是否匹配危险模式(使用编译后的正则)
96
+ if (!danger.compiled.test(command)) continue;
97
+
98
+ // 解析命令中的路径参数
99
+ const { readdirSync, statSync, existsSync } = await import("fs");
100
+ const details: string[] = [];
101
+
102
+ // 提取相关路径
103
+ const pathMatch = command.match(/(['"])([^\1]+)\1|\S+(?=\s|$)/g);
104
+ if (pathMatch) {
105
+ for (const p of pathMatch) {
106
+ const cleanPath = p.replace(/^['"]|['"]$/g, '').trim();
107
+ if (cleanPath && cleanPath.length > 1 && cleanPath.length < 200) {
108
+ try {
109
+ if (existsSync(cleanPath)) {
110
+ const stat = statSync(cleanPath);
111
+ if (stat.isDirectory()) {
112
+ const files = readdirSync(cleanPath);
113
+ details.push(`📁 ${cleanPath}/ (${files.length} 个文件)`);
114
+ } else {
115
+ details.push(`📄 ${cleanPath}`);
116
+ }
117
+ }
118
+ } catch (e) {
119
+ // 忽略读取错误
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ // 构建确认消息
126
+ const truncatedCmd = command.length > 100 ? command.slice(0, 100) + '...' : command;
127
+ const fileInfo = details.length > 0
128
+ ? `\n\n🗂️ 将操作的文件:\n${details.slice(0, 5).join('\n')}${details.length > 5 ? `\n... 还有 ${details.length - 5} 个` : ''}`
129
+ : '';
130
+
131
+ // 让用户选择操作
132
+ const choice = await ctx.ui.select(
133
+ `${danger.risk} 危险操作检测: ${danger.name}`,
134
+ [
135
+ `⚠️ 强制执行 (${danger.name})`,
136
+ "🔍 让 AI 解读此命令",
137
+ "❌ 取消操作",
138
+ ]
139
+ );
140
+
141
+ if (!choice) {
142
+ ctx.ui.notify("⛔ 操作已取消", "warning");
143
+ return { block: true, reason: "用户取消" };
144
+ }
145
+
146
+ if (choice.includes("取消")) {
147
+ ctx.ui.notify("⛔ 操作已取消", "warning");
148
+ return { block: true, reason: "用户取消" };
149
+ }
150
+
151
+ if (choice.includes("AI 解读")) {
152
+ // 显示详细解释
153
+ const explanation = `
154
+ 📋 命令: ${danger.name}
155
+
156
+ 📝 描述: ${danger.description}
157
+
158
+ ⚠️ 风险等级: ${danger.risk}
159
+
160
+ 💥 影响: ${danger.impact}
161
+
162
+ 📖 详细解释:
163
+ ${danger.explanation}
164
+
165
+ 🗂️ 涉及路径:${fileInfo || '\n (无)'}`.trim();
166
+
167
+ ctx.ui.notify(explanation, "info");
168
+
169
+ // 解释后再让用户选择
170
+ const confirmChoice = await ctx.ui.select(
171
+ "请确认操作",
172
+ [
173
+ `⚠️ 我已了解风险,继续执行 (${danger.name})`,
174
+ "❌ 取消操作",
175
+ ]
176
+ );
177
+
178
+ if (!confirmChoice || confirmChoice.includes("取消")) {
179
+ ctx.ui.notify("⛔ 操作已取消", "warning");
180
+ return { block: true, reason: "用户取消" };
181
+ }
182
+
183
+ // 执行数学验证
184
+ const mathProblem = generateMathProblem();
185
+ const mathAnswer = await ctx.ui.input(
186
+ `🔴 最终验证 - 请回答数学题\n\n⚠️ 命令: ${danger.name}\n\n${truncatedCmd}${fileInfo}\n\n📝 请计算: ${mathProblem.question}`,
187
+ "输入答案后回车"
188
+ );
189
+
190
+ if (!mathAnswer) {
191
+ ctx.ui.notify("⛔ 操作已取消", "warning");
192
+ return { block: true, reason: "用户未输入答案" };
193
+ }
194
+
195
+ const userAnswer = parseInt(mathAnswer.trim(), 10);
196
+ if (isNaN(userAnswer) || userAnswer !== mathProblem.answer) {
197
+ ctx.ui.notify(`⛔ 答案错误!正确答案是: ${mathProblem.answer}`, "error");
198
+ return { block: true, reason: "数学验证失败" };
199
+ }
200
+
201
+ ctx.ui.notify(`✅ 验证通过!执行: ${danger.name}`, "success");
202
+ return;
203
+ }
204
+
205
+ // 直接执行 - 数学验证
206
+ const mathProblem = generateMathProblem();
207
+ const mathAnswer = await ctx.ui.input(
208
+ `🔴 最终验证 - 请回答数学题\n\n⚠️ 命令: ${danger.name}\n\n${truncatedCmd}${fileInfo}\n\n📝 请计算: ${mathProblem.question}`,
209
+ "输入答案后回车"
210
+ );
211
+
212
+ if (!mathAnswer) {
213
+ ctx.ui.notify("⛔ 操作已取消", "warning");
214
+ return { block: true, reason: "用户未输入答案" };
215
+ }
216
+
217
+ const userAnswer = parseInt(mathAnswer.trim(), 10);
218
+ if (isNaN(userAnswer) || userAnswer !== mathProblem.answer) {
219
+ ctx.ui.notify(`⛔ 答案错误!正确答案是: ${mathProblem.answer}`, "error");
220
+ return { block: true, reason: "数学验证失败" };
221
+ }
222
+
223
+ ctx.ui.notify(`✅ 验证通过!执行: ${danger.name}`, "success");
224
+ break;
225
+ }
226
+ });
227
+ }
@@ -0,0 +1,275 @@
1
+ /**
2
+ * @author: xujianjiang
3
+ * Context Monitor Extension — 自动检测上下文大小并在接近阈值时警告
4
+ *
5
+ * 功能:
6
+ * 1. 自动检测每轮对话后的上下文使用情况
7
+ * 2. 在超过阈值时自动发出不同级别的警告
8
+ * 3. 提供清理建议和上下文统计
9
+ *
10
+ * 阈值级别:
11
+ * - 70% : info 级别提示
12
+ * - 80% : warning 级别警告
13
+ * - 90% : error 级别严重警告
14
+ * - 100% : 阻止继续并强制提示压缩
15
+ */
16
+
17
+ import type { ExtensionAPI, ExtensionContext, ToolResultEvent } from "@mariozechner/pi-coding-agent";
18
+
19
+ interface ContextThresholds {
20
+ info: number; // 70%
21
+ warning: number; // 80%
22
+ error: number; // 90%
23
+ critical: number; // 100%
24
+ }
25
+
26
+ const DEFAULT_THRESHOLDS: ContextThresholds = {
27
+ info: 70,
28
+ warning: 80,
29
+ error: 90,
30
+ critical: 100,
31
+ };
32
+
33
+ interface ContextStats {
34
+ contextWindow: number;
35
+ usedTokens: number;
36
+ remainingTokens: number;
37
+ percent: number;
38
+ systemTokens: number;
39
+ toolsTokens: number;
40
+ conversationTokens: number;
41
+ }
42
+
43
+ function estimateTokens(text: string): number {
44
+ return Math.max(0, Math.ceil(text.length / 4));
45
+ }
46
+
47
+ function formatTokens(n: number): string {
48
+ if (n < 1000) return n.toString();
49
+ if (n < 1000000) return `${(n / 1000).toFixed(1)}k`;
50
+ return `${(n / 1000000).toFixed(1)}M`;
51
+ }
52
+
53
+ function getContextLevel(percent: number): "normal" | "info" | "warning" | "error" | "critical" {
54
+ if (percent >= DEFAULT_THRESHOLDS.critical) return "critical";
55
+ if (percent >= DEFAULT_THRESHOLDS.error) return "error";
56
+ if (percent >= DEFAULT_THRESHOLDS.warning) return "warning";
57
+ if (percent >= DEFAULT_THRESHOLDS.info) return "info";
58
+ return "normal";
59
+ }
60
+
61
+ function getContextMessage(stats: ContextStats): { level: "info" | "warning" | "error"; title: string; body: string } {
62
+ const level = getContextLevel(stats.percent);
63
+ const contextBar = renderContextBar(stats.percent);
64
+
65
+ let title: string;
66
+ let body: string;
67
+
68
+ switch (level) {
69
+ case "critical":
70
+ title = "🚨 上下文已满!";
71
+ body = `上下文窗口已完全使用! (${contextBar})\n剩余: ${formatTokens(stats.remainingTokens)} tokens\n\n⚠️ 请立即使用 /clear 清理会话或开启新会话!`;
72
+ break;
73
+ case "error":
74
+ title = "⚠️ 上下文即将耗尽";
75
+ body = `上下文使用: ${contextBar}\n已用: ${formatTokens(stats.usedTokens)} / ${formatTokens(stats.contextWindow)}\n剩余: ${formatTokens(stats.remainingTokens)} tokens\n\n💡 建议: 使用 /clear 清理会话`;
76
+ break;
77
+ case "warning":
78
+ title = "📊 上下文使用较高";
79
+ body = `上下文使用: ${contextBar}\n已用: ${formatTokens(stats.usedTokens)} / ${formatTokens(stats.contextWindow)}\n剩余: ${formatTokens(stats.remainingTokens)} tokens\n\n💡 提示: 可以考虑压缩会话`;
80
+ break;
81
+ case "info":
82
+ title = "ℹ️ 上下文使用提醒";
83
+ body = `上下文使用: ${contextBar}\n已用: ${formatTokens(stats.usedTokens)} / ${formatTokens(stats.contextWindow)}\n\n💡 提示: 上下文已使用过半,注意控制对话长度`;
84
+ break;
85
+ default:
86
+ title = "✅ 上下文状态正常";
87
+ body = `上下文使用: ${contextBar}\n已用: ${formatTokens(stats.usedTokens)} / ${formatTokens(stats.contextWindow)}\n剩余: ${formatTokens(stats.remainingTokens)} tokens`;
88
+ }
89
+
90
+ return { level, title, body };
91
+ }
92
+
93
+ function renderContextBar(percent: number, width: number = 20): string {
94
+ const filled = Math.min(width, Math.round((percent / 100) * width));
95
+ const empty = width - filled;
96
+
97
+ const filledChar = "█";
98
+ const emptyChar = "░";
99
+
100
+ return filledChar.repeat(filled) + emptyChar.repeat(empty) + ` ${percent.toFixed(1)}%`;
101
+ }
102
+
103
+ export default function contextMonitorExtension(pi: ExtensionAPI) {
104
+ // 配置:是否启用自动警告
105
+ let autoWarnEnabled = true;
106
+ let lastWarnedLevel: string = "normal";
107
+ let warnCooldown = 0; // 防止连续警告
108
+
109
+ /**
110
+ * 获取当前上下文统计
111
+ */
112
+ function getContextStats(ctx: ExtensionContext): ContextStats | null {
113
+ const usage = ctx.getContextUsage();
114
+ if (!usage) return null;
115
+
116
+ const contextWindow = usage.contextWindow || ctx.model?.contextWindow || 0;
117
+ if (contextWindow === 0) return null;
118
+
119
+ const usedTokens = usage.tokens || 0;
120
+ const remainingTokens = Math.max(0, contextWindow - usedTokens);
121
+ const percent = (usedTokens / contextWindow) * 100;
122
+
123
+ // 估算各部分 token
124
+ const systemPrompt = ctx.getSystemPrompt();
125
+ const systemTokens = systemPrompt ? estimateTokens(systemPrompt) : 0;
126
+ const toolsTokens = Math.round(
127
+ pi.getActiveTools().reduce((sum, name) => {
128
+ const info = pi.getAllTools().find((t) => t.name === name);
129
+ return sum + estimateTokens(`${name}\n${info?.description || ""}`);
130
+ }, 0) * 1.5
131
+ );
132
+ const conversationTokens = Math.max(0, usedTokens - systemTokens - toolsTokens);
133
+
134
+ return {
135
+ contextWindow,
136
+ usedTokens,
137
+ remainingTokens,
138
+ percent,
139
+ systemTokens,
140
+ toolsTokens,
141
+ conversationTokens,
142
+ };
143
+ }
144
+
145
+ /**
146
+ * 处理上下文警告
147
+ */
148
+ async function handleContextWarning(stats: ContextStats, ctx: ExtensionContext) {
149
+ if (!autoWarnEnabled) return;
150
+
151
+ const level = getContextLevel(stats.percent);
152
+ const message = getContextMessage(stats);
153
+
154
+ // 避免重复警告(同级别)
155
+ if (level === lastWarnedLevel && warnCooldown > 0) {
156
+ warnCooldown--;
157
+ return;
158
+ }
159
+
160
+ // 只在有新级别时警告
161
+ const levels = ["normal", "info", "warning", "error", "critical"];
162
+ const currentIdx = levels.indexOf(level);
163
+ const lastIdx = levels.indexOf(lastWarnedLevel);
164
+
165
+ if (currentIdx <= lastIdx && level !== "critical") return;
166
+
167
+ lastWarnedLevel = level;
168
+ warnCooldown = 3; // 设置冷却
169
+
170
+ // 发送通知
171
+ ctx.ui.notify(message.title, message.level as any);
172
+ }
173
+
174
+ // 监听轮次结束事件,检查上下文使用
175
+ pi.on("turn_end", async (_event, ctx: ExtensionContext) => {
176
+ const stats = getContextStats(ctx);
177
+ if (!stats) return;
178
+
179
+ await handleContextWarning(stats, ctx);
180
+ });
181
+
182
+ // 监听会话开始,初始化
183
+ pi.on("session_start", async (_event, ctx: ExtensionContext) => {
184
+ lastWarnedLevel = "normal";
185
+ warnCooldown = 0;
186
+ });
187
+
188
+ /**
189
+ * /context-stats 命令 - 显示详细上下文统计
190
+ */
191
+ pi.registerCommand("context-stats", {
192
+ description: "显示当前上下文详细统计",
193
+ usage: "/context-stats",
194
+ handler: async (_args, ctx: ExtensionContext) => {
195
+ const stats = getContextStats(ctx);
196
+
197
+ if (!stats) {
198
+ ctx.ui.notify("无法获取上下文统计", "warning");
199
+ return;
200
+ }
201
+
202
+ const message = getContextMessage(stats);
203
+ const lines = message.body.split("\n");
204
+
205
+ // 构建详细统计文本
206
+ const modelName = ctx.model?.name || "unknown";
207
+ const modelMaxTokens = ctx.model?.maxTokens || 0;
208
+ const contextWindow = stats.contextWindow;
209
+
210
+ // 根据使用情况给出建议
211
+ let suggestion = "";
212
+ if (stats.percent >= 90) {
213
+ suggestion = `⚠️ 上下文使用过高,建议清理会话\n💡 模型 ${modelName} 最大窗口 ${formatTokens(contextWindow)}`;
214
+ } else if (stats.percent >= 70) {
215
+ suggestion = `💡 上下文已过半,注意控制对话长度`;
216
+ }
217
+
218
+ const detailLines = [
219
+ `${"─".repeat(40)}`,
220
+ `📊 上下文详细统计`,
221
+ `${"─".repeat(40)}`,
222
+ ``,
223
+ `模型: ${modelName}`,
224
+ `总窗口: ${formatTokens(contextWindow)} tokens`,
225
+ `最大输出: ${formatTokens(modelMaxTokens)} tokens`,
226
+ `已使用: ${formatTokens(stats.usedTokens)} tokens (${stats.percent.toFixed(1)}%)`,
227
+ `剩余: ${formatTokens(stats.remainingTokens)} tokens`,
228
+ ``,
229
+ `📝 分布估算:`,
230
+ ` 系统: ${formatTokens(stats.systemTokens)} tokens`,
231
+ ` 工具: ${formatTokens(stats.toolsTokens)} tokens`,
232
+ ` 对话: ${formatTokens(stats.conversationTokens)} tokens`,
233
+ ``,
234
+ suggestion,
235
+ ``,
236
+ `${"─".repeat(40)}`,
237
+ ];
238
+
239
+ // 显示给用户
240
+ const fullText = detailLines.join("\n");
241
+ pi.sendMessage(
242
+ {
243
+ customType: "context-stats",
244
+ content: fullText,
245
+ display: true,
246
+ },
247
+ { triggerTurn: false }
248
+ );
249
+
250
+ // 如果超过阈值也显示通知
251
+ if (stats.percent >= 80) {
252
+ ctx.ui.notify(message.title, message.level as any);
253
+ }
254
+ },
255
+ });
256
+
257
+ /**
258
+ * /context-warn 命令 - 切换自动警告
259
+ */
260
+ pi.registerCommand("context-warn", {
261
+ description: "开启/关闭上下文警告",
262
+ usage: "/context-warn [on|off]",
263
+ handler: async (args, ctx: ExtensionContext) => {
264
+ if (!args || args === "on") {
265
+ autoWarnEnabled = true;
266
+ ctx.ui.notify("✅ 上下文警告已开启", "info");
267
+ } else if (args === "off") {
268
+ autoWarnEnabled = false;
269
+ ctx.ui.notify("🔕 上下文警告已关闭", "info");
270
+ } else {
271
+ ctx.ui.notify(`当前状态: ${autoWarnEnabled ? "开启" : "关闭"}`, "info");
272
+ }
273
+ },
274
+ });
275
+ }
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * @author: xujianjiang
2
3
  * /context
3
4
  *
4
5
  * Small TUI view showing what's loaded/available: