deepseeker-code 1.0.3 → 1.0.41
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 +1 -1
- package/dist/cli.mjs +1513 -396
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -34,17 +34,19 @@ var init_strings = __esm({
|
|
|
34
34
|
toolRunning: (name) => `\u23FA ${name} \u8FD0\u884C\u4E2D\u2026`,
|
|
35
35
|
toolDone: (name, ok) => `\u23FA ${name} \xB7 ${ok ? "\u6210\u529F" : "\u5931\u8D25"}`,
|
|
36
36
|
toolDenied: (name) => `\u{1F6AB} ${name} \u5DF2\u88AB\u62D2\u7EDD`,
|
|
37
|
-
planTitle: "\
|
|
38
|
-
planPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4\uFF08\
|
|
39
|
-
planAcceptAuto: "\
|
|
40
|
-
planAcceptManual: "\
|
|
41
|
-
planEdit: "\
|
|
42
|
-
planReject: "\
|
|
37
|
+
planTitle: "\u51C6\u5907\u5F00\u59CB\u7F16\u7801\uFF1F",
|
|
38
|
+
planPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4\uFF08\u7F16\u8F91\u9879\u8FDB\u5165\u7F16\u8F91\u5668\uFF0CEnter \u63D0\u4EA4 / Esc \u53D6\u6D88\uFF09\u3002",
|
|
39
|
+
planAcceptAuto: "\u662F\uFF0C\u5E76\u81EA\u52A8\u63A5\u53D7\u7F16\u8F91\uFF08\u5B9E\u73B0\u9636\u6BB5\u514D\u5BA1\u6279\uFF09",
|
|
40
|
+
planAcceptManual: "\u662F\uFF0C\u5E76\u624B\u52A8\u5BA1\u6279\u7F16\u8F91\uFF08\u9010\u6B65\u5BA1\u6279\u6BCF\u4E2A\u5DE5\u5177\uFF09",
|
|
41
|
+
planEdit: "\u7F16\u8F91\u65B9\u6848",
|
|
42
|
+
planReject: "\u5426\uFF0C\u7EE7\u7EED\u89C4\u5212",
|
|
43
43
|
planEditTitle: "\u270F\uFE0F \u7F16\u8F91\u65B9\u6848",
|
|
44
44
|
planEditHint: "Enter \u6309\u6B64\u65B9\u6848\u6267\u884C \xB7 Esc \u53D6\u6D88\u56DE\u5230\u9009\u9879",
|
|
45
|
-
|
|
45
|
+
planKeepPlanning: "\u270B \u5DF2\u7559\u5728\u8BA1\u5212\u6A21\u5F0F\uFF1A\u7EE7\u7EED\u8F93\u5165\u8865\u5145\u8981\u6C42\uFF0C\u6A21\u578B\u5C06\u4FEE\u8BA2\u65B9\u6848\u540E\u518D\u6B21\u63D0\u4EA4\uFF08/plan \u53EF\u9000\u51FA\uFF09\u3002",
|
|
46
46
|
planEditEmpty: "\u65B9\u6848\u4E0D\u80FD\u4E3A\u7A7A",
|
|
47
47
|
planAutoExecute: "\u26A1 \u5DF2\u8FDB\u5165\u81EA\u52A8\u6267\u884C\uFF1A\u5B9E\u73B0\u9636\u6BB5\u5DE5\u5177\u5C06\u514D\u5BA1\u6279\u76F4\u63A5\u8FD0\u884C\u3002",
|
|
48
|
+
inputBadgePlan: "plan mode on\uFF08\u53EA\u8BFB\u8C03\u7814 \u2192 \u65B9\u6848\u5BA1\u6279 \u2192 \u5B9E\u73B0\uFF09",
|
|
49
|
+
inputBadgeAuto: "auto-accept edits on",
|
|
48
50
|
approvalTitle: "\u{1F510} \u64CD\u4F5C\u5BA1\u6279",
|
|
49
51
|
approvalPrompt: "\u2191\u2193 \u9009\u62E9\u540E Enter\uFF08Esc \u62D2\u7EDD\uFF09\uFF1A\u5141\u8BB8\u672C\u6B21 / \u603B\u662F\u5141\u8BB8\uFF08\u5199\u6301\u4E45\u89C4\u5219\uFF09/ \u62D2\u7EDD\u3002",
|
|
50
52
|
approvalAllow: "\u5141\u8BB8\u672C\u6B21",
|
|
@@ -52,6 +54,9 @@ var init_strings = __esm({
|
|
|
52
54
|
approvalDeny: "\u62D2\u7EDD",
|
|
53
55
|
errAborted: "\u5DF2\u4E2D\u6B62\u5F53\u524D\u8F6E\u3002",
|
|
54
56
|
busyBlockSend: "\u23F3 \u6B63\u5728\u751F\u6210\uFF0C\u8BF7\u7B49\u5F85\u6216\u6309 Esc \u4E2D\u6B62\u540E\u518D\u53D1\u9001\u3002",
|
|
57
|
+
inboxQueued: "\u{1F4EE} \u5DF2\u6392\u961F\uFF0C\u5C06\u5728\u56DE\u5408\u8FB9\u754C\u9001\u8FBE\u6A21\u578B\uFF08Esc \u4ECD\u53EF\u4E2D\u6B62\uFF09\u3002",
|
|
58
|
+
inboxClaimed: (n) => `\u{1F4EC} \u5DF2\u9001\u8FBE\u6A21\u578B\uFF08${n} \u6761\u8865\u5145\u8F93\u5165\uFF09`,
|
|
59
|
+
inboxCarryover: (n) => `\u{1F4EC} \u672C\u8F6E\u7ED3\u675F\u65F6 ${n} \u6761\u8865\u5145\u8F93\u5165\u672A\u5728\u56DE\u5408\u8FB9\u754C\u9001\u8FBE\uFF0C\u5DF2\u5199\u5165\u4F1A\u8BDD\u5386\u53F2\uFF0C\u4E0B\u8F6E\u5BF9\u8BDD\u81EA\u52A8\u5E26\u5165\u3002`,
|
|
55
60
|
cmdHint: "/help \u5E2E\u52A9 \xB7 /plan \u8BA1\u5212\u6A21\u5F0F \xB7 /auto \u81EA\u52A8\u6A21\u5F0F \xB7 /model \u5207\u6362\u6A21\u578B \xB7 /thinking \u601D\u8003\u7B49\u7EA7 \xB7 /lang \u8BED\u8A00 \xB7 /sessions \u5386\u53F2 \xB7 /clear \u6E05\u5C4F \xB7 /exit \u9000\u51FA",
|
|
56
61
|
statusStreaming: "\u751F\u6210\u4E2D",
|
|
57
62
|
statusIdle: "\u5C31\u7EEA",
|
|
@@ -98,6 +103,12 @@ ${dim} \u8FD0\u884C npm i -g deepseeker-code@latest \u66F4\u65B0${reset}
|
|
|
98
103
|
sessionsPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u8F7D\u5165 \xB7 Esc \u53D6\u6D88",
|
|
99
104
|
noHistory: "\uFF08\u6682\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF09",
|
|
100
105
|
sessionLoaded: (id) => `\u5DF2\u8F7D\u5165\u4F1A\u8BDD ${id}\uFF08\u7EE7\u7EED\u5BF9\u8BDD\u5C06\u7EED\u63A5\u6B64\u4F1A\u8BDD\uFF09`,
|
|
106
|
+
cmdFork: "\u4ECE\u5F53\u524D\u4F1A\u8BDD\u7684\u67D0\u8F6E\u56DE\u590D\u5904\u5206\u53C9\u51FA\u65B0\u4F1A\u8BDD",
|
|
107
|
+
forkTitle: "\u{1F33F} \u5206\u53C9\u5F53\u524D\u4F1A\u8BDD\uFF08\u2191\u2193 \u9009\u68C0\u67E5\u70B9 \xB7 Enter \u5206\u53C9\uFF09",
|
|
108
|
+
forkPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u5206\u53C9 \xB7 Esc \u53D6\u6D88",
|
|
109
|
+
forkEmpty: "\uFF08\u5F53\u524D\u4F1A\u8BDD\u6682\u65E0\u53EF\u5206\u53C9\u7684\u68C0\u67E5\u70B9\uFF09",
|
|
110
|
+
forkDone: (id, roundNo) => `\u5DF2\u4ECE\u7B2C ${roundNo} \u8F6E\u5206\u53C9 \u2192 \u65B0\u4F1A\u8BDD ${id}\uFF08\u5DF2\u8F7D\u5165\uFF0C\u540E\u7EED\u5BF9\u8BDD\u5199\u5165\u65B0\u4F1A\u8BDD\uFF0C\u539F\u4F1A\u8BDD\u4E0D\u53D8\uFF09`,
|
|
111
|
+
forkFailed: (e) => `\u5206\u53C9\u5931\u8D25\uFF1A${e}`,
|
|
101
112
|
relTime: (iso) => {
|
|
102
113
|
const t = Date.parse(iso);
|
|
103
114
|
if (!t) return "";
|
|
@@ -133,6 +144,7 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
|
|
|
133
144
|
`/thinking [off|high|max] \u2014 \u5207\u6362\u601D\u8003\u7B49\u7EA7\uFF08\u5F53\u524D ${thinking}\uFF09`,
|
|
134
145
|
`/lang [zh|en] \u2014 \u5207\u6362\u754C\u9762\u8BED\u8A00\uFF08\u5F53\u524D ${locale2}\uFF09`,
|
|
135
146
|
"/sessions \u2014 \u9009\u62E9\u5E76\u8F7D\u5165\u5386\u53F2\u4F1A\u8BDD\uFF08\u7EED\u63A5\u5BF9\u8BDD\uFF09",
|
|
147
|
+
"/fork \u2014 \u4ECE\u5F53\u524D\u4F1A\u8BDD\u7684\u67D0\u8F6E\u56DE\u590D\u5904\u5206\u53C9\u51FA\u65B0\u4F1A\u8BDD",
|
|
136
148
|
"/trust \u2014 \u7BA1\u7406\u5DF2\u4FE1\u4EFB\u76EE\u5F55\uFF08\u9879\u76EE\u7EA7 hooks/skills \u7B49\u4EC5\u5728\u4FE1\u4EFB\u76EE\u5F55\u52A0\u8F7D\uFF1BCI \u7528 --trust \u663E\u5F0F\u4FE1\u4EFB\uFF09",
|
|
137
149
|
"Ctrl+C \u9000\u51FA \xB7 Esc \u4E2D\u6B62/\u6E05\u8F93\u5165 \xB7 Ctrl+G \u4E2D\u6B62 \xB7 Ctrl+T \u5C55\u5F00/\u6536\u8D77\u601D\u8003"
|
|
138
150
|
].join("\n"),
|
|
@@ -162,17 +174,19 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
|
|
|
162
174
|
toolRunning: (name) => `\u23FA ${name} running\u2026`,
|
|
163
175
|
toolDone: (name, ok) => `\u23FA ${name} \xB7 ${ok ? "ok" : "failed"}`,
|
|
164
176
|
toolDenied: (name) => `\u{1F6AB} ${name} denied`,
|
|
165
|
-
planTitle: "
|
|
177
|
+
planTitle: "Ready to code?",
|
|
166
178
|
planPrompt: "\u2191\u2193 then Enter (edit opens the editor: Enter to save / Esc to cancel).",
|
|
167
|
-
planAcceptAuto: "
|
|
168
|
-
planAcceptManual: "
|
|
179
|
+
planAcceptAuto: "Yes, and auto-accept edits (skip impl approvals)",
|
|
180
|
+
planAcceptManual: "Yes, and manually approve edits (step-by-step)",
|
|
169
181
|
planEdit: "Edit plan",
|
|
170
|
-
planReject: "
|
|
182
|
+
planReject: "No, keep planning",
|
|
171
183
|
planEditTitle: "\u270F\uFE0F Edit plan",
|
|
172
184
|
planEditHint: "Enter to implement with this plan \xB7 Esc back to options",
|
|
173
|
-
|
|
185
|
+
planKeepPlanning: "\u270B Staying in plan mode: add feedback and the plan will be revised and resubmitted (/plan to exit).",
|
|
174
186
|
planEditEmpty: "Plan cannot be empty",
|
|
175
187
|
planAutoExecute: "\u26A1 Auto-run: implementation tools will execute without approval.",
|
|
188
|
+
inputBadgePlan: "plan mode on (read-only research \u2192 approve \u2192 implement)",
|
|
189
|
+
inputBadgeAuto: "auto-accept edits on",
|
|
176
190
|
approvalTitle: "\u{1F510} Action approval",
|
|
177
191
|
approvalPrompt: "\u2191\u2193 then Enter (Esc to deny): allow once / always allow (persist rule) / deny.",
|
|
178
192
|
approvalAllow: "Allow once",
|
|
@@ -180,6 +194,9 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
|
|
|
180
194
|
approvalDeny: "Deny",
|
|
181
195
|
errAborted: "Aborted current turn.",
|
|
182
196
|
busyBlockSend: "\u23F3 Still generating\u2014wait or press Esc to abort before sending.",
|
|
197
|
+
inboxQueued: "\u{1F4EE} Queued\u2014will reach the model at the next round boundary (Esc still aborts).",
|
|
198
|
+
inboxClaimed: (n) => `\u{1F4EC} Delivered to the model (${n} supplemental input${n > 1 ? "s" : ""})`,
|
|
199
|
+
inboxCarryover: (n) => `\u{1F4EC} ${n} supplemental input${n > 1 ? "s" : ""} not claimed at a round boundary before this run ended; saved to session history and carried into the next turn.`,
|
|
183
200
|
cmdHint: "/help help \xB7 /plan plan mode \xB7 /auto auto mode \xB7 /model switch model \xB7 /thinking thinking level \xB7 /lang language \xB7 /sessions history \xB7 /clear clear \xB7 /exit quit",
|
|
184
201
|
statusStreaming: "streaming",
|
|
185
202
|
statusIdle: "ready",
|
|
@@ -226,6 +243,12 @@ ${dim} Run npm i -g deepseeker-code@latest to update${reset}
|
|
|
226
243
|
sessionsPrompt: "\u2191\u2193 pick \xB7 Enter resume \xB7 Esc cancel",
|
|
227
244
|
noHistory: "(no past sessions)",
|
|
228
245
|
sessionLoaded: (id) => `Resumed session ${id} (new messages continue it)`,
|
|
246
|
+
cmdFork: "Fork the current session from a past round",
|
|
247
|
+
forkTitle: "\u{1F33F} Fork current session (\u2191\u2193 to pick \xB7 Enter to fork)",
|
|
248
|
+
forkPrompt: "\u2191\u2193 pick \xB7 Enter fork \xB7 Esc cancel",
|
|
249
|
+
forkEmpty: "(no checkpoints to fork from in this session)",
|
|
250
|
+
forkDone: (id, roundNo) => `Forked from round ${roundNo} \u2192 new session ${id} (loaded; new messages go to the fork, source untouched)`,
|
|
251
|
+
forkFailed: (e) => `Fork failed: ${e}`,
|
|
229
252
|
relTime: (iso) => {
|
|
230
253
|
const t = Date.parse(iso);
|
|
231
254
|
if (!t) return "";
|
|
@@ -261,6 +284,7 @@ DeepSeeker-Code will read, edit, and execute files here.`,
|
|
|
261
284
|
`/thinking [off|high|max] \u2014 Switch thinking level (current ${thinking})`,
|
|
262
285
|
`/lang [zh|en] \u2014 Switch interface language (current ${locale2})`,
|
|
263
286
|
"/sessions \u2014 Pick a past session to resume",
|
|
287
|
+
"/fork \u2014 Fork the current session from a past round",
|
|
264
288
|
"/trust \u2014 Manage trusted dirs (project hooks/skills load only when trusted; CI uses --trust)",
|
|
265
289
|
"Ctrl+C exit \xB7 Esc abort/clear input \xB7 Ctrl+G abort \xB7 Ctrl+T toggle thinking"
|
|
266
290
|
].join("\n"),
|
|
@@ -281,7 +305,7 @@ DeepSeeker-Code will read, edit, and execute files here.`,
|
|
|
281
305
|
S = new Proxy({}, {
|
|
282
306
|
get: (_t, k) => typeof k === "string" ? STRINGS[locale][k] : void 0
|
|
283
307
|
});
|
|
284
|
-
LOCAL_COMMAND_NAMES = ["help", "status", "plan", "auto", "model", "thinking", "lang", "output-style", "sessions", "usage", "context", "permissions", "mcp", "hooks", "trust", "debug", "clear", "exit"];
|
|
308
|
+
LOCAL_COMMAND_NAMES = ["help", "status", "plan", "auto", "model", "thinking", "lang", "output-style", "sessions", "fork", "usage", "context", "permissions", "mcp", "hooks", "trust", "debug", "clear", "exit"];
|
|
285
309
|
}
|
|
286
310
|
});
|
|
287
311
|
|
|
@@ -289,13 +313,15 @@ DeepSeeker-Code will read, edit, and execute files here.`,
|
|
|
289
313
|
var config_exports = {};
|
|
290
314
|
__export(config_exports, {
|
|
291
315
|
ENGINE_OVERRIDE_KEYS: () => ENGINE_OVERRIDE_KEYS,
|
|
292
|
-
|
|
316
|
+
ENV_SOURCES: () => ENV_SOURCES,
|
|
317
|
+
appConfig: () => appConfig,
|
|
318
|
+
configSources: () => configSources
|
|
293
319
|
});
|
|
294
320
|
import path2 from "path";
|
|
295
321
|
import os2 from "os";
|
|
296
322
|
import { readFileSync as readFileSync2 } from "fs";
|
|
297
323
|
import { createHash } from "crypto";
|
|
298
|
-
var _DataDir, appConfig, ENGINE_OVERRIDE_VALIDATORS, ENGINE_OVERRIDE_KEYS, applyEngineOverrides;
|
|
324
|
+
var _DataDir, appConfig, ENV_SOURCES, configSources, ENGINE_OVERRIDE_VALIDATORS, ENGINE_OVERRIDE_KEYS, applyEngineOverrides;
|
|
299
325
|
var init_config = __esm({
|
|
300
326
|
"../core/src/config/index.ts"() {
|
|
301
327
|
"use strict";
|
|
@@ -370,8 +396,51 @@ var init_config = __esm({
|
|
|
370
396
|
workflowMaxSteps: Number(process.env.DEEP_SEEK_WORKFLOW_MAX_STEPS) || 8,
|
|
371
397
|
/** P0-3 run_workflow 单个子 agent 结果的字符预算:超出按头尾截断,避免单个巨型结果挤占聚合输出。
|
|
372
398
|
* 最终聚合再受工具 maxOutputCharacters 兜底。 */
|
|
373
|
-
workflowPerStepChars: 6e3
|
|
374
|
-
|
|
399
|
+
workflowPerStepChars: 6e3,
|
|
400
|
+
/** ★ P0-A 计划模式强制位置:'runtime'(默认)= 工具表全会话恒定(两态统一 appendPlanControlTools),
|
|
401
|
+
* 计划期写工具由 processToolCall 执行层按 PLAN_ALLOWED_TOOLS 拒绝——保 DeepSeek 前缀缓存
|
|
402
|
+
* (tools 参数序列化在请求头部,计划模式裁表翻转 = 全会话历史 re-prefill 两次);
|
|
403
|
+
* 'schema' = 旧路径(计划期裁成只读白名单子表)。env DEEP_SEEK_PLAN_ENFORCEMENT=schema 回退。 */
|
|
404
|
+
planEnforcement: process.env.DEEP_SEEK_PLAN_ENFORCEMENT === "schema" ? "schema" : "runtime",
|
|
405
|
+
/** ★ P1-MCP 工具暴露模式:'dispatcher'(默认)= 只注入恒定 schema 的 mcp_list_tools + mcp_call
|
|
406
|
+
* (目录按需查、审批/权限用合成名 mcp__<server>__<tool> 匹配既有规则;工具表不随 MCP server
|
|
407
|
+
* 工具数增长,L1 恒定);'schemas' = 旧路径(每个 MCP 工具独立 schema 常驻)。
|
|
408
|
+
* env DEEP_SEEK_MCP_EXPOSE_MODE=schemas 回退。 */
|
|
409
|
+
mcpExposeMode: process.env.DEEP_SEEK_MCP_EXPOSE_MODE === "schemas" ? "schemas" : "dispatcher",
|
|
410
|
+
/** ★ 事件日志化:transcript 追加 turn/step 边界事件行(run.start/round.end/run.end/compaction/
|
|
411
|
+
* run.abandoned,带 dscEvent 标记,readMessages 自动过滤)——崩溃恢复从盲扫启发式升级为事件确认,
|
|
412
|
+
* compaction 事件携带归档计数+摘要文本使 transcript 自包含(分叉/审计不再押 state.json 单点)。
|
|
413
|
+
* 关闭时 appendEvent 全 no-op、恢复走纯内存启发式(= 改造前行为)。env DEEP_SEEK_TRANSCRIPT_EVENTS=0 回退。 */
|
|
414
|
+
transcriptEvents: process.env.DEEP_SEEK_TRANSCRIPT_EVENTS !== "0",
|
|
415
|
+
/** ★ inbox steering(第二梯队 #2):agent 运行中用户补充输入进 per-session 队列,runAgent 回合边界
|
|
416
|
+
* claim 注入上下文并落盘 transcript(长任务中途补指示不再只能中止重跑)。
|
|
417
|
+
* 关闭时全链路 no-op:端点 501 / CLI 回退 busy 提示 / VSCode 不排队。env DEEP_SEEK_INBOX=0 回退。 */
|
|
418
|
+
inboxSteering: process.env.DEEP_SEEK_INBOX !== "0",
|
|
419
|
+
/** ★ hooks 改写型拦截点(第二梯队 #3):PreToolUse 可改 args(argsOverride,前置到全部安全门禁
|
|
420
|
+
* 之前生效——门禁/审批评估的是改写后参数)、PostToolUse 可改 resultForModel(仅模型视图,
|
|
421
|
+
* 用户视图 resultForUser 不变)。关闭时 PreToolUse 回退旧位(审批后、仅 deny),改写字段全忽略,
|
|
422
|
+
* 行为与改造前一致。env DEEP_SEEK_HOOK_REWRITE=0 回退。 */
|
|
423
|
+
hookRewrite: process.env.DEEP_SEEK_HOOK_REWRITE !== "0"
|
|
424
|
+
};
|
|
425
|
+
ENV_SOURCES = {
|
|
426
|
+
dataDir: "DEEPSEEKER_CODE_DATA_DIR",
|
|
427
|
+
searchProvider: "SEARCH_PROVIDER",
|
|
428
|
+
tavilyApiKey: "TAVILY_API_KEY",
|
|
429
|
+
webFetchAllowPrivate: "WEB_FETCH_ALLOW_PRIVATE",
|
|
430
|
+
parallelSafeTools: "DEEP_SEEK_PARALLEL_SAFE_TOOLS",
|
|
431
|
+
workflowConcurrency: "DEEP_SEEK_WORKFLOW_CONCURRENCY",
|
|
432
|
+
workflowMaxSteps: "DEEP_SEEK_WORKFLOW_MAX_STEPS",
|
|
433
|
+
planEnforcement: "DEEP_SEEK_PLAN_ENFORCEMENT",
|
|
434
|
+
mcpExposeMode: "DEEP_SEEK_MCP_EXPOSE_MODE",
|
|
435
|
+
transcriptEvents: "DEEP_SEEK_TRANSCRIPT_EVENTS",
|
|
436
|
+
inboxSteering: "DEEP_SEEK_INBOX",
|
|
437
|
+
hookRewrite: "DEEP_SEEK_HOOK_REWRITE"
|
|
438
|
+
};
|
|
439
|
+
configSources = {};
|
|
440
|
+
for (const [key, envName] of Object.entries(ENV_SOURCES)) {
|
|
441
|
+
const v = process.env[envName];
|
|
442
|
+
if (v !== void 0 && v !== "") configSources[key] = "env";
|
|
443
|
+
}
|
|
375
444
|
ENGINE_OVERRIDE_VALIDATORS = {
|
|
376
445
|
undoEnabled: (v) => typeof v === "boolean" ? v : void 0,
|
|
377
446
|
undoBackupSensitive: (v) => v === "skip" || v === "deny" || v === "allow" ? v : void 0,
|
|
@@ -382,12 +451,12 @@ var init_config = __esm({
|
|
|
382
451
|
ENGINE_OVERRIDE_KEYS = Object.keys(ENGINE_OVERRIDE_VALIDATORS);
|
|
383
452
|
applyEngineOverrides = (cfg) => {
|
|
384
453
|
const paths = [
|
|
385
|
-
path2.join(cfg.dataDir, "settings.json"),
|
|
454
|
+
{ scope: "settings.global", configPath: path2.join(cfg.dataDir, "settings.json") },
|
|
386
455
|
// 全局用户级
|
|
387
|
-
path2.join(process.cwd(), ".deepseeker-code", "settings.json")
|
|
456
|
+
{ scope: "settings.project", configPath: path2.join(process.cwd(), ".deepseeker-code", "settings.json") }
|
|
388
457
|
// 项目级(覆盖全局)
|
|
389
458
|
];
|
|
390
|
-
for (const configPath of paths) {
|
|
459
|
+
for (const { scope, configPath } of paths) {
|
|
391
460
|
let raw;
|
|
392
461
|
try {
|
|
393
462
|
raw = readFileSync2(configPath, "utf-8");
|
|
@@ -411,6 +480,7 @@ var init_config = __esm({
|
|
|
411
480
|
continue;
|
|
412
481
|
}
|
|
413
482
|
cfg[key] = valid;
|
|
483
|
+
configSources[key] = scope;
|
|
414
484
|
}
|
|
415
485
|
}
|
|
416
486
|
};
|
|
@@ -491,13 +561,20 @@ var init_common = __esm({
|
|
|
491
561
|
injectMarkedBlock = (message, fence, body) => {
|
|
492
562
|
const sys = message[0];
|
|
493
563
|
if (!sys || sys.role !== "system" || typeof sys.content !== "string") return;
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
sys.content += `
|
|
564
|
+
const idx = sys.content.indexOf(fence);
|
|
565
|
+
if (idx === -1) {
|
|
566
|
+
sys.content += `
|
|
498
567
|
|
|
499
568
|
${fence}
|
|
500
569
|
${body}`;
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const after = sys.content.slice(idx + fence.length);
|
|
573
|
+
const next = after.match(/\n\n⟦[^\n]*?⟧/);
|
|
574
|
+
const oldBody = next?.index !== void 0 ? after.slice(0, next.index) : after;
|
|
575
|
+
if (oldBody === `
|
|
576
|
+
${body}`) return;
|
|
577
|
+
console.warn(`\u26A0\uFE0F ${fence} \u5DF2\u9501\u5B9A\uFF08\u4F1A\u8BDD\u5185\u4E0D\u53D8\u4EE5\u4FDD\u524D\u7F00\u7F13\u5B58\uFF09\uFF0C\u5185\u5BB9\u53D8\u5316\u5C06\u4E8E\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\u3002`);
|
|
501
578
|
};
|
|
502
579
|
decodeProcessOutput = (buf) => {
|
|
503
580
|
const utf8 = buf.toString("utf8");
|
|
@@ -811,17 +888,120 @@ var init_deepseek = __esm({
|
|
|
811
888
|
}
|
|
812
889
|
});
|
|
813
890
|
|
|
891
|
+
// ../core/src/llm/providers/replay/index.ts
|
|
892
|
+
var createReplayProvider;
|
|
893
|
+
var init_replay = __esm({
|
|
894
|
+
"../core/src/llm/providers/replay/index.ts"() {
|
|
895
|
+
"use strict";
|
|
896
|
+
createReplayProvider = (script) => {
|
|
897
|
+
const turns = Array.isArray(script.turns) ? script.turns : [];
|
|
898
|
+
let cursor = 0;
|
|
899
|
+
let attemptCounts = [];
|
|
900
|
+
const calls = [];
|
|
901
|
+
const makeFaultError = (fault) => {
|
|
902
|
+
const msg = fault.message ?? (fault.type === "idle" ? "stream_idle_timeout" : fault.type === "context_length" ? "context_length_exceeded\uFF08\u56DE\u653E\u6CE8\u5165\uFF09" : fault.type === "transient" ? "HTTP 429 rate limit\uFF08\u56DE\u653E\u6CE8\u5165\uFF09" : "\u56DE\u653E\u81F4\u547D\u9519\u8BEF\uFF08fatal\uFF09");
|
|
903
|
+
const e = new Error(msg);
|
|
904
|
+
e.replayFault = fault.type;
|
|
905
|
+
if (fault.type === "transient") e.status = 429;
|
|
906
|
+
return e;
|
|
907
|
+
};
|
|
908
|
+
const streamChat2 = async function* (messages, tools, opts) {
|
|
909
|
+
const turnIndex = cursor;
|
|
910
|
+
calls.push({ turnIndex, messages: [...messages], tools, opts });
|
|
911
|
+
const turn = turns[turnIndex];
|
|
912
|
+
if (!turn) return;
|
|
913
|
+
const attempt = attemptCounts[turnIndex] ?? 0;
|
|
914
|
+
attemptCounts[turnIndex] = attempt + 1;
|
|
915
|
+
const fault = turn.fault;
|
|
916
|
+
const shouldFault = !!fault && (fault.type === "fatal" || attempt < (fault.times ?? 1));
|
|
917
|
+
if (shouldFault) {
|
|
918
|
+
const f = fault;
|
|
919
|
+
const n = Math.min(f.afterChars ?? 0, (turn.content ?? "").length);
|
|
920
|
+
if (n > 0) yield { kind: "text", text: (turn.content ?? "").slice(0, n) };
|
|
921
|
+
throw makeFaultError(f);
|
|
922
|
+
}
|
|
923
|
+
if (turn.reasoning) yield { kind: "reasoning", text: turn.reasoning };
|
|
924
|
+
if (turn.content) yield { kind: "text", text: turn.content };
|
|
925
|
+
const tcs = turn.toolCalls ?? [];
|
|
926
|
+
for (let i = 0; i < tcs.length; i++) {
|
|
927
|
+
const tc = tcs[i];
|
|
928
|
+
yield { kind: "tool_call_delta", index: i, id: tc.id ?? `call_replay_${turnIndex}_${i}`, type: "function", nameDelta: tc.name };
|
|
929
|
+
yield { kind: "tool_call_delta", index: i, argumentsDelta: JSON.stringify(tc.args ?? {}) };
|
|
930
|
+
}
|
|
931
|
+
if (turn.usage) yield { kind: "usage", usage: turn.usage };
|
|
932
|
+
cursor++;
|
|
933
|
+
};
|
|
934
|
+
const summarize2 = async (_messages, _tools, _opts) => ({
|
|
935
|
+
id: "replay-summary",
|
|
936
|
+
object: "chat.completion",
|
|
937
|
+
created: 0,
|
|
938
|
+
// 确定性:固定值(回放产物不掺时间戳,diff 稳定)
|
|
939
|
+
model: "replay",
|
|
940
|
+
choices: [{
|
|
941
|
+
index: 0,
|
|
942
|
+
message: { role: "assistant", content: script.summarizeText ?? "\uFF08\u56DE\u653E\u6458\u8981\uFF1A\u538B\u7F29\u8DEF\u5F84\u7684\u786E\u5B9A\u6027\u5360\u4F4D\u6587\u672C\uFF09", refusal: null },
|
|
943
|
+
finish_reason: "stop",
|
|
944
|
+
logprobs: null
|
|
945
|
+
}],
|
|
946
|
+
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
|
|
947
|
+
});
|
|
948
|
+
return {
|
|
949
|
+
id: "replay",
|
|
950
|
+
displayName: "Replay",
|
|
951
|
+
modelLabel: "Replay",
|
|
952
|
+
streamChat: streamChat2,
|
|
953
|
+
summarize: summarize2,
|
|
954
|
+
classifyRisk: async () => script.riskVerdict ?? "safe",
|
|
955
|
+
buildAssistantMessage: (parts) => {
|
|
956
|
+
const m = { role: "assistant", content: parts.content };
|
|
957
|
+
if (parts.reasoning) m.reasoning_content = parts.reasoning;
|
|
958
|
+
if (parts.toolCalls?.length) m.tool_calls = parts.toolCalls;
|
|
959
|
+
return m;
|
|
960
|
+
},
|
|
961
|
+
// 自识别回放注入的故障(streamInference 经 activeProvider 调用这两个分类器驱动重试通道)
|
|
962
|
+
isContextLengthError: (e) => e?.replayFault === "context_length",
|
|
963
|
+
isTransientError: (e) => e?.replayFault === "transient",
|
|
964
|
+
get calls() {
|
|
965
|
+
return calls;
|
|
966
|
+
},
|
|
967
|
+
get cursor() {
|
|
968
|
+
return cursor;
|
|
969
|
+
},
|
|
970
|
+
reset: () => {
|
|
971
|
+
cursor = 0;
|
|
972
|
+
attemptCounts = [];
|
|
973
|
+
calls.length = 0;
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
});
|
|
979
|
+
|
|
814
980
|
// ../core/src/llm/model.ts
|
|
815
|
-
|
|
981
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
982
|
+
var resolveInitialProvider, activeProvider, chatWithModelWithSummary, classifyToolRisk;
|
|
816
983
|
var init_model = __esm({
|
|
817
984
|
"../core/src/llm/model.ts"() {
|
|
818
985
|
"use strict";
|
|
819
986
|
init_deepseek();
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
987
|
+
init_replay();
|
|
988
|
+
resolveInitialProvider = () => {
|
|
989
|
+
if (process.env.DEEP_SEEK_PROVIDER !== "replay") return deepseekProvider;
|
|
990
|
+
const scriptPath = process.env.DEEP_SEEK_REPLAY_SCRIPT;
|
|
991
|
+
if (!scriptPath) {
|
|
992
|
+
throw new Error("DEEP_SEEK_PROVIDER=replay \u9700\u540C\u65F6\u8BBE\u7F6E DEEP_SEEK_REPLAY_SCRIPT=<script.json>\uFF08\u56DE\u653E\u5267\u672C\u8DEF\u5F84\uFF09");
|
|
993
|
+
}
|
|
994
|
+
let raw;
|
|
995
|
+
try {
|
|
996
|
+
raw = JSON.parse(readFileSync3(scriptPath, "utf-8"));
|
|
997
|
+
} catch (e) {
|
|
998
|
+
throw new Error(`\u56DE\u653E\u5267\u672C\u52A0\u8F7D\u5931\u8D25\uFF08${scriptPath}\uFF09: ${e?.message ?? e}`);
|
|
999
|
+
}
|
|
1000
|
+
return createReplayProvider(Array.isArray(raw) ? { turns: raw } : raw);
|
|
1001
|
+
};
|
|
1002
|
+
activeProvider = resolveInitialProvider();
|
|
1003
|
+
chatWithModelWithSummary = (messages, tools, opts) => activeProvider.summarize(messages, tools, opts);
|
|
1004
|
+
classifyToolRisk = (toolName, args, detail, signal) => activeProvider.classifyRisk(toolName, args, detail, signal);
|
|
825
1005
|
}
|
|
826
1006
|
});
|
|
827
1007
|
|
|
@@ -1139,6 +1319,7 @@ var init_store = __esm({
|
|
|
1139
1319
|
} catch {
|
|
1140
1320
|
continue;
|
|
1141
1321
|
}
|
|
1322
|
+
if (typeof msg?.dscEvent === "string") continue;
|
|
1142
1323
|
messageCount++;
|
|
1143
1324
|
if (!preview && msg?.role === "user" && typeof msg.content === "string") {
|
|
1144
1325
|
const t = msg.content.replace(/\s+/g, " ").trim();
|
|
@@ -1193,6 +1374,87 @@ var init_store = __esm({
|
|
|
1193
1374
|
}
|
|
1194
1375
|
});
|
|
1195
1376
|
|
|
1377
|
+
// ../core/src/session/transcript.ts
|
|
1378
|
+
import fs5 from "fs/promises";
|
|
1379
|
+
var isEventLine, readTranscriptLines, appendLineWithRetry, appendMessage, appendEvent;
|
|
1380
|
+
var init_transcript = __esm({
|
|
1381
|
+
"../core/src/session/transcript.ts"() {
|
|
1382
|
+
"use strict";
|
|
1383
|
+
init_store();
|
|
1384
|
+
init_common();
|
|
1385
|
+
init_config();
|
|
1386
|
+
isEventLine = (l) => typeof l?.dscEvent === "string";
|
|
1387
|
+
readTranscriptLines = async (sessionId) => {
|
|
1388
|
+
await ensureSessionsDir(sessionId);
|
|
1389
|
+
const p = getTranscriptPath(sessionId);
|
|
1390
|
+
try {
|
|
1391
|
+
const text = await fs5.readFile(p, "utf-8");
|
|
1392
|
+
const lines = [];
|
|
1393
|
+
for (const s of text.split("\n")) {
|
|
1394
|
+
const line = s.trim();
|
|
1395
|
+
if (line.length === 0) continue;
|
|
1396
|
+
try {
|
|
1397
|
+
lines.push(JSON.parse(line));
|
|
1398
|
+
} catch {
|
|
1399
|
+
console.warn(`\u26A0\uFE0F [transcript] \u8DF3\u8FC7\u65E0\u6CD5\u89E3\u6790\u7684\u635F\u574F\u884C: ${line.slice(0, 120)}`);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
return lines;
|
|
1403
|
+
} catch (err) {
|
|
1404
|
+
if (err?.code === "ENOENT") return [];
|
|
1405
|
+
throw err;
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
appendLineWithRetry = async (p, payload) => {
|
|
1409
|
+
const MAX_ATTEMPTS = 3;
|
|
1410
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
1411
|
+
let beforeSize = 0;
|
|
1412
|
+
try {
|
|
1413
|
+
beforeSize = (await fs5.stat(p)).size;
|
|
1414
|
+
} catch {
|
|
1415
|
+
}
|
|
1416
|
+
try {
|
|
1417
|
+
await fs5.appendFile(p, payload, "utf-8");
|
|
1418
|
+
return;
|
|
1419
|
+
} catch (e) {
|
|
1420
|
+
try {
|
|
1421
|
+
await fs5.truncate(p, beforeSize);
|
|
1422
|
+
} catch {
|
|
1423
|
+
}
|
|
1424
|
+
if (attempt === MAX_ATTEMPTS) throw e;
|
|
1425
|
+
await new Promise((r) => setTimeout(r, 50 * attempt));
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
appendMessage = async (entry) => {
|
|
1430
|
+
try {
|
|
1431
|
+
await ensureSessionsDir(entry.sessionId);
|
|
1432
|
+
const { sessionId, ...rest } = entry;
|
|
1433
|
+
const line = { id: createUUID(), ...rest };
|
|
1434
|
+
const p = getTranscriptPath(sessionId);
|
|
1435
|
+
const payload = JSON.stringify(line) + "\n";
|
|
1436
|
+
if (payload.includes("\uFFFD")) {
|
|
1437
|
+
const fffdCount = (payload.match(/\uFFFD/g) || []).length;
|
|
1438
|
+
console.warn(`\u26A0\uFE0F [transcript] \u6D88\u606F\u542B ${fffdCount} \u4E2A\u4E71\u7801\u5B57\u7B26\uFF08U+FFFD\uFF09\uFF0C\u5DF2\u539F\u6837\u5199\u5165\u5386\u53F2\u3002\u6765\u6E90\u53EF\u80FD\u662F GBK \u5B50\u8FDB\u7A0B\u8F93\u51FA\u6216\u4E71\u7801\u7C98\u8D34\u3002`);
|
|
1439
|
+
}
|
|
1440
|
+
await appendLineWithRetry(p, payload);
|
|
1441
|
+
} catch (e) {
|
|
1442
|
+
console.warn(`\u26A0\uFE0F \u6D88\u606F\u843D\u76D8\u5931\u8D25\uFF08\u5DF2\u91CD\u8BD5 3 \u6B21\uFF0C\u5185\u5B58\u4E0E\u78C1\u76D8\u8F6C\u5F55\u53EF\u80FD\u4E0D\u4E00\u81F4\uFF09:`, e);
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1445
|
+
appendEvent = async (sessionId, ev) => {
|
|
1446
|
+
if (!appConfig.transcriptEvents) return;
|
|
1447
|
+
try {
|
|
1448
|
+
await ensureSessionsDir(sessionId);
|
|
1449
|
+
const line = { id: createUUID(), ts: (/* @__PURE__ */ new Date()).toISOString(), ...ev };
|
|
1450
|
+
await appendLineWithRetry(getTranscriptPath(sessionId), JSON.stringify(line) + "\n");
|
|
1451
|
+
} catch (e) {
|
|
1452
|
+
console.warn(`\u26A0\uFE0F [transcript] \u4E8B\u4EF6\u884C\u843D\u76D8\u5931\u8D25\uFF08${ev.dscEvent}\uFF0C\u6062\u590D/\u5206\u53C9\u5C06\u56DE\u9000\u542F\u53D1\u5F0F\uFF09:`, e);
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1196
1458
|
// ../core/src/hooks/types.ts
|
|
1197
1459
|
var INTERCEPTABLE_EVENTS, TOOL_EVENTS, ALL_EVENTS, DEFAULT_TIMEOUT_BY_EVENT;
|
|
1198
1460
|
var init_types = __esm({
|
|
@@ -1340,12 +1602,13 @@ var init_shellExecutor = __esm({
|
|
|
1340
1602
|
});
|
|
1341
1603
|
|
|
1342
1604
|
// ../core/src/hooks/registry.ts
|
|
1343
|
-
var rules, matches, registerHooks, listHooks, dispatch, runPreHooks, HOOK_RESULT_MAX, truncateForHook, runPostHooks;
|
|
1605
|
+
var rules, matches, registerHooks, listHooks, isPlainObject, dispatch, runPreHooks, HOOK_RESULT_MAX, truncateForHook, runPostHooks;
|
|
1344
1606
|
var init_registry = __esm({
|
|
1345
1607
|
"../core/src/hooks/registry.ts"() {
|
|
1346
1608
|
"use strict";
|
|
1347
1609
|
init_types();
|
|
1348
1610
|
init_shellExecutor();
|
|
1611
|
+
init_config();
|
|
1349
1612
|
rules = [];
|
|
1350
1613
|
matches = (matcher, toolName) => {
|
|
1351
1614
|
if (typeof matcher === "string") return matcher === "*" || matcher === toolName;
|
|
@@ -1368,6 +1631,7 @@ var init_registry = __esm({
|
|
|
1368
1631
|
};
|
|
1369
1632
|
return rules.map((r) => ({ event: r.event, matcher: strMatcher(r.matcher), source: r.source, onError: r.onError }));
|
|
1370
1633
|
};
|
|
1634
|
+
isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
1371
1635
|
dispatch = async (event, ctx) => {
|
|
1372
1636
|
const interceptable = INTERCEPTABLE_EVENTS.has(event);
|
|
1373
1637
|
const isToolEvent = TOOL_EVENTS.has(event);
|
|
@@ -1395,14 +1659,29 @@ var init_registry = __esm({
|
|
|
1395
1659
|
)
|
|
1396
1660
|
));
|
|
1397
1661
|
const additions2 = [];
|
|
1398
|
-
|
|
1399
|
-
|
|
1662
|
+
let resultOverride;
|
|
1663
|
+
for (const r of results) {
|
|
1664
|
+
if (r?.contextAdditions) additions2.push(...r.contextAdditions);
|
|
1665
|
+
if (event === "PostToolUse" && appConfig.hookRewrite && typeof r?.resultOverride === "string" && r.resultOverride) {
|
|
1666
|
+
resultOverride = r.resultOverride;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
return { ...pack(additions2), resultOverride };
|
|
1400
1670
|
}
|
|
1401
1671
|
const additions = [];
|
|
1672
|
+
let argsOverride = void 0;
|
|
1402
1673
|
for (const rule of matched) {
|
|
1403
1674
|
try {
|
|
1404
1675
|
const res = await rule.run(ctx);
|
|
1405
1676
|
if (res?.contextAdditions) additions.push(...res.contextAdditions);
|
|
1677
|
+
if (event === "PreToolUse" && appConfig.hookRewrite && res?.argsOverride !== void 0) {
|
|
1678
|
+
if (isPlainObject(res.argsOverride)) {
|
|
1679
|
+
ctx.args = res.argsOverride;
|
|
1680
|
+
argsOverride = res.argsOverride;
|
|
1681
|
+
} else {
|
|
1682
|
+
console.warn(`\u26A0\uFE0F [hook:PreToolUse] argsOverride \u987B\u4E3A\u666E\u901A\u5BF9\u8C61\uFF0C\u5DF2\u5FFD\u7565`);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1406
1685
|
if (res && res.deny) {
|
|
1407
1686
|
return { deny: true, reason: res.reason, contextAdditions: additions.length > 0 ? additions : void 0 };
|
|
1408
1687
|
}
|
|
@@ -1415,7 +1694,7 @@ var init_registry = __esm({
|
|
|
1415
1694
|
console.warn(`\u26A0\uFE0F [hook:${event}] \u6267\u884C\u5F02\u5E38\uFF0C\u6309\u653E\u884C\u5904\u7406: ${msg}`);
|
|
1416
1695
|
}
|
|
1417
1696
|
}
|
|
1418
|
-
return pack(additions);
|
|
1697
|
+
return { ...pack(additions), argsOverride };
|
|
1419
1698
|
};
|
|
1420
1699
|
runPreHooks = async (toolName, args, ctx) => {
|
|
1421
1700
|
return dispatch("PreToolUse", {
|
|
@@ -1431,7 +1710,7 @@ var init_registry = __esm({
|
|
|
1431
1710
|
truncateForHook = (s) => s.length <= HOOK_RESULT_MAX ? s : s.slice(0, HOOK_RESULT_MAX) + `
|
|
1432
1711
|
\u2026[hook \u89C6\u56FE\u622A\u65AD\uFF0C\u5171 ${s.length} \u5B57\u7B26]`;
|
|
1433
1712
|
runPostHooks = async (toolName, args, result, ctx) => {
|
|
1434
|
-
|
|
1713
|
+
return dispatch("PostToolUse", {
|
|
1435
1714
|
sessionId: ctx.sessionId,
|
|
1436
1715
|
cwd: ctx.cwd,
|
|
1437
1716
|
env: ctx.env,
|
|
@@ -1475,6 +1754,7 @@ var init_truncate = __esm({
|
|
|
1475
1754
|
init_model();
|
|
1476
1755
|
init_contextCore();
|
|
1477
1756
|
init_store();
|
|
1757
|
+
init_transcript();
|
|
1478
1758
|
init_hooks();
|
|
1479
1759
|
ANSI_ESCAPE = /\u001b\[[\d;?]*[ -/]*[@-~]|\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g;
|
|
1480
1760
|
getFileAccessRoots = () => {
|
|
@@ -1630,6 +1910,11 @@ ${line}` : line;
|
|
|
1630
1910
|
consecutiveFailures: 0,
|
|
1631
1911
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1632
1912
|
});
|
|
1913
|
+
await appendEvent(event.sessionId, {
|
|
1914
|
+
dscEvent: "compaction",
|
|
1915
|
+
archivedMessageCount: store.archivedMessageCount,
|
|
1916
|
+
summary: summaryMsg.content
|
|
1917
|
+
});
|
|
1633
1918
|
} else if (keep > 1) {
|
|
1634
1919
|
keep--;
|
|
1635
1920
|
continue;
|
|
@@ -1644,6 +1929,11 @@ ${line}` : line;
|
|
|
1644
1929
|
consecutiveFailures: 0,
|
|
1645
1930
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1646
1931
|
});
|
|
1932
|
+
await appendEvent(event.sessionId, {
|
|
1933
|
+
dscEvent: "compaction",
|
|
1934
|
+
archivedMessageCount: store.archivedMessageCount,
|
|
1935
|
+
summary: summaryMsg.content
|
|
1936
|
+
});
|
|
1647
1937
|
} else {
|
|
1648
1938
|
break;
|
|
1649
1939
|
}
|
|
@@ -1750,7 +2040,7 @@ ${line}` : line;
|
|
|
1750
2040
|
});
|
|
1751
2041
|
|
|
1752
2042
|
// ../core/src/tool/permissions.ts
|
|
1753
|
-
import
|
|
2043
|
+
import fs6 from "fs/promises";
|
|
1754
2044
|
import path8 from "path";
|
|
1755
2045
|
var PRIMARY_ARG, rules2, trustedProject, globCache, globToRegex, DANGER_COMMAND_TOOLS, compileRule, readPermissionConfig, toolNameMatches, ruleMatches, initPermissions, checkPermission, listPermissionRules, buildScopedAllowRule, resolveSettingsPath, addPermissionRule;
|
|
1756
2046
|
var init_permissions = __esm({
|
|
@@ -1821,7 +2111,7 @@ var init_permissions = __esm({
|
|
|
1821
2111
|
for (const configPath of paths) {
|
|
1822
2112
|
let raw;
|
|
1823
2113
|
try {
|
|
1824
|
-
raw = await
|
|
2114
|
+
raw = await fs6.readFile(configPath, "utf-8");
|
|
1825
2115
|
} catch {
|
|
1826
2116
|
continue;
|
|
1827
2117
|
}
|
|
@@ -1918,7 +2208,7 @@ var init_permissions = __esm({
|
|
|
1918
2208
|
const arr = Array.isArray(cfg.permissions[kind]) ? cfg.permissions[kind] : cfg.permissions[kind] = [];
|
|
1919
2209
|
if (!arr.includes(ruleStr)) {
|
|
1920
2210
|
arr.push(ruleStr);
|
|
1921
|
-
await
|
|
2211
|
+
await fs6.mkdir(path8.dirname(file), { recursive: true });
|
|
1922
2212
|
await atomicWriteJSON(file, cfg);
|
|
1923
2213
|
}
|
|
1924
2214
|
if (!rules2[kind].some((r) => r.raw === compiled.raw)) rules2[kind].push(compiled);
|
|
@@ -1956,7 +2246,7 @@ var init_sessionRegistry = __esm({
|
|
|
1956
2246
|
});
|
|
1957
2247
|
|
|
1958
2248
|
// ../core/src/tool/guard.ts
|
|
1959
|
-
import
|
|
2249
|
+
import fs7 from "fs/promises";
|
|
1960
2250
|
import fsSync from "fs";
|
|
1961
2251
|
import path9 from "path";
|
|
1962
2252
|
import ignore from "ignore";
|
|
@@ -2111,9 +2401,14 @@ var init_guard = __esm({
|
|
|
2111
2401
|
SENSITIVE_ENV_PATTERN = /(KEY|TOKEN|SECRET|PASSWORD|PASSPHRASE|CREDENTIAL|PRIVATE|AUTH)/i;
|
|
2112
2402
|
scrubCommandEnv = (env = process.env) => {
|
|
2113
2403
|
const next = {};
|
|
2404
|
+
const GIT_CONFIG_MEMBER = /^GIT_CONFIG_(KEY|VALUE)_\d+$/;
|
|
2405
|
+
const gitConfigFamilyHit = Object.keys(env).some(
|
|
2406
|
+
(k) => GIT_CONFIG_MEMBER.test(k) && (COMMAND_ENV_DENYLIST.includes(k) || SENSITIVE_ENV_PATTERN.test(k))
|
|
2407
|
+
);
|
|
2114
2408
|
for (const [k, v] of Object.entries(env)) {
|
|
2115
2409
|
if (COMMAND_ENV_DENYLIST.includes(k)) continue;
|
|
2116
2410
|
if (SENSITIVE_ENV_PATTERN.test(k)) continue;
|
|
2411
|
+
if (gitConfigFamilyHit && (k === "GIT_CONFIG_COUNT" || GIT_CONFIG_MEMBER.test(k))) continue;
|
|
2117
2412
|
next[k] = v;
|
|
2118
2413
|
}
|
|
2119
2414
|
return next;
|
|
@@ -2134,11 +2429,11 @@ var init_guard = __esm({
|
|
|
2134
2429
|
};
|
|
2135
2430
|
scanIgnoreFilesRecursive = async (dirPath, base, engine) => {
|
|
2136
2431
|
try {
|
|
2137
|
-
const entries = await
|
|
2432
|
+
const entries = await fs7.readdir(dirPath, { withFileTypes: true });
|
|
2138
2433
|
for (const entry of entries) {
|
|
2139
2434
|
if (entry.isFile() && (entry.name === ".gitignore" || entry.name === ".agentignore")) {
|
|
2140
2435
|
const fullPath = path9.join(dirPath, entry.name);
|
|
2141
|
-
const content = await
|
|
2436
|
+
const content = await fs7.readFile(fullPath, "utf-8");
|
|
2142
2437
|
const relDir = path9.relative(base, dirPath).replace(/\\/g, "/");
|
|
2143
2438
|
const rules3 = content.split(/\r?\n/).map((line) => {
|
|
2144
2439
|
const trimmed = line.trim();
|
|
@@ -3035,7 +3330,7 @@ ${capped || JSON.stringify(result)}`;
|
|
|
3035
3330
|
});
|
|
3036
3331
|
|
|
3037
3332
|
// ../core/src/tool/mcp/loader.ts
|
|
3038
|
-
import
|
|
3333
|
+
import fs8 from "fs/promises";
|
|
3039
3334
|
import path11 from "path";
|
|
3040
3335
|
import { homedir } from "os";
|
|
3041
3336
|
function sanitize(s) {
|
|
@@ -3045,7 +3340,7 @@ async function readMcpConfig() {
|
|
|
3045
3340
|
const configPath = process.env.MCP_CONFIG || path11.join(appConfig.dataDir, "mcp.json");
|
|
3046
3341
|
let raw;
|
|
3047
3342
|
try {
|
|
3048
|
-
raw = await
|
|
3343
|
+
raw = await fs8.readFile(configPath, "utf-8");
|
|
3049
3344
|
} catch {
|
|
3050
3345
|
return {};
|
|
3051
3346
|
}
|
|
@@ -3136,9 +3431,14 @@ async function loadMcpTools() {
|
|
|
3136
3431
|
}
|
|
3137
3432
|
async function initMcpTools(into) {
|
|
3138
3433
|
const mcpTools = await loadMcpTools();
|
|
3139
|
-
if (
|
|
3434
|
+
if (appConfig.mcpExposeMode === "dispatcher") {
|
|
3435
|
+
if (clients.length > 0) {
|
|
3436
|
+
into.push(...mcpDispatcherTools);
|
|
3437
|
+
console.log(`\u{1F50C} [MCP] dispatcher \u6A21\u5F0F\uFF1A\u6CE8\u5165 mcp_list_tools + mcp_call\uFF08\u8986\u76D6 ${clients.length} \u4E2A server / ${mcpTools.length} \u4E2A\u5DE5\u5177\uFF09`);
|
|
3438
|
+
}
|
|
3439
|
+
} else if (mcpTools.length > 0) {
|
|
3140
3440
|
into.push(...mcpTools);
|
|
3141
|
-
console.log(`\u{1F50C} [MCP] \u5171\u6CE8\u5165 ${mcpTools.length} \u4E2A MCP \u5DE5\u5177`);
|
|
3441
|
+
console.log(`\u{1F50C} [MCP] \u5171\u6CE8\u5165 ${mcpTools.length} \u4E2A MCP \u5DE5\u5177 schema\uFF08schemas \u6A21\u5F0F\uFF09`);
|
|
3142
3442
|
}
|
|
3143
3443
|
if (clients.some((c) => c.supportsResources)) {
|
|
3144
3444
|
into.push(...mcpResourceTools);
|
|
@@ -3174,7 +3474,7 @@ async function listMcpClients() {
|
|
|
3174
3474
|
}
|
|
3175
3475
|
return out;
|
|
3176
3476
|
}
|
|
3177
|
-
var clients, expandPlaceholders, expandServerConfig, mcpResourceTools, mcpPromptTools;
|
|
3477
|
+
var clients, expandPlaceholders, expandServerConfig, mcpResourceTools, mcpPromptTools, resolveMcpPermissionName, mcpDispatcherTools;
|
|
3178
3478
|
var init_loader = __esm({
|
|
3179
3479
|
"../core/src/tool/mcp/loader.ts"() {
|
|
3180
3480
|
"use strict";
|
|
@@ -3338,6 +3638,88 @@ ${text}`;
|
|
|
3338
3638
|
}
|
|
3339
3639
|
}
|
|
3340
3640
|
];
|
|
3641
|
+
resolveMcpPermissionName = (calledName, args) => {
|
|
3642
|
+
if (calledName !== "mcp_call") return calledName;
|
|
3643
|
+
const server = typeof args?.server === "string" ? sanitize(args.server) : "";
|
|
3644
|
+
const tool = typeof args?.tool === "string" ? sanitize(args.tool) : "";
|
|
3645
|
+
return server && tool ? `mcp__${server}__${tool}` : calledName;
|
|
3646
|
+
};
|
|
3647
|
+
mcpDispatcherTools = [
|
|
3648
|
+
{
|
|
3649
|
+
type: "function",
|
|
3650
|
+
function: {
|
|
3651
|
+
name: "mcp_list_tools",
|
|
3652
|
+
description: "\u5217\u51FA\u5DF2\u8FDE\u63A5 MCP server \u7684\u5916\u90E8\u5DE5\u5177\u76EE\u5F55\uFF08server / \u5DE5\u5177\u540D / \u4E00\u884C\u63CF\u8FF0 / \u53C2\u6570\u540D\uFF0C\u5FC5\u586B\u53C2\u6570\u5E26 *\uFF09\u3002\u8C03\u7528 MCP \u5DE5\u5177\u7528 mcp_call\uFF08\u987B\u4F20\u56DE server \u4E0E\u5DE5\u5177\u539F\u540D\uFF09\u3002\u76EE\u5F55\u5B9E\u65F6\u67E5\u8BE2\u2014\u2014\u65B0\u589E server \u540E\u5373\u67E5\u5373\u89C1\uFF0C\u65E0\u9700\u4EFB\u4F55\u53D8\u66F4\u3002",
|
|
3653
|
+
parameters: {
|
|
3654
|
+
type: "object",
|
|
3655
|
+
properties: {
|
|
3656
|
+
server: { type: "string", description: "\u4EC5\u5217\u51FA\u8BE5 server \u7684\u5DE5\u5177\uFF08\u7F3A\u7701\u5217\u51FA\u5168\u90E8\u5DF2\u8FDE\u63A5 server\uFF09" }
|
|
3657
|
+
}
|
|
3658
|
+
},
|
|
3659
|
+
safetyLevel: "safe" /* SAFE */,
|
|
3660
|
+
isSync: true,
|
|
3661
|
+
async execute(args) {
|
|
3662
|
+
const server = args?.server;
|
|
3663
|
+
const lines = [];
|
|
3664
|
+
for (const c of clients) {
|
|
3665
|
+
if (server && c.serverName !== server) continue;
|
|
3666
|
+
try {
|
|
3667
|
+
const ts = await c.listTools();
|
|
3668
|
+
for (const t of ts) {
|
|
3669
|
+
const props = t?.inputSchema?.properties && typeof t.inputSchema.properties === "object" ? Object.keys(t.inputSchema.properties) : [];
|
|
3670
|
+
const required = Array.isArray(t?.inputSchema?.required) ? t.inputSchema.required : [];
|
|
3671
|
+
const argList = props.map((p) => required.includes(p) ? `${p}*` : p).join(", ");
|
|
3672
|
+
lines.push(`- [${c.serverName}] ${t.name}${t.description ? `\uFF1A${String(t.description).split("\n")[0]}` : ""}${argList ? `\uFF08\u53C2\u6570\uFF1A${argList}\uFF09` : ""}`);
|
|
3673
|
+
}
|
|
3674
|
+
} catch (e) {
|
|
3675
|
+
console.warn(`\u26A0\uFE0F [MCP] listTools "${c.serverName}" \u5931\u8D25\uFF08\u5DF2\u8DF3\u8FC7\uFF09: ${e?.message ?? e}`);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
if (lines.length === 0) return server ? `(server "${server}" \u672A\u8FDE\u63A5\u6216\u65E0\u5DE5\u5177)` : "(\u65E0\u5DF2\u8FDE\u63A5\u7684 MCP server)";
|
|
3679
|
+
return `[MCP tools]
|
|
3680
|
+
${lines.join("\n")}`;
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
},
|
|
3684
|
+
{
|
|
3685
|
+
type: "function",
|
|
3686
|
+
function: {
|
|
3687
|
+
name: "mcp_call",
|
|
3688
|
+
description: '\u8C03\u7528\u6307\u5B9A MCP server \u7684\u5916\u90E8\u5DE5\u5177\u3002server \u4E0E\u5DE5\u5177\u540D\u5FC5\u586B\u2014\u2014\u5747\u6765\u81EA mcp_list_tools \u7684\u76EE\u5F55\u8F93\u51FA\uFF08\u7528\u539F\u540D\uFF0C\u4E0D\u8981\u6539\u5199\uFF09\u3002args \u4E3A\u8BE5\u5DE5\u5177\u53C2\u6570\u7684 JSON \u5B57\u7B26\u4E32\uFF08\u53C2\u6570\u540D\u89C1\u76EE\u5F55\uFF1B\u65E0\u53C2\u6570\u4F20 "{}"\uFF09\u3002\u6267\u884C\u5916\u90E8\u903B\u8F91\uFF0C\u6BCF\u6B21\u8C03\u7528\u9700\u5BA1\u6279\u3002',
|
|
3689
|
+
parameters: {
|
|
3690
|
+
type: "object",
|
|
3691
|
+
properties: {
|
|
3692
|
+
server: { type: "string", description: "MCP server \u540D\uFF08\u89C1 mcp_list_tools \u8F93\u51FA\uFF09" },
|
|
3693
|
+
tool: { type: "string", description: "\u5DE5\u5177\u540D\uFF08\u89C1 mcp_list_tools \u8F93\u51FA\uFF0C\u7528\u539F\u540D\uFF09" },
|
|
3694
|
+
args: { type: "string", description: '\u5DE5\u5177\u53C2\u6570\u7684 JSON \u5B57\u7B26\u4E32\uFF0C\u5982 {"query":"..."}\uFF1B\u65E0\u53C2\u6570\u4F20 "{}"' }
|
|
3695
|
+
},
|
|
3696
|
+
required: ["server", "tool"]
|
|
3697
|
+
},
|
|
3698
|
+
safetyLevel: "danger" /* DANGER */,
|
|
3699
|
+
isSync: true,
|
|
3700
|
+
requireApproval: (args) => `\u26A0\uFE0F\u3010MCP \u5DE5\u5177\u5BA1\u6279\u3011
|
|
3701
|
+
\u670D\u52A1: ${args?.server} / \u5DE5\u5177: ${args?.tool}
|
|
3702
|
+
\u53C2\u6570: ${args?.args}`,
|
|
3703
|
+
async execute(args) {
|
|
3704
|
+
const { server, tool } = args ?? {};
|
|
3705
|
+
if (!server || !tool) return "\u274C [mcp_call] \u7F3A\u5C11 server \u6216 tool\uFF08\u5148\u7528 mcp_list_tools \u67E5\u76EE\u5F55\uFF09\u3002";
|
|
3706
|
+
let parsed = {};
|
|
3707
|
+
if (typeof args.args === "string" && args.args.trim() && args.args.trim() !== "{}") {
|
|
3708
|
+
try {
|
|
3709
|
+
parsed = JSON.parse(args.args);
|
|
3710
|
+
} catch {
|
|
3711
|
+
return `\u274C [mcp_call] args \u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${String(args.args).slice(0, 200)}\u3002\u8BF7\u4F20\u8BE5\u5DE5\u5177\u53C2\u6570\u7684 JSON \u5B57\u7B26\u4E32\uFF08\u65E0\u53C2\u6570\u4F20 "{}"\uFF09\u3002`;
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
const c = findClient(server);
|
|
3715
|
+
if (!c) return `\u274C \u672A\u8FDE\u63A5\u7684 MCP server\uFF1A${server}\uFF08\u7528 mcp_list_tools \u67E5\u770B\u5DF2\u8FDE\u63A5\u5217\u8868\uFF09`;
|
|
3716
|
+
const result = await c.callTool(tool, parsed);
|
|
3717
|
+
return `[MCP ${server}/${tool}]
|
|
3718
|
+
${result}`;
|
|
3719
|
+
}
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
];
|
|
3341
3723
|
}
|
|
3342
3724
|
});
|
|
3343
3725
|
|
|
@@ -3373,68 +3755,44 @@ var init_httpExecutor = __esm({
|
|
|
3373
3755
|
}
|
|
3374
3756
|
});
|
|
3375
3757
|
|
|
3376
|
-
// ../core/src/
|
|
3377
|
-
|
|
3378
|
-
var
|
|
3379
|
-
|
|
3380
|
-
"../core/src/session/transcript.ts"() {
|
|
3758
|
+
// ../core/src/agent/inbox.ts
|
|
3759
|
+
var INBOX_MAX_ITEMS, sessionInboxes, pushSessionInbox, claimSessionInbox, flushLeftoverToTranscript;
|
|
3760
|
+
var init_inbox = __esm({
|
|
3761
|
+
"../core/src/agent/inbox.ts"() {
|
|
3381
3762
|
"use strict";
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
lines.push(JSON.parse(line));
|
|
3395
|
-
} catch {
|
|
3396
|
-
console.warn(`\u26A0\uFE0F [transcript] \u8DF3\u8FC7\u65E0\u6CD5\u89E3\u6790\u7684\u635F\u574F\u884C: ${line.slice(0, 120)}`);
|
|
3397
|
-
}
|
|
3398
|
-
}
|
|
3399
|
-
return lines;
|
|
3400
|
-
} catch (err) {
|
|
3401
|
-
if (err?.code === "ENOENT") return [];
|
|
3402
|
-
throw err;
|
|
3763
|
+
init_transcript();
|
|
3764
|
+
init_config();
|
|
3765
|
+
INBOX_MAX_ITEMS = 50;
|
|
3766
|
+
sessionInboxes = /* @__PURE__ */ new Map();
|
|
3767
|
+
pushSessionInbox = (sessionId, content) => {
|
|
3768
|
+
if (!appConfig.inboxSteering) return false;
|
|
3769
|
+
const text = (content ?? "").trim();
|
|
3770
|
+
if (!text) return false;
|
|
3771
|
+
const q = sessionInboxes.get(sessionId) ?? [];
|
|
3772
|
+
if (q.length >= INBOX_MAX_ITEMS) {
|
|
3773
|
+
console.warn(`[inbox] \u4F1A\u8BDD ${sessionId} \u961F\u5217\u5DF2\u6EE1\uFF08${INBOX_MAX_ITEMS}\uFF09\uFF0C\u4E22\u5F03\u65B0\u8F93\u5165`);
|
|
3774
|
+
return false;
|
|
3403
3775
|
}
|
|
3776
|
+
q.push(text);
|
|
3777
|
+
sessionInboxes.set(sessionId, q);
|
|
3778
|
+
return true;
|
|
3404
3779
|
};
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
}
|
|
3416
|
-
const MAX_ATTEMPTS = 3;
|
|
3417
|
-
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
3418
|
-
let beforeSize = 0;
|
|
3419
|
-
try {
|
|
3420
|
-
beforeSize = (await fs8.stat(p)).size;
|
|
3421
|
-
} catch {
|
|
3422
|
-
}
|
|
3423
|
-
try {
|
|
3424
|
-
await fs8.appendFile(p, payload, "utf-8");
|
|
3425
|
-
return;
|
|
3426
|
-
} catch (e) {
|
|
3427
|
-
try {
|
|
3428
|
-
await fs8.truncate(p, beforeSize);
|
|
3429
|
-
} catch {
|
|
3430
|
-
}
|
|
3431
|
-
if (attempt === MAX_ATTEMPTS) throw e;
|
|
3432
|
-
await new Promise((r) => setTimeout(r, 50 * attempt));
|
|
3433
|
-
}
|
|
3434
|
-
}
|
|
3435
|
-
} catch (e) {
|
|
3436
|
-
console.warn(`\u26A0\uFE0F \u6D88\u606F\u843D\u76D8\u5931\u8D25\uFF08\u5DF2\u91CD\u8BD5 3 \u6B21\uFF0C\u5185\u5B58\u4E0E\u78C1\u76D8\u8F6C\u5F55\u53EF\u80FD\u4E0D\u4E00\u81F4\uFF09:`, e);
|
|
3780
|
+
claimSessionInbox = (sessionId) => {
|
|
3781
|
+
if (!appConfig.inboxSteering) return [];
|
|
3782
|
+
const q = sessionInboxes.get(sessionId);
|
|
3783
|
+
if (!q || q.length === 0) return [];
|
|
3784
|
+
sessionInboxes.delete(sessionId);
|
|
3785
|
+
return q;
|
|
3786
|
+
};
|
|
3787
|
+
flushLeftoverToTranscript = async (sessionId) => {
|
|
3788
|
+
const texts = claimSessionInbox(sessionId);
|
|
3789
|
+
for (const t of texts) {
|
|
3790
|
+
await appendMessage({ sessionId, role: "user", content: t });
|
|
3437
3791
|
}
|
|
3792
|
+
if (texts.length > 0) {
|
|
3793
|
+
console.warn(`[inbox] \u4F1A\u8BDD ${sessionId} \u7ED3\u675F\u65F6 ${texts.length} \u6761\u8865\u5145\u8F93\u5165\u672A\u8BA4\u9886\uFF0C\u5DF2\u5199\u5165 transcript\uFF08\u4E0B\u8F6E\u81EA\u52A8\u5E26\u5165\uFF09`);
|
|
3794
|
+
}
|
|
3795
|
+
return texts.length;
|
|
3438
3796
|
};
|
|
3439
3797
|
}
|
|
3440
3798
|
});
|
|
@@ -3550,7 +3908,6 @@ var init_planMode = __esm({
|
|
|
3550
3908
|
"../core/src/agent/planMode.ts"() {
|
|
3551
3909
|
"use strict";
|
|
3552
3910
|
PLAN_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
|
|
3553
|
-
"getTime",
|
|
3554
3911
|
"read_file",
|
|
3555
3912
|
"list_dir",
|
|
3556
3913
|
"view_symbol_outline",
|
|
@@ -3561,6 +3918,9 @@ var init_planMode = __esm({
|
|
|
3561
3918
|
"git_status",
|
|
3562
3919
|
"git_log",
|
|
3563
3920
|
"inspect_dependencies",
|
|
3921
|
+
"get_diagnostics",
|
|
3922
|
+
"goto_definition",
|
|
3923
|
+
// ★ P0-A 补漏:LSP 导航/诊断恰是调研阶段最需要的(原白名单漂移漏登记,schema 档与 runtime 档共用此表)
|
|
3564
3924
|
"web_fetch",
|
|
3565
3925
|
"web_search"
|
|
3566
3926
|
// 只读研究类(虽为 DANGER 但不写本地状态;仍走各自审批)
|
|
@@ -3738,7 +4098,7 @@ var init_inject2 = __esm({
|
|
|
3738
4098
|
init_registry4();
|
|
3739
4099
|
AGENT_CATALOG_MARKER = "\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011";
|
|
3740
4100
|
AGENT_CATALOG_FENCE = "\u27E6DSC:AGENT_CATALOG\u27E7";
|
|
3741
|
-
AGENT_USAGE_HINT = '\u5F53\u67D0\u5B50\u4EFB\u52A1\u5339\u914D\u4E0B\u5217\u67D0\u4E2A\u5B50 Agent \u7684\u4E13\u957F\u65F6\uFF0C\u8C03\u7528 spawn_agent \u5E76\u4F20\u5165\u5BF9\u5E94 name \u53C2\u6570\uFF08\u5982 spawn_agent(name="code-reviewer", task="..."\uFF09\uFF09\u5C06\u5176\u59D4\u6D3E\u7ED9\u8BE5\u58F0\u660E\u5F0F\u5B50 Agent\uFF1B\u4E0D\u4F20 name \u5219\u8D70\u9ED8\u8BA4\u901A\u7528\u5B50 agent\u3002';
|
|
4101
|
+
AGENT_USAGE_HINT = '\u5F53\u67D0\u5B50\u4EFB\u52A1\u5339\u914D\u4E0B\u5217\u67D0\u4E2A\u5B50 Agent \u7684\u4E13\u957F\u65F6\uFF0C\u8C03\u7528 spawn_agent \u5E76\u4F20\u5165\u5BF9\u5E94 name \u53C2\u6570\uFF08\u5982 spawn_agent(name="code-reviewer", task="..."\uFF09\uFF09\u5C06\u5176\u59D4\u6D3E\u7ED9\u8BE5\u58F0\u660E\u5F0F\u5B50 Agent\uFF1B\u4E0D\u4F20 name \u5219\u8D70\u9ED8\u8BA4\u901A\u7528\u5B50 agent\u3002\n\u59D4\u6D3E\u4F18\u5148\u539F\u5219\uFF08P1-C\uFF09\uFF1A\u9700\u8981\u4E00\u5927\u5768\u4E13\u7528\u5DE5\u5177\u6216\u72EC\u7ACB\u4E0A\u4E0B\u6587\u7684\u5B50\u4EFB\u52A1\uFF08\u6DF1\u5EA6 web \u8C03\u7814\u3001\u6279\u91CF MCP \u5DE5\u5177\u64CD\u4F5C\u3001\u72EC\u7ACB worktree \u8BD5\u9A8C\u7B49\uFF09\uFF0C\u4F18\u5148\u59D4\u6D3E\u7ED9\u5BF9\u5E94\u5B50 Agent\uFF0C\u800C\u975E\u5728\u4E3B\u4F1A\u8BDD\u5806\u53E0\u8C03\u7528\u2014\u2014\u5B50 Agent \u6709\u81EA\u5DF1\u7684\u5DE5\u5177\u767D\u540D\u5355\u4E0E\u72EC\u7ACB\u4E0A\u4E0B\u6587\uFF0C\u4E3B\u4F1A\u8BDD\u4FDD\u6301\u7CBE\u7B80\u3001\u5DE5\u5177\u8868\u4FDD\u6301\u6052\u5B9A\u3002';
|
|
3742
4102
|
injectAgentCatalog = (message) => {
|
|
3743
4103
|
const catalog = getAgentCatalog();
|
|
3744
4104
|
if (!catalog) return;
|
|
@@ -3894,6 +4254,7 @@ var prepareToolsAndInjections;
|
|
|
3894
4254
|
var init_systemInjections = __esm({
|
|
3895
4255
|
"../core/src/agent/systemInjections.ts"() {
|
|
3896
4256
|
"use strict";
|
|
4257
|
+
init_config();
|
|
3897
4258
|
init_planMode();
|
|
3898
4259
|
init_toolFilter();
|
|
3899
4260
|
init_truncate();
|
|
@@ -3905,7 +4266,7 @@ var init_systemInjections = __esm({
|
|
|
3905
4266
|
init_common();
|
|
3906
4267
|
prepareToolsAndInjections = async (message, options, events) => {
|
|
3907
4268
|
const { toolSchemas, planMode, locale: locale2, outputStyle } = options;
|
|
3908
|
-
const rawToolsPreEnv = planMode ? filterToolsForPlanMode(toolSchemas ?? []) : appendPlanControlTools(toolSchemas ?? []);
|
|
4269
|
+
const rawToolsPreEnv = planMode && appConfig.planEnforcement === "schema" ? filterToolsForPlanMode(toolSchemas ?? []) : appendPlanControlTools(toolSchemas ?? []);
|
|
3909
4270
|
const validationCtx = {
|
|
3910
4271
|
sessionId: options.sessionId,
|
|
3911
4272
|
cwd: options.cwd ?? process.cwd(),
|
|
@@ -3940,36 +4301,6 @@ var init_systemInjections = __esm({
|
|
|
3940
4301
|
}
|
|
3941
4302
|
});
|
|
3942
4303
|
|
|
3943
|
-
// ../core/src/tool/registry/system.ts
|
|
3944
|
-
var systemTools;
|
|
3945
|
-
var init_system = __esm({
|
|
3946
|
-
"../core/src/tool/registry/system.ts"() {
|
|
3947
|
-
"use strict";
|
|
3948
|
-
init_type();
|
|
3949
|
-
systemTools = [
|
|
3950
|
-
{
|
|
3951
|
-
type: "function",
|
|
3952
|
-
function: {
|
|
3953
|
-
name: "getTime",
|
|
3954
|
-
description: "\u8FD4\u56DE\u5F53\u524D\u670D\u52A1\u5668\u7684\u65E5\u671F\u4E0E\u65F6\u95F4\uFF08\u672C\u5730\u65F6\u533A\uFF09",
|
|
3955
|
-
parameters: {
|
|
3956
|
-
type: "object",
|
|
3957
|
-
properties: {
|
|
3958
|
-
// Q-7:location 改为可选——旧版 required 却完全不消费,迫使模型填无意义城市名。
|
|
3959
|
-
location: { type: "string", description: "\u57CE\u5E02\u540D\u79F0\uFF08\u53EF\u9009\uFF0C\u4EC5\u4F5C\u8BB0\u5F55\uFF1B\u670D\u52A1\u5668\u59CB\u7EC8\u8FD4\u56DE\u5176\u672C\u5730\u65F6\u95F4\uFF09" }
|
|
3960
|
-
}
|
|
3961
|
-
},
|
|
3962
|
-
safetyLevel: "safe" /* SAFE */,
|
|
3963
|
-
isSync: true,
|
|
3964
|
-
async execute() {
|
|
3965
|
-
return (/* @__PURE__ */ new Date()).toLocaleString("zh-CN", { dateStyle: "medium", timeStyle: "medium" });
|
|
3966
|
-
}
|
|
3967
|
-
}
|
|
3968
|
-
}
|
|
3969
|
-
];
|
|
3970
|
-
}
|
|
3971
|
-
});
|
|
3972
|
-
|
|
3973
4304
|
// ../core/src/tool/registry/agent.ts
|
|
3974
4305
|
var createAgentTools;
|
|
3975
4306
|
var init_agent = __esm({
|
|
@@ -4564,7 +4895,7 @@ import fs12 from "fs/promises";
|
|
|
4564
4895
|
import path15 from "path";
|
|
4565
4896
|
import { createReadStream } from "fs";
|
|
4566
4897
|
import * as readline from "readline";
|
|
4567
|
-
var isSensitiveReadTarget, stripReadFileLineNumbers, maskSecretsInContent, makeTmpPath, ATOMIC_TMP_RE, sweepStaleAtomicTmp, assertReadable, stripEdgeBlankLines, matchLineBlockWith, diagnoseOldStr, reindentToBase, fsTools;
|
|
4898
|
+
var isSensitiveReadTarget, stripReadFileLineNumbers, maskSecretsInContent, makeTmpPath, ATOMIC_TMP_RE, sweepStaleAtomicTmp, assertReadable, stripEdgeBlankLines, matchLineBlockWith, diagnoseOldStr, reindentToBase, alignIndentsByAnchor, applyOneEditToContent, fsTools;
|
|
4568
4899
|
var init_fs = __esm({
|
|
4569
4900
|
"../core/src/tool/registry/fs.ts"() {
|
|
4570
4901
|
"use strict";
|
|
@@ -4652,7 +4983,7 @@ var init_fs = __esm({
|
|
|
4652
4983
|
while (lines.length > 1 && lines[lines.length - 1].trim() === "") lines.pop();
|
|
4653
4984
|
return lines.join("\n");
|
|
4654
4985
|
};
|
|
4655
|
-
matchLineBlockWith = (content, oldBlock, newBlock, replaceAll, norm) => {
|
|
4986
|
+
matchLineBlockWith = (content, oldBlock, newBlock, replaceAll, norm, anchorAlign) => {
|
|
4656
4987
|
const contentLines = content.split("\n");
|
|
4657
4988
|
const oldLines = oldBlock.split("\n");
|
|
4658
4989
|
if (oldLines.length === 0 || oldLines.length > contentLines.length) {
|
|
@@ -4681,7 +5012,11 @@ var init_fs = __esm({
|
|
|
4681
5012
|
break;
|
|
4682
5013
|
}
|
|
4683
5014
|
}
|
|
4684
|
-
|
|
5015
|
+
let aligned = baseIndent ? reindentToBase(newBlock, baseIndent) : newBlock;
|
|
5016
|
+
if (anchorAlign) {
|
|
5017
|
+
const anchored = alignIndentsByAnchor(newBlock, oldLines, contentLines, start);
|
|
5018
|
+
if (anchored !== null) aligned = anchored;
|
|
5019
|
+
}
|
|
4685
5020
|
out.splice(start, oldLines.length, ...aligned.split("\n"));
|
|
4686
5021
|
}
|
|
4687
5022
|
return { ok: true, content: out.join("\n"), count: hits.length };
|
|
@@ -4716,6 +5051,92 @@ var init_fs = __esm({
|
|
|
4716
5051
|
return baseIndent + (l.startsWith(common) ? l.slice(common.length) : l);
|
|
4717
5052
|
}).join("\n");
|
|
4718
5053
|
};
|
|
5054
|
+
alignIndentsByAnchor = (newBlock, oldLines, contentLines, start) => {
|
|
5055
|
+
const stripLead = (l) => l.replace(/^[ \t]+/, "");
|
|
5056
|
+
const out = [];
|
|
5057
|
+
let cursor = 0;
|
|
5058
|
+
let lastIndent = null;
|
|
5059
|
+
let anchors = 0;
|
|
5060
|
+
for (const line of newBlock.split("\n")) {
|
|
5061
|
+
if (line.trim() === "") {
|
|
5062
|
+
out.push(line);
|
|
5063
|
+
continue;
|
|
5064
|
+
}
|
|
5065
|
+
const bare = stripLead(line);
|
|
5066
|
+
let idx = -1;
|
|
5067
|
+
for (let i = cursor; i < oldLines.length; i++) {
|
|
5068
|
+
if (oldLines[i].trim() !== "" && stripLead(oldLines[i]) === bare) {
|
|
5069
|
+
idx = i;
|
|
5070
|
+
break;
|
|
5071
|
+
}
|
|
5072
|
+
}
|
|
5073
|
+
if (idx === -1) {
|
|
5074
|
+
out.push(lastIndent === null ? line : lastIndent + bare);
|
|
5075
|
+
continue;
|
|
5076
|
+
}
|
|
5077
|
+
cursor = idx + 1;
|
|
5078
|
+
lastIndent = contentLines[start + idx].match(/^[ \t]*/)?.[0] ?? "";
|
|
5079
|
+
anchors++;
|
|
5080
|
+
out.push(lastIndent + bare);
|
|
5081
|
+
}
|
|
5082
|
+
return anchors > 0 ? out.join("\n") : null;
|
|
5083
|
+
};
|
|
5084
|
+
applyOneEditToContent = (normalizedContent, oldStr, newStr, replaceAll) => {
|
|
5085
|
+
const normalizedNew = newStr.replace(/\r\n/g, "\n");
|
|
5086
|
+
const normalizedOldRaw = oldStr.replace(/\r\n/g, "\n");
|
|
5087
|
+
const lnStripped = stripReadFileLineNumbers(normalizedOldRaw);
|
|
5088
|
+
const candidates = [
|
|
5089
|
+
{ old: normalizedOldRaw, note: "" },
|
|
5090
|
+
{ old: stripEdgeBlankLines(normalizedOldRaw), note: "\uFF08\u5DF2\u5BB9\u9519\u9996\u5C3E\u7A7A\u884C\uFF09" }
|
|
5091
|
+
];
|
|
5092
|
+
if (lnStripped !== normalizedOldRaw) candidates.push({ old: lnStripped, note: "\uFF08\u5DF2\u5265\u79BB read_file \u884C\u53F7\u524D\u7F00\uFF09" });
|
|
5093
|
+
let normalizedOld = null;
|
|
5094
|
+
let note = "";
|
|
5095
|
+
for (const c of candidates) {
|
|
5096
|
+
if (c.old.length > 0 && normalizedContent.includes(c.old)) {
|
|
5097
|
+
normalizedOld = c.old;
|
|
5098
|
+
note = c.note;
|
|
5099
|
+
break;
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
if (normalizedOld == null) {
|
|
5103
|
+
const base = lnStripped !== normalizedOldRaw ? lnStripped : normalizedOldRaw;
|
|
5104
|
+
const norms = [
|
|
5105
|
+
// 行尾空白归一:old_str 前导缩进与文件一致(可信)→ 只对齐基线(anchor=false)
|
|
5106
|
+
{ norm: (l) => l.replace(/[ \t]+$/, ""), tag: "\u9010\u884C\u5C3E\u7A7A\u767D\u5BB9\u9519", anchor: false },
|
|
5107
|
+
// 全空白归一:模型前导缩进已证明不符(不可信)→ 逐行锚定文件真实缩进(anchor=true)
|
|
5108
|
+
{ norm: (l) => l.trim(), tag: "\u9010\u884C\u5168\u7A7A\u767D\u5BB9\u9519\uFF08\u524D\u5BFC Tab/\u7A7A\u683C\uFF09", anchor: true }
|
|
5109
|
+
];
|
|
5110
|
+
for (const { norm, tag, anchor } of norms) {
|
|
5111
|
+
const lm = matchLineBlockWith(normalizedContent, base, normalizedNew, replaceAll, norm, anchor);
|
|
5112
|
+
if (lm.ok) {
|
|
5113
|
+
return {
|
|
5114
|
+
ok: true,
|
|
5115
|
+
content: lm.content,
|
|
5116
|
+
summary: replaceAll ? `\u5DF2\u6279\u91CF\u66FF\u6362\u5168\u90E8 ${lm.count} \u5904\u5339\u914D\uFF08${tag}\uFF09\u3002` : `\u5DF2\u6210\u529F\u5B8C\u6210\u5C40\u90E8\u91CD\u6784\uFF08${tag}\uFF09\u3002`
|
|
5117
|
+
};
|
|
5118
|
+
}
|
|
5119
|
+
if (lm.reason === "conflict") {
|
|
5120
|
+
return { ok: false, error: `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u4EE3\u7801\u51B2\u7A81\uFF01old_str\uFF08${tag}\u5F52\u4E00\u540E\uFF09\u5728\u5168\u6587\u4E2D\u4E0D\u552F\u4E00\uFF08\u5171 ${lm.count} \u5904\uFF09\u3002\u8BF7\u591A\u5305\u88F9\u51E0\u884C\u4E0A\u4E0B\u6587\uFF0C\u6216\u663E\u5F0F\u8BBE replace_all=true \u6279\u91CF\u66FF\u6362\u3002` };
|
|
5121
|
+
}
|
|
5122
|
+
}
|
|
5123
|
+
const diag = diagnoseOldStr(normalizedContent, normalizedOldRaw);
|
|
5124
|
+
return { ok: false, error: `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u672A\u80FD\u5728\u6587\u4EF6\u4E2D\u627E\u5230\u6307\u5B9A\u7684 old_str \u65E7\u4EE3\u7801\u5757\u3002${diag}\u5E38\u89C1\u539F\u56E0\uFF1A\u2460 \u8BEF\u5E26\u4E86 read_file \u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF1B\u2461 \u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0D\u4E00\u81F4\uFF1B\u2462 \u884C\u5C3E\u591A\u4F59\u7A7A\u683C\uFF1B\u2463 \u6587\u4EF6\u5DF2\u88AB\u6539\u52A8/old_str \u975E\u8FDE\u7EED\u6574\u6BB5\u3002\u8BF7\u7528 read_file \u91CD\u65B0\u6838\u5BF9\u8BE5\u5904\u7247\u6BB5\uFF08\u53BB\u6389\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\u3001\u4FDD\u7559\u539F\u59CB Tab/\u7A7A\u683C\u7F29\u8FDB\uFF09\u540E\u91CD\u8BD5\u3002\u26A0\uFE0F \u4E25\u7981\u6539\u7528 run_command \u8C03\u7528 python/node/sed/awk \u7B49\u811A\u672C\u7ED5\u8FC7\u672C\u5DE5\u5177\u4FEE\u6539\u6587\u4EF6\u3002` };
|
|
5125
|
+
}
|
|
5126
|
+
const matchCount = normalizedContent.split(normalizedOld).length - 1;
|
|
5127
|
+
if (!replaceAll && matchCount > 1) {
|
|
5128
|
+
return { ok: false, error: `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u4EE3\u7801\u51B2\u7A81\uFF01old_str \u5728\u5168\u6587\u4E2D\u4E0D\u552F\u4E00\uFF08\u5171\u53D1\u73B0\u4E86 ${matchCount} \u5904\uFF09\u3002\u8BF7\u5411\u4E0A\u6216\u5411\u4E0B\u591A\u5305\u88F9\u51E0\u884C\u4E0A\u4E0B\u6587\u518D\u63D0\u8BF7\u4FEE\u6539\uFF0C\u6216\u663E\u5F0F\u8BBE replace_all=true \u6279\u91CF\u66FF\u6362\u3002` };
|
|
5129
|
+
}
|
|
5130
|
+
const oldFirstNonBlank = normalizedOld.split("\n").find((l) => l.trim() !== "") ?? "";
|
|
5131
|
+
const baseIndent = oldFirstNonBlank.match(/^[ \t]*/)?.[0] ?? "";
|
|
5132
|
+
const alignedNew = baseIndent ? reindentToBase(normalizedNew, baseIndent) : normalizedNew;
|
|
5133
|
+
const updatedContent = replaceAll ? normalizedContent.split(normalizedOld).join(alignedNew) : normalizedContent.replace(normalizedOld, () => alignedNew);
|
|
5134
|
+
return {
|
|
5135
|
+
ok: true,
|
|
5136
|
+
content: updatedContent,
|
|
5137
|
+
summary: replaceAll ? `\u5DF2\u6279\u91CF\u66FF\u6362\u5168\u90E8 ${matchCount} \u5904\u5339\u914D\u3002${note}` : `\u5DF2\u6210\u529F\u5B8C\u6210\u552F\u4E00\u6027\u5C40\u90E8\u91CD\u6784\u3002${note}`
|
|
5138
|
+
};
|
|
5139
|
+
};
|
|
4719
5140
|
fsTools = [
|
|
4720
5141
|
{
|
|
4721
5142
|
type: "function",
|
|
@@ -4847,78 +5268,65 @@ ${treeResult}`;
|
|
|
4847
5268
|
type: "function",
|
|
4848
5269
|
function: {
|
|
4849
5270
|
name: "edit_file",
|
|
4850
|
-
description: "\u9488\u5BF9\u6307\u5B9A\u7684\u6587\u4EF6\u8FDB\u884C\u5C40\u90E8\u7CBE\u51C6\u4FEE\u6539\u3002old_str \u5FC5\u987B\u4E0E\u6587\u4EF6\u4E2D\u7684\u539F\u59CB\u4EE3\u7801\u9010\u5B57\u7B26\u4E00\u81F4\uFF1A\u8BF7\u53BB\u6389 read_file \u8FD4\u56DE\u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF0C\u5E76\u4FDD\u7559\u539F\u6709\u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0E\u884C\u5C3E\u7A7A\u767D\uFF1B\u9ED8\u8BA4\u8981\u6C42\u5728\u5168\u6587\u4E2D\u552F\u4E00\uFF0C\u82E5\u8BBE replace_all=true \u5219\u66FF\u6362\u5168\u90E8\u5339\u914D\u5904\uFF08\u9002\u5408\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\uFF09\u3002",
|
|
5271
|
+
description: "\u9488\u5BF9\u6307\u5B9A\u7684\u6587\u4EF6\u8FDB\u884C\u5C40\u90E8\u7CBE\u51C6\u4FEE\u6539\u3002\u2605 \u540C\u4E00\u6587\u4EF6\u6709\u591A\u5904\u8981\u6539\u65F6\uFF0C\u52A1\u5FC5\u4E00\u6B21\u8C03\u7528\u4F20 edits \u6570\u7EC4\u5168\u90E8\u5B8C\u6210\uFF08\u6309\u5E8F\u5E94\u7528\u3001\u6574\u4F53\u539F\u5B50\uFF1A\u4EFB\u4E00\u5904\u5931\u8D25\u5219\u5168\u90E8\u4E0D\u5199\u5165\uFF09\uFF0C\u52FF\u9010\u5904\u591A\u6B21\u8C03\u7528\u3002old_str \u5FC5\u987B\u4E0E\u6587\u4EF6\u4E2D\u7684\u539F\u59CB\u4EE3\u7801\u9010\u5B57\u7B26\u4E00\u81F4\uFF1A\u8BF7\u53BB\u6389 read_file \u8FD4\u56DE\u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF0C\u5E76\u4FDD\u7559\u539F\u6709\u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0E\u884C\u5C3E\u7A7A\u767D\uFF1B\u9ED8\u8BA4\u8981\u6C42\u5728\u5168\u6587\u4E2D\u552F\u4E00\uFF0C\u82E5\u8BBE replace_all=true \u5219\u66FF\u6362\u5168\u90E8\u5339\u914D\u5904\uFF08\u9002\u5408\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\uFF09\u3002",
|
|
4851
5272
|
parameters: {
|
|
4852
5273
|
type: "object",
|
|
4853
5274
|
properties: {
|
|
4854
5275
|
path: { type: "string", description: "\u51C6\u5907\u4FEE\u6539\u7684\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84" },
|
|
4855
|
-
old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757" },
|
|
4856
|
-
new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757" },
|
|
4857
|
-
replace_all: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\u5904\uFF08\u9ED8\u8BA4 false \u4EC5\u66FF\u6362\u552F\u4E00\u5339\u914D\uFF1B\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\u65F6\u8BBE true\uFF09" }
|
|
5276
|
+
old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF1B\u591A\u5904\u4FEE\u6539\u8BF7\u6539\u7528 edits \u6570\u7EC4\u4E00\u6B21\u5B8C\u6210\uFF09" },
|
|
5277
|
+
new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF09" },
|
|
5278
|
+
replace_all: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\u5904\uFF08\u9ED8\u8BA4 false \u4EC5\u66FF\u6362\u552F\u4E00\u5339\u914D\uFF1B\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\u65F6\u8BBE true\uFF09\u3002\u9876\u5C42\u53C2\u6570\u4EC5\u4F5C\u7528\u4E8E\u5355\u6761 old_str/new_str\uFF1Bedits \u5185\u6BCF\u6761\u53EF\u72EC\u7ACB\u8BBE\u7F6E" },
|
|
5279
|
+
edits: {
|
|
5280
|
+
type: "array",
|
|
5281
|
+
description: "\u2605 \u540C\u4E00\u6587\u4EF6\u591A\u5904\u4FEE\u6539\u65F6\u4F18\u5148\u4F7F\u7528\uFF1A\u4E00\u6B21\u8C03\u7528\u6309\u5E8F\u5B8C\u6210\u5168\u90E8\u66FF\u6362\uFF0C\u7701\u53BB\u9010\u5904\u5F80\u8FD4\u3002\u7B2C N \u6761\u7684 old_str \u987B\u57FA\u4E8E\u524D N-1 \u6761\u5E94\u7528\u540E\u7684\u6587\u4EF6\u5185\u5BB9\u6784\u9020\uFF1B\u4EFB\u4E00\u6761\u672A\u547D\u4E2D\u5219\u6574\u4F53\u4E0D\u5199\u5165\uFF08\u539F\u5B50\uFF09\uFF0C\u4FEE\u6B63\u8BE5\u6761\u540E\u6574\u7EC4\u91CD\u8BD5",
|
|
5282
|
+
items: {
|
|
5283
|
+
type: "object",
|
|
5284
|
+
properties: {
|
|
5285
|
+
old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757" },
|
|
5286
|
+
new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757" },
|
|
5287
|
+
replace_all: { type: "boolean", description: "\u8BE5\u6761\u662F\u5426\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\u5904\uFF08\u9ED8\u8BA4 false\uFF09" }
|
|
5288
|
+
},
|
|
5289
|
+
required: ["old_str", "new_str"]
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
4858
5292
|
},
|
|
4859
|
-
required: ["path"
|
|
5293
|
+
required: ["path"]
|
|
4860
5294
|
},
|
|
4861
5295
|
safetyLevel: "mutation" /* MUTATION */,
|
|
4862
5296
|
isSync: true,
|
|
4863
|
-
requireApproval: (args) =>
|
|
5297
|
+
requireApproval: (args) => {
|
|
5298
|
+
const list = args.edits && args.edits.length > 0 ? args.edits : [{ old_str: args.old_str ?? "", new_str: args.new_str ?? "", replace_all: args.replace_all }];
|
|
5299
|
+
const patches = list.map((e, i) => `\u2014\u2014 \u7B2C ${i + 1} \u5904${e.replace_all ? "\uFF08\u{1F525} \u6279\u91CF\u66FF\u6362\u5168\u90E8\u5339\u914D\u5904\uFF09" : ""} \u2014\u2014
|
|
4864
5300
|
\u3010\u51CF\u5C11\u3011:
|
|
4865
|
-
${
|
|
5301
|
+
${e.old_str}
|
|
4866
5302
|
\u3010\u589E\u52A0\u3011:
|
|
4867
|
-
${
|
|
5303
|
+
${e.new_str}`).join("\n\n");
|
|
5304
|
+
return `\u7533\u8BF7\u4FEE\u6539\u6587\u4EF6 [${args.path}]\uFF08\u5171 ${list.length} \u5904\u4FEE\u6539\uFF0C\u4EFB\u4E00\u5904\u5931\u8D25\u5C06\u6574\u4F53\u4E0D\u5199\u5165\uFF09
|
|
5305
|
+
${patches}`;
|
|
5306
|
+
},
|
|
4868
5307
|
async execute(args) {
|
|
4869
5308
|
try {
|
|
4870
|
-
const
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
const normalizedContent = rawContent.replace(/\r\n/g, "\n");
|
|
4874
|
-
const normalizedNew = args.new_str.replace(/\r\n/g, "\n");
|
|
4875
|
-
const normalizedOldRaw = args.old_str.replace(/\r\n/g, "\n");
|
|
4876
|
-
const lnStripped = stripReadFileLineNumbers(normalizedOldRaw);
|
|
4877
|
-
const candidates = [
|
|
4878
|
-
{ old: normalizedOldRaw, note: "" },
|
|
4879
|
-
{ old: stripEdgeBlankLines(normalizedOldRaw), note: "\uFF08\u5DF2\u5BB9\u9519\u9996\u5C3E\u7A7A\u884C\uFF09" }
|
|
4880
|
-
];
|
|
4881
|
-
if (lnStripped !== normalizedOldRaw) candidates.push({ old: lnStripped, note: "\uFF08\u5DF2\u5265\u79BB read_file \u884C\u53F7\u524D\u7F00\uFF09" });
|
|
4882
|
-
let normalizedOld = null;
|
|
4883
|
-
let note = "";
|
|
4884
|
-
for (const c of candidates) {
|
|
4885
|
-
if (c.old.length > 0 && normalizedContent.includes(c.old)) {
|
|
4886
|
-
normalizedOld = c.old;
|
|
4887
|
-
note = c.note;
|
|
4888
|
-
break;
|
|
4889
|
-
}
|
|
5309
|
+
const editList = args.edits && args.edits.length > 0 ? args.edits : [{ old_str: args.old_str ?? "", new_str: args.new_str ?? "", replace_all: args.replace_all }];
|
|
5310
|
+
if (editList.length === 0 || editList.some((e) => typeof e.old_str !== "string" || e.old_str.length === 0)) {
|
|
5311
|
+
return `\u274C [\u53C2\u6570\u7F3A\u5931]\uFF1A\u8BF7\u4F20\u5165 edits \u6570\u7EC4\uFF08\u6BCF\u6761\u542B old_str/new_str\uFF09\u4E00\u6B21\u5B8C\u6210\u591A\u5904\u4FEE\u6539\uFF0C\u6216\u9876\u5C42 old_str + new_str \u4FEE\u6539\u5355\u5904\u3002old_str \u4E0D\u80FD\u4E3A\u7A7A\u3002`;
|
|
4890
5312
|
}
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
assertWithinWorkspace(absPath);
|
|
4901
|
-
await fs12.writeFile(absPath, isCRLF ? lm.content.replace(/\n/g, "\r\n") : lm.content, "utf-8");
|
|
4902
|
-
return args.replace_all ? `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u6279\u91CF\u66FF\u6362\u5168\u90E8 ${lm.count} \u5904\u5339\u914D\uFF08${tag}\uFF09\u3002` : `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u6210\u529F\u5B8C\u6210\u5C40\u90E8\u91CD\u6784\uFF08${tag}\uFF09\u3002`;
|
|
4903
|
-
}
|
|
4904
|
-
if (lm.reason === "conflict") {
|
|
4905
|
-
return `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u4EE3\u7801\u51B2\u7A81\uFF01old_str\uFF08${tag}\u5F52\u4E00\u540E\uFF09\u5728\u5168\u6587\u4E2D\u4E0D\u552F\u4E00\uFF08\u5171 ${lm.count} \u5904\uFF09\u3002\u8BF7\u591A\u5305\u88F9\u51E0\u884C\u4E0A\u4E0B\u6587\uFF0C\u6216\u663E\u5F0F\u8BBE replace_all=true \u6279\u91CF\u66FF\u6362\u3002`;
|
|
4906
|
-
}
|
|
5313
|
+
const absPath = resolveSafePath(args.path);
|
|
5314
|
+
const rawContent = await fs12.readFile(absPath, "utf-8");
|
|
5315
|
+
const isCRLF = rawContent.includes("\r\n");
|
|
5316
|
+
let content = rawContent.replace(/\r\n/g, "\n");
|
|
5317
|
+
const summaries = [];
|
|
5318
|
+
for (let i = 0; i < editList.length; i++) {
|
|
5319
|
+
const r = applyOneEditToContent(content, editList[i].old_str, editList[i].new_str ?? "", !!editList[i].replace_all);
|
|
5320
|
+
if (!r.ok) {
|
|
5321
|
+
return editList.length === 1 ? r.error : `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1Aedits \u7B2C ${i + 1}/${editList.length} \u6761\u672A\u547D\u4E2D\uFF0C\u5DF2\u6574\u4F53\u653E\u5F03\uFF08\u6587\u4EF6\u672A\u505A\u4EFB\u4F55\u6539\u52A8\uFF0C\u53EF\u4FEE\u6B63\u8BE5\u6761\u540E\u6574\u7EC4\u91CD\u8BD5\uFF09\u3002${r.error.replace(/^❌ \[代码修补失败\]:/, "")}`;
|
|
4907
5322
|
}
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
}
|
|
4911
|
-
const matchCount = normalizedContent.split(normalizedOld).length - 1;
|
|
4912
|
-
if (!args.replace_all && matchCount > 1) {
|
|
4913
|
-
return `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u4EE3\u7801\u51B2\u7A81\uFF01old_str \u5728\u5168\u6587\u4E2D\u4E0D\u552F\u4E00\uFF08\u5171\u53D1\u73B0\u4E86 ${matchCount} \u5904\uFF09\u3002\u8BF7\u5411\u4E0A\u6216\u5411\u4E0B\u591A\u5305\u88F9\u51E0\u884C\u4E0A\u4E0B\u6587\u518D\u63D0\u8BF7\u4FEE\u6539\uFF0C\u6216\u663E\u5F0F\u8BBE replace_all=true \u6279\u91CF\u66FF\u6362\u3002`;
|
|
5323
|
+
content = r.content;
|
|
5324
|
+
summaries.push(editList.length === 1 ? r.summary : ` ${i + 1}. ${r.summary}`);
|
|
4914
5325
|
}
|
|
4915
|
-
const oldFirstNonBlank = normalizedOld.split("\n").find((l) => l.trim() !== "") ?? "";
|
|
4916
|
-
const baseIndent = oldFirstNonBlank.match(/^[ \t]*/)?.[0] ?? "";
|
|
4917
|
-
const alignedNew = baseIndent ? reindentToBase(normalizedNew, baseIndent) : normalizedNew;
|
|
4918
|
-
const updatedContent = args.replace_all ? normalizedContent.split(normalizedOld).join(alignedNew) : normalizedContent.replace(normalizedOld, () => alignedNew);
|
|
4919
5326
|
assertWithinWorkspace(absPath);
|
|
4920
|
-
await fs12.writeFile(absPath, isCRLF ?
|
|
4921
|
-
return
|
|
5327
|
+
await fs12.writeFile(absPath, isCRLF ? content.replace(/\n/g, "\r\n") : content, "utf-8");
|
|
5328
|
+
return editList.length === 1 ? `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] ${summaries[0]}` : `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u6309\u5E8F\u5B8C\u6210 ${editList.length} \u5904\u4FEE\u6539\uFF08\u5355\u6B21\u539F\u5B50\u5199\u5165\uFF09\uFF1A
|
|
5329
|
+
${summaries.join("\n")}`;
|
|
4922
5330
|
} catch (error) {
|
|
4923
5331
|
return `\u64CD\u4F5C\u5931\u8D25: ${error.message}`;
|
|
4924
5332
|
}
|
|
@@ -5226,13 +5634,14 @@ var init_search = __esm({
|
|
|
5226
5634
|
type: "function",
|
|
5227
5635
|
function: {
|
|
5228
5636
|
name: "search_grep",
|
|
5229
|
-
description: "\u5728\u5DE5\u4F5C\u533A\u7684\u6240\u6709\u6587\u4EF6\u4E2D\u68C0\u7D22\u5339\u914D\u7684\u4EE3\u7801\u884C\uFF0C\u6BCF\u4E2A\u547D\u4E2D\u5E26\u524D\u540E\u5404 2 \u884C\u4E0A\u4E0B\u6587\uFF08\u53EF\u76F4\u63A5\u5224\u65AD\u7528\u6CD5\u3001\u514D\u7D27\u8DDF\u4E00\u6B21 read_file\uFF09\uFF1B\u9ED8\u8BA4\u6309\u5B57\u9762\u91CF\u5173\u952E\u8BCD\u5339\u914D\uFF0C\u5982\u9700\u6B63\u5219\u4F20 is_regex=true\u3002\u591A\
|
|
5637
|
+
description: "\u5728\u5DE5\u4F5C\u533A\u7684\u6240\u6709\u6587\u4EF6\u4E2D\u68C0\u7D22\u5339\u914D\u7684\u4EE3\u7801\u884C\uFF0C\u6BCF\u4E2A\u547D\u4E2D\u9ED8\u8BA4\u5E26\u524D\u540E\u5404 2 \u884C\u4E0A\u4E0B\u6587\uFF08\u53EF\u76F4\u63A5\u5224\u65AD\u7528\u6CD5\u3001\u514D\u7D27\u8DDF\u4E00\u6B21 read_file\uFF1B\u6784\u9020 edit_file \u7684 old_str \u524D\u53EF\u7528 context \u53C2\u6570\u8C03\u5927\u4E00\u6B21\u62FF\u8DB3\uFF09\uFF1B\u9ED8\u8BA4\u6309\u5B57\u9762\u91CF\u5173\u952E\u8BCD\u5339\u914D\uFF0C\u5982\u9700\u6B63\u5219\u4F20 is_regex=true\u3002\u2605 \u68C0\u7D22\u591A\u4E2A\u5173\u952E\u8BCD\u65F6\uFF0C\u7528 is_regex=true \u4EE5 | \u5408\u5E76\uFF08\u5982 'uploadVisible|uploadTip'\uFF09\u4E00\u6B21\u67E5\u5B8C\uFF0C\u52FF\u9010\u4E2A\u5173\u952E\u8BCD\u591A\u6B21\u8C03\u7528\u3002path \u53EF\u9650\u5B9A\u5230\u76EE\u5F55\u6216\u5177\u4F53\u6587\u4EF6\uFF08\u5728\u5355\u4E2A\u5927\u6587\u4EF6\u5185\u591A\u5904\u5B9A\u4F4D\u65F6\u4F20\u6587\u4EF6\u8DEF\u5F84\u6700\u9AD8\u6548\uFF09\u3002\u591A\u6839\u5DE5\u4F5C\u533A\u4E0B\uFF1A\u53EF\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF0C\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../\u5144\u5F1F\u76EE\u5F55\u3002\u2605 \u5F53\u7528\u6237\u5728\u5BF9\u8BDD\u91CC\u6307\u660E\u4E86\u67D0\u4E2A\u9879\u76EE\u65F6\uFF0C\u52A1\u5FC5\u628A\u8BE5\u9879\u76EE\u4F5C\u4E3A path \u4F20\u5165\u2014\u2014\u5426\u5219\u53EA\u4F1A\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u7684\u6D3B\u52A8\u6839\uFF0C\u5E38\u4E0E\u7528\u6237\u610F\u56FE\u4E0D\u7B26\u3002",
|
|
5230
5638
|
parameters: {
|
|
5231
5639
|
type: "object",
|
|
5232
5640
|
properties: {
|
|
5233
|
-
query: { type: "string", description: "\u68C0\u7D22\u5185\u5BB9\u3002\u9ED8\u8BA4\u4E3A\u5B57\u9762\u91CF\u5173\u952E\u8BCD\uFF08\u5982 'function runAgent'\uFF09\uFF1Bis_regex=true \u65F6\u6309\u6B63\u5219\u89E3\u6790\uFF08\u5982 'function\\s+runAgent'\uFF09
|
|
5641
|
+
query: { type: "string", description: "\u68C0\u7D22\u5185\u5BB9\u3002\u9ED8\u8BA4\u4E3A\u5B57\u9762\u91CF\u5173\u952E\u8BCD\uFF08\u5982 'function runAgent'\uFF09\uFF1Bis_regex=true \u65F6\u6309\u6B63\u5219\u89E3\u6790\uFF08\u5982 'function\\s+runAgent'\uFF0C\u591A\u5173\u952E\u8BCD\u7528 | \u5408\u5E76\uFF09" },
|
|
5234
5642
|
is_regex: { type: "boolean", description: "\u662F\u5426\u5C06 query \u4F5C\u4E3A\u6B63\u5219\u8868\u8FBE\u5F0F\u89E3\u6790\uFF0C\u9ED8\u8BA4 false\uFF08\u5B57\u9762\u91CF\u5339\u914D\uFF0C\u81EA\u52A8\u8F6C\u4E49\u7279\u6B8A\u5B57\u7B26\uFF09" },
|
|
5235
|
-
path: { type: "string", description: "\u9650\u5B9A\u641C\u7D22\u7684\u76EE\u5F55\uFF08\u53EF\u9009\uFF09\u3002\u9ED8\u8BA4\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u6D3B\u52A8\u6839\u3002\u591A\u6839\u573A\u666F\u4E0B\uFF1A\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF1B\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../<\u5144\u5F1F\u76EE\u5F55>\uFF1B\u5747\u7ECF\u6C99\u7BB1\u6821\u9A8C\u3002\u7528\u6237\u63D0\u5230\u5177\u4F53\u9879\u76EE\u65F6\u5FC5\u586B\u3002" }
|
|
5643
|
+
path: { type: "string", description: "\u9650\u5B9A\u641C\u7D22\u7684\u76EE\u5F55\u6216\u5177\u4F53\u6587\u4EF6\uFF08\u53EF\u9009\uFF09\u3002\u4F20\u5177\u4F53\u6587\u4EF6\u8DEF\u5F84\u65F6\u76F8\u5F53\u4E8E\u8BE5\u6587\u4EF6\u5185\u5168\u6587\u68C0\u7D22\uFF08\u5927\u6587\u4EF6\u591A\u5904\u5B9A\u4F4D\u9996\u9009\uFF09\u3002\u9ED8\u8BA4\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u6D3B\u52A8\u6839\u3002\u591A\u6839\u573A\u666F\u4E0B\uFF1A\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF1B\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../<\u5144\u5F1F\u76EE\u5F55>\uFF1B\u5747\u7ECF\u6C99\u7BB1\u6821\u9A8C\u3002\u7528\u6237\u63D0\u5230\u5177\u4F53\u9879\u76EE\u65F6\u5FC5\u586B\u3002" },
|
|
5644
|
+
context: { type: "number", description: "\u6BCF\u4E2A\u547D\u4E2D\u9644\u5E26\u7684\u524D\u540E\u4E0A\u4E0B\u6587\u884C\u6570\uFF080-10\uFF0C\u9ED8\u8BA4 2\uFF09\u3002\u9700\u8981\u62FF\u8DB3\u4E00\u6BB5\u5B8C\u6574\u4EE3\u7801\u4F5C edit_file \u7684 old_str \u65F6\u53EF\u8C03\u5927\uFF08\u5982 5-8\uFF09\uFF0C\u514D\u5F97\u4E8C\u6B21\u68C0\u7D22" }
|
|
5236
5645
|
},
|
|
5237
5646
|
required: ["query"]
|
|
5238
5647
|
},
|
|
@@ -5261,6 +5670,7 @@ var init_search = __esm({
|
|
|
5261
5670
|
return resolveReadablePath(args.path);
|
|
5262
5671
|
};
|
|
5263
5672
|
const searchRoot = resolveSearchRoot().replace(/\\/g, "/");
|
|
5673
|
+
const contextLines = Math.min(Math.max(args.context ?? 2, 0), 10);
|
|
5264
5674
|
const rgArgs = [
|
|
5265
5675
|
"--threads",
|
|
5266
5676
|
"1",
|
|
@@ -5271,8 +5681,8 @@ var init_search = __esm({
|
|
|
5271
5681
|
"--color",
|
|
5272
5682
|
"never",
|
|
5273
5683
|
"-C",
|
|
5274
|
-
|
|
5275
|
-
// ★
|
|
5684
|
+
String(contextLines),
|
|
5685
|
+
// ★ 每个命中带前后上下文:模型一次看懂用法,免去紧跟的 read_file 往返(减调用次数的关键)
|
|
5276
5686
|
"--max-count",
|
|
5277
5687
|
"10",
|
|
5278
5688
|
"--glob",
|
|
@@ -5575,48 +5985,90 @@ ${tail}`,
|
|
|
5575
5985
|
// ../core/src/tool/registry/glob.ts
|
|
5576
5986
|
import fs14 from "fs/promises";
|
|
5577
5987
|
import path17 from "path";
|
|
5578
|
-
var globToRegex2, globTools;
|
|
5988
|
+
var findMatchingBrace, splitTopLevel, globToRegex2, globTools;
|
|
5579
5989
|
var init_glob = __esm({
|
|
5580
5990
|
"../core/src/tool/registry/glob.ts"() {
|
|
5581
5991
|
"use strict";
|
|
5582
5992
|
init_type();
|
|
5583
5993
|
init_guard();
|
|
5994
|
+
findMatchingBrace = (s, start) => {
|
|
5995
|
+
let depth = 0;
|
|
5996
|
+
for (let i = start; i < s.length; i++) {
|
|
5997
|
+
if (s[i] === "{") depth++;
|
|
5998
|
+
else if (s[i] === "}") {
|
|
5999
|
+
depth--;
|
|
6000
|
+
if (depth === 0) return i;
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
return -1;
|
|
6004
|
+
};
|
|
6005
|
+
splitTopLevel = (s) => {
|
|
6006
|
+
const parts = [];
|
|
6007
|
+
let depth = 0, cur = "";
|
|
6008
|
+
for (const ch of s) {
|
|
6009
|
+
if (ch === "{") depth++;
|
|
6010
|
+
else if (ch === "}") depth--;
|
|
6011
|
+
if (ch === "," && depth === 0) {
|
|
6012
|
+
parts.push(cur);
|
|
6013
|
+
cur = "";
|
|
6014
|
+
continue;
|
|
6015
|
+
}
|
|
6016
|
+
cur += ch;
|
|
6017
|
+
}
|
|
6018
|
+
parts.push(cur);
|
|
6019
|
+
return parts;
|
|
6020
|
+
};
|
|
5584
6021
|
globToRegex2 = (pattern) => {
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
if (
|
|
5591
|
-
|
|
5592
|
-
|
|
6022
|
+
const walk = (s) => {
|
|
6023
|
+
let re = "";
|
|
6024
|
+
let i = 0;
|
|
6025
|
+
while (i < s.length) {
|
|
6026
|
+
const c = s[i];
|
|
6027
|
+
if (c === "{") {
|
|
6028
|
+
const close = findMatchingBrace(s, i);
|
|
6029
|
+
if (close === -1) {
|
|
6030
|
+
re += "\\{";
|
|
6031
|
+
i++;
|
|
6032
|
+
continue;
|
|
6033
|
+
}
|
|
6034
|
+
const alts = splitTopLevel(s.slice(i + 1, close));
|
|
6035
|
+
re += `(?:${alts.map((a) => walk(a)).join("|")})`;
|
|
6036
|
+
i = close + 1;
|
|
6037
|
+
continue;
|
|
6038
|
+
}
|
|
6039
|
+
if (c === "*" && s[i + 1] === "*") {
|
|
6040
|
+
if (s[i + 2] === "/") {
|
|
6041
|
+
re += "(?:.*/)?";
|
|
6042
|
+
i += 3;
|
|
6043
|
+
} else {
|
|
6044
|
+
re += ".*";
|
|
6045
|
+
i += 2;
|
|
6046
|
+
}
|
|
6047
|
+
} else if (c === "*") {
|
|
6048
|
+
re += "[^/]*";
|
|
6049
|
+
i++;
|
|
6050
|
+
} else if (c === "?") {
|
|
6051
|
+
re += ".";
|
|
6052
|
+
i++;
|
|
5593
6053
|
} else {
|
|
5594
|
-
re += "
|
|
5595
|
-
i
|
|
6054
|
+
re += /[.+^$}()|[\]\\]/.test(c) ? "\\" + c : c;
|
|
6055
|
+
i++;
|
|
5596
6056
|
}
|
|
5597
|
-
} else if (c === "*") {
|
|
5598
|
-
re += "[^/]*";
|
|
5599
|
-
i++;
|
|
5600
|
-
} else if (c === "?") {
|
|
5601
|
-
re += ".";
|
|
5602
|
-
i++;
|
|
5603
|
-
} else {
|
|
5604
|
-
re += /[.+^${}()|[\]\\]/.test(c) ? "\\" + c : c;
|
|
5605
|
-
i++;
|
|
5606
6057
|
}
|
|
5607
|
-
|
|
5608
|
-
|
|
6058
|
+
return re;
|
|
6059
|
+
};
|
|
6060
|
+
return new RegExp(`^${walk(pattern)}$`);
|
|
5609
6061
|
};
|
|
5610
6062
|
globTools = [
|
|
5611
6063
|
{
|
|
5612
6064
|
type: "function",
|
|
5613
6065
|
function: {
|
|
5614
6066
|
name: "glob",
|
|
5615
|
-
description: "\u6309\u6587\u4EF6\u540D glob \u6A21\u5F0F\u5FEB\u901F\u67E5\u627E\u6587\u4EF6\uFF08\u5982 '**/*.ts'\u3001'src/**/test*'\u3001'**/*.test.ts'\uFF09\u3002\u4E0E search_grep\uFF08\u6309\u5185\u5BB9\u68C0\u7D22\uFF09\u4E92\u8865\u3002\u81EA\u52A8\u5957\u7528 .gitignore / \u901A\u7528\u9ED1\u540D\u5355\u8FC7\u6EE4\u3002",
|
|
6067
|
+
description: "\u6309\u6587\u4EF6\u540D glob \u6A21\u5F0F\u5FEB\u901F\u67E5\u627E\u6587\u4EF6\uFF08\u5982 '**/*.ts'\u3001'src/**/test*'\u3001'**/*.test.ts'\uFF09\u3002\u2605 \u652F\u6301\u82B1\u62EC\u53F7\u591A\u9009\uFF1A'**/*.{ts,tsx,vue}'\u3001'src/{api,components}/**' \u4E00\u6B21\u67E5\u591A\u7C7B\u578B/\u591A\u76EE\u5F55\uFF0C\u52FF\u5206\u591A\u6B21\u8C03\u7528\u3002\u4E0E search_grep\uFF08\u6309\u5185\u5BB9\u68C0\u7D22\uFF09\u4E92\u8865\u3002\u81EA\u52A8\u5957\u7528 .gitignore / \u901A\u7528\u9ED1\u540D\u5355\u8FC7\u6EE4\u3002",
|
|
5616
6068
|
parameters: {
|
|
5617
6069
|
type: "object",
|
|
5618
6070
|
properties: {
|
|
5619
|
-
pattern: { type: "string", description: "glob \u6A21\u5F0F\uFF0C\u5982 '**/*.ts'
|
|
6071
|
+
pattern: { type: "string", description: "glob \u6A21\u5F0F\uFF0C\u652F\u6301 * / ** / ? \u4E0E\u82B1\u62EC\u53F7\u591A\u9009 {a,b}\uFF08\u5982 '**/*.{ts,vue}'\u3001'src/{api,components}/**'\uFF09" },
|
|
5620
6072
|
path: { type: "string", description: "\u9650\u5B9A\u641C\u7D22\u7684\u8D77\u59CB\u76EE\u5F55\uFF08\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u53EF\u9009\uFF0C\u9ED8\u8BA4\u5DE5\u4F5C\u533A\u6839\uFF09" }
|
|
5621
6073
|
},
|
|
5622
6074
|
required: ["pattern"]
|
|
@@ -6530,7 +6982,7 @@ var init_http = __esm({
|
|
|
6530
6982
|
// ../core/src/tool/registry/typescript.ts
|
|
6531
6983
|
import fs16 from "fs/promises";
|
|
6532
6984
|
import path19 from "path";
|
|
6533
|
-
var MAX_FILE_BYTES, toDisplayPath, precheck, MAX_DIAG_ENTRIES, typescriptTools;
|
|
6985
|
+
var MAX_FILE_BYTES, toDisplayPath, precheck, MAX_DIAG_ENTRIES, MAX_DIAG_FILES, diagnoseOneFile, typescriptTools;
|
|
6534
6986
|
var init_typescript = __esm({
|
|
6535
6987
|
"../core/src/tool/registry/typescript.ts"() {
|
|
6536
6988
|
"use strict";
|
|
@@ -6554,74 +7006,108 @@ var init_typescript = __esm({
|
|
|
6554
7006
|
return null;
|
|
6555
7007
|
};
|
|
6556
7008
|
MAX_DIAG_ENTRIES = 300;
|
|
7009
|
+
MAX_DIAG_FILES = 20;
|
|
7010
|
+
diagnoseOneFile = async (TS, displayPath, checkJs) => {
|
|
7011
|
+
try {
|
|
7012
|
+
const absPath = realpathNative(resolveReadablePath(displayPath));
|
|
7013
|
+
const block = await precheck(displayPath, absPath);
|
|
7014
|
+
if (block) return { ok: false, text: block };
|
|
7015
|
+
const { ls } = await getLanguageService(TS, absPath, { checkJs });
|
|
7016
|
+
const syntactic = ls.getSyntacticDiagnostics(absPath);
|
|
7017
|
+
const semantic = ls.getSemanticDiagnostics(absPath);
|
|
7018
|
+
const all = [...syntactic, ...semantic];
|
|
7019
|
+
if (all.length === 0) return { ok: true, errors: 0, warnings: 0, text: `\u2713 No diagnostics (0 errors, 0 warnings) for ${displayPath}` };
|
|
7020
|
+
const entries = [];
|
|
7021
|
+
let errors = 0, warnings = 0;
|
|
7022
|
+
for (const d of all) {
|
|
7023
|
+
const cat = d.category;
|
|
7024
|
+
let label;
|
|
7025
|
+
if (cat === TS.DiagnosticCategory.Error) {
|
|
7026
|
+
label = "error";
|
|
7027
|
+
errors++;
|
|
7028
|
+
} else if (cat === TS.DiagnosticCategory.Warning) {
|
|
7029
|
+
label = "warning";
|
|
7030
|
+
warnings++;
|
|
7031
|
+
} else if (cat === TS.DiagnosticCategory.Suggestion) label = "suggestion";
|
|
7032
|
+
else label = "info";
|
|
7033
|
+
let line = 0, column = 0;
|
|
7034
|
+
if (d.file && typeof d.start === "number") {
|
|
7035
|
+
({ line, column } = posToLineCol(TS, d.file, d.start));
|
|
7036
|
+
}
|
|
7037
|
+
entries.push({
|
|
7038
|
+
line,
|
|
7039
|
+
column,
|
|
7040
|
+
label,
|
|
7041
|
+
code: typeof d.code === "number" ? `TS${d.code}` : "",
|
|
7042
|
+
msg: TS.flattenDiagnosticMessageText(d.messageText, "\n")
|
|
7043
|
+
});
|
|
7044
|
+
}
|
|
7045
|
+
entries.sort((a, b) => a.line - b.line || a.column - b.column);
|
|
7046
|
+
const overflow = entries.length > MAX_DIAG_ENTRIES ? entries.length - MAX_DIAG_ENTRIES : 0;
|
|
7047
|
+
const shown = overflow ? entries.slice(0, MAX_DIAG_ENTRIES) : entries;
|
|
7048
|
+
const body = shown.map(
|
|
7049
|
+
(e) => `${displayPath}:${e.line}:${e.column} ${e.label}${e.code ? " " + e.code : ""} ${e.msg}`
|
|
7050
|
+
).join("\n");
|
|
7051
|
+
const tail = overflow ? `
|
|
7052
|
+
\u2026(\u53E6\u6709 ${overflow} \u6761\u8BCA\u65AD\u672A\u663E\u793A\uFF0C\u8BF7\u7F29\u5C0F\u8303\u56F4\u6216\u7528 run_command \u8DD1 tsc \u770B\u5168\u91CF)\u2026` : "";
|
|
7053
|
+
return { ok: true, errors, warnings, text: `[Diagnostics: ${displayPath}] ${errors} error(s), ${warnings} warning(s)
|
|
7054
|
+
${body}${tail}` };
|
|
7055
|
+
} catch (e) {
|
|
7056
|
+
return { ok: false, text: `\u274C \u7C7B\u578B\u8BCA\u65AD\u5931\u8D25 [${displayPath}]: ${e?.message ?? e}` };
|
|
7057
|
+
}
|
|
7058
|
+
};
|
|
6557
7059
|
typescriptTools = [
|
|
6558
7060
|
{
|
|
6559
7061
|
type: "function",
|
|
6560
7062
|
function: {
|
|
6561
7063
|
name: "get_diagnostics",
|
|
6562
|
-
description: "\u5BF9\
|
|
7064
|
+
description: "\u5BF9\u4E00\u4E2A\u6216\u591A\u4E2A TS/JS \u6587\u4EF6\u53D6 TypeScript \u8BED\u6CD5 + \u8BED\u4E49\u8BCA\u65AD\uFF08\u7C7B\u578B\u9519\u8BEF\u3001\u672A\u7528\u53D8\u91CF\u3001\u4E0D\u53EF\u8FBE\u4EE3\u7801\u7B49\uFF09\uFF0C\u8F93\u51FA\u5E26\u884C\u53F7/\u5217/\u4E25\u91CD\u5EA6/TS \u9519\u8BEF\u7801\uFF0C\u683C\u5F0F\u5BF9\u9F50 tsc\u3002\u7528\u4E8E\u7CBE\u51C6\u5B9A\u4F4D\u7F16\u8BD1/\u7C7B\u578B\u95EE\u9898\uFF0C\u66FF\u4EE3\u624B\u52A8\u8DD1 tsc \u518D\u89E3\u6790\u8F93\u51FA\u3002\u2605 \u6539\u5B8C\u591A\u4E2A\u6587\u4EF6\u540E\u9A8C\u8BC1\uFF1A\u4F20 paths \u6570\u7EC4\u4E00\u6B21\u8BCA\u65AD\u5168\u90E8\uFF08\u6700\u591A 20 \u4E2A\uFF09\uFF0C\u52FF\u9010\u6587\u4EF6\u591A\u6B21\u8C03\u7528\u3002\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B.vue SFC \u4E0D\u652F\u6301\uFF08\u9700 vue-tsc\uFF09\u3002\u9879\u76EE\u7EA7\u5168\u91CF\u8BCA\u65AD\u8BF7\u7528 run_command \u8DD1 `tsc --noEmit`\u3002\u4F9D\u8D56 typescript \u6A21\u5757\uFF08VSCode \u6269\u5C55\u5185\u53EF\u7528\uFF1B\u7F3A\u5931\u5219\u672C\u5DE5\u5177\u81EA\u52A8\u9690\u85CF\uFF09\u3002",
|
|
6563
7065
|
parameters: {
|
|
6564
7066
|
type: "object",
|
|
6565
7067
|
properties: {
|
|
6566
|
-
path: { type: "string", description: "\u76EE\u6807\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84\uFF08\u5982 'src/services/user.ts'\uFF09" },
|
|
7068
|
+
path: { type: "string", description: "\u76EE\u6807\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84\uFF08\u5982 'src/services/user.ts'\uFF09\u3002\u5355\u6587\u4EF6\u8BCA\u65AD\u7528\uFF1B\u6279\u91CF\u8BF7\u6539\u7528 paths" },
|
|
7069
|
+
paths: { type: "array", items: { type: "string" }, description: "\u2605 \u6279\u91CF\u8BCA\u65AD\uFF1A\u591A\u4E2A\u6587\u4EF6\u4E00\u6B21\u9A8C\u8BC1\uFF08\u5355\u6B21\u6700\u591A 20 \u4E2A\uFF0C\u8D85\u51FA\u4F1A\u62D2\u7EDD\uFF09\u3002\u4F20\u4E86 paths \u5219\u5FFD\u7565 path" },
|
|
6567
7070
|
check_js: { type: "boolean", description: "\u5BF9 .js/.jsx \u6587\u4EF6\u5F00\u542F\u8BED\u4E49\u68C0\u67E5\uFF08\u9ED8\u8BA4\u9075 tsconfig \u7684 checkJs\uFF1B\u76EE\u6807\u4E3A JS \u4E14\u60F3\u8981\u7C7B\u578B\u8BCA\u65AD\u65F6\u6309\u9700\u7F6E true\uFF09" }
|
|
6568
7071
|
},
|
|
6569
|
-
required: [
|
|
7072
|
+
required: []
|
|
6570
7073
|
},
|
|
6571
7074
|
safetyLevel: "safe" /* SAFE */,
|
|
6572
7075
|
isSync: true,
|
|
6573
|
-
maxOutputCharacters:
|
|
7076
|
+
maxOutputCharacters: 48e3,
|
|
7077
|
+
// ★ 批量多文件后上调(原单文件 24K;中心 truncateToolResult 仍是最终兜底)
|
|
6574
7078
|
privacyMaskingRules: maskSecretsInContent,
|
|
6575
7079
|
validateEnvironment: async () => !!await getTs(),
|
|
6576
7080
|
async execute(args, _ctx) {
|
|
6577
7081
|
try {
|
|
6578
7082
|
const TS = await getTs();
|
|
6579
7083
|
if (!TS) return `\u26A0\uFE0F [\u7C7B\u578B\u8BCA\u65AD\u4E0D\u53EF\u7528]\uFF1Atypescript \u6A21\u5757\u672A\u52A0\u8F7D\uFF08VSCode \u6269\u5C55\u5185\u53EF\u7528\uFF1BCLI \u73AF\u5883\u672A\u5FC5\u5B89\u88C5 typescript\uFF09\u3002\u53EF\u6539\u7528 run_command \u8DD1 \`tsc --noEmit\`\u3002`;
|
|
6580
|
-
const
|
|
6581
|
-
|
|
6582
|
-
if (
|
|
6583
|
-
const
|
|
6584
|
-
const
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
errors++;
|
|
6596
|
-
} else if (cat === TS.DiagnosticCategory.Warning) {
|
|
6597
|
-
label = "warning";
|
|
6598
|
-
warnings++;
|
|
6599
|
-
} else if (cat === TS.DiagnosticCategory.Suggestion) label = "suggestion";
|
|
6600
|
-
else label = "info";
|
|
6601
|
-
let line = 0, column = 0;
|
|
6602
|
-
if (d.file && typeof d.start === "number") {
|
|
6603
|
-
({ line, column } = posToLineCol(TS, d.file, d.start));
|
|
7084
|
+
const targets = args.paths && args.paths.length > 0 ? args.paths : args.path ? [args.path] : [];
|
|
7085
|
+
if (targets.length === 0) return `\u274C [\u53C2\u6570\u7F3A\u5931]\uFF1A\u8BF7\u4F20 path\uFF08\u5355\u6587\u4EF6\uFF09\u6216 paths\uFF08\u6279\u91CF\uFF0C\u6539\u5B8C\u591A\u4E2A\u6587\u4EF6\u540E\u4E00\u6B21\u9A8C\u8BC1\uFF09\u3002`;
|
|
7086
|
+
if (targets.length > MAX_DIAG_FILES) return `\u274C [\u53C2\u6570\u8D85\u9650]\uFF1A\u5355\u6B21\u6279\u91CF\u8BCA\u65AD\u6700\u591A ${MAX_DIAG_FILES} \u4E2A\u6587\u4EF6\uFF08\u6536\u5230 ${targets.length} \u4E2A\uFF09\u3002\u8BF7\u5206\u6279\u8C03\u7528\uFF0C\u6216\u7528 run_command \u8DD1 \`tsc --noEmit\` \u505A\u9879\u76EE\u7EA7\u5168\u91CF\u8BCA\u65AD\u3002`;
|
|
7087
|
+
const results = [];
|
|
7088
|
+
for (const p of targets) results.push(await diagnoseOneFile(TS, p, args.check_js));
|
|
7089
|
+
if (results.length === 1) return results[0].text;
|
|
7090
|
+
let totalErr = 0, totalWarn = 0, clean = 0, failed = 0;
|
|
7091
|
+
const sections = [];
|
|
7092
|
+
for (let i = 0; i < results.length; i++) {
|
|
7093
|
+
const r = results[i];
|
|
7094
|
+
if (!r.ok) {
|
|
7095
|
+
failed++;
|
|
7096
|
+
sections.push(`\u2014\u2014 ${targets[i]}\uFF08\u8BCA\u65AD\u672A\u4EA7\u51FA\uFF09\u2014\u2014
|
|
7097
|
+
${r.text}`);
|
|
7098
|
+
continue;
|
|
6604
7099
|
}
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
msg: TS.flattenDiagnosticMessageText(d.messageText, "\n")
|
|
6611
|
-
});
|
|
7100
|
+
totalErr += r.errors;
|
|
7101
|
+
totalWarn += r.warnings;
|
|
7102
|
+
if (r.errors === 0 && r.warnings === 0) clean++;
|
|
7103
|
+
sections.push(`\u2014\u2014 ${targets[i]} \u2014\u2014
|
|
7104
|
+
${r.text}`);
|
|
6612
7105
|
}
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
const body = shown.map(
|
|
6617
|
-
(e) => `${args.path}:${e.line}:${e.column} ${e.label}${e.code ? " " + e.code : ""} ${e.msg}`
|
|
6618
|
-
).join("\n");
|
|
6619
|
-
const tail = overflow ? `
|
|
6620
|
-
\u2026(\u53E6\u6709 ${overflow} \u6761\u8BCA\u65AD\u672A\u663E\u793A\uFF0C\u8BF7\u7F29\u5C0F\u8303\u56F4\u6216\u7528 run_command \u8DD1 tsc \u770B\u5168\u91CF)\u2026` : "";
|
|
6621
|
-
return `[Diagnostics: ${args.path}] ${errors} error(s), ${warnings} warning(s)
|
|
6622
|
-
${body}${tail}`;
|
|
7106
|
+
return `[\u6279\u91CF\u8BCA\u65AD: ${targets.length} \u4E2A\u6587\u4EF6] \u5171 ${totalErr} error(s), ${totalWarn} warning(s)\uFF1B${clean} \u4E2A\u6587\u4EF6\u5E72\u51C0${failed ? `\uFF0C${failed} \u4E2A\u8BCA\u65AD\u5931\u8D25` : ""}
|
|
7107
|
+
|
|
7108
|
+
${sections.join("\n\n")}`;
|
|
6623
7109
|
} catch (e) {
|
|
6624
|
-
return `\u274C \u7C7B\u578B\u8BCA\u65AD\u5931\u8D25
|
|
7110
|
+
return `\u274C \u7C7B\u578B\u8BCA\u65AD\u5931\u8D25: ${e?.message ?? e}`;
|
|
6625
7111
|
}
|
|
6626
7112
|
}
|
|
6627
7113
|
}
|
|
@@ -8465,7 +8951,6 @@ var agentTools, agentSubTools, workflowTools;
|
|
|
8465
8951
|
var init_tool = __esm({
|
|
8466
8952
|
"../core/src/tool/index.ts"() {
|
|
8467
8953
|
"use strict";
|
|
8468
|
-
init_system();
|
|
8469
8954
|
init_agent();
|
|
8470
8955
|
init_workflow();
|
|
8471
8956
|
init_fs();
|
|
@@ -8491,7 +8976,6 @@ var init_tool = __esm({
|
|
|
8491
8976
|
agentSubTools = createAgentTools(() => agentTools);
|
|
8492
8977
|
workflowTools = createWorkflowTools(() => agentTools);
|
|
8493
8978
|
agentTools.push(
|
|
8494
|
-
...systemTools,
|
|
8495
8979
|
...agentSubTools,
|
|
8496
8980
|
...workflowTools,
|
|
8497
8981
|
...fsTools,
|
|
@@ -8811,6 +9295,9 @@ var init_toolExecution = __esm({
|
|
|
8811
9295
|
init_backgroundTool();
|
|
8812
9296
|
init_backup();
|
|
8813
9297
|
init_autoPermission();
|
|
9298
|
+
init_loader();
|
|
9299
|
+
init_config();
|
|
9300
|
+
init_planMode();
|
|
8814
9301
|
applyPrivacyMasking = (rules3, args, output) => {
|
|
8815
9302
|
if (!rules3) return output;
|
|
8816
9303
|
try {
|
|
@@ -8836,6 +9323,7 @@ var init_toolExecution = __esm({
|
|
|
8836
9323
|
rawTools,
|
|
8837
9324
|
events,
|
|
8838
9325
|
permissionMode,
|
|
9326
|
+
planMode,
|
|
8839
9327
|
onUIEvent,
|
|
8840
9328
|
requestApproval: hostRequestApproval,
|
|
8841
9329
|
requestQuestion: hostRequestQuestion,
|
|
@@ -8862,6 +9350,10 @@ var init_toolExecution = __esm({
|
|
|
8862
9350
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: true, terminal: { kind: "exit_plan_mode", plan } };
|
|
8863
9351
|
}
|
|
8864
9352
|
if (calledName === "enter_plan_mode") {
|
|
9353
|
+
if (planMode) {
|
|
9354
|
+
const note2 = "\uFF08\u5DF2\u5728\u8BA1\u5212\u6A21\u5F0F\u4E2D\uFF0C\u65E0\u9700\u91CD\u590D\u8FDB\u5165\u3002\u8BF7\u7EE7\u7EED\u53EA\u8BFB\u8C03\u7814\uFF0C\u5B8C\u6210\u540E\u8C03 exit_plan_mode \u63D0\u4EA4\u65B9\u6848\u3002\uFF09";
|
|
9355
|
+
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note2, resultForUser: note2, ok: true };
|
|
9356
|
+
}
|
|
8865
9357
|
const reason = typeof calledArgs?.reason === "string" ? calledArgs.reason : "";
|
|
8866
9358
|
const note = "\u{1F4CB} [\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F] \u6A21\u578B\u8BF7\u6C42\u5148\u4EE5\u53EA\u8BFB\u65B9\u5F0F\u8C03\u7814\u5E76\u89C4\u5212\u65B9\u6848\uFF0C\u5DF2\u5207\u6362\u81F3\u8BA1\u5212\u6A21\u5F0F\u3002";
|
|
8867
9359
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: true, terminal: { kind: "enter_plan_mode", reason } };
|
|
@@ -8870,10 +9362,16 @@ var init_toolExecution = __esm({
|
|
|
8870
9362
|
const placeholder = "\uFF08\u5DF2\u4E2D\u6B62\uFF0C\u672A\u6267\u884C\uFF09";
|
|
8871
9363
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: placeholder, resultForUser: placeholder, ok: false, aborted: true };
|
|
8872
9364
|
}
|
|
9365
|
+
if (!parseFailed && planMode && appConfig.planEnforcement === "runtime" && calledName !== "enter_plan_mode" && calledName !== "exit_plan_mode" && !PLAN_ALLOWED_TOOLS.has(calledName)) {
|
|
9366
|
+
const note = `\u274C [\u8BA1\u5212\u6A21\u5F0F] \u5F53\u524D\u4E3A\u53EA\u8BFB\u8C03\u7814\u9636\u6BB5\uFF0C\u7981\u6B62 ${calledName}\u3002\u5B8C\u6210\u65B9\u6848\u8BF7\u8C03 exit_plan_mode \u63D0\u4EA4\uFF0C\u7ECF\u7528\u6237\u5BA1\u6279\u540E\u8FDB\u5165\u5B9E\u73B0\u9636\u6BB5\u3002`;
|
|
9367
|
+
events({ sessionId, eventType: "tool.validation.failed", metadata: { depth, decisionSource: llmDecisionSource, durationMs: performance.now() - startTime, round, tools_id: toolCall.id, toolName: calledName, toolSource: "builtin", ok: false, attempt: round }, payload: { output: note } });
|
|
9368
|
+
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: false };
|
|
9369
|
+
}
|
|
8873
9370
|
const matchedTool = rawTools.find((t) => t.function.name === calledName);
|
|
8874
9371
|
const toolCtx = { sessionId, cwd: getActiveWorkspaceRoot(), abortSignal: signal, depth, keepRecentUnits, compactRatio, modelWindow, parentSystemPrompt, events, onUIEvent, requestApproval: hostRequestApproval, requestQuestion: hostRequestQuestion, emitProgress: (m) => onUIEvent?.({ type: "tool.progress", toolsId: toolCall.id, toolName: calledName, message: m }), permissionMode };
|
|
8875
9372
|
let result = "";
|
|
8876
9373
|
let explicitOk = null;
|
|
9374
|
+
let postHookOverride;
|
|
8877
9375
|
if (parseFailed) {
|
|
8878
9376
|
result = `\u53C2\u6570\u89E3\u6790\u5931\u8D25\uFF1A\u6A21\u578B\u8FD4\u56DE\u7684 arguments \u4E0D\u662F\u5408\u6CD5 JSON${JSON.stringify(toolCall).slice(0, 300)}`;
|
|
8879
9377
|
events({ sessionId, eventType: "tool.validation.failed", metadata: { depth, decisionSource: llmDecisionSource, durationMs: performance.now() - startTime, round, tools_id: toolCall.id, toolName: calledName, toolSource: "builtin", ok: false, attempt: round }, payload: { output: result } });
|
|
@@ -8881,6 +9379,23 @@ var init_toolExecution = __esm({
|
|
|
8881
9379
|
const level = matchedTool.function.safetyLevel;
|
|
8882
9380
|
let needApproval = level === "mutation" /* MUTATION */ || level === "danger" /* DANGER */;
|
|
8883
9381
|
let denied = false;
|
|
9382
|
+
let preHooksAdvanced = false;
|
|
9383
|
+
if (appConfig.hookRewrite) {
|
|
9384
|
+
preHooksAdvanced = true;
|
|
9385
|
+
let veto;
|
|
9386
|
+
try {
|
|
9387
|
+
veto = await runPreHooks(calledName, calledArgs, toolCtx);
|
|
9388
|
+
} catch (e) {
|
|
9389
|
+
veto = { deny: true, reason: `\u274C [Pre-hook \u5F02\u5E38]\uFF1A${e?.message ?? e}\u3002\u51FA\u4E8E\u5B89\u5168\u9ED8\u8BA4\u62D2\u7EDD [${calledName}] \u7684\u6267\u884C\u3002` };
|
|
9390
|
+
}
|
|
9391
|
+
if (veto.deny) {
|
|
9392
|
+
denied = true;
|
|
9393
|
+
result = veto.reason || `\u274C [Hook \u62E6\u622A]\uFF1Apre-hook \u62D2\u7EDD\u4E86 [${calledName}] \u7684\u6267\u884C\u3002`;
|
|
9394
|
+
} else if (veto.argsOverride !== void 0 && veto.argsOverride !== null && typeof veto.argsOverride === "object" && !Array.isArray(veto.argsOverride)) {
|
|
9395
|
+
console.log(`\u270F\uFE0F [Pre-hook] [${calledName}] args \u5DF2\u88AB hook \u6539\u5199`);
|
|
9396
|
+
calledArgs = veto.argsOverride;
|
|
9397
|
+
}
|
|
9398
|
+
}
|
|
8884
9399
|
const protectedPaths = calledName === "move_file" ? [calledArgs?.source, calledArgs?.destination] : isUndoTrigger(calledName) ? [calledArgs?.path] : [];
|
|
8885
9400
|
const hitProtected = protectedPaths.find((p) => typeof p === "string" && isProtectedWrite(p, toolCtx.cwd));
|
|
8886
9401
|
if (hitProtected) {
|
|
@@ -8889,7 +9404,7 @@ var init_toolExecution = __esm({
|
|
|
8889
9404
|
}
|
|
8890
9405
|
let perm = null;
|
|
8891
9406
|
try {
|
|
8892
|
-
perm = checkPermission(calledName, calledArgs);
|
|
9407
|
+
perm = checkPermission(resolveMcpPermissionName(calledName, calledArgs), calledArgs);
|
|
8893
9408
|
if (perm === "deny") {
|
|
8894
9409
|
denied = true;
|
|
8895
9410
|
result = `\u274C [\u6743\u9650\u89C4\u5219]\uFF1A[${calledName}] \u88AB\u6743\u9650\u89C4\u5219 deny \u62D2\u7EDD\u3002`;
|
|
@@ -8915,7 +9430,7 @@ var init_toolExecution = __esm({
|
|
|
8915
9430
|
result = `\u{1F512} [\u4E92\u65A5\u9501\u963B\u585E]\uFF1A\u5DF2\u6709\u540E\u53F0\u4EFB\u52A1\u6301\u6709\u9501 [${lockKey}]\uFF0C[${calledName}] \u8C03\u7528\u88AB\u8DF3\u8FC7\u3002`;
|
|
8916
9431
|
}
|
|
8917
9432
|
if (needApproval && !denied) {
|
|
8918
|
-
const auto = await runAutoCheck(calledName, calledArgs, toolCtx, permissionMode === "auto");
|
|
9433
|
+
const auto = await runAutoCheck(resolveMcpPermissionName(calledName, calledArgs), calledArgs, toolCtx, permissionMode === "auto");
|
|
8919
9434
|
if (auto === "allow") {
|
|
8920
9435
|
needApproval = false;
|
|
8921
9436
|
} else if (auto === "deny") {
|
|
@@ -8946,7 +9461,7 @@ var init_toolExecution = __esm({
|
|
|
8946
9461
|
}
|
|
8947
9462
|
}
|
|
8948
9463
|
}
|
|
8949
|
-
if (!denied) {
|
|
9464
|
+
if (!denied && !preHooksAdvanced) {
|
|
8950
9465
|
let veto;
|
|
8951
9466
|
try {
|
|
8952
9467
|
veto = await runPreHooks(calledName, calledArgs, toolCtx);
|
|
@@ -8990,9 +9505,12 @@ ${result}`;
|
|
|
8990
9505
|
result = `\u5DE5\u5177\u6267\u884C\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`;
|
|
8991
9506
|
events({ sessionId, eventType: "tool.failed", metadata: { depth, decisionSource: llmDecisionSource, durationMs: performance.now() - startTime, round, tools_id: toolCall.id, toolName: calledName, toolSource: "builtin", ok: false, attempt: round }, payload: { output: result } });
|
|
8992
9507
|
}
|
|
8993
|
-
|
|
9508
|
+
try {
|
|
9509
|
+
const post = await runPostHooks(calledName, calledArgs, result, toolCtx);
|
|
9510
|
+
postHookOverride = post?.resultOverride;
|
|
9511
|
+
} catch (e) {
|
|
8994
9512
|
console.warn(`\u26A0\uFE0F post-hook [${calledName}] \u5F02\u5E38\uFF08\u5DF2\u5FFD\u7565\uFF09:`, e?.message ?? e);
|
|
8995
|
-
}
|
|
9513
|
+
}
|
|
8996
9514
|
}
|
|
8997
9515
|
} else {
|
|
8998
9516
|
result = `\u9519\u8BEF\uFF1A\u672A\u77E5\u5DE5\u5177 "${calledName}" \u6216\u8BE5\u5DE5\u5177\u65E0\u53EF\u6267\u884C\u51FD\u6570`;
|
|
@@ -9013,6 +9531,10 @@ ${result}`;
|
|
|
9013
9531
|
} catch {
|
|
9014
9532
|
}
|
|
9015
9533
|
}
|
|
9534
|
+
if (postHookOverride !== void 0) {
|
|
9535
|
+
console.log(`\u270F\uFE0F [Post-hook] [${calledName}] \u6A21\u578B\u89C6\u56FE\u7ED3\u679C\u5DF2\u88AB hook \u6539\u5199`);
|
|
9536
|
+
resultForModel = truncateToolResult(postHookOverride, matchedTool?.function?.maxOutputCharacters);
|
|
9537
|
+
}
|
|
9016
9538
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel, resultForUser, ok };
|
|
9017
9539
|
};
|
|
9018
9540
|
}
|
|
@@ -9536,6 +10058,18 @@ async function* runAgent(message, options) {
|
|
|
9536
10058
|
let lastRealPromptTokens = persistedCalib.lastRealPromptTokens;
|
|
9537
10059
|
let lastCachedTokens = persistedCalib.lastCachedTokens;
|
|
9538
10060
|
const breaker = createRepeatBreaker({ sessionId, depth, llmDecisionSource, startTime, events });
|
|
10061
|
+
const runId = createUUID();
|
|
10062
|
+
let usageSum;
|
|
10063
|
+
const addUsage = (u) => {
|
|
10064
|
+
if (!u) return;
|
|
10065
|
+
usageSum = {
|
|
10066
|
+
prompt_tokens: (usageSum?.prompt_tokens ?? 0) + (u.prompt_tokens ?? 0),
|
|
10067
|
+
completion_tokens: (usageSum?.completion_tokens ?? 0) + (u.completion_tokens ?? 0),
|
|
10068
|
+
total_tokens: (usageSum?.total_tokens ?? 0) + (u.total_tokens ?? 0),
|
|
10069
|
+
cached_tokens: (usageSum?.cached_tokens ?? 0) + (u.cached_tokens ?? 0)
|
|
10070
|
+
};
|
|
10071
|
+
};
|
|
10072
|
+
await appendEvent(sessionId, { dscEvent: "run.start", runId, depth });
|
|
9539
10073
|
try {
|
|
9540
10074
|
while (true) {
|
|
9541
10075
|
round++;
|
|
@@ -9563,6 +10097,14 @@ async function* runAgent(message, options) {
|
|
|
9563
10097
|
yield { type: "final", text: lastContent || "\uFF08\u5DF2\u4E2D\u6B62\uFF09" };
|
|
9564
10098
|
return;
|
|
9565
10099
|
}
|
|
10100
|
+
const inboxTexts = claimSessionInbox(sessionId);
|
|
10101
|
+
if (inboxTexts.length > 0) {
|
|
10102
|
+
for (const t of inboxTexts) {
|
|
10103
|
+
message.push({ role: "user", content: t });
|
|
10104
|
+
await appendMessage({ sessionId, role: "user", content: t });
|
|
10105
|
+
}
|
|
10106
|
+
yield { type: "inbox.claimed", texts: inboxTexts };
|
|
10107
|
+
}
|
|
9566
10108
|
yield { type: "round.start", round };
|
|
9567
10109
|
try {
|
|
9568
10110
|
await ensureFitsWindow(
|
|
@@ -9629,6 +10171,7 @@ async function* runAgent(message, options) {
|
|
|
9629
10171
|
lastRealPromptTokens = infResult.usage.prompt_tokens;
|
|
9630
10172
|
lastCachedTokens = infResult.usage.cached_tokens;
|
|
9631
10173
|
}
|
|
10174
|
+
addUsage(infResult.usage);
|
|
9632
10175
|
const assistantMessage = infResult.assistantMessage;
|
|
9633
10176
|
message.push(assistantMessage);
|
|
9634
10177
|
await appendMessage({ ...assistantMessage, sessionId });
|
|
@@ -9637,6 +10180,7 @@ async function* runAgent(message, options) {
|
|
|
9637
10180
|
}
|
|
9638
10181
|
const tcCount = assistantMessage.tool_calls?.length ?? 0;
|
|
9639
10182
|
if (!assistantMessage.tool_calls || assistantMessage.tool_calls.length === 0) {
|
|
10183
|
+
await appendEvent(sessionId, { dscEvent: "round.end", runId, round, usage: infResult.usage });
|
|
9640
10184
|
const finalText = (typeof assistantMessage.content === "string" ? assistantMessage.content : "") || "";
|
|
9641
10185
|
const intercepted = nudges.interceptFinal(finalText, round);
|
|
9642
10186
|
if (intercepted) continue;
|
|
@@ -9647,6 +10191,11 @@ async function* runAgent(message, options) {
|
|
|
9647
10191
|
const repeatVerdict = breaker.check(assistantMessage.tool_calls, round, lastContent);
|
|
9648
10192
|
if (repeatVerdict.tripped) {
|
|
9649
10193
|
stopReason = "repeat";
|
|
10194
|
+
for (const tc of assistantMessage.tool_calls) {
|
|
10195
|
+
const ph = "\uFF08\u91CD\u590D\u8C03\u7528\u7194\u65AD\uFF0C\u672A\u6267\u884C\uFF09";
|
|
10196
|
+
message.push({ role: "tool", tool_call_id: tc.id, content: ph });
|
|
10197
|
+
await appendMessage({ sessionId, role: "tool", tool_call_id: tc.id, content: ph });
|
|
10198
|
+
}
|
|
9650
10199
|
yield { type: "final", text: repeatVerdict.text };
|
|
9651
10200
|
return;
|
|
9652
10201
|
}
|
|
@@ -9661,6 +10210,8 @@ async function* runAgent(message, options) {
|
|
|
9661
10210
|
rawTools,
|
|
9662
10211
|
events,
|
|
9663
10212
|
permissionMode: options.permissionMode,
|
|
10213
|
+
planMode: !!options.planMode,
|
|
10214
|
+
// ★ P0-A runtime 档:计划期写工具在 processToolCall 执行层拒绝(工具表恒定不裁剪)
|
|
9664
10215
|
onUIEvent: options.onUIEvent,
|
|
9665
10216
|
requestApproval: options.requestApproval,
|
|
9666
10217
|
requestQuestion: options.requestQuestion,
|
|
@@ -9678,6 +10229,7 @@ async function* runAgent(message, options) {
|
|
|
9678
10229
|
yield { type: "final", text: scheduleResult.terminalText };
|
|
9679
10230
|
return;
|
|
9680
10231
|
}
|
|
10232
|
+
await appendEvent(sessionId, { dscEvent: "round.end", runId, round, usage: infResult.usage });
|
|
9681
10233
|
}
|
|
9682
10234
|
} catch (toolErr) {
|
|
9683
10235
|
if (signal?.aborted) {
|
|
@@ -9691,6 +10243,14 @@ async function* runAgent(message, options) {
|
|
|
9691
10243
|
\uFF08\u5DE5\u5177\u6267\u884C\u5F02\u5E38\uFF1A${errMsg}\uFF09` };
|
|
9692
10244
|
return;
|
|
9693
10245
|
} finally {
|
|
10246
|
+
try {
|
|
10247
|
+
await flushLeftoverToTranscript(sessionId);
|
|
10248
|
+
} catch {
|
|
10249
|
+
}
|
|
10250
|
+
try {
|
|
10251
|
+
await appendEvent(sessionId, { dscEvent: "run.end", runId, stopReason: signal?.aborted ? "aborted" : stopReason, rounds: round, usage: usageSum });
|
|
10252
|
+
} catch {
|
|
10253
|
+
}
|
|
9694
10254
|
try {
|
|
9695
10255
|
const reason = signal?.aborted ? "aborted" : stopReason;
|
|
9696
10256
|
await dispatch("Stop", { sessionId, cwd, lastText: lastContent || "", reason });
|
|
@@ -9706,6 +10266,8 @@ var init_runAgent = __esm({
|
|
|
9706
10266
|
"../core/src/agent/runAgent.ts"() {
|
|
9707
10267
|
"use strict";
|
|
9708
10268
|
init_transcript();
|
|
10269
|
+
init_inbox();
|
|
10270
|
+
init_common();
|
|
9709
10271
|
init_contextCore();
|
|
9710
10272
|
init_store();
|
|
9711
10273
|
init_truncate();
|
|
@@ -9718,17 +10280,30 @@ var init_runAgent = __esm({
|
|
|
9718
10280
|
}
|
|
9719
10281
|
});
|
|
9720
10282
|
|
|
9721
|
-
// ../core/src/session/
|
|
9722
|
-
var repairOrphanToolCalls,
|
|
9723
|
-
var
|
|
9724
|
-
"../core/src/session/
|
|
10283
|
+
// ../core/src/session/recovery.ts
|
|
10284
|
+
var detectInterruption, repairOrphanToolCalls, reconcileCompaction, recoverSession;
|
|
10285
|
+
var init_recovery = __esm({
|
|
10286
|
+
"../core/src/session/recovery.ts"() {
|
|
9725
10287
|
"use strict";
|
|
9726
|
-
init_contextCore();
|
|
9727
10288
|
init_transcript();
|
|
9728
10289
|
init_store();
|
|
9729
|
-
|
|
9730
|
-
|
|
10290
|
+
detectInterruption = (lines) => {
|
|
10291
|
+
let sawEvents = false;
|
|
10292
|
+
let lastStart;
|
|
10293
|
+
const closed = /* @__PURE__ */ new Set();
|
|
10294
|
+
for (const l of lines) {
|
|
10295
|
+
if (!isEventLine(l)) continue;
|
|
10296
|
+
sawEvents = true;
|
|
10297
|
+
if (l.dscEvent === "run.start") lastStart = l;
|
|
10298
|
+
else if (l.dscEvent === "run.end" || l.dscEvent === "run.abandoned") closed.add(l.runId);
|
|
10299
|
+
}
|
|
10300
|
+
if (!sawEvents || !lastStart) return { kind: "legacy" };
|
|
10301
|
+
return closed.has(lastStart.runId) ? { kind: "clean" } : { kind: "crashed", runId: lastStart.runId };
|
|
10302
|
+
};
|
|
10303
|
+
repairOrphanToolCalls = (msgs, confirmedCrash) => {
|
|
10304
|
+
const placeholder = confirmedCrash ? "\uFF08\u4E0A\u6B21\u4F1A\u8BDD\u5728\u5DE5\u5177\u6267\u884C\u4E2D\u5D29\u6E83\uFF08run \u672A\u95ED\u5408\uFF09\uFF0C\u8BE5\u8C03\u7528\u672A\u6267\u884C\uFF0C\u5DF2\u8DF3\u8FC7\u3002\uFF09" : "\uFF08\u8BE5\u5DE5\u5177\u8C03\u7528\u56E0\u4E0A\u6B21\u4F1A\u8BDD\u5F02\u5E38\u4E2D\u65AD\u672A\u7559\u4E0B\u7ED3\u679C\uFF0C\u5DF2\u8DF3\u8FC7\u3002\uFF09";
|
|
9731
10305
|
const out = [];
|
|
10306
|
+
const repairedToolCallIds = [];
|
|
9732
10307
|
for (let i = 0; i < msgs.length; i++) {
|
|
9733
10308
|
const m = msgs[i];
|
|
9734
10309
|
out.push(m);
|
|
@@ -9741,13 +10316,60 @@ var init_content = __esm({
|
|
|
9741
10316
|
}
|
|
9742
10317
|
for (const tc of m.tool_calls) {
|
|
9743
10318
|
if (tc.id && !answered.has(tc.id)) {
|
|
9744
|
-
out.push({ role: "tool", tool_call_id: tc.id, content:
|
|
10319
|
+
out.push({ role: "tool", tool_call_id: tc.id, content: placeholder });
|
|
10320
|
+
repairedToolCallIds.push(tc.id);
|
|
9745
10321
|
}
|
|
9746
10322
|
}
|
|
9747
10323
|
}
|
|
9748
10324
|
}
|
|
9749
|
-
return out;
|
|
10325
|
+
return { msgs: out, repairedToolCallIds, confirmedCrash };
|
|
10326
|
+
};
|
|
10327
|
+
reconcileCompaction = (state, lines) => {
|
|
10328
|
+
let last;
|
|
10329
|
+
for (const l of lines) {
|
|
10330
|
+
if (isEventLine(l) && l.dscEvent === "compaction") last = l;
|
|
10331
|
+
}
|
|
10332
|
+
if (!last) return { archivedMessageCount: state.archivedMessageCount, rollingSummary: state.rollingSummary, desync: "legacy" };
|
|
10333
|
+
let desync = "none";
|
|
10334
|
+
if (last.archivedMessageCount !== state.archivedMessageCount) {
|
|
10335
|
+
desync = state.archivedMessageCount > last.archivedMessageCount ? "state-ahead" : "event-ahead";
|
|
10336
|
+
console.warn(
|
|
10337
|
+
`\u26A0\uFE0F [recovery] \u538B\u7F29\u72B6\u6001 desync\uFF08${desync}\uFF09\uFF1Astate.json archivedMessageCount=${state.archivedMessageCount} vs \u672B\u4E2A compaction \u4E8B\u4EF6=${last.archivedMessageCount}\u3002\u4EE5 state \u4E3A\u51C6\uFF08slice \u6267\u884C\u95F8\u95E8\uFF09\uFF0C\u4E8B\u4EF6\u4FA7\u4EC5\u955C\u50CF\u3002`
|
|
10338
|
+
);
|
|
10339
|
+
}
|
|
10340
|
+
return { archivedMessageCount: state.archivedMessageCount, rollingSummary: state.rollingSummary, desync };
|
|
9750
10341
|
};
|
|
10342
|
+
recoverSession = async (sessionId) => {
|
|
10343
|
+
const lines = await readTranscriptLines(sessionId);
|
|
10344
|
+
const interruption = detectInterruption(lines);
|
|
10345
|
+
if (interruption.kind === "crashed") {
|
|
10346
|
+
await appendEvent(sessionId, {
|
|
10347
|
+
dscEvent: "run.abandoned",
|
|
10348
|
+
runId: interruption.runId,
|
|
10349
|
+
reason: "run.end missing: interrupted by process exit/kill"
|
|
10350
|
+
});
|
|
10351
|
+
console.warn(`\u27E6recovery\u27E7 \u68C0\u6D4B\u5230\u672A\u95ED\u5408 run\uFF08${interruption.runId.slice(0, 8)}\u2026\uFF09\u2192 \u5DF2\u8865 run.abandoned \u95ED\u5893\u6807\u8BB0\uFF1B\u5B64\u513F\u4FEE\u590D\u6309\u300C\u5D29\u6E83\u786E\u8BA4\u300D\u6863\u6267\u884C\u3002`);
|
|
10352
|
+
}
|
|
10353
|
+
const state = await getRollingState(sessionId);
|
|
10354
|
+
const compaction = reconcileCompaction(
|
|
10355
|
+
{ archivedMessageCount: state.archivedMessageCount, rollingSummary: state.rollingSummary },
|
|
10356
|
+
lines
|
|
10357
|
+
);
|
|
10358
|
+
return { interruption, compaction };
|
|
10359
|
+
};
|
|
10360
|
+
}
|
|
10361
|
+
});
|
|
10362
|
+
|
|
10363
|
+
// ../core/src/session/content.ts
|
|
10364
|
+
var decayOldToolResults, buildContextMessages;
|
|
10365
|
+
var init_content = __esm({
|
|
10366
|
+
"../core/src/session/content.ts"() {
|
|
10367
|
+
"use strict";
|
|
10368
|
+
init_contextCore();
|
|
10369
|
+
init_transcript();
|
|
10370
|
+
init_store();
|
|
10371
|
+
init_config();
|
|
10372
|
+
init_recovery();
|
|
9751
10373
|
decayOldToolResults = (msgs) => {
|
|
9752
10374
|
const units = groupUnits(msgs);
|
|
9753
10375
|
const cutoffUnitIdx = Math.max(0, units.length - appConfig.KEEP_RECENT_UNITS);
|
|
@@ -9773,21 +10395,28 @@ var init_content = __esm({
|
|
|
9773
10395
|
});
|
|
9774
10396
|
};
|
|
9775
10397
|
buildContextMessages = async (sessionId, currentUserMsg, systemPrompt) => {
|
|
9776
|
-
const
|
|
10398
|
+
const lines = await readTranscriptLines(sessionId);
|
|
9777
10399
|
const store = await getRollingState(sessionId);
|
|
10400
|
+
const eventAware = appConfig.transcriptEvents || lines.some(isEventLine);
|
|
10401
|
+
const recovery = eventAware ? await recoverSession(sessionId) : {
|
|
10402
|
+
interruption: { kind: "legacy" },
|
|
10403
|
+
compaction: { archivedMessageCount: store.archivedMessageCount, rollingSummary: store.rollingSummary, desync: "legacy" }
|
|
10404
|
+
};
|
|
10405
|
+
const all = lines.filter((l) => !isEventLine(l)).map(cleanMsg);
|
|
9778
10406
|
const result = [
|
|
9779
10407
|
{ role: "system", content: systemPrompt },
|
|
9780
10408
|
// 存储系统提示词
|
|
9781
|
-
{ role: "system", content:
|
|
10409
|
+
{ role: "system", content: recovery.compaction.rollingSummary }
|
|
9782
10410
|
// 后续存储摘要使用
|
|
9783
10411
|
];
|
|
9784
|
-
const archivedMessageCount =
|
|
10412
|
+
const archivedMessageCount = recovery.compaction.archivedMessageCount;
|
|
9785
10413
|
const messageAll = all.slice(archivedMessageCount);
|
|
9786
10414
|
if (messageAll.length === 0) {
|
|
9787
10415
|
result.push(currentUserMsg);
|
|
9788
10416
|
return result;
|
|
9789
10417
|
}
|
|
9790
|
-
|
|
10418
|
+
const repair = repairOrphanToolCalls(messageAll, recovery.interruption.kind === "crashed");
|
|
10419
|
+
result.push(...decayOldToolResults(repair.msgs));
|
|
9791
10420
|
result.push(currentUserMsg);
|
|
9792
10421
|
return result;
|
|
9793
10422
|
};
|
|
@@ -9851,7 +10480,8 @@ var init_subagent = __esm({
|
|
|
9851
10480
|
parentSystemPrompt
|
|
9852
10481
|
].join("\n");
|
|
9853
10482
|
const allTools = getGlobalTools();
|
|
9854
|
-
const
|
|
10483
|
+
const wantsMcp = manifest?.tools.some((t) => t === "mcp_call" || t === "mcp_list_tools" || t.startsWith("mcp__")) ?? false;
|
|
10484
|
+
const toolSchemas = manifest && manifest.tools.length > 0 ? allTools.filter((t) => manifest.tools.includes(t.function.name) || wantsMcp && (t.function.name === "mcp_call" || t.function.name === "mcp_list_tools")) : allTools.filter((t) => !SUBAGENT_DENYLIST.has(t.function.name));
|
|
9855
10485
|
console.log(`\u{1F423} \u6D3E\u751F\u5B50 Agent [\u6DF1\u5EA6: ${ctx.depth + 1}/${MAX_AGENT_DEPTH}]${manifest ? ` \u58F0\u660E\u5F0F=${manifest.name}` : ""} \u4EFB\u52A1: "${task.slice(0, 50)}..."`);
|
|
9856
10486
|
try {
|
|
9857
10487
|
const subMessages = await buildContextMessages(subSessionId, { role: "user", content: task }, subSystem);
|
|
@@ -9917,7 +10547,7 @@ var init_subagent = __esm({
|
|
|
9917
10547
|
// ../core/src/hooks/loader.ts
|
|
9918
10548
|
import fs27 from "fs/promises";
|
|
9919
10549
|
import path29 from "path";
|
|
9920
|
-
var readHooksConfig, appendValidated, validateRule, parseAgentDecision, compileRule2, loadHooks, initHooks;
|
|
10550
|
+
var readHooksConfig, appendValidated, validateRule, parseStdoutDecision, parseAgentDecision, compileRule2, loadHooks, initHooks;
|
|
9921
10551
|
var init_loader4 = __esm({
|
|
9922
10552
|
"../core/src/hooks/loader.ts"() {
|
|
9923
10553
|
"use strict";
|
|
@@ -10061,6 +10691,24 @@ var init_loader4 = __esm({
|
|
|
10061
10691
|
requireApproval: raw.requireApproval === true ? true : void 0
|
|
10062
10692
|
};
|
|
10063
10693
|
};
|
|
10694
|
+
parseStdoutDecision = (stdout) => {
|
|
10695
|
+
const s = (stdout ?? "").trim();
|
|
10696
|
+
if (!s || !s.startsWith("{")) return void 0;
|
|
10697
|
+
try {
|
|
10698
|
+
const parsed = JSON.parse(s);
|
|
10699
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
10700
|
+
const out = {};
|
|
10701
|
+
if (parsed.deny === true) {
|
|
10702
|
+
out.deny = true;
|
|
10703
|
+
if (typeof parsed.reason === "string" && parsed.reason) out.reason = parsed.reason;
|
|
10704
|
+
}
|
|
10705
|
+
if (parsed.argsOverride !== void 0) out.argsOverride = parsed.argsOverride;
|
|
10706
|
+
if (typeof parsed.resultOverride === "string" && parsed.resultOverride) out.resultOverride = parsed.resultOverride;
|
|
10707
|
+
return out.deny !== void 0 || out.argsOverride !== void 0 || out.resultOverride !== void 0 ? out : void 0;
|
|
10708
|
+
} catch {
|
|
10709
|
+
return void 0;
|
|
10710
|
+
}
|
|
10711
|
+
};
|
|
10064
10712
|
parseAgentDecision = (output) => {
|
|
10065
10713
|
const lines = (output ?? "").split(/\r?\n/);
|
|
10066
10714
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
@@ -10129,9 +10777,15 @@ var init_loader4 = __esm({
|
|
|
10129
10777
|
}
|
|
10130
10778
|
try {
|
|
10131
10779
|
const parsed = JSON.parse(res.responseBody);
|
|
10132
|
-
if (parsed && typeof parsed === "object" && parsed
|
|
10133
|
-
|
|
10134
|
-
|
|
10780
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
10781
|
+
if (parsed.deny === true) {
|
|
10782
|
+
const reason = typeof parsed.reason === "string" ? parsed.reason : `hook http \u62D2\u7EDD\uFF08status ${res.status}\uFF09`;
|
|
10783
|
+
return { deny: true, reason };
|
|
10784
|
+
}
|
|
10785
|
+
const out = {};
|
|
10786
|
+
if (parsed.argsOverride !== void 0) out.argsOverride = parsed.argsOverride;
|
|
10787
|
+
if (typeof parsed.resultOverride === "string" && parsed.resultOverride) out.resultOverride = parsed.resultOverride;
|
|
10788
|
+
if (out.argsOverride !== void 0 || out.resultOverride !== void 0) return out;
|
|
10135
10789
|
}
|
|
10136
10790
|
} catch {
|
|
10137
10791
|
}
|
|
@@ -10160,6 +10814,10 @@ var init_loader4 = __esm({
|
|
|
10160
10814
|
const detail = res.stderr ? `\uFF1A${res.stderr.slice(0, 200)}` : "";
|
|
10161
10815
|
return { deny: true, reason: `hook \u9000\u51FA\u7801 ${res.exitCode}${detail}` };
|
|
10162
10816
|
}
|
|
10817
|
+
if (res.exitCode === 0) {
|
|
10818
|
+
const out = parseStdoutDecision(res.stdout);
|
|
10819
|
+
if (out) return out;
|
|
10820
|
+
}
|
|
10163
10821
|
return { deny: false };
|
|
10164
10822
|
}
|
|
10165
10823
|
};
|
|
@@ -10394,9 +11052,9 @@ var init_loader6 = __esm({
|
|
|
10394
11052
|
);
|
|
10395
11053
|
for (const { item: m, file, source } of picked) {
|
|
10396
11054
|
if (m.tools.length > 0) {
|
|
10397
|
-
const unknown = m.tools.filter((t) => !known.has(t));
|
|
11055
|
+
const unknown = m.tools.filter((t) => !known.has(t) && !t.startsWith("mcp__"));
|
|
10398
11056
|
if (unknown.length) console.warn(`\u26A0\uFE0F [agents] ${m.name} \u58F0\u660E\u4E86\u672A\u77E5\u5DE5\u5177 [${unknown.join(", ")}]\uFF0C\u5DF2\u5254\u9664`);
|
|
10399
|
-
m.tools = m.tools.filter((t) => known.has(t));
|
|
11057
|
+
m.tools = m.tools.filter((t) => known.has(t) || t.startsWith("mcp__"));
|
|
10400
11058
|
}
|
|
10401
11059
|
if (source === "project") {
|
|
10402
11060
|
console.warn(`\u26A0\uFE0F\u3010\u5B89\u5168\u63D0\u793A\u3011\u5DF2\u52A0\u8F7D\u9879\u76EE\u7EA7\u58F0\u660E\u5F0F\u5B50 Agent [${m.name}]\uFF08${file}\uFF09\u3002\u5176 tools \u767D\u540D\u5355\u53EF\u663E\u5F0F\u6388\u6743\u9AD8\u5371\u5DE5\u5177\uFF0C\u8BF7\u5728\u4FE1\u4EFB\u8BE5\u9879\u76EE\u65F6\u542F\u7528\uFF1B\u514B\u9686\u672A\u77E5\u4ED3\u5E93\u524D\u8BF7\u6838\u67E5 .deepseeker-code/agents/\u3002`);
|
|
@@ -11262,6 +11920,124 @@ ${lines.join("\n")}
|
|
|
11262
11920
|
}
|
|
11263
11921
|
});
|
|
11264
11922
|
|
|
11923
|
+
// ../core/src/session/fork.ts
|
|
11924
|
+
import fs37 from "fs/promises";
|
|
11925
|
+
var listForkAnchors, derivePrefix, forkSession;
|
|
11926
|
+
var init_fork = __esm({
|
|
11927
|
+
"../core/src/session/fork.ts"() {
|
|
11928
|
+
"use strict";
|
|
11929
|
+
init_common();
|
|
11930
|
+
init_transcript();
|
|
11931
|
+
init_store();
|
|
11932
|
+
listForkAnchors = (lines) => {
|
|
11933
|
+
const anchors = [];
|
|
11934
|
+
let lastUser = "";
|
|
11935
|
+
for (const l of lines) {
|
|
11936
|
+
if (isEventLine(l)) continue;
|
|
11937
|
+
const row = l;
|
|
11938
|
+
if (row?.role === "user") {
|
|
11939
|
+
lastUser = typeof row.content === "string" ? row.content : "";
|
|
11940
|
+
} else if (row?.role === "assistant") {
|
|
11941
|
+
const content = typeof row.content === "string" ? row.content : "";
|
|
11942
|
+
const names = Array.isArray(row.tool_calls) ? row.tool_calls.map((tc) => tc?.function?.name ?? "").filter(Boolean).join(", ") : "";
|
|
11943
|
+
anchors.push({
|
|
11944
|
+
lineId: row.id,
|
|
11945
|
+
roundNo: anchors.length + 1,
|
|
11946
|
+
userPreview: lastUser,
|
|
11947
|
+
assistantPreview: content || (names ? `\u{1F527} ${names}` : "(\u7A7A\u56DE\u590D)")
|
|
11948
|
+
});
|
|
11949
|
+
}
|
|
11950
|
+
}
|
|
11951
|
+
return anchors;
|
|
11952
|
+
};
|
|
11953
|
+
derivePrefix = (lines, upToLineId) => {
|
|
11954
|
+
let endIdx = lines.length - 1;
|
|
11955
|
+
if (upToLineId !== void 0) {
|
|
11956
|
+
const idx = lines.findIndex((l) => l?.id === upToLineId);
|
|
11957
|
+
if (idx < 0) throw new Error(`upToLineId\uFF08${upToLineId}\uFF09\u5728\u6E90\u4F1A\u8BDD\u8F6C\u5F55\u4E2D\u672A\u627E\u5230`);
|
|
11958
|
+
endIdx = idx;
|
|
11959
|
+
} else {
|
|
11960
|
+
let lastEnd = -1;
|
|
11961
|
+
let lastStart = -1;
|
|
11962
|
+
lines.forEach((l, i) => {
|
|
11963
|
+
if (!isEventLine(l)) return;
|
|
11964
|
+
if (l.dscEvent === "run.end" || l.dscEvent === "run.abandoned") lastEnd = i;
|
|
11965
|
+
else if (l.dscEvent === "run.start") lastStart = i;
|
|
11966
|
+
});
|
|
11967
|
+
if (lastEnd >= 0) endIdx = lastEnd;
|
|
11968
|
+
else if (lastStart >= 0) endIdx = lastStart - 1;
|
|
11969
|
+
}
|
|
11970
|
+
const prefix = endIdx < 0 ? [] : lines.slice(0, endIdx + 1);
|
|
11971
|
+
let archivedMessageCount = 0;
|
|
11972
|
+
let rollingSummary = "";
|
|
11973
|
+
let lastStartRunId;
|
|
11974
|
+
const closed = /* @__PURE__ */ new Set();
|
|
11975
|
+
for (const l of prefix) {
|
|
11976
|
+
if (!isEventLine(l)) continue;
|
|
11977
|
+
if (l.dscEvent === "compaction") {
|
|
11978
|
+
archivedMessageCount = l.archivedMessageCount;
|
|
11979
|
+
rollingSummary = l.summary;
|
|
11980
|
+
} else if (l.dscEvent === "run.start") {
|
|
11981
|
+
lastStartRunId = l.runId;
|
|
11982
|
+
} else if (l.dscEvent === "run.end" || l.dscEvent === "run.abandoned") {
|
|
11983
|
+
closed.add(l.runId);
|
|
11984
|
+
}
|
|
11985
|
+
}
|
|
11986
|
+
const unclosedRunId = lastStartRunId && !closed.has(lastStartRunId) ? lastStartRunId : void 0;
|
|
11987
|
+
return { lines: prefix, archivedMessageCount, rollingSummary, unclosedRunId };
|
|
11988
|
+
};
|
|
11989
|
+
forkSession = async (sourceId, upToLineId) => {
|
|
11990
|
+
assertSafeSessionId(sourceId);
|
|
11991
|
+
const lines = await readTranscriptLines(sourceId);
|
|
11992
|
+
if (lines.length === 0) throw new Error("\u6E90\u4F1A\u8BDD\u4E0D\u5B58\u5728\u6216\u8F6C\u5F55\u4E3A\u7A7A");
|
|
11993
|
+
const prefix = derivePrefix(lines, upToLineId);
|
|
11994
|
+
const newId = createUUID();
|
|
11995
|
+
await ensureSessionsDir(newId);
|
|
11996
|
+
const rawText = await fs37.readFile(getTranscriptPath(sourceId), "utf-8");
|
|
11997
|
+
const kept = [];
|
|
11998
|
+
let good = 0;
|
|
11999
|
+
for (const s of rawText.split("\n")) {
|
|
12000
|
+
if (good >= prefix.lines.length) break;
|
|
12001
|
+
kept.push(s);
|
|
12002
|
+
const t = s.trim();
|
|
12003
|
+
if (!t) continue;
|
|
12004
|
+
try {
|
|
12005
|
+
JSON.parse(t);
|
|
12006
|
+
good++;
|
|
12007
|
+
} catch {
|
|
12008
|
+
}
|
|
12009
|
+
}
|
|
12010
|
+
let payload = kept.join("\n");
|
|
12011
|
+
if (payload.length > 0 && !payload.endsWith("\n")) payload += "\n";
|
|
12012
|
+
await fs37.writeFile(getTranscriptPath(newId), payload, "utf-8");
|
|
12013
|
+
const srcState = await readStore(sourceId);
|
|
12014
|
+
const srcRolling = await getRollingState(sourceId);
|
|
12015
|
+
const legacy = !lines.some(isEventLine);
|
|
12016
|
+
const wholeFile = prefix.lines.length === lines.length;
|
|
12017
|
+
const archivedMessageCount = legacy && wholeFile ? srcRolling.archivedMessageCount : prefix.archivedMessageCount;
|
|
12018
|
+
const rollingSummary = legacy && wholeFile ? srcRolling.rollingSummary : prefix.rollingSummary;
|
|
12019
|
+
const srcTitle = typeof srcState?.title === "string" && srcState.title ? srcState.title : "\u4F1A\u8BDD";
|
|
12020
|
+
await writeStore(newId, {
|
|
12021
|
+
sessionId: newId,
|
|
12022
|
+
createAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12023
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12024
|
+
archivedMessageCount,
|
|
12025
|
+
rollingSummary,
|
|
12026
|
+
consecutiveFailures: 0,
|
|
12027
|
+
title: `${srcTitle}(\u5206\u53C9)`.slice(0, 200),
|
|
12028
|
+
// ★ 校准数据透传:fork 首轮压缩判定不从 1.4 重来(纯收益,语义同源会话续接)
|
|
12029
|
+
calibRatio: srcRolling.calibRatio,
|
|
12030
|
+
lastRealPromptTokens: srcRolling.lastRealPromptTokens,
|
|
12031
|
+
lastCachedTokens: srcRolling.lastCachedTokens
|
|
12032
|
+
});
|
|
12033
|
+
if (prefix.unclosedRunId) {
|
|
12034
|
+
await appendEvent(newId, { dscEvent: "run.abandoned", runId: prefix.unclosedRunId, reason: "forked from interrupted run" });
|
|
12035
|
+
}
|
|
12036
|
+
return { sessionId: newId, copiedLines: prefix.lines.length, archivedMessageCount };
|
|
12037
|
+
};
|
|
12038
|
+
}
|
|
12039
|
+
});
|
|
12040
|
+
|
|
11265
12041
|
// src/cliHost.ts
|
|
11266
12042
|
var createCliRequestApproval, createCliRequestQuestion;
|
|
11267
12043
|
var init_cliHost = __esm({
|
|
@@ -11346,13 +12122,47 @@ var init_util = __esm({
|
|
|
11346
12122
|
|
|
11347
12123
|
// src/replay.ts
|
|
11348
12124
|
var buildReplayRows;
|
|
11349
|
-
var
|
|
12125
|
+
var init_replay2 = __esm({
|
|
11350
12126
|
"src/replay.ts"() {
|
|
11351
12127
|
"use strict";
|
|
11352
|
-
|
|
12128
|
+
init_transcript();
|
|
12129
|
+
buildReplayRows = (lines, nid) => {
|
|
11353
12130
|
const rows = [];
|
|
11354
12131
|
const pending = /* @__PURE__ */ new Map();
|
|
11355
|
-
|
|
12132
|
+
let lastStartRunId;
|
|
12133
|
+
const closedRuns = /* @__PURE__ */ new Set();
|
|
12134
|
+
const attachUsage = (u) => {
|
|
12135
|
+
for (let i = rows.length - 1; i >= 0; i--) {
|
|
12136
|
+
const r = rows[i];
|
|
12137
|
+
if (r.kind === "assistant") {
|
|
12138
|
+
rows[i] = {
|
|
12139
|
+
...r,
|
|
12140
|
+
usage: {
|
|
12141
|
+
...r.usage ?? {},
|
|
12142
|
+
prompt_tokens: u.prompt_tokens,
|
|
12143
|
+
completion_tokens: u.completion_tokens,
|
|
12144
|
+
total_tokens: u.total_tokens,
|
|
12145
|
+
prompt_cache_hit_tokens: u.cached_tokens
|
|
12146
|
+
}
|
|
12147
|
+
};
|
|
12148
|
+
return;
|
|
12149
|
+
}
|
|
12150
|
+
}
|
|
12151
|
+
};
|
|
12152
|
+
for (const line of lines) {
|
|
12153
|
+
if (isEventLine(line)) {
|
|
12154
|
+
if (line.dscEvent === "run.start") lastStartRunId = line.runId;
|
|
12155
|
+
else if (line.dscEvent === "run.end" || line.dscEvent === "run.abandoned") closedRuns.add(line.runId);
|
|
12156
|
+
if ((line.dscEvent === "round.end" || line.dscEvent === "run.end") && line.usage && (line.usage.prompt_tokens != null || line.usage.total_tokens != null)) {
|
|
12157
|
+
const last = [...rows].reverse().find((r) => r.kind === "assistant");
|
|
12158
|
+
if (line.dscEvent === "round.end" || !last?.usage) attachUsage(line.usage);
|
|
12159
|
+
}
|
|
12160
|
+
if (line.dscEvent === "run.abandoned") {
|
|
12161
|
+
rows.push({ id: nid(), kind: "info", text: "\u26A0\uFE0F \u6B64\u56DE\u5408\u88AB\u4E2D\u65AD\uFF0C\u672A\u5B8C\u6210" });
|
|
12162
|
+
}
|
|
12163
|
+
continue;
|
|
12164
|
+
}
|
|
12165
|
+
const m = line;
|
|
11356
12166
|
const role = m?.role;
|
|
11357
12167
|
if (role === "user") {
|
|
11358
12168
|
const text = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.filter((p) => typeof p?.text === "string").map((p) => p.text).join("") : "";
|
|
@@ -11402,6 +12212,9 @@ var init_replay = __esm({
|
|
|
11402
12212
|
rows[idx] = { ...r, result: r.result ?? "", ok: false, status: "done" };
|
|
11403
12213
|
}
|
|
11404
12214
|
}
|
|
12215
|
+
if (lastStartRunId && !closedRuns.has(lastStartRunId)) {
|
|
12216
|
+
rows.push({ id: nid(), kind: "info", text: "\u26A0\uFE0F \u6B64\u56DE\u5408\u88AB\u4E2D\u65AD\uFF0C\u672A\u5B8C\u6210" });
|
|
12217
|
+
}
|
|
11405
12218
|
return rows;
|
|
11406
12219
|
};
|
|
11407
12220
|
}
|
|
@@ -11416,13 +12229,15 @@ var init_useChatState = __esm({
|
|
|
11416
12229
|
init_chatProcessing();
|
|
11417
12230
|
init_store();
|
|
11418
12231
|
init_transcript();
|
|
12232
|
+
init_fork();
|
|
12233
|
+
init_inbox();
|
|
11419
12234
|
init_contextCore();
|
|
11420
12235
|
init_createModel();
|
|
11421
12236
|
init_tool();
|
|
11422
12237
|
init_cliHost();
|
|
11423
12238
|
init_strings();
|
|
11424
12239
|
init_util();
|
|
11425
|
-
|
|
12240
|
+
init_replay2();
|
|
11426
12241
|
FLUSH_MS = 120;
|
|
11427
12242
|
ABORT_GRACE_MS = 8e3;
|
|
11428
12243
|
ENTER_PLAN_RESEARCH_PROMPT = "\uFF08\u5DF2\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\u3002\u8BF7\u4EE5\u53EA\u8BFB\u65B9\u5F0F\u5B8C\u6210\u8C03\u7814\uFF0C\u7136\u540E\u8C03\u7528 exit_plan_mode \u63D0\u4EA4\u5B8C\u6574\u5B9E\u73B0\u65B9\u6848\u3002\uFF09";
|
|
@@ -11440,6 +12255,7 @@ var init_useChatState = __esm({
|
|
|
11440
12255
|
const [pendingQuestion, setPendingQuestion] = useState(null);
|
|
11441
12256
|
const [pendingPlan, setPendingPlan] = useState(null);
|
|
11442
12257
|
const [pendingSessions, setPendingSessions] = useState(null);
|
|
12258
|
+
const [pendingFork, setPendingFork] = useState(null);
|
|
11443
12259
|
const nextId = useRef(1);
|
|
11444
12260
|
const assistantStreamingId = useRef(null);
|
|
11445
12261
|
const thinkingStreamingId = useRef(null);
|
|
@@ -11452,6 +12268,7 @@ var init_useChatState = __esm({
|
|
|
11452
12268
|
const currentAcRef = useRef(null);
|
|
11453
12269
|
const turnGenRef = useRef(0);
|
|
11454
12270
|
const abortGuardRef = useRef(null);
|
|
12271
|
+
const queuedUnclaimedRef = useRef(0);
|
|
11455
12272
|
const proposedPlanRef = useRef(null);
|
|
11456
12273
|
const enterPlanReasonRef = useRef(null);
|
|
11457
12274
|
const modelRef = useRef("");
|
|
@@ -11466,8 +12283,8 @@ var init_useChatState = __esm({
|
|
|
11466
12283
|
if (!initialSessionId) return;
|
|
11467
12284
|
void (async () => {
|
|
11468
12285
|
try {
|
|
11469
|
-
const
|
|
11470
|
-
const seeded = buildReplayRows(
|
|
12286
|
+
const lines = await readTranscriptLines(initialSessionId);
|
|
12287
|
+
const seeded = buildReplayRows(lines, newRowId);
|
|
11471
12288
|
if (seeded.length) setRows(seeded);
|
|
11472
12289
|
} catch {
|
|
11473
12290
|
}
|
|
@@ -11650,10 +12467,18 @@ var init_useChatState = __esm({
|
|
|
11650
12467
|
}
|
|
11651
12468
|
case "approval_request":
|
|
11652
12469
|
break;
|
|
12470
|
+
case "inbox.claimed": {
|
|
12471
|
+
const n = Array.isArray(obj.texts) ? obj.texts.length : 0;
|
|
12472
|
+
if (n > 0) {
|
|
12473
|
+
queuedUnclaimedRef.current = Math.max(0, queuedUnclaimedRef.current - n);
|
|
12474
|
+
pushInfo(S.inboxClaimed(n));
|
|
12475
|
+
}
|
|
12476
|
+
break;
|
|
12477
|
+
}
|
|
11653
12478
|
default:
|
|
11654
12479
|
break;
|
|
11655
12480
|
}
|
|
11656
|
-
}, [closeStreaming, flush, scheduleFlush]);
|
|
12481
|
+
}, [closeStreaming, flush, scheduleFlush, pushInfo]);
|
|
11657
12482
|
const askApproval = useCallback((detail, toolName) => new Promise((resolve) => setPendingApproval({ detail, toolName, resolve })), []);
|
|
11658
12483
|
const resolveApproval = useCallback((v) => {
|
|
11659
12484
|
setPendingApproval((prev) => {
|
|
@@ -11733,9 +12558,13 @@ var init_useChatState = __esm({
|
|
|
11733
12558
|
clearTimeout(abortGuardRef.current);
|
|
11734
12559
|
abortGuardRef.current = null;
|
|
11735
12560
|
}
|
|
12561
|
+
if (queuedUnclaimedRef.current > 0) {
|
|
12562
|
+
pushInfo(S.inboxCarryover(queuedUnclaimedRef.current));
|
|
12563
|
+
queuedUnclaimedRef.current = 0;
|
|
12564
|
+
}
|
|
11736
12565
|
}
|
|
11737
12566
|
}
|
|
11738
|
-
}, [askApproval, autoRequestApproval, flush, onTrace, pushEvent]);
|
|
12567
|
+
}, [askApproval, autoRequestApproval, flush, onTrace, pushEvent, pushInfo]);
|
|
11739
12568
|
const approveAndImplement = useCallback(async (sid, plan) => {
|
|
11740
12569
|
const res = await setPlan(plan);
|
|
11741
12570
|
if (res.action === "accept") {
|
|
@@ -11744,15 +12573,27 @@ var init_useChatState = __esm({
|
|
|
11744
12573
|
await runOnce(sid, `\uFF08\u7528\u6237\u5DF2\u6279\u51C6\u4EE5\u4E0B\u65B9\u6848\uFF0C\u8BF7\u4E25\u683C\u6309\u65B9\u6848\u5F00\u59CB\u5B9E\u73B0\uFF09\uFF1A
|
|
11745
12574
|
|
|
11746
12575
|
${finalPlan}`, false, res.autoExecute);
|
|
11747
|
-
|
|
11748
|
-
pushInfo(S.planRejected);
|
|
12576
|
+
return true;
|
|
11749
12577
|
}
|
|
12578
|
+
planModeRef.current = true;
|
|
12579
|
+
pushInfo(S.planKeepPlanning);
|
|
12580
|
+
return false;
|
|
11750
12581
|
}, [runOnce, setPlan, pushInfo]);
|
|
11751
12582
|
const runPlanStage = useCallback(async (sid, researchPrompt) => {
|
|
11752
12583
|
await runOnce(sid, researchPrompt, true);
|
|
11753
12584
|
const plan = takeProposedPlan();
|
|
11754
|
-
if (plan
|
|
12585
|
+
if (plan == null) return false;
|
|
12586
|
+
return await approveAndImplement(sid, plan);
|
|
11755
12587
|
}, [runOnce, takeProposedPlan, approveAndImplement]);
|
|
12588
|
+
const queueInput = useCallback((content) => {
|
|
12589
|
+
const text = content.trim();
|
|
12590
|
+
const sid = sessionIdRef.current;
|
|
12591
|
+
if (!text || !sid || !pushSessionInbox(sid, text)) return false;
|
|
12592
|
+
pushUser(text);
|
|
12593
|
+
pushInfo(S.inboxQueued);
|
|
12594
|
+
queuedUnclaimedRef.current++;
|
|
12595
|
+
return true;
|
|
12596
|
+
}, [pushUser, pushInfo]);
|
|
11756
12597
|
const submit = useCallback(async (content) => {
|
|
11757
12598
|
const text = content.trim();
|
|
11758
12599
|
if (!text || busy) return;
|
|
@@ -11765,7 +12606,8 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11765
12606
|
const sid = sessionIdRef.current;
|
|
11766
12607
|
pushUser(text);
|
|
11767
12608
|
if (planModeRef.current) {
|
|
11768
|
-
await runPlanStage(sid, text);
|
|
12609
|
+
const kept = await runPlanStage(sid, text);
|
|
12610
|
+
if (kept) planModeRef.current = false;
|
|
11769
12611
|
} else {
|
|
11770
12612
|
await runOnce(sid, text, false);
|
|
11771
12613
|
const proposedPlan = takeProposedPlan();
|
|
@@ -11776,8 +12618,8 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11776
12618
|
if (enterReason != null) {
|
|
11777
12619
|
pushInfo(`\u{1F4CB} \u6A21\u578B\u8BF7\u6C42\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F${enterReason ? `\uFF1A${enterReason}` : ""}\uFF0C\u5DF2\u5207\u6362\u2026`);
|
|
11778
12620
|
planModeRef.current = true;
|
|
11779
|
-
await runPlanStage(sid, ENTER_PLAN_RESEARCH_PROMPT);
|
|
11780
|
-
planModeRef.current = false;
|
|
12621
|
+
const kept = await runPlanStage(sid, ENTER_PLAN_RESEARCH_PROMPT);
|
|
12622
|
+
if (kept) planModeRef.current = false;
|
|
11781
12623
|
}
|
|
11782
12624
|
}
|
|
11783
12625
|
}
|
|
@@ -11813,8 +12655,8 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11813
12655
|
sessionIdRef.current = id;
|
|
11814
12656
|
clearRows();
|
|
11815
12657
|
try {
|
|
11816
|
-
const
|
|
11817
|
-
const seeded = buildReplayRows(
|
|
12658
|
+
const lines = await readTranscriptLines(id);
|
|
12659
|
+
const seeded = buildReplayRows(lines, newRowId);
|
|
11818
12660
|
if (seeded.length) setRows(seeded);
|
|
11819
12661
|
} catch {
|
|
11820
12662
|
}
|
|
@@ -11835,6 +12677,37 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11835
12677
|
const picked = await new Promise((resolve) => setPendingSessions({ sessions: sessions2, resolve }));
|
|
11836
12678
|
if (picked) await loadSession(picked);
|
|
11837
12679
|
}, [pushInfo, loadSession]);
|
|
12680
|
+
const resolveFork = useCallback((anchor) => {
|
|
12681
|
+
setPendingFork((prev) => {
|
|
12682
|
+
prev?.resolve(anchor);
|
|
12683
|
+
return null;
|
|
12684
|
+
});
|
|
12685
|
+
}, []);
|
|
12686
|
+
const openForkPicker = useCallback(async () => {
|
|
12687
|
+
const sid = sessionIdRef.current;
|
|
12688
|
+
if (!sid) {
|
|
12689
|
+
pushInfo(S.forkEmpty);
|
|
12690
|
+
return;
|
|
12691
|
+
}
|
|
12692
|
+
let anchors = [];
|
|
12693
|
+
try {
|
|
12694
|
+
anchors = listForkAnchors(await readTranscriptLines(sid));
|
|
12695
|
+
} catch {
|
|
12696
|
+
}
|
|
12697
|
+
if (anchors.length === 0) {
|
|
12698
|
+
pushInfo(S.forkEmpty);
|
|
12699
|
+
return;
|
|
12700
|
+
}
|
|
12701
|
+
const picked = await new Promise((resolve) => setPendingFork({ anchors, resolve }));
|
|
12702
|
+
if (!picked) return;
|
|
12703
|
+
try {
|
|
12704
|
+
const r = await forkSession(sid, picked.lineId);
|
|
12705
|
+
await loadSession(r.sessionId);
|
|
12706
|
+
pushInfo(S.forkDone(truncateMiddle(r.sessionId, 12), picked.roundNo));
|
|
12707
|
+
} catch (e) {
|
|
12708
|
+
pushInfo(S.forkFailed(e?.message ?? String(e)));
|
|
12709
|
+
}
|
|
12710
|
+
}, [pushInfo, loadSession]);
|
|
11838
12711
|
const setModelOverride = useCallback((m) => {
|
|
11839
12712
|
modelRef.current = m;
|
|
11840
12713
|
}, []);
|
|
@@ -11864,9 +12737,11 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11864
12737
|
pendingQuestion,
|
|
11865
12738
|
pendingPlan,
|
|
11866
12739
|
pendingSessions,
|
|
12740
|
+
pendingFork,
|
|
11867
12741
|
sessionIdRef,
|
|
11868
12742
|
// 动作
|
|
11869
12743
|
submit,
|
|
12744
|
+
queueInput,
|
|
11870
12745
|
abortCurrent,
|
|
11871
12746
|
pushUser,
|
|
11872
12747
|
pushInfo,
|
|
@@ -11889,7 +12764,9 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11889
12764
|
getOutputStyle: getOutputStyle2,
|
|
11890
12765
|
openSessionPicker,
|
|
11891
12766
|
resolveSession,
|
|
11892
|
-
loadSession
|
|
12767
|
+
loadSession,
|
|
12768
|
+
openForkPicker,
|
|
12769
|
+
resolveFork
|
|
11893
12770
|
};
|
|
11894
12771
|
};
|
|
11895
12772
|
}
|
|
@@ -12006,6 +12883,8 @@ var init_MessageBlock = __esm({
|
|
|
12006
12883
|
return { bullet: `${m[2]} `, rest: m[3] };
|
|
12007
12884
|
};
|
|
12008
12885
|
AssistantLine = ({ line }) => {
|
|
12886
|
+
const heading = line.match(/^#{1,6}\s+(.*)$/);
|
|
12887
|
+
if (heading) return /* @__PURE__ */ jsx3(Text3, { bold: true, color: "#ffffff", children: heading[1] });
|
|
12009
12888
|
const list = listPrefix(line);
|
|
12010
12889
|
if (list) {
|
|
12011
12890
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
@@ -12155,6 +13034,149 @@ var init_ThinkingBlock = __esm({
|
|
|
12155
13034
|
}
|
|
12156
13035
|
});
|
|
12157
13036
|
|
|
13037
|
+
// src/lineDiff.ts
|
|
13038
|
+
var splitLines, lineDiff, collapseContext;
|
|
13039
|
+
var init_lineDiff = __esm({
|
|
13040
|
+
"src/lineDiff.ts"() {
|
|
13041
|
+
"use strict";
|
|
13042
|
+
splitLines = (s) => {
|
|
13043
|
+
const t = String(s ?? "").replace(/\r\n/g, "\n");
|
|
13044
|
+
return t === "" ? [] : t.split("\n");
|
|
13045
|
+
};
|
|
13046
|
+
lineDiff = (oldStr, newStr) => {
|
|
13047
|
+
const a = splitLines(oldStr);
|
|
13048
|
+
const b = splitLines(newStr);
|
|
13049
|
+
let s = 0;
|
|
13050
|
+
while (s < a.length && s < b.length && a[s] === b[s]) s++;
|
|
13051
|
+
let e = 0;
|
|
13052
|
+
while (e < a.length - s && e < b.length - s && a[a.length - 1 - e] === b[b.length - 1 - e]) e++;
|
|
13053
|
+
const m1 = a.slice(s, a.length - e);
|
|
13054
|
+
const m2 = b.slice(s, b.length - e);
|
|
13055
|
+
const rows = [];
|
|
13056
|
+
for (let i = 0; i < s; i++) rows.push({ t: "ctx", s: a[i] });
|
|
13057
|
+
const n = m1.length, m = m2.length;
|
|
13058
|
+
if (n === 0 && m === 0) {
|
|
13059
|
+
} else if (n * m > 4e6) {
|
|
13060
|
+
for (const l of m1) rows.push({ t: "del", s: l });
|
|
13061
|
+
for (const l of m2) rows.push({ t: "add", s: l });
|
|
13062
|
+
} else {
|
|
13063
|
+
const w = m + 1;
|
|
13064
|
+
const dp = new Uint32Array((n + 1) * w);
|
|
13065
|
+
for (let i2 = n - 1; i2 >= 0; i2--) {
|
|
13066
|
+
for (let j2 = m - 1; j2 >= 0; j2--) {
|
|
13067
|
+
dp[i2 * w + j2] = m1[i2] === m2[j2] ? dp[(i2 + 1) * w + j2 + 1] + 1 : Math.max(dp[(i2 + 1) * w + j2], dp[i2 * w + j2 + 1]);
|
|
13068
|
+
}
|
|
13069
|
+
}
|
|
13070
|
+
let i = 0, j = 0;
|
|
13071
|
+
while (i < n && j < m) {
|
|
13072
|
+
if (m1[i] === m2[j]) {
|
|
13073
|
+
rows.push({ t: "ctx", s: m1[i] });
|
|
13074
|
+
i++;
|
|
13075
|
+
j++;
|
|
13076
|
+
} else if (dp[(i + 1) * w + j] >= dp[i * w + j + 1]) {
|
|
13077
|
+
rows.push({ t: "del", s: m1[i] });
|
|
13078
|
+
i++;
|
|
13079
|
+
} else {
|
|
13080
|
+
rows.push({ t: "add", s: m2[j] });
|
|
13081
|
+
j++;
|
|
13082
|
+
}
|
|
13083
|
+
}
|
|
13084
|
+
while (i < n) {
|
|
13085
|
+
rows.push({ t: "del", s: m1[i] });
|
|
13086
|
+
i++;
|
|
13087
|
+
}
|
|
13088
|
+
while (j < m) {
|
|
13089
|
+
rows.push({ t: "add", s: m2[j] });
|
|
13090
|
+
j++;
|
|
13091
|
+
}
|
|
13092
|
+
}
|
|
13093
|
+
for (let k = 0; k < e; k++) rows.push({ t: "ctx", s: a[a.length - e + k] });
|
|
13094
|
+
return rows;
|
|
13095
|
+
};
|
|
13096
|
+
collapseContext = (rows, keep = 2) => {
|
|
13097
|
+
const out = [];
|
|
13098
|
+
let i = 0;
|
|
13099
|
+
while (i < rows.length) {
|
|
13100
|
+
if (rows[i].t !== "ctx") {
|
|
13101
|
+
out.push(rows[i]);
|
|
13102
|
+
i++;
|
|
13103
|
+
continue;
|
|
13104
|
+
}
|
|
13105
|
+
let j = i;
|
|
13106
|
+
while (j < rows.length && rows[j].t === "ctx") j++;
|
|
13107
|
+
const run = j - i;
|
|
13108
|
+
if (run > keep * 2 + 1) {
|
|
13109
|
+
for (let k = 0; k < keep; k++) out.push(rows[i + k]);
|
|
13110
|
+
out.push({ t: "ellip", n: run - keep * 2 });
|
|
13111
|
+
for (let k = run - keep; k < run; k++) out.push(rows[i + k]);
|
|
13112
|
+
} else {
|
|
13113
|
+
for (let k = 0; k < run; k++) out.push(rows[i + k]);
|
|
13114
|
+
}
|
|
13115
|
+
i = j;
|
|
13116
|
+
}
|
|
13117
|
+
return out;
|
|
13118
|
+
};
|
|
13119
|
+
}
|
|
13120
|
+
});
|
|
13121
|
+
|
|
13122
|
+
// src/diffView.ts
|
|
13123
|
+
var EDIT_TOOL_NAMES, extractEditPairs, pairsToDisplayRows, parseApprovalDiff;
|
|
13124
|
+
var init_diffView = __esm({
|
|
13125
|
+
"src/diffView.ts"() {
|
|
13126
|
+
"use strict";
|
|
13127
|
+
init_lineDiff();
|
|
13128
|
+
EDIT_TOOL_NAMES = ["edit_file", "create_file", "write_file"];
|
|
13129
|
+
extractEditPairs = (toolName, args) => {
|
|
13130
|
+
if (args == null || typeof args !== "object") return null;
|
|
13131
|
+
const o = args;
|
|
13132
|
+
if (toolName === "edit_file") {
|
|
13133
|
+
const list = Array.isArray(o.edits) && o.edits.length > 0 ? o.edits : [o];
|
|
13134
|
+
const pairs = list.filter((e) => typeof e.old_str === "string" && e.old_str.length > 0);
|
|
13135
|
+
if (pairs.length === 0) return null;
|
|
13136
|
+
return pairs.map((e, i) => ({
|
|
13137
|
+
label: pairs.length > 1 ? `\u7B2C ${i + 1} \u5904${e.replace_all ? "\uFF08\u6279\u91CF\u66FF\u6362\u5168\u90E8\u5339\u914D\uFF09" : ""}` : "",
|
|
13138
|
+
old: e.old_str,
|
|
13139
|
+
new: typeof e.new_str === "string" ? e.new_str : ""
|
|
13140
|
+
}));
|
|
13141
|
+
}
|
|
13142
|
+
if (toolName === "create_file" || toolName === "write_file") {
|
|
13143
|
+
return typeof o.content === "string" && o.content.length > 0 ? [{ label: "", old: "", new: o.content }] : null;
|
|
13144
|
+
}
|
|
13145
|
+
return null;
|
|
13146
|
+
};
|
|
13147
|
+
pairsToDisplayRows = (pairs, keep = 2) => {
|
|
13148
|
+
const out = [];
|
|
13149
|
+
let changed = false;
|
|
13150
|
+
for (const p of pairs) {
|
|
13151
|
+
const collapsed = collapseContext(lineDiff(p.old, p.new), keep);
|
|
13152
|
+
if (!collapsed.some((r) => r.t !== "ctx" && r.t !== "ellip")) continue;
|
|
13153
|
+
changed = true;
|
|
13154
|
+
if (p.label) {
|
|
13155
|
+
if (out.length > 0) out.push({ t: "ellip", n: 0 });
|
|
13156
|
+
out.push({ t: "ctx", s: `\u2014\u2014 ${p.label} \u2014\u2014` });
|
|
13157
|
+
}
|
|
13158
|
+
out.push(...collapsed);
|
|
13159
|
+
}
|
|
13160
|
+
return changed ? out : null;
|
|
13161
|
+
};
|
|
13162
|
+
parseApprovalDiff = (detail, toolName) => {
|
|
13163
|
+
if (toolName !== "edit_file" || !detail.includes("\u3010\u51CF\u5C11\u3011:")) return null;
|
|
13164
|
+
const parts = detail.split(/\n(?=—— 第 )/);
|
|
13165
|
+
const sections = [];
|
|
13166
|
+
for (const part of parts.slice(1)) {
|
|
13167
|
+
const label = (part.match(/^—— (第 \d+ 处[^\n]*)——/)?.[1] ?? "").trim();
|
|
13168
|
+
const rIdx = part.indexOf("\u3010\u51CF\u5C11\u3011:");
|
|
13169
|
+
const aIdx = part.indexOf("\u3010\u589E\u52A0\u3011:");
|
|
13170
|
+
if (rIdx < 0 || aIdx < 0 || aIdx < rIdx) continue;
|
|
13171
|
+
const old = part.slice(rIdx + "\u3010\u51CF\u5C11\u3011:".length, aIdx).replace(/^\n+|\n+$/g, "");
|
|
13172
|
+
const neu = part.slice(aIdx + "\u3010\u589E\u52A0\u3011:".length).replace(/^\n+|\n+$/g, "");
|
|
13173
|
+
sections.push({ label, old, new: neu });
|
|
13174
|
+
}
|
|
13175
|
+
return sections.length > 0 ? { header: parts[0], sections } : null;
|
|
13176
|
+
};
|
|
13177
|
+
}
|
|
13178
|
+
});
|
|
13179
|
+
|
|
12158
13180
|
// src/components/ToolCard.tsx
|
|
12159
13181
|
import { Box as Box3, Text as Text5 } from "ink";
|
|
12160
13182
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -12164,6 +13186,7 @@ var init_ToolCard = __esm({
|
|
|
12164
13186
|
"use strict";
|
|
12165
13187
|
init_theme();
|
|
12166
13188
|
init_util();
|
|
13189
|
+
init_diffView();
|
|
12167
13190
|
ToolCard = ({ toolName, args, result, ok, status, progress, wrapW }) => {
|
|
12168
13191
|
const tool = findTool(toolName);
|
|
12169
13192
|
const level = tool?.function?.safetyLevel;
|
|
@@ -12180,6 +13203,15 @@ var init_ToolCard = __esm({
|
|
|
12180
13203
|
const last = progress.replace(/\r/g, "").split("\n").map((s) => s.trim()).filter(Boolean).pop() ?? "";
|
|
12181
13204
|
return truncateMiddle(last, Math.max(20, wrapW - 6));
|
|
12182
13205
|
})();
|
|
13206
|
+
const MAX_DIFF_LINES2 = 14;
|
|
13207
|
+
const diffAll = (() => {
|
|
13208
|
+
if (status !== "done" || !ok) return null;
|
|
13209
|
+
if (!EDIT_TOOL_NAMES.includes(toolName)) return null;
|
|
13210
|
+
const pairs = extractEditPairs(toolName, args);
|
|
13211
|
+
return pairs ? pairsToDisplayRows(pairs) : null;
|
|
13212
|
+
})();
|
|
13213
|
+
const diffRows = diffAll ? diffAll.slice(0, MAX_DIFF_LINES2) : null;
|
|
13214
|
+
const diffHidden = diffAll ? Math.max(0, diffAll.length - MAX_DIFF_LINES2) : 0;
|
|
12183
13215
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 0.3, marginBottom: 0.3, children: [
|
|
12184
13216
|
/* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexShrink: 0, children: [
|
|
12185
13217
|
/* @__PURE__ */ jsx5(Text5, { color: markerColor, bold: true, children: "\u23FA " }),
|
|
@@ -12193,6 +13225,14 @@ var init_ToolCard = __esm({
|
|
|
12193
13225
|
] }, i)) : status === "running" ? /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexShrink: 0, children: [
|
|
12194
13226
|
/* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: " \u23BF " }),
|
|
12195
13227
|
/* @__PURE__ */ jsx5(Text5, { color: THEME.gray, children: runningLine || "\u8FD0\u884C\u4E2D\u2026" })
|
|
13228
|
+
] }) : null,
|
|
13229
|
+
diffRows && diffRows.length > 0 ? diffRows.map((r, i) => /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexShrink: 0, children: [
|
|
13230
|
+
/* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: " " }),
|
|
13231
|
+
r.t === "ellip" ? /* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: r.n > 0 ? ` \u22EF ${r.n} \u884C\u672A\u53D8` : " \u22EF" }) : /* @__PURE__ */ jsx5(Text5, { color: r.t === "del" ? THEME.danger : r.t === "add" ? THEME.ok : THEME.grayDim, children: `${r.t === "del" ? "- " : r.t === "add" ? "+ " : " "}${truncateMiddle(r.s, Math.max(20, wrapW - 8))}` })
|
|
13232
|
+
] }, `diff-${i}`)) : null,
|
|
13233
|
+
diffHidden > 0 ? /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexShrink: 0, children: [
|
|
13234
|
+
/* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: " " }),
|
|
13235
|
+
/* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: ` \u2026\uFF08\u53E6\u6709 ${diffHidden} \u884C\u6539\u52A8\u672A\u663E\u793A\uFF09` })
|
|
12196
13236
|
] }) : null
|
|
12197
13237
|
] });
|
|
12198
13238
|
};
|
|
@@ -12236,28 +13276,36 @@ var init_TodosPanel = __esm({
|
|
|
12236
13276
|
|
|
12237
13277
|
// src/components/ApprovalModal.tsx
|
|
12238
13278
|
import { Box as Box5, Text as Text7 } from "ink";
|
|
12239
|
-
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
12240
|
-
var OPTIONS, ApprovalModal;
|
|
13279
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
13280
|
+
var OPTIONS, MAX_DIFF_LINES, ApprovalModal;
|
|
12241
13281
|
var init_ApprovalModal = __esm({
|
|
12242
13282
|
"src/components/ApprovalModal.tsx"() {
|
|
12243
13283
|
"use strict";
|
|
12244
13284
|
init_theme();
|
|
12245
13285
|
init_strings();
|
|
12246
13286
|
init_util();
|
|
13287
|
+
init_diffView();
|
|
12247
13288
|
OPTIONS = [
|
|
12248
13289
|
{ label: S.approvalAllow, value: "allow-once", color: THEME.ok },
|
|
12249
13290
|
{ label: S.approvalAllowAlways, value: "allow-always", color: THEME.warn },
|
|
12250
13291
|
{ label: S.approvalDeny, value: "deny", color: THEME.danger }
|
|
12251
13292
|
];
|
|
13293
|
+
MAX_DIFF_LINES = 18;
|
|
12252
13294
|
ApprovalModal = ({ toolName, detail, selectedIndex, wrapW }) => {
|
|
12253
13295
|
const contentW = Math.max(16, wrapW);
|
|
13296
|
+
const parsed = parseApprovalDiff(detail, toolName);
|
|
13297
|
+
const diffRows = parsed ? pairsToDisplayRows(parsed.sections) : null;
|
|
12254
13298
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: THEME.warn, paddingX: 1, paddingY: 1, marginTop: 1, children: [
|
|
12255
13299
|
/* @__PURE__ */ jsxs5(Text7, { color: THEME.warn, bold: true, children: [
|
|
12256
13300
|
S.approvalTitle,
|
|
12257
13301
|
" \xB7 ",
|
|
12258
13302
|
toolName
|
|
12259
13303
|
] }),
|
|
12260
|
-
/* @__PURE__ */ jsx7(Box5, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children:
|
|
13304
|
+
/* @__PURE__ */ jsx7(Box5, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: parsed && diffRows ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
13305
|
+
wrapText(parsed.header, contentW).map((line, j) => /* @__PURE__ */ jsx7(Text7, { color: THEME.white, children: line }, `h-${j}`)),
|
|
13306
|
+
diffRows.slice(0, MAX_DIFF_LINES).map((r, i) => /* @__PURE__ */ jsx7(Text7, { color: r.t === "del" ? THEME.danger : r.t === "add" ? THEME.ok : THEME.grayDim, children: r.t === "ellip" ? r.n > 0 ? ` \u22EF ${r.n} \u884C\u672A\u53D8` : " \u22EF" : `${r.t === "del" ? "- " : r.t === "add" ? "+ " : " "}${truncateMiddle(r.s, Math.max(20, contentW - 2))}` }, `d-${i}`)),
|
|
13307
|
+
diffRows.length > MAX_DIFF_LINES ? /* @__PURE__ */ jsx7(Text7, { color: THEME.grayDim, children: ` \u2026\uFF08\u53E6\u6709 ${diffRows.length - MAX_DIFF_LINES} \u884C\u672A\u663E\u793A\uFF09` }) : null
|
|
13308
|
+
] }) : wrapText(detail || "(\u65E0\u8BF4\u660E)", contentW).map((line, j) => /* @__PURE__ */ jsx7(Text7, { color: THEME.white, children: line }, j)) }),
|
|
12261
13309
|
/* @__PURE__ */ jsx7(Text7, { color: THEME.grayDim, children: S.approvalPrompt }),
|
|
12262
13310
|
OPTIONS.map((opt, i) => {
|
|
12263
13311
|
const active = i === selectedIndex;
|
|
@@ -12491,9 +13539,45 @@ var init_SessionPicker = __esm({
|
|
|
12491
13539
|
}
|
|
12492
13540
|
});
|
|
12493
13541
|
|
|
12494
|
-
// src/components/
|
|
13542
|
+
// src/components/ForkPicker.tsx
|
|
12495
13543
|
import { Box as Box11, Text as Text13 } from "ink";
|
|
12496
13544
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
13545
|
+
var PAGE_SIZE2, ForkPicker;
|
|
13546
|
+
var init_ForkPicker = __esm({
|
|
13547
|
+
"src/components/ForkPicker.tsx"() {
|
|
13548
|
+
"use strict";
|
|
13549
|
+
init_theme();
|
|
13550
|
+
init_strings();
|
|
13551
|
+
init_util();
|
|
13552
|
+
PAGE_SIZE2 = 8;
|
|
13553
|
+
ForkPicker = ({ anchors, selectedIndex, wrapW }) => {
|
|
13554
|
+
const start = Math.floor(selectedIndex / PAGE_SIZE2) * PAGE_SIZE2;
|
|
13555
|
+
const visible = anchors.slice(start, start + PAGE_SIZE2);
|
|
13556
|
+
const contentW = Math.max(24, wrapW);
|
|
13557
|
+
const userW = Math.max(10, Math.floor(contentW * 0.45));
|
|
13558
|
+
const replyW = Math.max(10, contentW - userW - 4);
|
|
13559
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: THEME.blue, paddingX: 1, paddingY: 1, marginTop: 1, children: [
|
|
13560
|
+
/* @__PURE__ */ jsx13(Text13, { color: THEME.blue, bold: true, children: S.forkTitle }),
|
|
13561
|
+
/* @__PURE__ */ jsx13(Text13, { color: THEME.grayDim, children: S.forkPrompt }),
|
|
13562
|
+
/* @__PURE__ */ jsx13(Box11, { flexDirection: "column", marginTop: 0.5, children: visible.map((a, i) => {
|
|
13563
|
+
const active = start + i === selectedIndex;
|
|
13564
|
+
const user = truncateMiddle(a.userPreview || "(\u65E0\u63D0\u95EE)", userW);
|
|
13565
|
+
const reply = truncateMiddle(a.assistantPreview, replyW);
|
|
13566
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", children: [
|
|
13567
|
+
/* @__PURE__ */ jsx13(Text13, { color: active ? THEME.coralBright : void 0, bold: true, children: active ? "\u203A " : " " }),
|
|
13568
|
+
/* @__PURE__ */ jsx13(Text13, { color: active ? THEME.white : THEME.gray, bold: active, children: `#${a.roundNo} ${user}` }),
|
|
13569
|
+
/* @__PURE__ */ jsx13(Text13, { color: THEME.grayDim, children: ` \u2192 ${reply}` })
|
|
13570
|
+
] }, a.lineId);
|
|
13571
|
+
}) }),
|
|
13572
|
+
anchors.length > PAGE_SIZE2 ? /* @__PURE__ */ jsx13(Text13, { color: THEME.grayDim, children: `\u7B2C ${start + 1}-${Math.min(start + PAGE_SIZE2, anchors.length)} / ${anchors.length} \u4E2A\uFF08\u2191\u2193 \u9009\u62E9\xB7\u81EA\u52A8\u7FFB\u9875\uFF09` }) : null
|
|
13573
|
+
] });
|
|
13574
|
+
};
|
|
13575
|
+
}
|
|
13576
|
+
});
|
|
13577
|
+
|
|
13578
|
+
// src/components/SlashMenu.tsx
|
|
13579
|
+
import { Box as Box12, Text as Text14 } from "ink";
|
|
13580
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
12497
13581
|
var MAX_ROWS, SlashMenu;
|
|
12498
13582
|
var init_SlashMenu = __esm({
|
|
12499
13583
|
"src/components/SlashMenu.tsx"() {
|
|
@@ -12505,22 +13589,22 @@ var init_SlashMenu = __esm({
|
|
|
12505
13589
|
const more = entries.length > MAX_ROWS;
|
|
12506
13590
|
const cmdW = Math.min(22, Math.max(8, ...visible.map((e) => e.name.length)) + 1);
|
|
12507
13591
|
const descMax = Math.max(12, cols - cmdW - 6);
|
|
12508
|
-
return /* @__PURE__ */
|
|
13592
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: THEME.coral, paddingX: 1, paddingY: 0, marginTop: 1, children: [
|
|
12509
13593
|
visible.map((e, i) => {
|
|
12510
13594
|
const active = i === selectedIndex;
|
|
12511
13595
|
const desc = e.description.length > descMax ? `${e.description.slice(0, descMax - 1)}\u2026` : e.description;
|
|
12512
13596
|
const gap = Math.max(1, cmdW - e.name.length);
|
|
12513
|
-
return /* @__PURE__ */
|
|
12514
|
-
/* @__PURE__ */
|
|
12515
|
-
/* @__PURE__ */
|
|
13597
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
|
|
13598
|
+
/* @__PURE__ */ jsx14(Text14, { color: active ? THEME.coralBright : void 0, bold: true, children: active ? "\u276F " : " " }),
|
|
13599
|
+
/* @__PURE__ */ jsxs12(Text14, { color: active ? THEME.white : THEME.gray, bold: active, children: [
|
|
12516
13600
|
"/",
|
|
12517
13601
|
e.name
|
|
12518
13602
|
] }),
|
|
12519
|
-
/* @__PURE__ */
|
|
12520
|
-
/* @__PURE__ */
|
|
13603
|
+
/* @__PURE__ */ jsx14(Text14, { color: THEME.grayDim, children: " ".repeat(gap) }),
|
|
13604
|
+
/* @__PURE__ */ jsx14(Text14, { color: active ? THEME.gray : THEME.grayDim, children: desc })
|
|
12521
13605
|
] }, e.name);
|
|
12522
13606
|
}),
|
|
12523
|
-
more ? /* @__PURE__ */
|
|
13607
|
+
more ? /* @__PURE__ */ jsxs12(Text14, { color: THEME.coralMuted, children: [
|
|
12524
13608
|
"\u2026 \u8FD8\u6709 ",
|
|
12525
13609
|
entries.length - MAX_ROWS,
|
|
12526
13610
|
" \u6761"
|
|
@@ -12531,8 +13615,8 @@ var init_SlashMenu = __esm({
|
|
|
12531
13615
|
});
|
|
12532
13616
|
|
|
12533
13617
|
// src/components/StatusStrip.tsx
|
|
12534
|
-
import { Box as
|
|
12535
|
-
import { jsx as
|
|
13618
|
+
import { Box as Box13, Text as Text15 } from "ink";
|
|
13619
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
12536
13620
|
var StatusStrip;
|
|
12537
13621
|
var init_StatusStrip = __esm({
|
|
12538
13622
|
"src/components/StatusStrip.tsx"() {
|
|
@@ -12549,18 +13633,18 @@ var init_StatusStrip = __esm({
|
|
|
12549
13633
|
`state: ${stateText}`,
|
|
12550
13634
|
sessionShort ? `session: ${sessionShort}` : ""
|
|
12551
13635
|
].filter(Boolean);
|
|
12552
|
-
return /* @__PURE__ */
|
|
12553
|
-
/* @__PURE__ */
|
|
12554
|
-
/* @__PURE__ */
|
|
12555
|
-
/* @__PURE__ */
|
|
13636
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexShrink: 0, children: [
|
|
13637
|
+
/* @__PURE__ */ jsx15(Text15, { color: THEME.coralMuted, children: customLine && customLine.trim() ? customLine : bits.join(" \xB7 ") }),
|
|
13638
|
+
/* @__PURE__ */ jsx15(Text15, { color: stateColor, children: "" }),
|
|
13639
|
+
/* @__PURE__ */ jsx15(Text15, { color: THEME.grayDim, children: S.cmdHint })
|
|
12556
13640
|
] });
|
|
12557
13641
|
};
|
|
12558
13642
|
}
|
|
12559
13643
|
});
|
|
12560
13644
|
|
|
12561
13645
|
// src/components/TopPanel.tsx
|
|
12562
|
-
import { Box as
|
|
12563
|
-
import { jsx as
|
|
13646
|
+
import { Box as Box14, Text as Text16 } from "ink";
|
|
13647
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
12564
13648
|
var ROBOT, INNER_H, TopPanel;
|
|
12565
13649
|
var init_TopPanel = __esm({
|
|
12566
13650
|
"src/components/TopPanel.tsx"() {
|
|
@@ -12580,36 +13664,36 @@ var init_TopPanel = __esm({
|
|
|
12580
13664
|
const leftW = Math.floor(innerW * 0.33);
|
|
12581
13665
|
const rightW = innerW - leftW - 1;
|
|
12582
13666
|
const ruleLen = Math.max(8, rightW - 2);
|
|
12583
|
-
const VDivider = /* @__PURE__ */
|
|
12584
|
-
return /* @__PURE__ */
|
|
12585
|
-
/* @__PURE__ */
|
|
12586
|
-
/* @__PURE__ */
|
|
12587
|
-
/* @__PURE__ */
|
|
12588
|
-
/* @__PURE__ */
|
|
12589
|
-
/* @__PURE__ */
|
|
12590
|
-
/* @__PURE__ */
|
|
13667
|
+
const VDivider = /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", width: 1, flexShrink: 0, children: Array.from({ length: INNER_H }).map((_, i) => /* @__PURE__ */ jsx16(Text16, { color: THEME.coral, children: "\u2502" }, i)) });
|
|
13668
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: panelW, marginBottom: 1, children: [
|
|
13669
|
+
/* @__PURE__ */ jsxs14(Text16, { children: [
|
|
13670
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "* Welcome to " }),
|
|
13671
|
+
/* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.white, children: "deep" }),
|
|
13672
|
+
/* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.coralBright, children: "Seek" }),
|
|
13673
|
+
/* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.white, children: "Code" }),
|
|
13674
|
+
/* @__PURE__ */ jsxs14(Text16, { color: THEME.coralMuted, children: [
|
|
12591
13675
|
" ",
|
|
12592
13676
|
VERSION
|
|
12593
13677
|
] })
|
|
12594
13678
|
] }),
|
|
12595
|
-
/* @__PURE__ */
|
|
12596
|
-
/* @__PURE__ */
|
|
12597
|
-
/* @__PURE__ */
|
|
12598
|
-
/* @__PURE__ */
|
|
12599
|
-
ROBOT.map((l, i) => /* @__PURE__ */
|
|
12600
|
-
/* @__PURE__ */
|
|
12601
|
-
/* @__PURE__ */
|
|
13679
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: cwd }),
|
|
13680
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", borderStyle: "round", borderColor: THEME.coral, marginTop: 1, paddingX: 0, paddingY: 0, children: [
|
|
13681
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: leftW, height: INNER_H, alignItems: "center", justifyContent: "center", children: [
|
|
13682
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.white, bold: true, children: "Welcome back!" }),
|
|
13683
|
+
ROBOT.map((l, i) => /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, children: l }, i)),
|
|
13684
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "Ctrl+C \u9000\u51FA \xB7 Esc \u4E2D\u6B62" }),
|
|
13685
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "\u8F93\u5165 / \u67E5\u770B\u547D\u4EE4" })
|
|
12602
13686
|
] }),
|
|
12603
13687
|
VDivider,
|
|
12604
|
-
/* @__PURE__ */
|
|
12605
|
-
/* @__PURE__ */
|
|
12606
|
-
/* @__PURE__ */
|
|
12607
|
-
/* @__PURE__ */
|
|
13688
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: rightW, height: INNER_H, justifyContent: "space-between", paddingX: 1, children: [
|
|
13689
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
13690
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "Tips for getting started" }),
|
|
13691
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.white, children: "\u8F93\u5165\u9700\u6C42\u5F00\u59CB\uFF0C\u8F93\u5165 / \u5524\u51FA\u547D\u4EE4\u3002" })
|
|
12608
13692
|
] }),
|
|
12609
|
-
/* @__PURE__ */
|
|
12610
|
-
/* @__PURE__ */
|
|
12611
|
-
/* @__PURE__ */
|
|
12612
|
-
/* @__PURE__ */
|
|
13693
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "\u2500".repeat(ruleLen) }),
|
|
13694
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
13695
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "What's new" }),
|
|
13696
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.white, children: "\u5DF2\u5BF9\u63A5\u672C\u5730 Tool Call \u667A\u80FD\u51FD\u6570\u8C03\u7528\u3002" })
|
|
12613
13697
|
] })
|
|
12614
13698
|
] })
|
|
12615
13699
|
] })
|
|
@@ -12619,7 +13703,7 @@ var init_TopPanel = __esm({
|
|
|
12619
13703
|
});
|
|
12620
13704
|
|
|
12621
13705
|
// src/inspect.ts
|
|
12622
|
-
import
|
|
13706
|
+
import fs38 from "fs";
|
|
12623
13707
|
var CWD, fmt, readTrace, inspectUsage, inspectContext, inspectPermissions, inspectMcp, inspectHooks, inspectDebug;
|
|
12624
13708
|
var init_inspect = __esm({
|
|
12625
13709
|
"src/inspect.ts"() {
|
|
@@ -12637,7 +13721,7 @@ var init_inspect = __esm({
|
|
|
12637
13721
|
if (!sessionId) return [];
|
|
12638
13722
|
try {
|
|
12639
13723
|
const p = await getTraceStorePath(sessionId);
|
|
12640
|
-
const text = await
|
|
13724
|
+
const text = await fs38.promises.readFile(p, "utf8");
|
|
12641
13725
|
const out = [];
|
|
12642
13726
|
for (const line of text.split("\n")) {
|
|
12643
13727
|
if (!line.trim()) continue;
|
|
@@ -12760,8 +13844,8 @@ __export(App_exports, {
|
|
|
12760
13844
|
App: () => App
|
|
12761
13845
|
});
|
|
12762
13846
|
import { useCallback as useCallback2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState4 } from "react";
|
|
12763
|
-
import { Box as
|
|
12764
|
-
import { jsx as
|
|
13847
|
+
import { Box as Box15, Static, Text as Text17, useApp, useInput as useInput2, useStdout } from "ink";
|
|
13848
|
+
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
12765
13849
|
var KNOWN_MODELS, CWD2, RowView, isDynamicRow, App;
|
|
12766
13850
|
var init_App = __esm({
|
|
12767
13851
|
"src/App.tsx"() {
|
|
@@ -12786,6 +13870,7 @@ var init_App = __esm({
|
|
|
12786
13870
|
init_PlanModal();
|
|
12787
13871
|
init_PlanEditor();
|
|
12788
13872
|
init_SessionPicker();
|
|
13873
|
+
init_ForkPicker();
|
|
12789
13874
|
init_SlashMenu();
|
|
12790
13875
|
init_MultilineInput();
|
|
12791
13876
|
init_StatusStrip();
|
|
@@ -12794,16 +13879,16 @@ var init_App = __esm({
|
|
|
12794
13879
|
KNOWN_MODELS = ["deepseek-v4", "deepseek-v4-flash"];
|
|
12795
13880
|
CWD2 = process.cwd();
|
|
12796
13881
|
RowView = ({ row, wrapW, streamTail, showThinking }) => {
|
|
12797
|
-
if (row.kind === "todos") return /* @__PURE__ */
|
|
12798
|
-
if (row.kind === "tool") return /* @__PURE__ */
|
|
12799
|
-
if (row.kind === "thinking") return /* @__PURE__ */
|
|
13882
|
+
if (row.kind === "todos") return /* @__PURE__ */ jsx17(TodosPanel, { todos: row.todos, wrapW });
|
|
13883
|
+
if (row.kind === "tool") return /* @__PURE__ */ jsx17(ToolCard, { toolName: row.toolName, args: row.args, result: row.result, ok: row.ok, status: row.status, progress: row.progress, wrapW });
|
|
13884
|
+
if (row.kind === "thinking") return /* @__PURE__ */ jsx17(ThinkingBlock, { streaming: row.streaming ?? false, startedAt: row.startedAt, durationMs: row.durationMs, tokens: row.tokens, text: row.text, expanded: showThinking, wrapW });
|
|
12800
13885
|
if (row.kind === "user") {
|
|
12801
|
-
return /* @__PURE__ */
|
|
12802
|
-
/* @__PURE__ */
|
|
12803
|
-
/* @__PURE__ */
|
|
13886
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
|
|
13887
|
+
/* @__PURE__ */ jsx17(Text17, { color: THEME.grayDim, children: "\u2500".repeat(Math.max(8, wrapW)) }),
|
|
13888
|
+
/* @__PURE__ */ jsx17(MessageBlock, { row, wrapW, streamTail })
|
|
12804
13889
|
] });
|
|
12805
13890
|
}
|
|
12806
|
-
return /* @__PURE__ */
|
|
13891
|
+
return /* @__PURE__ */ jsx17(MessageBlock, { row, wrapW, streamTail });
|
|
12807
13892
|
};
|
|
12808
13893
|
isDynamicRow = (r) => r.kind === "assistant" && !!r.streaming || r.kind === "thinking" && !!r.streaming || r.kind === "tool" && r.status === "running" || r.kind === "todos" && !!r.active;
|
|
12809
13894
|
App = ({ resumeSessionId, initialPlanMode, initialAutoMode, initialIncludeProject }) => {
|
|
@@ -12903,6 +13988,8 @@ var init_App = __esm({
|
|
|
12903
13988
|
return S.cmdOutputStyle;
|
|
12904
13989
|
case "sessions":
|
|
12905
13990
|
return S.cmdSessions;
|
|
13991
|
+
case "fork":
|
|
13992
|
+
return S.cmdFork;
|
|
12906
13993
|
case "usage":
|
|
12907
13994
|
return S.cmdUsage;
|
|
12908
13995
|
case "context":
|
|
@@ -12935,13 +14022,13 @@ var init_App = __esm({
|
|
|
12935
14022
|
const q = input.slice(1).toLowerCase();
|
|
12936
14023
|
return menuEntries.filter((c) => c.name.toLowerCase().startsWith(q));
|
|
12937
14024
|
}, [input, menuEntries]);
|
|
12938
|
-
const menuActive = state.pendingApproval != null || state.pendingQuestion != null || state.pendingPlan != null || state.pendingSessions != null;
|
|
14025
|
+
const menuActive = state.pendingApproval != null || state.pendingQuestion != null || state.pendingPlan != null || state.pendingSessions != null || state.pendingFork != null;
|
|
12939
14026
|
const slashVisible = !menuActive && input.startsWith("/") && filteredCommands.length > 0;
|
|
12940
14027
|
const inputActive = !menuActive;
|
|
12941
14028
|
useEffect4(() => {
|
|
12942
14029
|
setSelectIdx(0);
|
|
12943
14030
|
setPlanEditing(false);
|
|
12944
|
-
}, [state.pendingApproval, state.pendingQuestion, state.pendingPlan, state.pendingSessions, slashVisible, filteredCommands.length]);
|
|
14031
|
+
}, [state.pendingApproval, state.pendingQuestion, state.pendingPlan, state.pendingSessions, state.pendingFork, slashVisible, filteredCommands.length]);
|
|
12945
14032
|
useEffect4(() => {
|
|
12946
14033
|
setQCursor(0);
|
|
12947
14034
|
setQChecked(/* @__PURE__ */ new Set());
|
|
@@ -12960,6 +14047,9 @@ var init_App = __esm({
|
|
|
12960
14047
|
case "/sessions":
|
|
12961
14048
|
void state.openSessionPicker();
|
|
12962
14049
|
return true;
|
|
14050
|
+
case "/fork":
|
|
14051
|
+
void state.openForkPicker();
|
|
14052
|
+
return true;
|
|
12963
14053
|
case "/help":
|
|
12964
14054
|
state.pushInfo(S.helpText(modelDisplay, state.getThinkingLevel(), getLocale()));
|
|
12965
14055
|
return true;
|
|
@@ -13108,7 +14198,12 @@ ${listText}`);
|
|
|
13108
14198
|
const v = inputRef.current.trim();
|
|
13109
14199
|
if (!v) return;
|
|
13110
14200
|
if (busyRef.current) {
|
|
13111
|
-
|
|
14201
|
+
if (!v.startsWith("/") && state.queueInput(v)) {
|
|
14202
|
+
setInput("");
|
|
14203
|
+
setCursor(0);
|
|
14204
|
+
} else {
|
|
14205
|
+
state.pushEvent({ type: "error", message: S.busyBlockSend });
|
|
14206
|
+
}
|
|
13112
14207
|
return;
|
|
13113
14208
|
}
|
|
13114
14209
|
setInput("");
|
|
@@ -13190,6 +14285,16 @@ ${listText}`);
|
|
|
13190
14285
|
} else if (key.escape || key.ctrl && ch === "g") state.resolveSession(null);
|
|
13191
14286
|
return;
|
|
13192
14287
|
}
|
|
14288
|
+
if (state.pendingFork) {
|
|
14289
|
+
const list = state.pendingFork.anchors;
|
|
14290
|
+
if (key.upArrow) setSelectIdx((i) => (i - 1 + list.length) % list.length);
|
|
14291
|
+
else if (key.downArrow) setSelectIdx((i) => (i + 1) % list.length);
|
|
14292
|
+
else if (key.return) {
|
|
14293
|
+
const sel = list[Math.min(selectIdxRef.current, list.length - 1)];
|
|
14294
|
+
state.resolveFork(sel ?? null);
|
|
14295
|
+
} else if (key.escape || key.ctrl && ch === "g") state.resolveFork(null);
|
|
14296
|
+
return;
|
|
14297
|
+
}
|
|
13193
14298
|
if (key.ctrl && ch === "t") {
|
|
13194
14299
|
state.toggleShowThinking();
|
|
13195
14300
|
return;
|
|
@@ -13230,19 +14335,19 @@ ${listText}`);
|
|
|
13230
14335
|
}
|
|
13231
14336
|
});
|
|
13232
14337
|
const sessionShort = state.sessionIdRef.current ? truncateMiddle(state.sessionIdRef.current, 12) : "";
|
|
13233
|
-
return /* @__PURE__ */
|
|
13234
|
-
/* @__PURE__ */
|
|
13235
|
-
/* @__PURE__ */
|
|
13236
|
-
menuActive ? null : /* @__PURE__ */
|
|
13237
|
-
dynamicRows.map((row) => /* @__PURE__ */
|
|
13238
|
-
state.busy ? /* @__PURE__ */
|
|
14338
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: cols, children: [
|
|
14339
|
+
/* @__PURE__ */ jsx17(Static, { items: staticItems, children: (item) => item.kind === "__header" ? /* @__PURE__ */ jsx17(TopPanel, { cwd: CWD2, cols }, "header") : /* @__PURE__ */ jsx17(RowView, { row: item, wrapW, streamTail, showThinking: state.showThinkingText }, item.id) }),
|
|
14340
|
+
/* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: cols, children: [
|
|
14341
|
+
menuActive ? null : /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, children: [
|
|
14342
|
+
dynamicRows.map((row) => /* @__PURE__ */ jsx17(RowView, { row, wrapW, streamTail, showThinking: state.showThinkingText }, row.id)),
|
|
14343
|
+
state.busy ? /* @__PURE__ */ jsx17(Box15, { marginTop: 0.5, children: /* @__PURE__ */ jsxs15(Text17, { color: THEME.coralBright, children: [
|
|
13239
14344
|
"\u25CF ",
|
|
13240
14345
|
S.generating
|
|
13241
14346
|
] }) }) : null
|
|
13242
14347
|
] }),
|
|
13243
|
-
/* @__PURE__ */
|
|
13244
|
-
state.pendingApproval ? /* @__PURE__ */
|
|
13245
|
-
state.pendingQuestion ? /* @__PURE__ */
|
|
14348
|
+
/* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, flexShrink: 0, children: [
|
|
14349
|
+
state.pendingApproval ? /* @__PURE__ */ jsx17(ApprovalModal, { toolName: state.pendingApproval.toolName, detail: state.pendingApproval.detail, selectedIndex: selectIdx, wrapW }) : null,
|
|
14350
|
+
state.pendingQuestion ? /* @__PURE__ */ jsx17(
|
|
13246
14351
|
QuestionModal,
|
|
13247
14352
|
{
|
|
13248
14353
|
question: state.pendingQuestion.req.question,
|
|
@@ -13253,7 +14358,7 @@ ${listText}`);
|
|
|
13253
14358
|
wrapW
|
|
13254
14359
|
}
|
|
13255
14360
|
) : null,
|
|
13256
|
-
state.pendingPlan ? planEditing ? /* @__PURE__ */
|
|
14361
|
+
state.pendingPlan ? planEditing ? /* @__PURE__ */ jsx17(
|
|
13257
14362
|
PlanEditor,
|
|
13258
14363
|
{
|
|
13259
14364
|
value: planDraft,
|
|
@@ -13264,13 +14369,15 @@ ${listText}`);
|
|
|
13264
14369
|
},
|
|
13265
14370
|
onSubmit: confirmPlanEdit
|
|
13266
14371
|
}
|
|
13267
|
-
) : /* @__PURE__ */
|
|
13268
|
-
state.pendingSessions ? /* @__PURE__ */
|
|
13269
|
-
|
|
14372
|
+
) : /* @__PURE__ */ jsx17(PlanModal, { selectedIndex: selectIdx }) : null,
|
|
14373
|
+
state.pendingSessions ? /* @__PURE__ */ jsx17(SessionPicker, { sessions: state.pendingSessions.sessions, selectedIndex: selectIdx, wrapW }) : null,
|
|
14374
|
+
state.pendingFork ? /* @__PURE__ */ jsx17(ForkPicker, { anchors: state.pendingFork.anchors, selectedIndex: selectIdx, wrapW }) : null,
|
|
14375
|
+
slashVisible ? /* @__PURE__ */ jsx17(SlashMenu, { entries: filteredCommands, selectedIndex: selectIdx, cols }) : null
|
|
13270
14376
|
] }),
|
|
13271
|
-
/* @__PURE__ */
|
|
13272
|
-
|
|
13273
|
-
|
|
14377
|
+
/* @__PURE__ */ jsx17(Box15, { flexDirection: "column", paddingX: 1, marginTop: 1, flexShrink: 0, children: (() => {
|
|
14378
|
+
const planOn = state.getPlanMode();
|
|
14379
|
+
const autoOn = !planOn && state.getAutoMode();
|
|
14380
|
+
const inputEl = /* @__PURE__ */ jsx17(
|
|
13274
14381
|
MultilineInput,
|
|
13275
14382
|
{
|
|
13276
14383
|
value: input,
|
|
@@ -13286,9 +14393,19 @@ ${listText}`);
|
|
|
13286
14393
|
suppressSubmit: slashVisible,
|
|
13287
14394
|
placeholder: S.placeholder
|
|
13288
14395
|
}
|
|
13289
|
-
)
|
|
13290
|
-
|
|
13291
|
-
|
|
14396
|
+
);
|
|
14397
|
+
if (planOn || autoOn) {
|
|
14398
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: planOn ? THEME.thinking : THEME.warn, paddingX: 1, children: [
|
|
14399
|
+
/* @__PURE__ */ jsx17(Text17, { color: planOn ? THEME.thinking : THEME.warn, children: planOn ? S.inputBadgePlan : S.inputBadgeAuto }),
|
|
14400
|
+
inputEl
|
|
14401
|
+
] });
|
|
14402
|
+
}
|
|
14403
|
+
return /* @__PURE__ */ jsxs15(Fragment3, { children: [
|
|
14404
|
+
/* @__PURE__ */ jsx17(Text17, { dimColor: true, color: THEME.gray, children: dimRule(cols) }),
|
|
14405
|
+
inputEl
|
|
14406
|
+
] });
|
|
14407
|
+
})() }),
|
|
14408
|
+
/* @__PURE__ */ jsx17(Box15, { paddingX: 1, marginTop: 1, flexShrink: 0, children: /* @__PURE__ */ jsx17(StatusStrip, { model: modelDisplay, busy: state.busy, aborting: state.aborting, planMode: state.getPlanMode(), autoMode: state.getAutoMode(), sessionShort, cols, customLine: statusLineText }) })
|
|
13292
14409
|
] })
|
|
13293
14410
|
] });
|
|
13294
14411
|
};
|
|
@@ -13302,7 +14419,7 @@ __export(updateCheck_exports, {
|
|
|
13302
14419
|
readLocalVersion: () => readLocalVersion,
|
|
13303
14420
|
refreshUpdateCache: () => refreshUpdateCache
|
|
13304
14421
|
});
|
|
13305
|
-
import { readFileSync as
|
|
14422
|
+
import { readFileSync as readFileSync4, writeFileSync, mkdirSync } from "node:fs";
|
|
13306
14423
|
import path39 from "node:path";
|
|
13307
14424
|
import os4 from "os";
|
|
13308
14425
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
@@ -13318,7 +14435,7 @@ var init_updateCheck = __esm({
|
|
|
13318
14435
|
readLocalVersion = () => {
|
|
13319
14436
|
try {
|
|
13320
14437
|
const here = path39.dirname(fileURLToPath6(import.meta.url));
|
|
13321
|
-
return JSON.parse(
|
|
14438
|
+
return JSON.parse(readFileSync4(path39.join(here, "..", "package.json"), "utf8")).version ?? "0.0.0";
|
|
13322
14439
|
} catch {
|
|
13323
14440
|
return "0.0.0";
|
|
13324
14441
|
}
|
|
@@ -13334,7 +14451,7 @@ var init_updateCheck = __esm({
|
|
|
13334
14451
|
};
|
|
13335
14452
|
readCache = () => {
|
|
13336
14453
|
try {
|
|
13337
|
-
const obj = JSON.parse(
|
|
14454
|
+
const obj = JSON.parse(readFileSync4(cacheFile(), "utf8"));
|
|
13338
14455
|
return typeof obj.latestVersion === "string" && typeof obj.lastCheck === "number" ? obj : null;
|
|
13339
14456
|
} catch {
|
|
13340
14457
|
return null;
|
|
@@ -13422,7 +14539,7 @@ import { render } from "ink";
|
|
|
13422
14539
|
import os5 from "os";
|
|
13423
14540
|
import path40 from "path";
|
|
13424
14541
|
import { emitKeypressEvents } from "node:readline";
|
|
13425
|
-
import { jsx as
|
|
14542
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
13426
14543
|
var parseArgs = (argv) => {
|
|
13427
14544
|
const out = {};
|
|
13428
14545
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -13566,7 +14683,7 @@ var main = async () => {
|
|
|
13566
14683
|
resumeId = await getMostRecentSessionId2() ?? void 0;
|
|
13567
14684
|
}
|
|
13568
14685
|
const { waitUntilExit } = render(
|
|
13569
|
-
/* @__PURE__ */
|
|
14686
|
+
/* @__PURE__ */ jsx18(App2, { resumeSessionId: resumeId, initialPlanMode: args.plan, initialAutoMode: args.auto, initialIncludeProject: includeProject }),
|
|
13570
14687
|
// exitOnCtrlC:false:Ctrl+C 交由 App useInput 处理(统一退出/中止语义);
|
|
13571
14688
|
// patchConsole:false:避免 console 劫持与全屏重绘叠加闪屏。
|
|
13572
14689
|
{ exitOnCtrlC: false, patchConsole: false }
|