jinzd-ai-cli 0.4.260 → 0.4.262
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/README.md +10 -8
- package/README.zh-CN.md +11 -9
- package/dist/{batch-LBMJWMMO.js → batch-2B7UUX27.js} +2 -2
- package/dist/{chunk-U2HN3EW6.js → chunk-25HFWCM3.js} +19 -7
- package/dist/{chunk-2BGNEVS5.js → chunk-2XPJRRBB.js} +4 -4
- package/dist/{chunk-AAWV4BP4.js → chunk-A6JLBNAI.js} +2 -2
- package/dist/{chunk-XTA3LSPQ.js → chunk-BS44XEZ4.js} +1 -1
- package/dist/{chunk-NEYNE6UE.js → chunk-D6DHS5GL.js} +11 -9
- package/dist/{chunk-63M2ELJS.js → chunk-FWBSGBB7.js} +4 -4
- package/dist/{chunk-HBR33J6J.js → chunk-HPDI4F5F.js} +1 -1
- package/dist/{chunk-Y7UZSFGS.js → chunk-JEJHNVA2.js} +1 -1
- package/dist/{chunk-CLJKNKUN.js → chunk-JFXKQPKY.js} +1 -1
- package/dist/{chunk-3TE7ZWO5.js → chunk-KMS3LBO3.js} +1 -1
- package/dist/{chunk-KRENSXPC.js → chunk-KWYJFLXY.js} +1 -1
- package/dist/{chunk-K6WMQBUP.js → chunk-MTIS7H6V.js} +1 -1
- package/dist/{chunk-VJP2GLW5.js → chunk-WAAFA32V.js} +1 -1
- package/dist/{chunk-FCPYMBTA.js → chunk-XZNRZGG2.js} +57 -25
- package/dist/{chunk-26C6YZ3A.js → chunk-ZQZEBPAQ.js} +1 -1
- package/dist/{ci-PSA7F4EI.js → ci-G6OZDH4H.js} +6 -6
- package/dist/{ci-format-WAHEZZMY.js → ci-format-BRS7G5X5.js} +2 -2
- package/dist/{constants-C55LGUR7.js → constants-24AD5JQV.js} +1 -1
- package/dist/{doctor-cli-YANDJBHC.js → doctor-cli-WWZRFGQJ.js} +6 -6
- package/dist/electron-server.js +87 -42
- package/dist/{hub-CBOC3TT3.js → hub-2DYZQVEN.js} +1 -1
- package/dist/index.js +90 -41
- package/dist/{persistent-memory-DUFOZTDV.js → persistent-memory-DFSZZSYP.js} +2 -2
- package/dist/{persistent-memory-KEYVKD54.js → persistent-memory-LJT37XVO.js} +2 -2
- package/dist/{pr-T6KCK5DT.js → pr-OOIQPCBX.js} +6 -6
- package/dist/{run-tests-K43DLTA3.js → run-tests-ICTVJSJN.js} +2 -2
- package/dist/{run-tests-S2RLPMCR.js → run-tests-W4TG4OQV.js} +2 -2
- package/dist/{server-GTRCCOXN.js → server-GTVYIHBG.js} +6 -6
- package/dist/{server-SV3TV5BJ.js → server-IXUVVPTV.js} +14 -14
- package/dist/{task-orchestrator-DW5AWW7J.js → task-orchestrator-6MHSDOFR.js} +6 -6
- package/dist/{usage-BP442V2Q.js → usage-23I3ZJZO.js} +2 -2
- package/dist/web/client/actions.js +12 -7
- package/dist/web/client/app.js +4 -36
- package/dist/web/client/sidebar-tabs.js +48 -0
- package/dist/web/client/sw.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<!-- AICLI:DOCS_DEFAULT_WEB_PORT=3000 -->
|
|
6
6
|
<!-- AICLI:DOCS_BUILTIN_TOOL_COUNT=30 -->
|
|
7
7
|
<!-- AICLI:DOCS_REPL_COMMAND_COUNT=48 -->
|
|
8
|
+
<!-- AICLI:DOCS_BUILTIN_PROVIDER_COUNT=10 -->
|
|
8
9
|
<!-- AICLI:DOCS_MEMORY_SOURCE=memory.jsonl -->
|
|
9
10
|
|
|
10
11
|
> A cross-platform AI coding assistant — CLI, Web UI, and Desktop App — with multi-provider support and agentic tool calling
|
|
@@ -12,7 +13,6 @@
|
|
|
12
13
|
[](https://www.npmjs.com/package/jinzd-ai-cli)
|
|
13
14
|
[](LICENSE)
|
|
14
15
|
[](https://nodejs.org)
|
|
15
|
-
[]()
|
|
16
16
|
[](https://github.com/jinzhengdong/ai-cli/releases)
|
|
17
17
|
[](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml)
|
|
18
18
|
|
|
@@ -131,13 +131,14 @@ aicli user delete x # Delete user
|
|
|
131
131
|
|----------|--------|-------------|
|
|
132
132
|
| **Claude** | Opus 4, Sonnet 4, Haiku 4 | [console.anthropic.com](https://console.anthropic.com) |
|
|
133
133
|
| **Gemini** | 2.5 Pro, 2.5 Flash | [aistudio.google.com](https://aistudio.google.com) |
|
|
134
|
-
| **DeepSeek** |
|
|
134
|
+
| **DeepSeek** | deepseek-v4-flash (default), deepseek-v4-pro | [platform.deepseek.com](https://platform.deepseek.com) |
|
|
135
135
|
| **OpenAI** | GPT-5.4, GPT-5, GPT-4.1, o3, o4-mini | [platform.openai.com](https://platform.openai.com) |
|
|
136
136
|
| **OpenRouter** | 300+ models (Claude, GPT, Gemini, Llama, Qwen, Mistral...) | [openrouter.ai](https://openrouter.ai) |
|
|
137
137
|
| **Zhipu** | GLM-4, GLM-5 | [open.bigmodel.cn](https://open.bigmodel.cn) |
|
|
138
138
|
| **Kimi** | Kimi K2.6, K2.5, K2 Thinking | [platform.moonshot.cn](https://platform.moonshot.cn) |
|
|
139
|
-
| **Qwen** | qwen-plus, qwen-max, qwen-turbo, qwen-coder-plus | [bailian.console.aliyun.com](https://bailian.console.aliyun.com) |
|
|
140
|
-
| **
|
|
139
|
+
| **Qwen** | qwen-plus, qwen-max, qwen-turbo, qwen-coder-plus | [bailian.console.aliyun.com](https://bailian.console.aliyun.com) |
|
|
140
|
+
| **MiniMax** | MiniMax-M3 (default), M2.7, M2.5, M2.1, M2 | [platform.minimaxi.com](https://platform.minimaxi.com) |
|
|
141
|
+
| **Ollama** | Any locally installed model (Llama, Qwen, Gemma, Mistral...) | No API key — [ollama.com](https://ollama.com) |
|
|
141
142
|
|
|
142
143
|
Any OpenAI-compatible API can also be used via `customBaseUrls` in config.
|
|
143
144
|
|
|
@@ -462,8 +463,9 @@ Environment variables take precedence over config file values:
|
|
|
462
463
|
| `AICLI_API_KEY_OPENROUTER` | OpenRouter API Key |
|
|
463
464
|
| `AICLI_API_KEY_ZHIPU` | Zhipu API Key |
|
|
464
465
|
| `AICLI_API_KEY_KIMI` | Kimi API Key |
|
|
465
|
-
| `AICLI_API_KEY_QWEN` | Qwen / Alibaba Cloud API Key |
|
|
466
|
-
| `
|
|
466
|
+
| `AICLI_API_KEY_QWEN` | Qwen / Alibaba Cloud API Key |
|
|
467
|
+
| `AICLI_API_KEY_MINIMAX` | MiniMax API Key |
|
|
468
|
+
| `AICLI_PROVIDER` | Default provider ID |
|
|
467
469
|
| `AICLI_NO_STREAM` | Set to `1` to disable streaming |
|
|
468
470
|
| `HTTPS_PROXY` / `HTTP_PROXY` | Proxy URL |
|
|
469
471
|
|
|
@@ -517,13 +519,13 @@ The Web UI (`aicli web`) provides a full-featured browser interface:
|
|
|
517
519
|
## Testing
|
|
518
520
|
|
|
519
521
|
```bash
|
|
520
|
-
npm test # Offline regression suite
|
|
522
|
+
npm test # Offline regression suite
|
|
521
523
|
npm run test:providers # Real-provider smoke tests (network/API-key dependent)
|
|
522
524
|
npm run test:e2e-web # Playwright browser smoke; may need browser-process permission in sandboxes
|
|
523
525
|
npm run test:watch # Watch mode
|
|
524
526
|
```
|
|
525
527
|
|
|
526
|
-
|
|
528
|
+
Offline tests cover authentication, sessions, tool types and danger levels, permissions, output truncation, diff rendering, edit-file similarity, error hierarchy, config management, env loading, provider registry, web-fetch, grep-files, Hub, dev-state, token estimation, tool registry budgets, parallel tool execution, cost tracking, and session tool history.
|
|
527
529
|
|
|
528
530
|
## Releasing (Version Bump → npm Publish → GitHub Push)
|
|
529
531
|
|
package/README.zh-CN.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<!-- AICLI:DOCS_DEFAULT_WEB_PORT=3000 -->
|
|
6
6
|
<!-- AICLI:DOCS_BUILTIN_TOOL_COUNT=30 -->
|
|
7
7
|
<!-- AICLI:DOCS_REPL_COMMAND_COUNT=48 -->
|
|
8
|
+
<!-- AICLI:DOCS_BUILTIN_PROVIDER_COUNT=10 -->
|
|
8
9
|
<!-- AICLI:DOCS_MEMORY_SOURCE=memory.jsonl -->
|
|
9
10
|
|
|
10
11
|
> 跨平台 AI 编程助手 — CLI 终端、Web 界面、桌面应用三合一,支持 10 大 Provider(含本地 Ollama)与 Agentic 工具调用
|
|
@@ -12,7 +13,6 @@
|
|
|
12
13
|
[](https://www.npmjs.com/package/jinzd-ai-cli)
|
|
13
14
|
[](LICENSE)
|
|
14
15
|
[](https://nodejs.org)
|
|
15
|
-
[]()
|
|
16
16
|
[](https://github.com/jinzhengdong/ai-cli/releases)
|
|
17
17
|
[](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml)
|
|
18
18
|
|
|
@@ -119,13 +119,14 @@ aicli user delete x # 删除用户
|
|
|
119
119
|
|----------|------|-------------|
|
|
120
120
|
| **Claude** | Opus 4, Sonnet 4, Haiku 4 | [console.anthropic.com](https://console.anthropic.com) |
|
|
121
121
|
| **Gemini** | 2.5 Pro, 2.5 Flash | [aistudio.google.com](https://aistudio.google.com) |
|
|
122
|
-
| **DeepSeek** |
|
|
122
|
+
| **DeepSeek** | deepseek-v4-flash(默认), deepseek-v4-pro | [platform.deepseek.com](https://platform.deepseek.com) |
|
|
123
123
|
| **OpenAI** | GPT-5.4, GPT-5, GPT-4.1, o3, o4-mini | [platform.openai.com](https://platform.openai.com) |
|
|
124
124
|
| **OpenRouter** | 300+ 模型(Claude/GPT/Gemini/Llama/Qwen/Mistral...) | [openrouter.ai](https://openrouter.ai) |
|
|
125
|
-
|
|
|
125
|
+
| **Zhipu(智谱)** | GLM-4, GLM-5 | [open.bigmodel.cn](https://open.bigmodel.cn) |
|
|
126
126
|
| **Kimi** | Kimi K2.6, K2.5, K2 Thinking | [platform.moonshot.cn](https://platform.moonshot.cn) |
|
|
127
|
-
| **Qwen** | qwen-plus, qwen-max, qwen-turbo, qwen-coder-plus | [bailian.console.aliyun.com](https://bailian.console.aliyun.com) |
|
|
128
|
-
| **
|
|
127
|
+
| **Qwen** | qwen-plus, qwen-max, qwen-turbo, qwen-coder-plus | [bailian.console.aliyun.com](https://bailian.console.aliyun.com) |
|
|
128
|
+
| **MiniMax** | MiniMax-M3(默认)、M2.7、M2.5、M2.1、M2 | [platform.minimaxi.com](https://platform.minimaxi.com) |
|
|
129
|
+
| **Ollama** | 任意本地模型(Llama、Qwen、Gemma、Mistral...) | 无需 API Key — [ollama.com](https://ollama.com) |
|
|
129
130
|
|
|
130
131
|
也可通过 `customBaseUrls` 配置接入任意 OpenAI 兼容 API。
|
|
131
132
|
|
|
@@ -420,8 +421,9 @@ Auto Mode 不会被项目配置静默开启。用 `/permissions recently-denied`
|
|
|
420
421
|
| `AICLI_API_KEY_OPENROUTER` | OpenRouter API Key |
|
|
421
422
|
| `AICLI_API_KEY_ZHIPU` | 智谱 API Key |
|
|
422
423
|
| `AICLI_API_KEY_KIMI` | Kimi API Key |
|
|
423
|
-
| `AICLI_API_KEY_QWEN` | Qwen / Alibaba Cloud API Key |
|
|
424
|
-
| `
|
|
424
|
+
| `AICLI_API_KEY_QWEN` | Qwen / Alibaba Cloud API Key |
|
|
425
|
+
| `AICLI_API_KEY_MINIMAX` | MiniMax API Key |
|
|
426
|
+
| `AICLI_PROVIDER` | 默认 Provider |
|
|
425
427
|
| `AICLI_NO_STREAM` | 设为 `1` 禁用流式输出 |
|
|
426
428
|
| `HTTPS_PROXY` / `HTTP_PROXY` | 代理地址 |
|
|
427
429
|
|
|
@@ -475,11 +477,11 @@ Web UI(`aicli web`)提供功能完备的浏览器界面:
|
|
|
475
477
|
## 测试
|
|
476
478
|
|
|
477
479
|
```bash
|
|
478
|
-
npm test #
|
|
480
|
+
npm test # 运行离线回归测试
|
|
479
481
|
npm run test:watch # 监听模式
|
|
480
482
|
```
|
|
481
483
|
|
|
482
|
-
|
|
484
|
+
离线测试覆盖:认证、会话、工具类型与危险级别、权限、输出截断、diff 渲染、edit-file 相似度、错误层级、配置管理、环境变量、Provider 注册、web-fetch、grep-files、Hub、开发状态、Token 估算、工具注册表预算、并行工具执行、费用追踪和会话工具历史。
|
|
483
485
|
|
|
484
486
|
## 发布(版本提升 → npm 发布 → 推送 GitHub)
|
|
485
487
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MTIS7H6V.js";
|
|
5
5
|
import "./chunk-TU3L3PW7.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-KWYJFLXY.js";
|
|
7
7
|
import {
|
|
8
8
|
atomicWriteFileSync
|
|
9
9
|
} from "./chunk-IW3Q7AE5.js";
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
detectsHallucinatedFileOp,
|
|
4
4
|
parseToolCallArguments,
|
|
5
5
|
schemaToJsonSchema
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XZNRZGG2.js";
|
|
7
7
|
import {
|
|
8
8
|
AuthError,
|
|
9
9
|
ProviderError,
|
|
@@ -2116,6 +2116,18 @@ var BUILT_IN_PROVIDERS = [
|
|
|
2116
2116
|
OpenRouterProvider,
|
|
2117
2117
|
OllamaProvider
|
|
2118
2118
|
];
|
|
2119
|
+
function listBuiltInProviderMetadata() {
|
|
2120
|
+
return BUILT_IN_PROVIDERS.map((ProviderClass) => {
|
|
2121
|
+
const { info } = new ProviderClass();
|
|
2122
|
+
return {
|
|
2123
|
+
id: info.id,
|
|
2124
|
+
displayName: info.displayName,
|
|
2125
|
+
defaultModel: info.defaultModel,
|
|
2126
|
+
apiKeyEnvVar: info.apiKeyEnvVar,
|
|
2127
|
+
requiresApiKey: info.requiresApiKey
|
|
2128
|
+
};
|
|
2129
|
+
});
|
|
2130
|
+
}
|
|
2119
2131
|
var ProviderRegistry = class {
|
|
2120
2132
|
providers = /* @__PURE__ */ new Map();
|
|
2121
2133
|
customConfigs = [];
|
|
@@ -2210,13 +2222,12 @@ var ProviderRegistry = class {
|
|
|
2210
2222
|
return [...this.providers.values()];
|
|
2211
2223
|
}
|
|
2212
2224
|
listAll() {
|
|
2213
|
-
const builtIn =
|
|
2214
|
-
const p = new P();
|
|
2225
|
+
const builtIn = listBuiltInProviderMetadata().map((info) => {
|
|
2215
2226
|
return {
|
|
2216
|
-
id:
|
|
2217
|
-
displayName:
|
|
2218
|
-
configured: this.providers.has(
|
|
2219
|
-
defaultModel:
|
|
2227
|
+
id: info.id,
|
|
2228
|
+
displayName: info.displayName,
|
|
2229
|
+
configured: this.providers.has(info.id),
|
|
2230
|
+
defaultModel: info.defaultModel,
|
|
2220
2231
|
isCustom: false
|
|
2221
2232
|
};
|
|
2222
2233
|
});
|
|
@@ -2235,5 +2246,6 @@ var ProviderRegistry = class {
|
|
|
2235
2246
|
};
|
|
2236
2247
|
|
|
2237
2248
|
export {
|
|
2249
|
+
listBuiltInProviderMetadata,
|
|
2238
2250
|
ProviderRegistry
|
|
2239
2251
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
evaluateCiGate,
|
|
4
4
|
normalizeCiThresholds
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-WAAFA32V.js";
|
|
6
6
|
import {
|
|
7
7
|
buildReviewPrompt,
|
|
8
8
|
buildSecurityReviewPrompt,
|
|
@@ -10,13 +10,13 @@ import {
|
|
|
10
10
|
} from "./chunk-HLWUDRBO.js";
|
|
11
11
|
import {
|
|
12
12
|
ProviderRegistry
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-25HFWCM3.js";
|
|
14
14
|
import {
|
|
15
15
|
ConfigManager
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-MTIS7H6V.js";
|
|
17
17
|
import {
|
|
18
18
|
VERSION
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-KWYJFLXY.js";
|
|
20
20
|
|
|
21
21
|
// src/cli/ci.ts
|
|
22
22
|
import { execFileSync } from "child_process";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
truncateForPersist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-D6DHS5GL.js";
|
|
5
5
|
import {
|
|
6
6
|
APP_NAME,
|
|
7
7
|
CONFIG_DIR_NAME,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
MCP_PROTOCOL_VERSION,
|
|
12
12
|
MCP_TOOL_PREFIX,
|
|
13
13
|
VERSION
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-KWYJFLXY.js";
|
|
15
15
|
import {
|
|
16
16
|
atomicWriteFileSync
|
|
17
17
|
} from "./chunk-IW3Q7AE5.js";
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
searchPersistentMemories,
|
|
8
8
|
touchMemoryReferences,
|
|
9
9
|
updateMemoryEntry
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-KMS3LBO3.js";
|
|
11
11
|
import {
|
|
12
12
|
indexProject
|
|
13
13
|
} from "./chunk-GLSR2NR3.js";
|
|
@@ -23,13 +23,13 @@ import {
|
|
|
23
23
|
runHook,
|
|
24
24
|
runLifecycleHooks,
|
|
25
25
|
runTool
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-JEJHNVA2.js";
|
|
27
27
|
import {
|
|
28
28
|
buildTruncatedArgumentsError,
|
|
29
29
|
getDangerLevel,
|
|
30
30
|
isFileWriteTool,
|
|
31
31
|
runLeanAgentLoop
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-XZNRZGG2.js";
|
|
33
33
|
import {
|
|
34
34
|
EnvLoader,
|
|
35
35
|
NetworkError,
|
|
@@ -40,14 +40,14 @@ import {
|
|
|
40
40
|
} from "./chunk-4BKXL7SM.js";
|
|
41
41
|
import {
|
|
42
42
|
runTestsTool
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-HPDI4F5F.js";
|
|
44
44
|
import {
|
|
45
45
|
CONFIG_DIR_NAME,
|
|
46
46
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
47
47
|
SUBAGENT_ALLOWED_TOOLS,
|
|
48
48
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
49
49
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-KWYJFLXY.js";
|
|
51
51
|
import {
|
|
52
52
|
loadChatIndex,
|
|
53
53
|
searchChatMemory
|
|
@@ -169,9 +169,9 @@ function buildWrappedCommand(command, id, isWindows) {
|
|
|
169
169
|
if (!isWindows) {
|
|
170
170
|
return `echo "${markerStart}"; ${command}; echo "${markerEnd}:$?"`;
|
|
171
171
|
}
|
|
172
|
-
const
|
|
173
|
-
const
|
|
174
|
-
return
|
|
172
|
+
const b64 = Buffer.from(command, "utf-8").toString("base64");
|
|
173
|
+
const decoded = `[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${b64}'))`;
|
|
174
|
+
return `${WIN_UTF8_PREAMBLE} Write-Output "${markerStart}"; $global:LASTEXITCODE = 0; Invoke-Expression (${decoded}); $__ok = $?; $__ec = $LASTEXITCODE; $__code = if ($null -ne $__ec -and $__ec -ne 0) { $__ec } elseif ($__ok) { 0 } else { 1 }; Write-Output "${markerEnd}:$__code"`;
|
|
175
175
|
}
|
|
176
176
|
async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
177
177
|
let entry = pool.get(sessionKey);
|
|
@@ -3477,7 +3477,9 @@ Note: Path can be absolute or relative to cwd.`,
|
|
|
3477
3477
|
}
|
|
3478
3478
|
const lines = [];
|
|
3479
3479
|
if (anyFailed && stopOnError) {
|
|
3480
|
-
|
|
3480
|
+
const failedIdx = reports.find((r) => !r.ok)?.index;
|
|
3481
|
+
const failedLabel = failedIdx != null ? `#${failedIdx + 1}` : "an edit";
|
|
3482
|
+
lines.push(`ERROR: Batch edit aborted \u2014 ${appliedCount}/${edits.length} applied, then edit ${failedLabel} failed. No changes written (stop_on_error=true).`);
|
|
3481
3483
|
} else if (anyFailed) {
|
|
3482
3484
|
lines.push(`Partial success: ${appliedCount}/${edits.length} edits applied to ${filePath} (stop_on_error=false).`);
|
|
3483
3485
|
} else {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ProviderRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-25HFWCM3.js";
|
|
5
5
|
import {
|
|
6
6
|
ConfigManager
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MTIS7H6V.js";
|
|
8
8
|
import {
|
|
9
9
|
getActivePluginAssets,
|
|
10
10
|
getPendingHookTrust,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
listHooks,
|
|
15
15
|
listInstalledPlugins,
|
|
16
16
|
resetStats
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-JEJHNVA2.js";
|
|
18
18
|
import {
|
|
19
19
|
getGitRoot
|
|
20
20
|
} from "./chunk-HOSJZMQS.js";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
MCP_PROJECT_CONFIG_NAME,
|
|
27
27
|
MEMORY_FILE_NAME,
|
|
28
28
|
VERSION
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-KWYJFLXY.js";
|
|
30
30
|
|
|
31
31
|
// src/diagnostics/doctor-report.ts
|
|
32
32
|
import { existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
@@ -188,6 +188,52 @@ function buildWriteRoundReminder(writtenCount) {
|
|
|
188
188
|
You have successfully called write_file ${writtenCount} time(s) so far in this turn. If there are more files to write, call write_file NOW for the next file. Do NOT produce a text summary until ALL files have been written via tool calls.`;
|
|
189
189
|
}
|
|
190
190
|
var HALLUCINATION_CORRECTION_MESSAGE = "You did NOT actually call the write_file tool \u2014 the file was NOT created! Please immediately use the write_file tool via the function calling API to perform the actual file write. Do NOT describe file content in text \u2014 you MUST invoke write_file through the tool_calls mechanism.";
|
|
191
|
+
var ACTION_WORD_RE = /(?:已[生保写创]|saved|written|created|完成.*(?:写入|保存|创建|生成)|输出|file\s+(?:saved|written|created))/i;
|
|
192
|
+
var CLAUSE_BOUNDARY_RE = /[。.!?!?;;,,]/;
|
|
193
|
+
var LIST_LINE_RE = /^\s*(?:[-*+]|\d+[.)]|\|)/;
|
|
194
|
+
function hasWriteIntentNear(content, pathStart, pathEnd) {
|
|
195
|
+
const lineStart = content.lastIndexOf("\n", pathStart - 1) + 1;
|
|
196
|
+
const lineEndRaw = content.indexOf("\n", pathEnd);
|
|
197
|
+
const lineEnd = lineEndRaw === -1 ? content.length : lineEndRaw;
|
|
198
|
+
const currentLine = content.slice(lineStart, lineEnd);
|
|
199
|
+
const prevLineStart = lineStart === 0 ? 0 : content.lastIndexOf("\n", lineStart - 2) + 1;
|
|
200
|
+
const prevLine = lineStart === 0 ? "" : content.slice(prevLineStart, lineStart - 1);
|
|
201
|
+
const introColon = /[::]\s*$/.test(prevLine);
|
|
202
|
+
if (LIST_LINE_RE.test(currentLine) || introColon) {
|
|
203
|
+
let pos = pathStart;
|
|
204
|
+
let linesBack = 0;
|
|
205
|
+
while (linesBack < 9 && pos > 0) {
|
|
206
|
+
pos--;
|
|
207
|
+
if (content[pos] === "\n") linesBack++;
|
|
208
|
+
}
|
|
209
|
+
const windowStart = pos === 0 ? 0 : pos + 1;
|
|
210
|
+
return ACTION_WORD_RE.test(content.slice(windowStart, lineEnd));
|
|
211
|
+
}
|
|
212
|
+
const boundaryBefore = (from) => {
|
|
213
|
+
for (let i = from - 1; i >= lineStart; i--) {
|
|
214
|
+
if (CLAUSE_BOUNDARY_RE.test(content[i] ?? "")) return i + 1;
|
|
215
|
+
}
|
|
216
|
+
return lineStart;
|
|
217
|
+
};
|
|
218
|
+
let clauseEnd = lineEnd;
|
|
219
|
+
for (let i = pathEnd; i < lineEnd; i++) {
|
|
220
|
+
if (CLAUSE_BOUNDARY_RE.test(content[i] ?? "")) {
|
|
221
|
+
clauseEnd = i + 1;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const isBareClause = (text2) => text2.replace(/`[^`\n]*`/g, "").replace(content.slice(pathStart, pathEnd), "").replace(/[\s'"“”‘’()()、,,。;;::+\-和与及]/g, "").length <= 2;
|
|
226
|
+
let start = boundaryBefore(pathStart);
|
|
227
|
+
let text = content.slice(start, clauseEnd);
|
|
228
|
+
if (ACTION_WORD_RE.test(text)) return true;
|
|
229
|
+
for (let step = 0; step < 6 && start > lineStart && isBareClause(text); step++) {
|
|
230
|
+
const prevEnd = start - 1;
|
|
231
|
+
start = boundaryBefore(prevEnd);
|
|
232
|
+
text = content.slice(start, prevEnd);
|
|
233
|
+
if (ACTION_WORD_RE.test(text)) return true;
|
|
234
|
+
}
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
191
237
|
function extractClaimedFilePaths(content) {
|
|
192
238
|
const paths = /* @__PURE__ */ new Set();
|
|
193
239
|
const add = (p) => {
|
|
@@ -195,36 +241,19 @@ function extractClaimedFilePaths(content) {
|
|
|
195
241
|
if (trimmed && /\.\w{1,6}$/.test(trimmed)) paths.add(trimmed);
|
|
196
242
|
};
|
|
197
243
|
let m;
|
|
198
|
-
const actionLineRe = /(?:已[生保写创]|saved|written|created|完成.*(?:写入|保存|创建|生成)|输出|file\s+(?:saved|written|created))/i;
|
|
199
244
|
const backtickRe = /`([^`\n]+?\.\w{1,6})`/g;
|
|
200
245
|
while ((m = backtickRe.exec(content)) !== null) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
while (linesBack < 9 && pos > 0) {
|
|
204
|
-
pos--;
|
|
205
|
-
if (content[pos] === "\n") linesBack++;
|
|
206
|
-
}
|
|
207
|
-
const windowStart = pos === 0 ? 0 : pos + 1;
|
|
208
|
-
const lineEndIdx = content.indexOf("\n", m.index + m[0].length);
|
|
209
|
-
const window = content.slice(windowStart, lineEndIdx === -1 ? void 0 : lineEndIdx);
|
|
210
|
-
if (actionLineRe.test(window)) add(m[1]);
|
|
246
|
+
const pathStart = m.index + m[0].indexOf(m[1]);
|
|
247
|
+
if (hasWriteIntentNear(content, pathStart, pathStart + m[1].length)) add(m[1]);
|
|
211
248
|
}
|
|
212
|
-
const zhRe = /(?:已保存(?:到)?|已写入(?:到)?|已创建|已生成|文件路径[::]|保存为|写入到)\s*[`'”””]?([^\s`'”””,,。\n]
|
|
249
|
+
const zhRe = /(?:已保存(?:到)?|已写入(?:到)?|已创建|已生成|文件路径[::]|保存为|写入到)\s*[`'”””]?([^\s`'”””,,。\n]+\.\w{1,6})/g;
|
|
213
250
|
while ((m = zhRe.exec(content)) !== null) add(m[1]);
|
|
214
|
-
const enRe = /(?:saved|written|created)\s+(?:to|as|at)\s+[`'”]?([^\s`'”\n,]
|
|
251
|
+
const enRe = /(?:saved|written|created)\s+(?:to|as|at)\s+[`'”]?([^\s`'”\n,]+\.\w{1,6})/gi;
|
|
215
252
|
while ((m = enRe.exec(content)) !== null) add(m[1]);
|
|
216
253
|
const checkRe = /✅[^\n`]*?[`'”]?([^\s`'”\n,,。]+?\.\w{1,6})/g;
|
|
217
254
|
while ((m = checkRe.exec(content)) !== null) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
while (linesBack < 9 && pos > 0) {
|
|
221
|
-
pos--;
|
|
222
|
-
if (content[pos] === "\n") linesBack++;
|
|
223
|
-
}
|
|
224
|
-
const windowStart = pos === 0 ? 0 : pos + 1;
|
|
225
|
-
const lineEndIdx = content.indexOf("\n", m.index + m[0].length);
|
|
226
|
-
const window = content.slice(windowStart, lineEndIdx === -1 ? void 0 : lineEndIdx);
|
|
227
|
-
if (actionLineRe.test(window)) add(m[1]);
|
|
255
|
+
const pathStart = m.index + m[0].lastIndexOf(m[1]);
|
|
256
|
+
if (hasWriteIntentNear(content, pathStart, pathStart + m[1].length)) add(m[1]);
|
|
228
257
|
}
|
|
229
258
|
return Array.from(paths);
|
|
230
259
|
}
|
|
@@ -337,7 +366,7 @@ function findPhantomClaims(content, extraMessages) {
|
|
|
337
366
|
}
|
|
338
367
|
function buildPhantomCorrectionMessage(phantoms) {
|
|
339
368
|
const list = phantoms.map((p) => ` - ${p}`).join("\n");
|
|
340
|
-
return
|
|
369
|
+
return 'Your reply mentions the following file(s) alongside a "written / saved / created" claim, but no matching write_file or edit_file tool call was made in this turn:\n' + list + "\n\nIf you did intend to create or modify them, invoke write_file / edit_file NOW \u2014 they do not exist on disk yet, and you must not report the task as done until the tool calls return.\n\nIf you were only REFERENCING them (files you merely read, cited as examples, or named as prior art), then this was a false alarm: do NOT create them, do NOT overwrite anything. Simply restate your answer and say explicitly which of the listed paths you only read or cited. Creating a file that the user never asked for is worse than the false alarm.";
|
|
341
370
|
}
|
|
342
371
|
var DSML_PIPE_CLASS = "[|\\uFF5C\\u2502\\u2503\\u01C0]";
|
|
343
372
|
var PSEUDO_TOOL_CALL_PATTERNS = [
|
|
@@ -972,6 +1001,8 @@ async function runAgentLoop(host) {
|
|
|
972
1001
|
const freeRounds = new FreeRoundTracker();
|
|
973
1002
|
const roundToolHistory = [];
|
|
974
1003
|
const hasWriteTools = host.toolDefs.some((t) => t.name === "write_file" || t.name === "edit_file");
|
|
1004
|
+
let hallucinationRetries = 0;
|
|
1005
|
+
const MAX_HALLUCINATION_RETRIES = 2;
|
|
975
1006
|
for (let round = 0; round < maxToolRounds; round++) {
|
|
976
1007
|
if (host.signal?.aborted) return { reason: "aborted", usage };
|
|
977
1008
|
host.onRoundStart?.(round, maxToolRounds);
|
|
@@ -1009,7 +1040,8 @@ async function runAgentLoop(host) {
|
|
|
1009
1040
|
const phantomPaths = (coarseHallucination || alreadyWrote) && !host.planMode && hasWriteTools && content ? findPhantomClaims(content, extraMessages) : [];
|
|
1010
1041
|
const bashRanThisTurn = extractBashCommands(extraMessages).length > 0;
|
|
1011
1042
|
const coarseShouldFire = coarseHallucination && !bashRanThisTurn;
|
|
1012
|
-
if ((phantomPaths.length > 0 || coarseShouldFire) && round < maxToolRounds - 1) {
|
|
1043
|
+
if ((phantomPaths.length > 0 || coarseShouldFire) && round < maxToolRounds - 1 && hallucinationRetries < MAX_HALLUCINATION_RETRIES) {
|
|
1044
|
+
hallucinationRetries++;
|
|
1013
1045
|
host.onHallucinationRetry?.({ phantomPaths, round, alreadyRendered });
|
|
1014
1046
|
const correctionMsg = phantomPaths.length > 0 ? buildPhantomCorrectionMessage(phantomPaths) : HALLUCINATION_CORRECTION_MESSAGE;
|
|
1015
1047
|
const reasoningField = outcome.reasoningContent ? { reasoning_content: outcome.reasoningContent } : host.providerId === "deepseek" ? { reasoning_content: "" } : {};
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
CI_COMMENT_MARKER,
|
|
4
4
|
countSeverity,
|
|
5
5
|
runCi
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-2XPJRRBB.js";
|
|
7
|
+
import "./chunk-WAAFA32V.js";
|
|
8
8
|
import "./chunk-HLWUDRBO.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-25HFWCM3.js";
|
|
10
|
+
import "./chunk-MTIS7H6V.js";
|
|
11
|
+
import "./chunk-XZNRZGG2.js";
|
|
12
12
|
import "./chunk-TU3L3PW7.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-KWYJFLXY.js";
|
|
14
14
|
import "./chunk-IW3Q7AE5.js";
|
|
15
15
|
export {
|
|
16
16
|
CI_COMMENT_MARKER,
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
formatDoctorReport,
|
|
4
4
|
runDoctorCli
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-FWBSGBB7.js";
|
|
6
|
+
import "./chunk-25HFWCM3.js";
|
|
7
|
+
import "./chunk-MTIS7H6V.js";
|
|
8
|
+
import "./chunk-JEJHNVA2.js";
|
|
9
|
+
import "./chunk-XZNRZGG2.js";
|
|
10
10
|
import "./chunk-TU3L3PW7.js";
|
|
11
11
|
import "./chunk-HOSJZMQS.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-KWYJFLXY.js";
|
|
13
13
|
import "./chunk-IW3Q7AE5.js";
|
|
14
14
|
export {
|
|
15
15
|
formatDoctorReport,
|