jinzd-ai-cli 0.1.19 → 0.1.21

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/CLAUDE.md CHANGED
@@ -302,6 +302,7 @@ const stdinLines = Array.isArray(rawStdin) ? rawStdin.map(String)
302
302
  - [x] **Google 搜索集成**(2026-02-23):`google_search` 工具通过 Google Custom Search JSON API 搜索网页。需配置 API Key(`apiKeys['google-search']` 或 `AICLI_API_KEY_GOOGLESEARCH`)和 Search Engine ID(`googleSearchEngineId` 或 `AICLI_GOOGLE_CX`)。自动走全局 proxy,15s 超时,返回 Markdown 格式结果列表。配置向导新增 `Configure Google Search` 入口。
303
303
 
304
304
  - [x] **MCP 协议支持**(2026-02-23):轻量级 MCP 客户端(不依赖 SDK),STDIO 传输 + JSON-RPC 2.0 通信。`src/mcp/` 模块:`types.ts`(协议类型)、`client.ts`(单服务器连接)、`manager.ts`(多服务器管理 + Tool 转换)。配置兼容 Claude Desktop(`config.json` 的 `mcpServers` 字段)。启动自动连接、发现工具并注册到 ToolRegistry,工具名格式 `mcp__<serverId>__<toolName>`。新增 `/mcp` REPL 命令查看连接状态和工具列表。
305
+ - [x] **Kimi XML 伪工具调用修复**(2026-02-25):Kimi-k2 在生成长内容时退化为文本 XML 伪工具调用。`kimi.ts` 覆写 `chatWithTools()`:方案 B 在 system prompt 注入强制规范提示(预防),方案 A 解析文本中的 XML 工具标签并转换为真实 ToolCall 执行(兜底)。`parseXmlToolCalls()` 使用 indexOf 避免正则回溯,快速路径优化。
305
306
 
306
307
  ### P0 — 核心竞争力缺口(下一步最先实现)
307
308
  - [x] **`/compact` 上下文压缩**(2026-02-25):调用当前 provider 生成对话摘要,替换 session.messages 前 N 条为 user/assistant 摘要对,保留最近 4 条。`session.compact()` 方法 + `repl.compactSession()` + `/compact [instruction]` 命令。
@@ -332,6 +333,39 @@ const stdinLines = Array.isArray(rawStdin) ? rawStdin.map(String)
332
333
  - [ ] **web_fetch DNS 解析时 SSRF 防护**:当前只检查 URL hostname 字符串,若 hostname 是域名(非裸 IP)则未检查其解析后的 IP 是否为私有地址。需在发起请求后对实际连接 IP 做二次校验(复杂,低频风险)。
333
334
  - [ ] **`persistentCwd` 全局状态**:bash 工具的当前工作目录是模块级全局变量,多 session 并发时可能串扰。现阶段单 session REPL 无影响,GUI 多会话扩展时需重构为 per-session 状态。
334
335
 
336
+ ## 本轮开发完成记录(2026-02-25,v0.1.18 → v0.1.20)
337
+
338
+ ### Bug 修复:Kimi XML 伪工具调用(v0.1.19)
339
+
340
+ **背景**:Kimi-k2 在 OpenAI function calling 接口下存在已知缺陷——当生成内容较长时,会在回复文本中输出 `<write_file>...</write_file>` 等 XML 格式的伪工具调用标签,而非通过 API 的 `tool_calls` 机制。ai-cli 无法捕获文本中的 XML,导致文件写入等操作静默丢失,任务失败。
341
+
342
+ **根本原因**:Kimi-k2 训练时混合了旧版 XML 工具调用格式,当模型注意力涣散(长内容生成)时退化为文本输出工具调用,而非通过结构化 `tool_calls` 数组返回。
343
+
344
+ **修复**:`src/providers/kimi.ts` 覆写 `chatWithTools()`,叠加两道防线:
345
+
346
+ - **方案 B(预防)**:在 `request.systemPrompt` 末尾追加 `KIMI_TOOL_CALL_REMINDER`——中文强制规范提示,指示 Kimi 必须使用 API function calling,禁止文本中输出 XML 工具标签
347
+ - **方案 A(兜底)**:响应返回后,若 `content` 中含有 `<tool_name>...</tool_name>` 模式,调用私有 `parseXmlToolCalls()` 方法解析并转换为 `ToolCall[]`,注入到 agentic 执行循环
348
+
349
+ **`parseXmlToolCalls()` 设计要点**:
350
+ - 使用 `indexOf` 而非正则,避免 14KB+ Markdown 内容时的正则回溯性能问题
351
+ - 快速路径:`!content.includes('</')` 直接跳过无 XML 的响应
352
+ - 按已知参数名(`tool.parameters` 的 key)逐一提取参数值,安全可靠
353
+ - tool call id 格式 `xml-fallback-{ts}-{idx}`,便于调试日志追踪
354
+ - stderr 输出警告提示用户发生了 XML 伪调用救援
355
+
356
+ **架构约束**:仅在 `kimi.ts` 中覆写,不影响 DeepSeek / Zhipu / Claude / Gemini 等其他 Provider
357
+
358
+ ### `/about` 特性列表更新(v0.1.20)
359
+
360
+ **变更**:`src/repl/renderer.ts` → `printAbout()` 主要特性列表新增 4 项、更新 1 项:
361
+ - 项目上下文文件说明补充「三层级:全局/项目/子目录」
362
+ - Plan Mode(`/plan` 进入只读规划 → `/plan execute` 切回)
363
+ - Headless 模式(`-p` 单轮非交互 + stdin 管道 + `--json`)
364
+ - `/compact` 上下文压缩(摘要替换旧消息,保留最近 4 条)
365
+ - Kimi 工具调用可靠性增强(XML 伪调用自动检测并转换,v0.1.19)
366
+
367
+ ---
368
+
335
369
  ## 本轮开发完成记录(2026-02-25,v0.1.17 → v0.1.18)
336
370
 
337
371
  ### 新增功能:`/compact` 上下文压缩
package/dist/index.js CHANGED
@@ -129,7 +129,7 @@ var EnvLoader = class {
129
129
  };
130
130
 
131
131
  // src/core/constants.ts
132
- var VERSION = "0.1.19";
132
+ var VERSION = "0.1.21";
133
133
  var APP_NAME = "ai-cli";
134
134
  var CONFIG_DIR_NAME = ".aicli";
135
135
  var CONFIG_FILE_NAME = "config.json";
@@ -1615,13 +1615,17 @@ var Renderer = class {
1615
1615
  console.log(feat("Agentic \u5FAA\u73AF\uFF08\u6700\u591A 20 \u8F6E\u5DE5\u5177\u8C03\u7528\uFF0C\u6700\u7EC8\u56DE\u7B54\u6D41\u5F0F\u8F93\u51FA\uFF09"));
1616
1616
  console.log(feat("\u591A\u6A21\u6001\u8F93\u5165\uFF1A@\u6587\u4EF6\u8DEF\u5F84 \u5185\u8054\u56FE\u7247\uFF08base64\uFF09\u6216\u6587\u672C\u5230\u6D88\u606F"));
1617
1617
  console.log(feat("Git \u4E0A\u4E0B\u6587\u611F\u77E5\uFF1A\u542F\u52A8\u81EA\u52A8\u6CE8\u5165\u5206\u652F\u540D\u4E0E\u6587\u4EF6\u53D8\u66F4\u72B6\u6001"));
1618
- console.log(feat("\u9879\u76EE\u4E0A\u4E0B\u6587\u6587\u4EF6\uFF1A\u81EA\u52A8\u52A0\u8F7D AICLI.md / CLAUDE.md"));
1618
+ console.log(feat("\u9879\u76EE\u4E0A\u4E0B\u6587\u6587\u4EF6\uFF1A\u81EA\u52A8\u52A0\u8F7D AICLI.md / CLAUDE.md\uFF08\u4E09\u5C42\u7EA7\uFF1A\u5168\u5C40/\u9879\u76EE/\u5B50\u76EE\u5F55\uFF09"));
1619
1619
  console.log(feat("\u8DE8 session \u5386\u53F2\u5168\u6587\u641C\u7D22\uFF08/search <\u5173\u952E\u8BCD>\uFF09"));
1620
1620
  console.log(feat("\u6587\u4EF6\u64CD\u4F5C\u64A4\u9500\uFF08/undo\uFF0C\u652F\u6301 write_file / edit_file\uFF09"));
1621
1621
  console.log(feat("Thinking \u6A21\u5F0F\u6298\u53E0\uFF08<think> \u5757\u81EA\u52A8\u6298\u53E0\uFF0CGLM-5 \u7B49\uFF09"));
1622
1622
  console.log(feat("Token \u7528\u91CF\u8FFD\u8E2A\uFF08\u6BCF\u6B21\u56DE\u590D + session \u7D2F\u8BA1\uFF0C\u652F\u6301 Gemini/Claude/DeepSeek \u7B49\uFF09"));
1623
1623
  console.log(feat("MCP \u534F\u8BAE\u652F\u6301\uFF1A\u63A5\u5165\u5916\u90E8 MCP \u670D\u52A1\u5668\u5DE5\u5177\uFF08config.json mcpServers \u914D\u7F6E\uFF09"));
1624
1624
  console.log(feat("\u63D2\u4EF6\u7CFB\u7EDF\uFF1A~/.aicli/plugins/*.js \u81EA\u5B9A\u4E49\u5DE5\u5177\uFF08\u9700 allowPlugins:true \u542F\u7528\uFF0C\u9ED8\u8BA4\u5173\u95ED\uFF09"));
1625
+ console.log(feat("Plan Mode\uFF1A/plan \u8FDB\u5165\u53EA\u8BFB\u89C4\u5212\uFF0CAI \u4EC5\u53EF\u4F7F\u7528\u5B89\u5168\u5DE5\u5177\uFF0C/plan execute \u5207\u56DE\u6267\u884C"));
1626
+ console.log(feat('Headless \u6A21\u5F0F\uFF1Aaicli -p "..." \u5355\u8F6E\u975E\u4EA4\u4E92\uFF0C\u652F\u6301 stdin \u7BA1\u9053\u4E0E --json \u8F93\u51FA'));
1627
+ console.log(feat("/compact \u4E0A\u4E0B\u6587\u538B\u7F29\uFF1A\u751F\u6210\u6458\u8981\u66FF\u6362\u65E7\u6D88\u606F\uFF0C\u4FDD\u7559\u6700\u8FD1 4 \u6761\uFF0C\u89E3\u51B3 context \u6EA2\u51FA"));
1628
+ console.log(feat("Kimi \u5DE5\u5177\u8C03\u7528\u53EF\u9760\u6027\u589E\u5F3A\uFF1AXML \u4F2A\u8C03\u7528\u81EA\u52A8\u68C0\u6D4B\u5E76\u8F6C\u6362\u4E3A\u771F\u5B9E API \u8C03\u7528\uFF08v0.1.19\uFF09"));
1625
1629
  console.log(feat("\u72EC\u7ACB\u53EF\u6267\u884C\u6587\u4EF6\u6253\u5305\uFF08~56MB\uFF0C\u65E0\u9700 Node.js \u73AF\u5883\uFF09"));
1626
1630
  console.log();
1627
1631
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",