deepseeker-code 1.0.2 → 1.0.4
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/dist/cli.mjs +1142 -216
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -52,6 +52,9 @@ var init_strings = __esm({
|
|
|
52
52
|
approvalDeny: "\u62D2\u7EDD",
|
|
53
53
|
errAborted: "\u5DF2\u4E2D\u6B62\u5F53\u524D\u8F6E\u3002",
|
|
54
54
|
busyBlockSend: "\u23F3 \u6B63\u5728\u751F\u6210\uFF0C\u8BF7\u7B49\u5F85\u6216\u6309 Esc \u4E2D\u6B62\u540E\u518D\u53D1\u9001\u3002",
|
|
55
|
+
inboxQueued: "\u{1F4EE} \u5DF2\u6392\u961F\uFF0C\u5C06\u5728\u56DE\u5408\u8FB9\u754C\u9001\u8FBE\u6A21\u578B\uFF08Esc \u4ECD\u53EF\u4E2D\u6B62\uFF09\u3002",
|
|
56
|
+
inboxClaimed: (n) => `\u{1F4EC} \u5DF2\u9001\u8FBE\u6A21\u578B\uFF08${n} \u6761\u8865\u5145\u8F93\u5165\uFF09`,
|
|
57
|
+
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
58
|
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
59
|
statusStreaming: "\u751F\u6210\u4E2D",
|
|
57
60
|
statusIdle: "\u5C31\u7EEA",
|
|
@@ -67,6 +70,13 @@ var init_strings = __esm({
|
|
|
67
70
|
${yellow} \u5DE5\u5177\u5C06\u4EE5\u8BE5\u76EE\u5F55\u4E3A\u9879\u76EE\u6839\u8BFB\u5199\u6587\u4EF6\uFF0C\u5EFA\u8BAE\u5148 cd \u5230\u5177\u4F53\u9879\u76EE\u76EE\u5F55\u518D\u8FD0\u884C\u3002${reset}
|
|
68
71
|
${dim} \u9879\u76EE\u952E\uFF1A${projectKey}${reset}
|
|
69
72
|
|
|
73
|
+
`;
|
|
74
|
+
},
|
|
75
|
+
updateAvailable: (latest, current) => {
|
|
76
|
+
const cyan = "\x1B[36m", dim = "\x1B[2m", reset = "\x1B[0m";
|
|
77
|
+
return `${cyan}\u21BB \u68C0\u6D4B\u5230\u65B0\u7248\u672C ${latest}${reset} ${dim}\uFF08\u5F53\u524D ${current}\uFF09${reset}
|
|
78
|
+
${dim} \u8FD0\u884C npm i -g deepseeker-code@latest \u66F4\u65B0${reset}
|
|
79
|
+
|
|
70
80
|
`;
|
|
71
81
|
},
|
|
72
82
|
cmdHelp: "\u67E5\u770B\u5E2E\u52A9\u4E0E\u5FEB\u6377\u952E",
|
|
@@ -91,6 +101,12 @@ ${dim} \u9879\u76EE\u952E\uFF1A${projectKey}${reset}
|
|
|
91
101
|
sessionsPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u8F7D\u5165 \xB7 Esc \u53D6\u6D88",
|
|
92
102
|
noHistory: "\uFF08\u6682\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF09",
|
|
93
103
|
sessionLoaded: (id) => `\u5DF2\u8F7D\u5165\u4F1A\u8BDD ${id}\uFF08\u7EE7\u7EED\u5BF9\u8BDD\u5C06\u7EED\u63A5\u6B64\u4F1A\u8BDD\uFF09`,
|
|
104
|
+
cmdFork: "\u4ECE\u5F53\u524D\u4F1A\u8BDD\u7684\u67D0\u8F6E\u56DE\u590D\u5904\u5206\u53C9\u51FA\u65B0\u4F1A\u8BDD",
|
|
105
|
+
forkTitle: "\u{1F33F} \u5206\u53C9\u5F53\u524D\u4F1A\u8BDD\uFF08\u2191\u2193 \u9009\u68C0\u67E5\u70B9 \xB7 Enter \u5206\u53C9\uFF09",
|
|
106
|
+
forkPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u5206\u53C9 \xB7 Esc \u53D6\u6D88",
|
|
107
|
+
forkEmpty: "\uFF08\u5F53\u524D\u4F1A\u8BDD\u6682\u65E0\u53EF\u5206\u53C9\u7684\u68C0\u67E5\u70B9\uFF09",
|
|
108
|
+
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`,
|
|
109
|
+
forkFailed: (e) => `\u5206\u53C9\u5931\u8D25\uFF1A${e}`,
|
|
94
110
|
relTime: (iso) => {
|
|
95
111
|
const t = Date.parse(iso);
|
|
96
112
|
if (!t) return "";
|
|
@@ -126,6 +142,7 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
|
|
|
126
142
|
`/thinking [off|high|max] \u2014 \u5207\u6362\u601D\u8003\u7B49\u7EA7\uFF08\u5F53\u524D ${thinking}\uFF09`,
|
|
127
143
|
`/lang [zh|en] \u2014 \u5207\u6362\u754C\u9762\u8BED\u8A00\uFF08\u5F53\u524D ${locale2}\uFF09`,
|
|
128
144
|
"/sessions \u2014 \u9009\u62E9\u5E76\u8F7D\u5165\u5386\u53F2\u4F1A\u8BDD\uFF08\u7EED\u63A5\u5BF9\u8BDD\uFF09",
|
|
145
|
+
"/fork \u2014 \u4ECE\u5F53\u524D\u4F1A\u8BDD\u7684\u67D0\u8F6E\u56DE\u590D\u5904\u5206\u53C9\u51FA\u65B0\u4F1A\u8BDD",
|
|
129
146
|
"/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",
|
|
130
147
|
"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"
|
|
131
148
|
].join("\n"),
|
|
@@ -173,6 +190,9 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
|
|
|
173
190
|
approvalDeny: "Deny",
|
|
174
191
|
errAborted: "Aborted current turn.",
|
|
175
192
|
busyBlockSend: "\u23F3 Still generating\u2014wait or press Esc to abort before sending.",
|
|
193
|
+
inboxQueued: "\u{1F4EE} Queued\u2014will reach the model at the next round boundary (Esc still aborts).",
|
|
194
|
+
inboxClaimed: (n) => `\u{1F4EC} Delivered to the model (${n} supplemental input${n > 1 ? "s" : ""})`,
|
|
195
|
+
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.`,
|
|
176
196
|
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",
|
|
177
197
|
statusStreaming: "streaming",
|
|
178
198
|
statusIdle: "ready",
|
|
@@ -188,6 +208,13 @@ Set it as an env var and retry, or start serve for the Web UI.`,
|
|
|
188
208
|
${yellow} Tools will read/write files with this as project root\u2014cd into the actual project first.${reset}
|
|
189
209
|
${dim} Project key: ${projectKey}${reset}
|
|
190
210
|
|
|
211
|
+
`;
|
|
212
|
+
},
|
|
213
|
+
updateAvailable: (latest, current) => {
|
|
214
|
+
const cyan = "\x1B[36m", dim = "\x1B[2m", reset = "\x1B[0m";
|
|
215
|
+
return `${cyan}\u21BB New version ${latest} available${reset} ${dim}(current ${current})${reset}
|
|
216
|
+
${dim} Run npm i -g deepseeker-code@latest to update${reset}
|
|
217
|
+
|
|
191
218
|
`;
|
|
192
219
|
},
|
|
193
220
|
cmdHelp: "Show help & shortcuts",
|
|
@@ -212,6 +239,12 @@ ${dim} Project key: ${projectKey}${reset}
|
|
|
212
239
|
sessionsPrompt: "\u2191\u2193 pick \xB7 Enter resume \xB7 Esc cancel",
|
|
213
240
|
noHistory: "(no past sessions)",
|
|
214
241
|
sessionLoaded: (id) => `Resumed session ${id} (new messages continue it)`,
|
|
242
|
+
cmdFork: "Fork the current session from a past round",
|
|
243
|
+
forkTitle: "\u{1F33F} Fork current session (\u2191\u2193 to pick \xB7 Enter to fork)",
|
|
244
|
+
forkPrompt: "\u2191\u2193 pick \xB7 Enter fork \xB7 Esc cancel",
|
|
245
|
+
forkEmpty: "(no checkpoints to fork from in this session)",
|
|
246
|
+
forkDone: (id, roundNo) => `Forked from round ${roundNo} \u2192 new session ${id} (loaded; new messages go to the fork, source untouched)`,
|
|
247
|
+
forkFailed: (e) => `Fork failed: ${e}`,
|
|
215
248
|
relTime: (iso) => {
|
|
216
249
|
const t = Date.parse(iso);
|
|
217
250
|
if (!t) return "";
|
|
@@ -247,6 +280,7 @@ DeepSeeker-Code will read, edit, and execute files here.`,
|
|
|
247
280
|
`/thinking [off|high|max] \u2014 Switch thinking level (current ${thinking})`,
|
|
248
281
|
`/lang [zh|en] \u2014 Switch interface language (current ${locale2})`,
|
|
249
282
|
"/sessions \u2014 Pick a past session to resume",
|
|
283
|
+
"/fork \u2014 Fork the current session from a past round",
|
|
250
284
|
"/trust \u2014 Manage trusted dirs (project hooks/skills load only when trusted; CI uses --trust)",
|
|
251
285
|
"Ctrl+C exit \xB7 Esc abort/clear input \xB7 Ctrl+G abort \xB7 Ctrl+T toggle thinking"
|
|
252
286
|
].join("\n"),
|
|
@@ -267,7 +301,7 @@ DeepSeeker-Code will read, edit, and execute files here.`,
|
|
|
267
301
|
S = new Proxy({}, {
|
|
268
302
|
get: (_t, k) => typeof k === "string" ? STRINGS[locale][k] : void 0
|
|
269
303
|
});
|
|
270
|
-
LOCAL_COMMAND_NAMES = ["help", "status", "plan", "auto", "model", "thinking", "lang", "output-style", "sessions", "usage", "context", "permissions", "mcp", "hooks", "trust", "debug", "clear", "exit"];
|
|
304
|
+
LOCAL_COMMAND_NAMES = ["help", "status", "plan", "auto", "model", "thinking", "lang", "output-style", "sessions", "fork", "usage", "context", "permissions", "mcp", "hooks", "trust", "debug", "clear", "exit"];
|
|
271
305
|
}
|
|
272
306
|
});
|
|
273
307
|
|
|
@@ -275,13 +309,15 @@ DeepSeeker-Code will read, edit, and execute files here.`,
|
|
|
275
309
|
var config_exports = {};
|
|
276
310
|
__export(config_exports, {
|
|
277
311
|
ENGINE_OVERRIDE_KEYS: () => ENGINE_OVERRIDE_KEYS,
|
|
278
|
-
|
|
312
|
+
ENV_SOURCES: () => ENV_SOURCES,
|
|
313
|
+
appConfig: () => appConfig,
|
|
314
|
+
configSources: () => configSources
|
|
279
315
|
});
|
|
280
316
|
import path2 from "path";
|
|
281
317
|
import os2 from "os";
|
|
282
318
|
import { readFileSync as readFileSync2 } from "fs";
|
|
283
319
|
import { createHash } from "crypto";
|
|
284
|
-
var _DataDir, appConfig, ENGINE_OVERRIDE_VALIDATORS, ENGINE_OVERRIDE_KEYS, applyEngineOverrides;
|
|
320
|
+
var _DataDir, appConfig, ENV_SOURCES, configSources, ENGINE_OVERRIDE_VALIDATORS, ENGINE_OVERRIDE_KEYS, applyEngineOverrides;
|
|
285
321
|
var init_config = __esm({
|
|
286
322
|
"../core/src/config/index.ts"() {
|
|
287
323
|
"use strict";
|
|
@@ -356,8 +392,51 @@ var init_config = __esm({
|
|
|
356
392
|
workflowMaxSteps: Number(process.env.DEEP_SEEK_WORKFLOW_MAX_STEPS) || 8,
|
|
357
393
|
/** P0-3 run_workflow 单个子 agent 结果的字符预算:超出按头尾截断,避免单个巨型结果挤占聚合输出。
|
|
358
394
|
* 最终聚合再受工具 maxOutputCharacters 兜底。 */
|
|
359
|
-
workflowPerStepChars: 6e3
|
|
360
|
-
|
|
395
|
+
workflowPerStepChars: 6e3,
|
|
396
|
+
/** ★ P0-A 计划模式强制位置:'runtime'(默认)= 工具表全会话恒定(两态统一 appendPlanControlTools),
|
|
397
|
+
* 计划期写工具由 processToolCall 执行层按 PLAN_ALLOWED_TOOLS 拒绝——保 DeepSeek 前缀缓存
|
|
398
|
+
* (tools 参数序列化在请求头部,计划模式裁表翻转 = 全会话历史 re-prefill 两次);
|
|
399
|
+
* 'schema' = 旧路径(计划期裁成只读白名单子表)。env DEEP_SEEK_PLAN_ENFORCEMENT=schema 回退。 */
|
|
400
|
+
planEnforcement: process.env.DEEP_SEEK_PLAN_ENFORCEMENT === "schema" ? "schema" : "runtime",
|
|
401
|
+
/** ★ P1-MCP 工具暴露模式:'dispatcher'(默认)= 只注入恒定 schema 的 mcp_list_tools + mcp_call
|
|
402
|
+
* (目录按需查、审批/权限用合成名 mcp__<server>__<tool> 匹配既有规则;工具表不随 MCP server
|
|
403
|
+
* 工具数增长,L1 恒定);'schemas' = 旧路径(每个 MCP 工具独立 schema 常驻)。
|
|
404
|
+
* env DEEP_SEEK_MCP_EXPOSE_MODE=schemas 回退。 */
|
|
405
|
+
mcpExposeMode: process.env.DEEP_SEEK_MCP_EXPOSE_MODE === "schemas" ? "schemas" : "dispatcher",
|
|
406
|
+
/** ★ 事件日志化:transcript 追加 turn/step 边界事件行(run.start/round.end/run.end/compaction/
|
|
407
|
+
* run.abandoned,带 dscEvent 标记,readMessages 自动过滤)——崩溃恢复从盲扫启发式升级为事件确认,
|
|
408
|
+
* compaction 事件携带归档计数+摘要文本使 transcript 自包含(分叉/审计不再押 state.json 单点)。
|
|
409
|
+
* 关闭时 appendEvent 全 no-op、恢复走纯内存启发式(= 改造前行为)。env DEEP_SEEK_TRANSCRIPT_EVENTS=0 回退。 */
|
|
410
|
+
transcriptEvents: process.env.DEEP_SEEK_TRANSCRIPT_EVENTS !== "0",
|
|
411
|
+
/** ★ inbox steering(第二梯队 #2):agent 运行中用户补充输入进 per-session 队列,runAgent 回合边界
|
|
412
|
+
* claim 注入上下文并落盘 transcript(长任务中途补指示不再只能中止重跑)。
|
|
413
|
+
* 关闭时全链路 no-op:端点 501 / CLI 回退 busy 提示 / VSCode 不排队。env DEEP_SEEK_INBOX=0 回退。 */
|
|
414
|
+
inboxSteering: process.env.DEEP_SEEK_INBOX !== "0",
|
|
415
|
+
/** ★ hooks 改写型拦截点(第二梯队 #3):PreToolUse 可改 args(argsOverride,前置到全部安全门禁
|
|
416
|
+
* 之前生效——门禁/审批评估的是改写后参数)、PostToolUse 可改 resultForModel(仅模型视图,
|
|
417
|
+
* 用户视图 resultForUser 不变)。关闭时 PreToolUse 回退旧位(审批后、仅 deny),改写字段全忽略,
|
|
418
|
+
* 行为与改造前一致。env DEEP_SEEK_HOOK_REWRITE=0 回退。 */
|
|
419
|
+
hookRewrite: process.env.DEEP_SEEK_HOOK_REWRITE !== "0"
|
|
420
|
+
};
|
|
421
|
+
ENV_SOURCES = {
|
|
422
|
+
dataDir: "DEEPSEEKER_CODE_DATA_DIR",
|
|
423
|
+
searchProvider: "SEARCH_PROVIDER",
|
|
424
|
+
tavilyApiKey: "TAVILY_API_KEY",
|
|
425
|
+
webFetchAllowPrivate: "WEB_FETCH_ALLOW_PRIVATE",
|
|
426
|
+
parallelSafeTools: "DEEP_SEEK_PARALLEL_SAFE_TOOLS",
|
|
427
|
+
workflowConcurrency: "DEEP_SEEK_WORKFLOW_CONCURRENCY",
|
|
428
|
+
workflowMaxSteps: "DEEP_SEEK_WORKFLOW_MAX_STEPS",
|
|
429
|
+
planEnforcement: "DEEP_SEEK_PLAN_ENFORCEMENT",
|
|
430
|
+
mcpExposeMode: "DEEP_SEEK_MCP_EXPOSE_MODE",
|
|
431
|
+
transcriptEvents: "DEEP_SEEK_TRANSCRIPT_EVENTS",
|
|
432
|
+
inboxSteering: "DEEP_SEEK_INBOX",
|
|
433
|
+
hookRewrite: "DEEP_SEEK_HOOK_REWRITE"
|
|
434
|
+
};
|
|
435
|
+
configSources = {};
|
|
436
|
+
for (const [key, envName] of Object.entries(ENV_SOURCES)) {
|
|
437
|
+
const v = process.env[envName];
|
|
438
|
+
if (v !== void 0 && v !== "") configSources[key] = "env";
|
|
439
|
+
}
|
|
361
440
|
ENGINE_OVERRIDE_VALIDATORS = {
|
|
362
441
|
undoEnabled: (v) => typeof v === "boolean" ? v : void 0,
|
|
363
442
|
undoBackupSensitive: (v) => v === "skip" || v === "deny" || v === "allow" ? v : void 0,
|
|
@@ -368,12 +447,12 @@ var init_config = __esm({
|
|
|
368
447
|
ENGINE_OVERRIDE_KEYS = Object.keys(ENGINE_OVERRIDE_VALIDATORS);
|
|
369
448
|
applyEngineOverrides = (cfg) => {
|
|
370
449
|
const paths = [
|
|
371
|
-
path2.join(cfg.dataDir, "settings.json"),
|
|
450
|
+
{ scope: "settings.global", configPath: path2.join(cfg.dataDir, "settings.json") },
|
|
372
451
|
// 全局用户级
|
|
373
|
-
path2.join(process.cwd(), ".deepseeker-code", "settings.json")
|
|
452
|
+
{ scope: "settings.project", configPath: path2.join(process.cwd(), ".deepseeker-code", "settings.json") }
|
|
374
453
|
// 项目级(覆盖全局)
|
|
375
454
|
];
|
|
376
|
-
for (const configPath of paths) {
|
|
455
|
+
for (const { scope, configPath } of paths) {
|
|
377
456
|
let raw;
|
|
378
457
|
try {
|
|
379
458
|
raw = readFileSync2(configPath, "utf-8");
|
|
@@ -397,6 +476,7 @@ var init_config = __esm({
|
|
|
397
476
|
continue;
|
|
398
477
|
}
|
|
399
478
|
cfg[key] = valid;
|
|
479
|
+
configSources[key] = scope;
|
|
400
480
|
}
|
|
401
481
|
}
|
|
402
482
|
};
|
|
@@ -477,13 +557,20 @@ var init_common = __esm({
|
|
|
477
557
|
injectMarkedBlock = (message, fence, body) => {
|
|
478
558
|
const sys = message[0];
|
|
479
559
|
if (!sys || sys.role !== "system" || typeof sys.content !== "string") return;
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
sys.content += `
|
|
560
|
+
const idx = sys.content.indexOf(fence);
|
|
561
|
+
if (idx === -1) {
|
|
562
|
+
sys.content += `
|
|
484
563
|
|
|
485
564
|
${fence}
|
|
486
565
|
${body}`;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
const after = sys.content.slice(idx + fence.length);
|
|
569
|
+
const next = after.match(/\n\n⟦[^\n]*?⟧/);
|
|
570
|
+
const oldBody = next?.index !== void 0 ? after.slice(0, next.index) : after;
|
|
571
|
+
if (oldBody === `
|
|
572
|
+
${body}`) return;
|
|
573
|
+
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`);
|
|
487
574
|
};
|
|
488
575
|
decodeProcessOutput = (buf) => {
|
|
489
576
|
const utf8 = buf.toString("utf8");
|
|
@@ -797,17 +884,120 @@ var init_deepseek = __esm({
|
|
|
797
884
|
}
|
|
798
885
|
});
|
|
799
886
|
|
|
887
|
+
// ../core/src/llm/providers/replay/index.ts
|
|
888
|
+
var createReplayProvider;
|
|
889
|
+
var init_replay = __esm({
|
|
890
|
+
"../core/src/llm/providers/replay/index.ts"() {
|
|
891
|
+
"use strict";
|
|
892
|
+
createReplayProvider = (script) => {
|
|
893
|
+
const turns = Array.isArray(script.turns) ? script.turns : [];
|
|
894
|
+
let cursor = 0;
|
|
895
|
+
let attemptCounts = [];
|
|
896
|
+
const calls = [];
|
|
897
|
+
const makeFaultError = (fault) => {
|
|
898
|
+
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");
|
|
899
|
+
const e = new Error(msg);
|
|
900
|
+
e.replayFault = fault.type;
|
|
901
|
+
if (fault.type === "transient") e.status = 429;
|
|
902
|
+
return e;
|
|
903
|
+
};
|
|
904
|
+
const streamChat2 = async function* (messages, tools, opts) {
|
|
905
|
+
const turnIndex = cursor;
|
|
906
|
+
calls.push({ turnIndex, messages: [...messages], tools, opts });
|
|
907
|
+
const turn = turns[turnIndex];
|
|
908
|
+
if (!turn) return;
|
|
909
|
+
const attempt = attemptCounts[turnIndex] ?? 0;
|
|
910
|
+
attemptCounts[turnIndex] = attempt + 1;
|
|
911
|
+
const fault = turn.fault;
|
|
912
|
+
const shouldFault = !!fault && (fault.type === "fatal" || attempt < (fault.times ?? 1));
|
|
913
|
+
if (shouldFault) {
|
|
914
|
+
const f = fault;
|
|
915
|
+
const n = Math.min(f.afterChars ?? 0, (turn.content ?? "").length);
|
|
916
|
+
if (n > 0) yield { kind: "text", text: (turn.content ?? "").slice(0, n) };
|
|
917
|
+
throw makeFaultError(f);
|
|
918
|
+
}
|
|
919
|
+
if (turn.reasoning) yield { kind: "reasoning", text: turn.reasoning };
|
|
920
|
+
if (turn.content) yield { kind: "text", text: turn.content };
|
|
921
|
+
const tcs = turn.toolCalls ?? [];
|
|
922
|
+
for (let i = 0; i < tcs.length; i++) {
|
|
923
|
+
const tc = tcs[i];
|
|
924
|
+
yield { kind: "tool_call_delta", index: i, id: tc.id ?? `call_replay_${turnIndex}_${i}`, type: "function", nameDelta: tc.name };
|
|
925
|
+
yield { kind: "tool_call_delta", index: i, argumentsDelta: JSON.stringify(tc.args ?? {}) };
|
|
926
|
+
}
|
|
927
|
+
if (turn.usage) yield { kind: "usage", usage: turn.usage };
|
|
928
|
+
cursor++;
|
|
929
|
+
};
|
|
930
|
+
const summarize2 = async (_messages, _tools, _opts) => ({
|
|
931
|
+
id: "replay-summary",
|
|
932
|
+
object: "chat.completion",
|
|
933
|
+
created: 0,
|
|
934
|
+
// 确定性:固定值(回放产物不掺时间戳,diff 稳定)
|
|
935
|
+
model: "replay",
|
|
936
|
+
choices: [{
|
|
937
|
+
index: 0,
|
|
938
|
+
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 },
|
|
939
|
+
finish_reason: "stop",
|
|
940
|
+
logprobs: null
|
|
941
|
+
}],
|
|
942
|
+
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
|
|
943
|
+
});
|
|
944
|
+
return {
|
|
945
|
+
id: "replay",
|
|
946
|
+
displayName: "Replay",
|
|
947
|
+
modelLabel: "Replay",
|
|
948
|
+
streamChat: streamChat2,
|
|
949
|
+
summarize: summarize2,
|
|
950
|
+
classifyRisk: async () => script.riskVerdict ?? "safe",
|
|
951
|
+
buildAssistantMessage: (parts) => {
|
|
952
|
+
const m = { role: "assistant", content: parts.content };
|
|
953
|
+
if (parts.reasoning) m.reasoning_content = parts.reasoning;
|
|
954
|
+
if (parts.toolCalls?.length) m.tool_calls = parts.toolCalls;
|
|
955
|
+
return m;
|
|
956
|
+
},
|
|
957
|
+
// 自识别回放注入的故障(streamInference 经 activeProvider 调用这两个分类器驱动重试通道)
|
|
958
|
+
isContextLengthError: (e) => e?.replayFault === "context_length",
|
|
959
|
+
isTransientError: (e) => e?.replayFault === "transient",
|
|
960
|
+
get calls() {
|
|
961
|
+
return calls;
|
|
962
|
+
},
|
|
963
|
+
get cursor() {
|
|
964
|
+
return cursor;
|
|
965
|
+
},
|
|
966
|
+
reset: () => {
|
|
967
|
+
cursor = 0;
|
|
968
|
+
attemptCounts = [];
|
|
969
|
+
calls.length = 0;
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
|
|
800
976
|
// ../core/src/llm/model.ts
|
|
801
|
-
|
|
977
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
978
|
+
var resolveInitialProvider, activeProvider, chatWithModelWithSummary, classifyToolRisk;
|
|
802
979
|
var init_model = __esm({
|
|
803
980
|
"../core/src/llm/model.ts"() {
|
|
804
981
|
"use strict";
|
|
805
982
|
init_deepseek();
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
983
|
+
init_replay();
|
|
984
|
+
resolveInitialProvider = () => {
|
|
985
|
+
if (process.env.DEEP_SEEK_PROVIDER !== "replay") return deepseekProvider;
|
|
986
|
+
const scriptPath = process.env.DEEP_SEEK_REPLAY_SCRIPT;
|
|
987
|
+
if (!scriptPath) {
|
|
988
|
+
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");
|
|
989
|
+
}
|
|
990
|
+
let raw;
|
|
991
|
+
try {
|
|
992
|
+
raw = JSON.parse(readFileSync3(scriptPath, "utf-8"));
|
|
993
|
+
} catch (e) {
|
|
994
|
+
throw new Error(`\u56DE\u653E\u5267\u672C\u52A0\u8F7D\u5931\u8D25\uFF08${scriptPath}\uFF09: ${e?.message ?? e}`);
|
|
995
|
+
}
|
|
996
|
+
return createReplayProvider(Array.isArray(raw) ? { turns: raw } : raw);
|
|
997
|
+
};
|
|
998
|
+
activeProvider = resolveInitialProvider();
|
|
999
|
+
chatWithModelWithSummary = (messages, tools, opts) => activeProvider.summarize(messages, tools, opts);
|
|
1000
|
+
classifyToolRisk = (toolName, args, detail, signal) => activeProvider.classifyRisk(toolName, args, detail, signal);
|
|
811
1001
|
}
|
|
812
1002
|
});
|
|
813
1003
|
|
|
@@ -1125,6 +1315,7 @@ var init_store = __esm({
|
|
|
1125
1315
|
} catch {
|
|
1126
1316
|
continue;
|
|
1127
1317
|
}
|
|
1318
|
+
if (typeof msg?.dscEvent === "string") continue;
|
|
1128
1319
|
messageCount++;
|
|
1129
1320
|
if (!preview && msg?.role === "user" && typeof msg.content === "string") {
|
|
1130
1321
|
const t = msg.content.replace(/\s+/g, " ").trim();
|
|
@@ -1179,6 +1370,87 @@ var init_store = __esm({
|
|
|
1179
1370
|
}
|
|
1180
1371
|
});
|
|
1181
1372
|
|
|
1373
|
+
// ../core/src/session/transcript.ts
|
|
1374
|
+
import fs5 from "fs/promises";
|
|
1375
|
+
var isEventLine, readTranscriptLines, appendLineWithRetry, appendMessage, appendEvent;
|
|
1376
|
+
var init_transcript = __esm({
|
|
1377
|
+
"../core/src/session/transcript.ts"() {
|
|
1378
|
+
"use strict";
|
|
1379
|
+
init_store();
|
|
1380
|
+
init_common();
|
|
1381
|
+
init_config();
|
|
1382
|
+
isEventLine = (l) => typeof l?.dscEvent === "string";
|
|
1383
|
+
readTranscriptLines = async (sessionId) => {
|
|
1384
|
+
await ensureSessionsDir(sessionId);
|
|
1385
|
+
const p = getTranscriptPath(sessionId);
|
|
1386
|
+
try {
|
|
1387
|
+
const text = await fs5.readFile(p, "utf-8");
|
|
1388
|
+
const lines = [];
|
|
1389
|
+
for (const s of text.split("\n")) {
|
|
1390
|
+
const line = s.trim();
|
|
1391
|
+
if (line.length === 0) continue;
|
|
1392
|
+
try {
|
|
1393
|
+
lines.push(JSON.parse(line));
|
|
1394
|
+
} catch {
|
|
1395
|
+
console.warn(`\u26A0\uFE0F [transcript] \u8DF3\u8FC7\u65E0\u6CD5\u89E3\u6790\u7684\u635F\u574F\u884C: ${line.slice(0, 120)}`);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
return lines;
|
|
1399
|
+
} catch (err) {
|
|
1400
|
+
if (err?.code === "ENOENT") return [];
|
|
1401
|
+
throw err;
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
appendLineWithRetry = async (p, payload) => {
|
|
1405
|
+
const MAX_ATTEMPTS = 3;
|
|
1406
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
1407
|
+
let beforeSize = 0;
|
|
1408
|
+
try {
|
|
1409
|
+
beforeSize = (await fs5.stat(p)).size;
|
|
1410
|
+
} catch {
|
|
1411
|
+
}
|
|
1412
|
+
try {
|
|
1413
|
+
await fs5.appendFile(p, payload, "utf-8");
|
|
1414
|
+
return;
|
|
1415
|
+
} catch (e) {
|
|
1416
|
+
try {
|
|
1417
|
+
await fs5.truncate(p, beforeSize);
|
|
1418
|
+
} catch {
|
|
1419
|
+
}
|
|
1420
|
+
if (attempt === MAX_ATTEMPTS) throw e;
|
|
1421
|
+
await new Promise((r) => setTimeout(r, 50 * attempt));
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
appendMessage = async (entry) => {
|
|
1426
|
+
try {
|
|
1427
|
+
await ensureSessionsDir(entry.sessionId);
|
|
1428
|
+
const { sessionId, ...rest } = entry;
|
|
1429
|
+
const line = { id: createUUID(), ...rest };
|
|
1430
|
+
const p = getTranscriptPath(sessionId);
|
|
1431
|
+
const payload = JSON.stringify(line) + "\n";
|
|
1432
|
+
if (payload.includes("\uFFFD")) {
|
|
1433
|
+
const fffdCount = (payload.match(/\uFFFD/g) || []).length;
|
|
1434
|
+
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`);
|
|
1435
|
+
}
|
|
1436
|
+
await appendLineWithRetry(p, payload);
|
|
1437
|
+
} catch (e) {
|
|
1438
|
+
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);
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
appendEvent = async (sessionId, ev) => {
|
|
1442
|
+
if (!appConfig.transcriptEvents) return;
|
|
1443
|
+
try {
|
|
1444
|
+
await ensureSessionsDir(sessionId);
|
|
1445
|
+
const line = { id: createUUID(), ts: (/* @__PURE__ */ new Date()).toISOString(), ...ev };
|
|
1446
|
+
await appendLineWithRetry(getTranscriptPath(sessionId), JSON.stringify(line) + "\n");
|
|
1447
|
+
} catch (e) {
|
|
1448
|
+
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);
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
});
|
|
1453
|
+
|
|
1182
1454
|
// ../core/src/hooks/types.ts
|
|
1183
1455
|
var INTERCEPTABLE_EVENTS, TOOL_EVENTS, ALL_EVENTS, DEFAULT_TIMEOUT_BY_EVENT;
|
|
1184
1456
|
var init_types = __esm({
|
|
@@ -1326,12 +1598,13 @@ var init_shellExecutor = __esm({
|
|
|
1326
1598
|
});
|
|
1327
1599
|
|
|
1328
1600
|
// ../core/src/hooks/registry.ts
|
|
1329
|
-
var rules, matches, registerHooks, listHooks, dispatch, runPreHooks, HOOK_RESULT_MAX, truncateForHook, runPostHooks;
|
|
1601
|
+
var rules, matches, registerHooks, listHooks, isPlainObject, dispatch, runPreHooks, HOOK_RESULT_MAX, truncateForHook, runPostHooks;
|
|
1330
1602
|
var init_registry = __esm({
|
|
1331
1603
|
"../core/src/hooks/registry.ts"() {
|
|
1332
1604
|
"use strict";
|
|
1333
1605
|
init_types();
|
|
1334
1606
|
init_shellExecutor();
|
|
1607
|
+
init_config();
|
|
1335
1608
|
rules = [];
|
|
1336
1609
|
matches = (matcher, toolName) => {
|
|
1337
1610
|
if (typeof matcher === "string") return matcher === "*" || matcher === toolName;
|
|
@@ -1354,6 +1627,7 @@ var init_registry = __esm({
|
|
|
1354
1627
|
};
|
|
1355
1628
|
return rules.map((r) => ({ event: r.event, matcher: strMatcher(r.matcher), source: r.source, onError: r.onError }));
|
|
1356
1629
|
};
|
|
1630
|
+
isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
1357
1631
|
dispatch = async (event, ctx) => {
|
|
1358
1632
|
const interceptable = INTERCEPTABLE_EVENTS.has(event);
|
|
1359
1633
|
const isToolEvent = TOOL_EVENTS.has(event);
|
|
@@ -1381,14 +1655,29 @@ var init_registry = __esm({
|
|
|
1381
1655
|
)
|
|
1382
1656
|
));
|
|
1383
1657
|
const additions2 = [];
|
|
1384
|
-
|
|
1385
|
-
|
|
1658
|
+
let resultOverride;
|
|
1659
|
+
for (const r of results) {
|
|
1660
|
+
if (r?.contextAdditions) additions2.push(...r.contextAdditions);
|
|
1661
|
+
if (event === "PostToolUse" && appConfig.hookRewrite && typeof r?.resultOverride === "string" && r.resultOverride) {
|
|
1662
|
+
resultOverride = r.resultOverride;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return { ...pack(additions2), resultOverride };
|
|
1386
1666
|
}
|
|
1387
1667
|
const additions = [];
|
|
1668
|
+
let argsOverride = void 0;
|
|
1388
1669
|
for (const rule of matched) {
|
|
1389
1670
|
try {
|
|
1390
1671
|
const res = await rule.run(ctx);
|
|
1391
1672
|
if (res?.contextAdditions) additions.push(...res.contextAdditions);
|
|
1673
|
+
if (event === "PreToolUse" && appConfig.hookRewrite && res?.argsOverride !== void 0) {
|
|
1674
|
+
if (isPlainObject(res.argsOverride)) {
|
|
1675
|
+
ctx.args = res.argsOverride;
|
|
1676
|
+
argsOverride = res.argsOverride;
|
|
1677
|
+
} else {
|
|
1678
|
+
console.warn(`\u26A0\uFE0F [hook:PreToolUse] argsOverride \u987B\u4E3A\u666E\u901A\u5BF9\u8C61\uFF0C\u5DF2\u5FFD\u7565`);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1392
1681
|
if (res && res.deny) {
|
|
1393
1682
|
return { deny: true, reason: res.reason, contextAdditions: additions.length > 0 ? additions : void 0 };
|
|
1394
1683
|
}
|
|
@@ -1401,7 +1690,7 @@ var init_registry = __esm({
|
|
|
1401
1690
|
console.warn(`\u26A0\uFE0F [hook:${event}] \u6267\u884C\u5F02\u5E38\uFF0C\u6309\u653E\u884C\u5904\u7406: ${msg}`);
|
|
1402
1691
|
}
|
|
1403
1692
|
}
|
|
1404
|
-
return pack(additions);
|
|
1693
|
+
return { ...pack(additions), argsOverride };
|
|
1405
1694
|
};
|
|
1406
1695
|
runPreHooks = async (toolName, args, ctx) => {
|
|
1407
1696
|
return dispatch("PreToolUse", {
|
|
@@ -1417,7 +1706,7 @@ var init_registry = __esm({
|
|
|
1417
1706
|
truncateForHook = (s) => s.length <= HOOK_RESULT_MAX ? s : s.slice(0, HOOK_RESULT_MAX) + `
|
|
1418
1707
|
\u2026[hook \u89C6\u56FE\u622A\u65AD\uFF0C\u5171 ${s.length} \u5B57\u7B26]`;
|
|
1419
1708
|
runPostHooks = async (toolName, args, result, ctx) => {
|
|
1420
|
-
|
|
1709
|
+
return dispatch("PostToolUse", {
|
|
1421
1710
|
sessionId: ctx.sessionId,
|
|
1422
1711
|
cwd: ctx.cwd,
|
|
1423
1712
|
env: ctx.env,
|
|
@@ -1461,6 +1750,7 @@ var init_truncate = __esm({
|
|
|
1461
1750
|
init_model();
|
|
1462
1751
|
init_contextCore();
|
|
1463
1752
|
init_store();
|
|
1753
|
+
init_transcript();
|
|
1464
1754
|
init_hooks();
|
|
1465
1755
|
ANSI_ESCAPE = /\u001b\[[\d;?]*[ -/]*[@-~]|\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g;
|
|
1466
1756
|
getFileAccessRoots = () => {
|
|
@@ -1616,6 +1906,11 @@ ${line}` : line;
|
|
|
1616
1906
|
consecutiveFailures: 0,
|
|
1617
1907
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1618
1908
|
});
|
|
1909
|
+
await appendEvent(event.sessionId, {
|
|
1910
|
+
dscEvent: "compaction",
|
|
1911
|
+
archivedMessageCount: store.archivedMessageCount,
|
|
1912
|
+
summary: summaryMsg.content
|
|
1913
|
+
});
|
|
1619
1914
|
} else if (keep > 1) {
|
|
1620
1915
|
keep--;
|
|
1621
1916
|
continue;
|
|
@@ -1630,6 +1925,11 @@ ${line}` : line;
|
|
|
1630
1925
|
consecutiveFailures: 0,
|
|
1631
1926
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1632
1927
|
});
|
|
1928
|
+
await appendEvent(event.sessionId, {
|
|
1929
|
+
dscEvent: "compaction",
|
|
1930
|
+
archivedMessageCount: store.archivedMessageCount,
|
|
1931
|
+
summary: summaryMsg.content
|
|
1932
|
+
});
|
|
1633
1933
|
} else {
|
|
1634
1934
|
break;
|
|
1635
1935
|
}
|
|
@@ -1736,7 +2036,7 @@ ${line}` : line;
|
|
|
1736
2036
|
});
|
|
1737
2037
|
|
|
1738
2038
|
// ../core/src/tool/permissions.ts
|
|
1739
|
-
import
|
|
2039
|
+
import fs6 from "fs/promises";
|
|
1740
2040
|
import path8 from "path";
|
|
1741
2041
|
var PRIMARY_ARG, rules2, trustedProject, globCache, globToRegex, DANGER_COMMAND_TOOLS, compileRule, readPermissionConfig, toolNameMatches, ruleMatches, initPermissions, checkPermission, listPermissionRules, buildScopedAllowRule, resolveSettingsPath, addPermissionRule;
|
|
1742
2042
|
var init_permissions = __esm({
|
|
@@ -1807,7 +2107,7 @@ var init_permissions = __esm({
|
|
|
1807
2107
|
for (const configPath of paths) {
|
|
1808
2108
|
let raw;
|
|
1809
2109
|
try {
|
|
1810
|
-
raw = await
|
|
2110
|
+
raw = await fs6.readFile(configPath, "utf-8");
|
|
1811
2111
|
} catch {
|
|
1812
2112
|
continue;
|
|
1813
2113
|
}
|
|
@@ -1904,7 +2204,7 @@ var init_permissions = __esm({
|
|
|
1904
2204
|
const arr = Array.isArray(cfg.permissions[kind]) ? cfg.permissions[kind] : cfg.permissions[kind] = [];
|
|
1905
2205
|
if (!arr.includes(ruleStr)) {
|
|
1906
2206
|
arr.push(ruleStr);
|
|
1907
|
-
await
|
|
2207
|
+
await fs6.mkdir(path8.dirname(file), { recursive: true });
|
|
1908
2208
|
await atomicWriteJSON(file, cfg);
|
|
1909
2209
|
}
|
|
1910
2210
|
if (!rules2[kind].some((r) => r.raw === compiled.raw)) rules2[kind].push(compiled);
|
|
@@ -1942,7 +2242,7 @@ var init_sessionRegistry = __esm({
|
|
|
1942
2242
|
});
|
|
1943
2243
|
|
|
1944
2244
|
// ../core/src/tool/guard.ts
|
|
1945
|
-
import
|
|
2245
|
+
import fs7 from "fs/promises";
|
|
1946
2246
|
import fsSync from "fs";
|
|
1947
2247
|
import path9 from "path";
|
|
1948
2248
|
import ignore from "ignore";
|
|
@@ -2051,7 +2351,16 @@ var init_guard = __esm({
|
|
|
2051
2351
|
};
|
|
2052
2352
|
resolveReadablePath = (rel) => {
|
|
2053
2353
|
const root = getActiveWorkspaceRoot();
|
|
2054
|
-
|
|
2354
|
+
const absPath = path9.resolve(root, rel);
|
|
2355
|
+
if (!fsSync.existsSync(absPath)) {
|
|
2356
|
+
const rootName = path9.basename(root);
|
|
2357
|
+
const firstSeg = rel.split(/[\\/]/)[0];
|
|
2358
|
+
if (rootName && firstSeg === rootName) {
|
|
2359
|
+
const alt = path9.resolve(root, rel.slice(firstSeg.length + 1));
|
|
2360
|
+
if (fsSync.existsSync(alt)) return alt;
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
return absPath;
|
|
2055
2364
|
};
|
|
2056
2365
|
assertWithinWorkspace = (absPath, base) => {
|
|
2057
2366
|
const root = base ?? getActiveWorkspaceRoot();
|
|
@@ -2111,11 +2420,11 @@ var init_guard = __esm({
|
|
|
2111
2420
|
};
|
|
2112
2421
|
scanIgnoreFilesRecursive = async (dirPath, base, engine) => {
|
|
2113
2422
|
try {
|
|
2114
|
-
const entries = await
|
|
2423
|
+
const entries = await fs7.readdir(dirPath, { withFileTypes: true });
|
|
2115
2424
|
for (const entry of entries) {
|
|
2116
2425
|
if (entry.isFile() && (entry.name === ".gitignore" || entry.name === ".agentignore")) {
|
|
2117
2426
|
const fullPath = path9.join(dirPath, entry.name);
|
|
2118
|
-
const content = await
|
|
2427
|
+
const content = await fs7.readFile(fullPath, "utf-8");
|
|
2119
2428
|
const relDir = path9.relative(base, dirPath).replace(/\\/g, "/");
|
|
2120
2429
|
const rules3 = content.split(/\r?\n/).map((line) => {
|
|
2121
2430
|
const trimmed = line.trim();
|
|
@@ -3012,7 +3321,7 @@ ${capped || JSON.stringify(result)}`;
|
|
|
3012
3321
|
});
|
|
3013
3322
|
|
|
3014
3323
|
// ../core/src/tool/mcp/loader.ts
|
|
3015
|
-
import
|
|
3324
|
+
import fs8 from "fs/promises";
|
|
3016
3325
|
import path11 from "path";
|
|
3017
3326
|
import { homedir } from "os";
|
|
3018
3327
|
function sanitize(s) {
|
|
@@ -3022,7 +3331,7 @@ async function readMcpConfig() {
|
|
|
3022
3331
|
const configPath = process.env.MCP_CONFIG || path11.join(appConfig.dataDir, "mcp.json");
|
|
3023
3332
|
let raw;
|
|
3024
3333
|
try {
|
|
3025
|
-
raw = await
|
|
3334
|
+
raw = await fs8.readFile(configPath, "utf-8");
|
|
3026
3335
|
} catch {
|
|
3027
3336
|
return {};
|
|
3028
3337
|
}
|
|
@@ -3113,9 +3422,14 @@ async function loadMcpTools() {
|
|
|
3113
3422
|
}
|
|
3114
3423
|
async function initMcpTools(into) {
|
|
3115
3424
|
const mcpTools = await loadMcpTools();
|
|
3116
|
-
if (
|
|
3425
|
+
if (appConfig.mcpExposeMode === "dispatcher") {
|
|
3426
|
+
if (clients.length > 0) {
|
|
3427
|
+
into.push(...mcpDispatcherTools);
|
|
3428
|
+
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`);
|
|
3429
|
+
}
|
|
3430
|
+
} else if (mcpTools.length > 0) {
|
|
3117
3431
|
into.push(...mcpTools);
|
|
3118
|
-
console.log(`\u{1F50C} [MCP] \u5171\u6CE8\u5165 ${mcpTools.length} \u4E2A MCP \u5DE5\u5177`);
|
|
3432
|
+
console.log(`\u{1F50C} [MCP] \u5171\u6CE8\u5165 ${mcpTools.length} \u4E2A MCP \u5DE5\u5177 schema\uFF08schemas \u6A21\u5F0F\uFF09`);
|
|
3119
3433
|
}
|
|
3120
3434
|
if (clients.some((c) => c.supportsResources)) {
|
|
3121
3435
|
into.push(...mcpResourceTools);
|
|
@@ -3151,7 +3465,7 @@ async function listMcpClients() {
|
|
|
3151
3465
|
}
|
|
3152
3466
|
return out;
|
|
3153
3467
|
}
|
|
3154
|
-
var clients, expandPlaceholders, expandServerConfig, mcpResourceTools, mcpPromptTools;
|
|
3468
|
+
var clients, expandPlaceholders, expandServerConfig, mcpResourceTools, mcpPromptTools, resolveMcpPermissionName, mcpDispatcherTools;
|
|
3155
3469
|
var init_loader = __esm({
|
|
3156
3470
|
"../core/src/tool/mcp/loader.ts"() {
|
|
3157
3471
|
"use strict";
|
|
@@ -3315,6 +3629,88 @@ ${text}`;
|
|
|
3315
3629
|
}
|
|
3316
3630
|
}
|
|
3317
3631
|
];
|
|
3632
|
+
resolveMcpPermissionName = (calledName, args) => {
|
|
3633
|
+
if (calledName !== "mcp_call") return calledName;
|
|
3634
|
+
const server = typeof args?.server === "string" ? sanitize(args.server) : "";
|
|
3635
|
+
const tool = typeof args?.tool === "string" ? sanitize(args.tool) : "";
|
|
3636
|
+
return server && tool ? `mcp__${server}__${tool}` : calledName;
|
|
3637
|
+
};
|
|
3638
|
+
mcpDispatcherTools = [
|
|
3639
|
+
{
|
|
3640
|
+
type: "function",
|
|
3641
|
+
function: {
|
|
3642
|
+
name: "mcp_list_tools",
|
|
3643
|
+
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",
|
|
3644
|
+
parameters: {
|
|
3645
|
+
type: "object",
|
|
3646
|
+
properties: {
|
|
3647
|
+
server: { type: "string", description: "\u4EC5\u5217\u51FA\u8BE5 server \u7684\u5DE5\u5177\uFF08\u7F3A\u7701\u5217\u51FA\u5168\u90E8\u5DF2\u8FDE\u63A5 server\uFF09" }
|
|
3648
|
+
}
|
|
3649
|
+
},
|
|
3650
|
+
safetyLevel: "safe" /* SAFE */,
|
|
3651
|
+
isSync: true,
|
|
3652
|
+
async execute(args) {
|
|
3653
|
+
const server = args?.server;
|
|
3654
|
+
const lines = [];
|
|
3655
|
+
for (const c of clients) {
|
|
3656
|
+
if (server && c.serverName !== server) continue;
|
|
3657
|
+
try {
|
|
3658
|
+
const ts = await c.listTools();
|
|
3659
|
+
for (const t of ts) {
|
|
3660
|
+
const props = t?.inputSchema?.properties && typeof t.inputSchema.properties === "object" ? Object.keys(t.inputSchema.properties) : [];
|
|
3661
|
+
const required = Array.isArray(t?.inputSchema?.required) ? t.inputSchema.required : [];
|
|
3662
|
+
const argList = props.map((p) => required.includes(p) ? `${p}*` : p).join(", ");
|
|
3663
|
+
lines.push(`- [${c.serverName}] ${t.name}${t.description ? `\uFF1A${String(t.description).split("\n")[0]}` : ""}${argList ? `\uFF08\u53C2\u6570\uFF1A${argList}\uFF09` : ""}`);
|
|
3664
|
+
}
|
|
3665
|
+
} catch (e) {
|
|
3666
|
+
console.warn(`\u26A0\uFE0F [MCP] listTools "${c.serverName}" \u5931\u8D25\uFF08\u5DF2\u8DF3\u8FC7\uFF09: ${e?.message ?? e}`);
|
|
3667
|
+
}
|
|
3668
|
+
}
|
|
3669
|
+
if (lines.length === 0) return server ? `(server "${server}" \u672A\u8FDE\u63A5\u6216\u65E0\u5DE5\u5177)` : "(\u65E0\u5DF2\u8FDE\u63A5\u7684 MCP server)";
|
|
3670
|
+
return `[MCP tools]
|
|
3671
|
+
${lines.join("\n")}`;
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
},
|
|
3675
|
+
{
|
|
3676
|
+
type: "function",
|
|
3677
|
+
function: {
|
|
3678
|
+
name: "mcp_call",
|
|
3679
|
+
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',
|
|
3680
|
+
parameters: {
|
|
3681
|
+
type: "object",
|
|
3682
|
+
properties: {
|
|
3683
|
+
server: { type: "string", description: "MCP server \u540D\uFF08\u89C1 mcp_list_tools \u8F93\u51FA\uFF09" },
|
|
3684
|
+
tool: { type: "string", description: "\u5DE5\u5177\u540D\uFF08\u89C1 mcp_list_tools \u8F93\u51FA\uFF0C\u7528\u539F\u540D\uFF09" },
|
|
3685
|
+
args: { type: "string", description: '\u5DE5\u5177\u53C2\u6570\u7684 JSON \u5B57\u7B26\u4E32\uFF0C\u5982 {"query":"..."}\uFF1B\u65E0\u53C2\u6570\u4F20 "{}"' }
|
|
3686
|
+
},
|
|
3687
|
+
required: ["server", "tool"]
|
|
3688
|
+
},
|
|
3689
|
+
safetyLevel: "danger" /* DANGER */,
|
|
3690
|
+
isSync: true,
|
|
3691
|
+
requireApproval: (args) => `\u26A0\uFE0F\u3010MCP \u5DE5\u5177\u5BA1\u6279\u3011
|
|
3692
|
+
\u670D\u52A1: ${args?.server} / \u5DE5\u5177: ${args?.tool}
|
|
3693
|
+
\u53C2\u6570: ${args?.args}`,
|
|
3694
|
+
async execute(args) {
|
|
3695
|
+
const { server, tool } = args ?? {};
|
|
3696
|
+
if (!server || !tool) return "\u274C [mcp_call] \u7F3A\u5C11 server \u6216 tool\uFF08\u5148\u7528 mcp_list_tools \u67E5\u76EE\u5F55\uFF09\u3002";
|
|
3697
|
+
let parsed = {};
|
|
3698
|
+
if (typeof args.args === "string" && args.args.trim() && args.args.trim() !== "{}") {
|
|
3699
|
+
try {
|
|
3700
|
+
parsed = JSON.parse(args.args);
|
|
3701
|
+
} catch {
|
|
3702
|
+
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`;
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
const c = findClient(server);
|
|
3706
|
+
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`;
|
|
3707
|
+
const result = await c.callTool(tool, parsed);
|
|
3708
|
+
return `[MCP ${server}/${tool}]
|
|
3709
|
+
${result}`;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
];
|
|
3318
3714
|
}
|
|
3319
3715
|
});
|
|
3320
3716
|
|
|
@@ -3350,68 +3746,44 @@ var init_httpExecutor = __esm({
|
|
|
3350
3746
|
}
|
|
3351
3747
|
});
|
|
3352
3748
|
|
|
3353
|
-
// ../core/src/
|
|
3354
|
-
|
|
3355
|
-
var
|
|
3356
|
-
|
|
3357
|
-
"../core/src/session/transcript.ts"() {
|
|
3749
|
+
// ../core/src/agent/inbox.ts
|
|
3750
|
+
var INBOX_MAX_ITEMS, sessionInboxes, pushSessionInbox, claimSessionInbox, flushLeftoverToTranscript;
|
|
3751
|
+
var init_inbox = __esm({
|
|
3752
|
+
"../core/src/agent/inbox.ts"() {
|
|
3358
3753
|
"use strict";
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
lines.push(JSON.parse(line));
|
|
3372
|
-
} catch {
|
|
3373
|
-
console.warn(`\u26A0\uFE0F [transcript] \u8DF3\u8FC7\u65E0\u6CD5\u89E3\u6790\u7684\u635F\u574F\u884C: ${line.slice(0, 120)}`);
|
|
3374
|
-
}
|
|
3375
|
-
}
|
|
3376
|
-
return lines;
|
|
3377
|
-
} catch (err) {
|
|
3378
|
-
if (err?.code === "ENOENT") return [];
|
|
3379
|
-
throw err;
|
|
3754
|
+
init_transcript();
|
|
3755
|
+
init_config();
|
|
3756
|
+
INBOX_MAX_ITEMS = 50;
|
|
3757
|
+
sessionInboxes = /* @__PURE__ */ new Map();
|
|
3758
|
+
pushSessionInbox = (sessionId, content) => {
|
|
3759
|
+
if (!appConfig.inboxSteering) return false;
|
|
3760
|
+
const text = (content ?? "").trim();
|
|
3761
|
+
if (!text) return false;
|
|
3762
|
+
const q = sessionInboxes.get(sessionId) ?? [];
|
|
3763
|
+
if (q.length >= INBOX_MAX_ITEMS) {
|
|
3764
|
+
console.warn(`[inbox] \u4F1A\u8BDD ${sessionId} \u961F\u5217\u5DF2\u6EE1\uFF08${INBOX_MAX_ITEMS}\uFF09\uFF0C\u4E22\u5F03\u65B0\u8F93\u5165`);
|
|
3765
|
+
return false;
|
|
3380
3766
|
}
|
|
3767
|
+
q.push(text);
|
|
3768
|
+
sessionInboxes.set(sessionId, q);
|
|
3769
|
+
return true;
|
|
3381
3770
|
};
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
}
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
try {
|
|
3397
|
-
beforeSize = (await fs8.stat(p)).size;
|
|
3398
|
-
} catch {
|
|
3399
|
-
}
|
|
3400
|
-
try {
|
|
3401
|
-
await fs8.appendFile(p, payload, "utf-8");
|
|
3402
|
-
return;
|
|
3403
|
-
} catch (e) {
|
|
3404
|
-
try {
|
|
3405
|
-
await fs8.truncate(p, beforeSize);
|
|
3406
|
-
} catch {
|
|
3407
|
-
}
|
|
3408
|
-
if (attempt === MAX_ATTEMPTS) throw e;
|
|
3409
|
-
await new Promise((r) => setTimeout(r, 50 * attempt));
|
|
3410
|
-
}
|
|
3411
|
-
}
|
|
3412
|
-
} catch (e) {
|
|
3413
|
-
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);
|
|
3771
|
+
claimSessionInbox = (sessionId) => {
|
|
3772
|
+
if (!appConfig.inboxSteering) return [];
|
|
3773
|
+
const q = sessionInboxes.get(sessionId);
|
|
3774
|
+
if (!q || q.length === 0) return [];
|
|
3775
|
+
sessionInboxes.delete(sessionId);
|
|
3776
|
+
return q;
|
|
3777
|
+
};
|
|
3778
|
+
flushLeftoverToTranscript = async (sessionId) => {
|
|
3779
|
+
const texts = claimSessionInbox(sessionId);
|
|
3780
|
+
for (const t of texts) {
|
|
3781
|
+
await appendMessage({ sessionId, role: "user", content: t });
|
|
3782
|
+
}
|
|
3783
|
+
if (texts.length > 0) {
|
|
3784
|
+
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`);
|
|
3414
3785
|
}
|
|
3786
|
+
return texts.length;
|
|
3415
3787
|
};
|
|
3416
3788
|
}
|
|
3417
3789
|
});
|
|
@@ -3538,6 +3910,9 @@ var init_planMode = __esm({
|
|
|
3538
3910
|
"git_status",
|
|
3539
3911
|
"git_log",
|
|
3540
3912
|
"inspect_dependencies",
|
|
3913
|
+
"get_diagnostics",
|
|
3914
|
+
"goto_definition",
|
|
3915
|
+
// ★ P0-A 补漏:LSP 导航/诊断恰是调研阶段最需要的(原白名单漂移漏登记,schema 档与 runtime 档共用此表)
|
|
3541
3916
|
"web_fetch",
|
|
3542
3917
|
"web_search"
|
|
3543
3918
|
// 只读研究类(虽为 DANGER 但不写本地状态;仍走各自审批)
|
|
@@ -3715,7 +4090,7 @@ var init_inject2 = __esm({
|
|
|
3715
4090
|
init_registry4();
|
|
3716
4091
|
AGENT_CATALOG_MARKER = "\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011";
|
|
3717
4092
|
AGENT_CATALOG_FENCE = "\u27E6DSC:AGENT_CATALOG\u27E7";
|
|
3718
|
-
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';
|
|
4093
|
+
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';
|
|
3719
4094
|
injectAgentCatalog = (message) => {
|
|
3720
4095
|
const catalog = getAgentCatalog();
|
|
3721
4096
|
if (!catalog) return;
|
|
@@ -3871,6 +4246,7 @@ var prepareToolsAndInjections;
|
|
|
3871
4246
|
var init_systemInjections = __esm({
|
|
3872
4247
|
"../core/src/agent/systemInjections.ts"() {
|
|
3873
4248
|
"use strict";
|
|
4249
|
+
init_config();
|
|
3874
4250
|
init_planMode();
|
|
3875
4251
|
init_toolFilter();
|
|
3876
4252
|
init_truncate();
|
|
@@ -3882,7 +4258,7 @@ var init_systemInjections = __esm({
|
|
|
3882
4258
|
init_common();
|
|
3883
4259
|
prepareToolsAndInjections = async (message, options, events) => {
|
|
3884
4260
|
const { toolSchemas, planMode, locale: locale2, outputStyle } = options;
|
|
3885
|
-
const rawToolsPreEnv = planMode ? filterToolsForPlanMode(toolSchemas ?? []) : appendPlanControlTools(toolSchemas ?? []);
|
|
4261
|
+
const rawToolsPreEnv = planMode && appConfig.planEnforcement === "schema" ? filterToolsForPlanMode(toolSchemas ?? []) : appendPlanControlTools(toolSchemas ?? []);
|
|
3886
4262
|
const validationCtx = {
|
|
3887
4263
|
sessionId: options.sessionId,
|
|
3888
4264
|
cwd: options.cwd ?? process.cwd(),
|
|
@@ -4648,9 +5024,19 @@ var init_fs = __esm({
|
|
|
4648
5024
|
}
|
|
4649
5025
|
if (hits.length === 0) return { ok: false, reason: "none", count: 0 };
|
|
4650
5026
|
if (!replaceAll && hits.length > 1) return { ok: false, reason: "conflict", count: hits.length };
|
|
4651
|
-
const newLines = newBlock.split("\n");
|
|
4652
5027
|
const out = [...contentLines];
|
|
4653
|
-
for (let k = hits.length - 1; k >= 0; k--)
|
|
5028
|
+
for (let k = hits.length - 1; k >= 0; k--) {
|
|
5029
|
+
const start = hits[k];
|
|
5030
|
+
let baseIndent = "";
|
|
5031
|
+
for (let j = start; j < start + oldLines.length; j++) {
|
|
5032
|
+
if (contentLines[j].trim() !== "") {
|
|
5033
|
+
baseIndent = contentLines[j].match(/^[ \t]*/)?.[0] ?? "";
|
|
5034
|
+
break;
|
|
5035
|
+
}
|
|
5036
|
+
}
|
|
5037
|
+
const aligned = baseIndent ? reindentToBase(newBlock, baseIndent) : newBlock;
|
|
5038
|
+
out.splice(start, oldLines.length, ...aligned.split("\n"));
|
|
5039
|
+
}
|
|
4654
5040
|
return { ok: true, content: out.join("\n"), count: hits.length };
|
|
4655
5041
|
};
|
|
4656
5042
|
diagnoseOldStr = (content, oldBlock) => {
|
|
@@ -8778,6 +9164,9 @@ var init_toolExecution = __esm({
|
|
|
8778
9164
|
init_backgroundTool();
|
|
8779
9165
|
init_backup();
|
|
8780
9166
|
init_autoPermission();
|
|
9167
|
+
init_loader();
|
|
9168
|
+
init_config();
|
|
9169
|
+
init_planMode();
|
|
8781
9170
|
applyPrivacyMasking = (rules3, args, output) => {
|
|
8782
9171
|
if (!rules3) return output;
|
|
8783
9172
|
try {
|
|
@@ -8803,6 +9192,7 @@ var init_toolExecution = __esm({
|
|
|
8803
9192
|
rawTools,
|
|
8804
9193
|
events,
|
|
8805
9194
|
permissionMode,
|
|
9195
|
+
planMode,
|
|
8806
9196
|
onUIEvent,
|
|
8807
9197
|
requestApproval: hostRequestApproval,
|
|
8808
9198
|
requestQuestion: hostRequestQuestion,
|
|
@@ -8829,6 +9219,10 @@ var init_toolExecution = __esm({
|
|
|
8829
9219
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: true, terminal: { kind: "exit_plan_mode", plan } };
|
|
8830
9220
|
}
|
|
8831
9221
|
if (calledName === "enter_plan_mode") {
|
|
9222
|
+
if (planMode) {
|
|
9223
|
+
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";
|
|
9224
|
+
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note2, resultForUser: note2, ok: true };
|
|
9225
|
+
}
|
|
8832
9226
|
const reason = typeof calledArgs?.reason === "string" ? calledArgs.reason : "";
|
|
8833
9227
|
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";
|
|
8834
9228
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: true, terminal: { kind: "enter_plan_mode", reason } };
|
|
@@ -8837,10 +9231,16 @@ var init_toolExecution = __esm({
|
|
|
8837
9231
|
const placeholder = "\uFF08\u5DF2\u4E2D\u6B62\uFF0C\u672A\u6267\u884C\uFF09";
|
|
8838
9232
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: placeholder, resultForUser: placeholder, ok: false, aborted: true };
|
|
8839
9233
|
}
|
|
9234
|
+
if (!parseFailed && planMode && appConfig.planEnforcement === "runtime" && calledName !== "enter_plan_mode" && calledName !== "exit_plan_mode" && !PLAN_ALLOWED_TOOLS.has(calledName)) {
|
|
9235
|
+
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`;
|
|
9236
|
+
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 } });
|
|
9237
|
+
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: false };
|
|
9238
|
+
}
|
|
8840
9239
|
const matchedTool = rawTools.find((t) => t.function.name === calledName);
|
|
8841
9240
|
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 };
|
|
8842
9241
|
let result = "";
|
|
8843
9242
|
let explicitOk = null;
|
|
9243
|
+
let postHookOverride;
|
|
8844
9244
|
if (parseFailed) {
|
|
8845
9245
|
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)}`;
|
|
8846
9246
|
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 } });
|
|
@@ -8848,6 +9248,23 @@ var init_toolExecution = __esm({
|
|
|
8848
9248
|
const level = matchedTool.function.safetyLevel;
|
|
8849
9249
|
let needApproval = level === "mutation" /* MUTATION */ || level === "danger" /* DANGER */;
|
|
8850
9250
|
let denied = false;
|
|
9251
|
+
let preHooksAdvanced = false;
|
|
9252
|
+
if (appConfig.hookRewrite) {
|
|
9253
|
+
preHooksAdvanced = true;
|
|
9254
|
+
let veto;
|
|
9255
|
+
try {
|
|
9256
|
+
veto = await runPreHooks(calledName, calledArgs, toolCtx);
|
|
9257
|
+
} catch (e) {
|
|
9258
|
+
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` };
|
|
9259
|
+
}
|
|
9260
|
+
if (veto.deny) {
|
|
9261
|
+
denied = true;
|
|
9262
|
+
result = veto.reason || `\u274C [Hook \u62E6\u622A]\uFF1Apre-hook \u62D2\u7EDD\u4E86 [${calledName}] \u7684\u6267\u884C\u3002`;
|
|
9263
|
+
} else if (veto.argsOverride !== void 0 && veto.argsOverride !== null && typeof veto.argsOverride === "object" && !Array.isArray(veto.argsOverride)) {
|
|
9264
|
+
console.log(`\u270F\uFE0F [Pre-hook] [${calledName}] args \u5DF2\u88AB hook \u6539\u5199`);
|
|
9265
|
+
calledArgs = veto.argsOverride;
|
|
9266
|
+
}
|
|
9267
|
+
}
|
|
8851
9268
|
const protectedPaths = calledName === "move_file" ? [calledArgs?.source, calledArgs?.destination] : isUndoTrigger(calledName) ? [calledArgs?.path] : [];
|
|
8852
9269
|
const hitProtected = protectedPaths.find((p) => typeof p === "string" && isProtectedWrite(p, toolCtx.cwd));
|
|
8853
9270
|
if (hitProtected) {
|
|
@@ -8856,7 +9273,7 @@ var init_toolExecution = __esm({
|
|
|
8856
9273
|
}
|
|
8857
9274
|
let perm = null;
|
|
8858
9275
|
try {
|
|
8859
|
-
perm = checkPermission(calledName, calledArgs);
|
|
9276
|
+
perm = checkPermission(resolveMcpPermissionName(calledName, calledArgs), calledArgs);
|
|
8860
9277
|
if (perm === "deny") {
|
|
8861
9278
|
denied = true;
|
|
8862
9279
|
result = `\u274C [\u6743\u9650\u89C4\u5219]\uFF1A[${calledName}] \u88AB\u6743\u9650\u89C4\u5219 deny \u62D2\u7EDD\u3002`;
|
|
@@ -8882,7 +9299,7 @@ var init_toolExecution = __esm({
|
|
|
8882
9299
|
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`;
|
|
8883
9300
|
}
|
|
8884
9301
|
if (needApproval && !denied) {
|
|
8885
|
-
const auto = await runAutoCheck(calledName, calledArgs, toolCtx, permissionMode === "auto");
|
|
9302
|
+
const auto = await runAutoCheck(resolveMcpPermissionName(calledName, calledArgs), calledArgs, toolCtx, permissionMode === "auto");
|
|
8886
9303
|
if (auto === "allow") {
|
|
8887
9304
|
needApproval = false;
|
|
8888
9305
|
} else if (auto === "deny") {
|
|
@@ -8913,7 +9330,7 @@ var init_toolExecution = __esm({
|
|
|
8913
9330
|
}
|
|
8914
9331
|
}
|
|
8915
9332
|
}
|
|
8916
|
-
if (!denied) {
|
|
9333
|
+
if (!denied && !preHooksAdvanced) {
|
|
8917
9334
|
let veto;
|
|
8918
9335
|
try {
|
|
8919
9336
|
veto = await runPreHooks(calledName, calledArgs, toolCtx);
|
|
@@ -8957,9 +9374,12 @@ ${result}`;
|
|
|
8957
9374
|
result = `\u5DE5\u5177\u6267\u884C\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`;
|
|
8958
9375
|
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 } });
|
|
8959
9376
|
}
|
|
8960
|
-
|
|
9377
|
+
try {
|
|
9378
|
+
const post = await runPostHooks(calledName, calledArgs, result, toolCtx);
|
|
9379
|
+
postHookOverride = post?.resultOverride;
|
|
9380
|
+
} catch (e) {
|
|
8961
9381
|
console.warn(`\u26A0\uFE0F post-hook [${calledName}] \u5F02\u5E38\uFF08\u5DF2\u5FFD\u7565\uFF09:`, e?.message ?? e);
|
|
8962
|
-
}
|
|
9382
|
+
}
|
|
8963
9383
|
}
|
|
8964
9384
|
} else {
|
|
8965
9385
|
result = `\u9519\u8BEF\uFF1A\u672A\u77E5\u5DE5\u5177 "${calledName}" \u6216\u8BE5\u5DE5\u5177\u65E0\u53EF\u6267\u884C\u51FD\u6570`;
|
|
@@ -8980,6 +9400,10 @@ ${result}`;
|
|
|
8980
9400
|
} catch {
|
|
8981
9401
|
}
|
|
8982
9402
|
}
|
|
9403
|
+
if (postHookOverride !== void 0) {
|
|
9404
|
+
console.log(`\u270F\uFE0F [Post-hook] [${calledName}] \u6A21\u578B\u89C6\u56FE\u7ED3\u679C\u5DF2\u88AB hook \u6539\u5199`);
|
|
9405
|
+
resultForModel = truncateToolResult(postHookOverride, matchedTool?.function?.maxOutputCharacters);
|
|
9406
|
+
}
|
|
8983
9407
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel, resultForUser, ok };
|
|
8984
9408
|
};
|
|
8985
9409
|
}
|
|
@@ -9503,6 +9927,18 @@ async function* runAgent(message, options) {
|
|
|
9503
9927
|
let lastRealPromptTokens = persistedCalib.lastRealPromptTokens;
|
|
9504
9928
|
let lastCachedTokens = persistedCalib.lastCachedTokens;
|
|
9505
9929
|
const breaker = createRepeatBreaker({ sessionId, depth, llmDecisionSource, startTime, events });
|
|
9930
|
+
const runId = createUUID();
|
|
9931
|
+
let usageSum;
|
|
9932
|
+
const addUsage = (u) => {
|
|
9933
|
+
if (!u) return;
|
|
9934
|
+
usageSum = {
|
|
9935
|
+
prompt_tokens: (usageSum?.prompt_tokens ?? 0) + (u.prompt_tokens ?? 0),
|
|
9936
|
+
completion_tokens: (usageSum?.completion_tokens ?? 0) + (u.completion_tokens ?? 0),
|
|
9937
|
+
total_tokens: (usageSum?.total_tokens ?? 0) + (u.total_tokens ?? 0),
|
|
9938
|
+
cached_tokens: (usageSum?.cached_tokens ?? 0) + (u.cached_tokens ?? 0)
|
|
9939
|
+
};
|
|
9940
|
+
};
|
|
9941
|
+
await appendEvent(sessionId, { dscEvent: "run.start", runId, depth });
|
|
9506
9942
|
try {
|
|
9507
9943
|
while (true) {
|
|
9508
9944
|
round++;
|
|
@@ -9530,6 +9966,14 @@ async function* runAgent(message, options) {
|
|
|
9530
9966
|
yield { type: "final", text: lastContent || "\uFF08\u5DF2\u4E2D\u6B62\uFF09" };
|
|
9531
9967
|
return;
|
|
9532
9968
|
}
|
|
9969
|
+
const inboxTexts = claimSessionInbox(sessionId);
|
|
9970
|
+
if (inboxTexts.length > 0) {
|
|
9971
|
+
for (const t of inboxTexts) {
|
|
9972
|
+
message.push({ role: "user", content: t });
|
|
9973
|
+
await appendMessage({ sessionId, role: "user", content: t });
|
|
9974
|
+
}
|
|
9975
|
+
yield { type: "inbox.claimed", texts: inboxTexts };
|
|
9976
|
+
}
|
|
9533
9977
|
yield { type: "round.start", round };
|
|
9534
9978
|
try {
|
|
9535
9979
|
await ensureFitsWindow(
|
|
@@ -9596,6 +10040,7 @@ async function* runAgent(message, options) {
|
|
|
9596
10040
|
lastRealPromptTokens = infResult.usage.prompt_tokens;
|
|
9597
10041
|
lastCachedTokens = infResult.usage.cached_tokens;
|
|
9598
10042
|
}
|
|
10043
|
+
addUsage(infResult.usage);
|
|
9599
10044
|
const assistantMessage = infResult.assistantMessage;
|
|
9600
10045
|
message.push(assistantMessage);
|
|
9601
10046
|
await appendMessage({ ...assistantMessage, sessionId });
|
|
@@ -9604,6 +10049,7 @@ async function* runAgent(message, options) {
|
|
|
9604
10049
|
}
|
|
9605
10050
|
const tcCount = assistantMessage.tool_calls?.length ?? 0;
|
|
9606
10051
|
if (!assistantMessage.tool_calls || assistantMessage.tool_calls.length === 0) {
|
|
10052
|
+
await appendEvent(sessionId, { dscEvent: "round.end", runId, round, usage: infResult.usage });
|
|
9607
10053
|
const finalText = (typeof assistantMessage.content === "string" ? assistantMessage.content : "") || "";
|
|
9608
10054
|
const intercepted = nudges.interceptFinal(finalText, round);
|
|
9609
10055
|
if (intercepted) continue;
|
|
@@ -9614,6 +10060,11 @@ async function* runAgent(message, options) {
|
|
|
9614
10060
|
const repeatVerdict = breaker.check(assistantMessage.tool_calls, round, lastContent);
|
|
9615
10061
|
if (repeatVerdict.tripped) {
|
|
9616
10062
|
stopReason = "repeat";
|
|
10063
|
+
for (const tc of assistantMessage.tool_calls) {
|
|
10064
|
+
const ph = "\uFF08\u91CD\u590D\u8C03\u7528\u7194\u65AD\uFF0C\u672A\u6267\u884C\uFF09";
|
|
10065
|
+
message.push({ role: "tool", tool_call_id: tc.id, content: ph });
|
|
10066
|
+
await appendMessage({ sessionId, role: "tool", tool_call_id: tc.id, content: ph });
|
|
10067
|
+
}
|
|
9617
10068
|
yield { type: "final", text: repeatVerdict.text };
|
|
9618
10069
|
return;
|
|
9619
10070
|
}
|
|
@@ -9628,6 +10079,8 @@ async function* runAgent(message, options) {
|
|
|
9628
10079
|
rawTools,
|
|
9629
10080
|
events,
|
|
9630
10081
|
permissionMode: options.permissionMode,
|
|
10082
|
+
planMode: !!options.planMode,
|
|
10083
|
+
// ★ P0-A runtime 档:计划期写工具在 processToolCall 执行层拒绝(工具表恒定不裁剪)
|
|
9631
10084
|
onUIEvent: options.onUIEvent,
|
|
9632
10085
|
requestApproval: options.requestApproval,
|
|
9633
10086
|
requestQuestion: options.requestQuestion,
|
|
@@ -9645,6 +10098,7 @@ async function* runAgent(message, options) {
|
|
|
9645
10098
|
yield { type: "final", text: scheduleResult.terminalText };
|
|
9646
10099
|
return;
|
|
9647
10100
|
}
|
|
10101
|
+
await appendEvent(sessionId, { dscEvent: "round.end", runId, round, usage: infResult.usage });
|
|
9648
10102
|
}
|
|
9649
10103
|
} catch (toolErr) {
|
|
9650
10104
|
if (signal?.aborted) {
|
|
@@ -9658,6 +10112,14 @@ async function* runAgent(message, options) {
|
|
|
9658
10112
|
\uFF08\u5DE5\u5177\u6267\u884C\u5F02\u5E38\uFF1A${errMsg}\uFF09` };
|
|
9659
10113
|
return;
|
|
9660
10114
|
} finally {
|
|
10115
|
+
try {
|
|
10116
|
+
await flushLeftoverToTranscript(sessionId);
|
|
10117
|
+
} catch {
|
|
10118
|
+
}
|
|
10119
|
+
try {
|
|
10120
|
+
await appendEvent(sessionId, { dscEvent: "run.end", runId, stopReason: signal?.aborted ? "aborted" : stopReason, rounds: round, usage: usageSum });
|
|
10121
|
+
} catch {
|
|
10122
|
+
}
|
|
9661
10123
|
try {
|
|
9662
10124
|
const reason = signal?.aborted ? "aborted" : stopReason;
|
|
9663
10125
|
await dispatch("Stop", { sessionId, cwd, lastText: lastContent || "", reason });
|
|
@@ -9673,6 +10135,8 @@ var init_runAgent = __esm({
|
|
|
9673
10135
|
"../core/src/agent/runAgent.ts"() {
|
|
9674
10136
|
"use strict";
|
|
9675
10137
|
init_transcript();
|
|
10138
|
+
init_inbox();
|
|
10139
|
+
init_common();
|
|
9676
10140
|
init_contextCore();
|
|
9677
10141
|
init_store();
|
|
9678
10142
|
init_truncate();
|
|
@@ -9685,17 +10149,30 @@ var init_runAgent = __esm({
|
|
|
9685
10149
|
}
|
|
9686
10150
|
});
|
|
9687
10151
|
|
|
9688
|
-
// ../core/src/session/
|
|
9689
|
-
var repairOrphanToolCalls,
|
|
9690
|
-
var
|
|
9691
|
-
"../core/src/session/
|
|
10152
|
+
// ../core/src/session/recovery.ts
|
|
10153
|
+
var detectInterruption, repairOrphanToolCalls, reconcileCompaction, recoverSession;
|
|
10154
|
+
var init_recovery = __esm({
|
|
10155
|
+
"../core/src/session/recovery.ts"() {
|
|
9692
10156
|
"use strict";
|
|
9693
|
-
init_contextCore();
|
|
9694
10157
|
init_transcript();
|
|
9695
10158
|
init_store();
|
|
9696
|
-
|
|
9697
|
-
|
|
10159
|
+
detectInterruption = (lines) => {
|
|
10160
|
+
let sawEvents = false;
|
|
10161
|
+
let lastStart;
|
|
10162
|
+
const closed = /* @__PURE__ */ new Set();
|
|
10163
|
+
for (const l of lines) {
|
|
10164
|
+
if (!isEventLine(l)) continue;
|
|
10165
|
+
sawEvents = true;
|
|
10166
|
+
if (l.dscEvent === "run.start") lastStart = l;
|
|
10167
|
+
else if (l.dscEvent === "run.end" || l.dscEvent === "run.abandoned") closed.add(l.runId);
|
|
10168
|
+
}
|
|
10169
|
+
if (!sawEvents || !lastStart) return { kind: "legacy" };
|
|
10170
|
+
return closed.has(lastStart.runId) ? { kind: "clean" } : { kind: "crashed", runId: lastStart.runId };
|
|
10171
|
+
};
|
|
10172
|
+
repairOrphanToolCalls = (msgs, confirmedCrash) => {
|
|
10173
|
+
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";
|
|
9698
10174
|
const out = [];
|
|
10175
|
+
const repairedToolCallIds = [];
|
|
9699
10176
|
for (let i = 0; i < msgs.length; i++) {
|
|
9700
10177
|
const m = msgs[i];
|
|
9701
10178
|
out.push(m);
|
|
@@ -9708,13 +10185,60 @@ var init_content = __esm({
|
|
|
9708
10185
|
}
|
|
9709
10186
|
for (const tc of m.tool_calls) {
|
|
9710
10187
|
if (tc.id && !answered.has(tc.id)) {
|
|
9711
|
-
out.push({ role: "tool", tool_call_id: tc.id, content:
|
|
10188
|
+
out.push({ role: "tool", tool_call_id: tc.id, content: placeholder });
|
|
10189
|
+
repairedToolCallIds.push(tc.id);
|
|
9712
10190
|
}
|
|
9713
10191
|
}
|
|
9714
10192
|
}
|
|
9715
10193
|
}
|
|
9716
|
-
return out;
|
|
10194
|
+
return { msgs: out, repairedToolCallIds, confirmedCrash };
|
|
10195
|
+
};
|
|
10196
|
+
reconcileCompaction = (state, lines) => {
|
|
10197
|
+
let last;
|
|
10198
|
+
for (const l of lines) {
|
|
10199
|
+
if (isEventLine(l) && l.dscEvent === "compaction") last = l;
|
|
10200
|
+
}
|
|
10201
|
+
if (!last) return { archivedMessageCount: state.archivedMessageCount, rollingSummary: state.rollingSummary, desync: "legacy" };
|
|
10202
|
+
let desync = "none";
|
|
10203
|
+
if (last.archivedMessageCount !== state.archivedMessageCount) {
|
|
10204
|
+
desync = state.archivedMessageCount > last.archivedMessageCount ? "state-ahead" : "event-ahead";
|
|
10205
|
+
console.warn(
|
|
10206
|
+
`\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`
|
|
10207
|
+
);
|
|
10208
|
+
}
|
|
10209
|
+
return { archivedMessageCount: state.archivedMessageCount, rollingSummary: state.rollingSummary, desync };
|
|
9717
10210
|
};
|
|
10211
|
+
recoverSession = async (sessionId) => {
|
|
10212
|
+
const lines = await readTranscriptLines(sessionId);
|
|
10213
|
+
const interruption = detectInterruption(lines);
|
|
10214
|
+
if (interruption.kind === "crashed") {
|
|
10215
|
+
await appendEvent(sessionId, {
|
|
10216
|
+
dscEvent: "run.abandoned",
|
|
10217
|
+
runId: interruption.runId,
|
|
10218
|
+
reason: "run.end missing: interrupted by process exit/kill"
|
|
10219
|
+
});
|
|
10220
|
+
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`);
|
|
10221
|
+
}
|
|
10222
|
+
const state = await getRollingState(sessionId);
|
|
10223
|
+
const compaction = reconcileCompaction(
|
|
10224
|
+
{ archivedMessageCount: state.archivedMessageCount, rollingSummary: state.rollingSummary },
|
|
10225
|
+
lines
|
|
10226
|
+
);
|
|
10227
|
+
return { interruption, compaction };
|
|
10228
|
+
};
|
|
10229
|
+
}
|
|
10230
|
+
});
|
|
10231
|
+
|
|
10232
|
+
// ../core/src/session/content.ts
|
|
10233
|
+
var decayOldToolResults, buildContextMessages;
|
|
10234
|
+
var init_content = __esm({
|
|
10235
|
+
"../core/src/session/content.ts"() {
|
|
10236
|
+
"use strict";
|
|
10237
|
+
init_contextCore();
|
|
10238
|
+
init_transcript();
|
|
10239
|
+
init_store();
|
|
10240
|
+
init_config();
|
|
10241
|
+
init_recovery();
|
|
9718
10242
|
decayOldToolResults = (msgs) => {
|
|
9719
10243
|
const units = groupUnits(msgs);
|
|
9720
10244
|
const cutoffUnitIdx = Math.max(0, units.length - appConfig.KEEP_RECENT_UNITS);
|
|
@@ -9740,21 +10264,28 @@ var init_content = __esm({
|
|
|
9740
10264
|
});
|
|
9741
10265
|
};
|
|
9742
10266
|
buildContextMessages = async (sessionId, currentUserMsg, systemPrompt) => {
|
|
9743
|
-
const
|
|
10267
|
+
const lines = await readTranscriptLines(sessionId);
|
|
9744
10268
|
const store = await getRollingState(sessionId);
|
|
10269
|
+
const eventAware = appConfig.transcriptEvents || lines.some(isEventLine);
|
|
10270
|
+
const recovery = eventAware ? await recoverSession(sessionId) : {
|
|
10271
|
+
interruption: { kind: "legacy" },
|
|
10272
|
+
compaction: { archivedMessageCount: store.archivedMessageCount, rollingSummary: store.rollingSummary, desync: "legacy" }
|
|
10273
|
+
};
|
|
10274
|
+
const all = lines.filter((l) => !isEventLine(l)).map(cleanMsg);
|
|
9745
10275
|
const result = [
|
|
9746
10276
|
{ role: "system", content: systemPrompt },
|
|
9747
10277
|
// 存储系统提示词
|
|
9748
|
-
{ role: "system", content:
|
|
10278
|
+
{ role: "system", content: recovery.compaction.rollingSummary }
|
|
9749
10279
|
// 后续存储摘要使用
|
|
9750
10280
|
];
|
|
9751
|
-
const archivedMessageCount =
|
|
10281
|
+
const archivedMessageCount = recovery.compaction.archivedMessageCount;
|
|
9752
10282
|
const messageAll = all.slice(archivedMessageCount);
|
|
9753
10283
|
if (messageAll.length === 0) {
|
|
9754
10284
|
result.push(currentUserMsg);
|
|
9755
10285
|
return result;
|
|
9756
10286
|
}
|
|
9757
|
-
|
|
10287
|
+
const repair = repairOrphanToolCalls(messageAll, recovery.interruption.kind === "crashed");
|
|
10288
|
+
result.push(...decayOldToolResults(repair.msgs));
|
|
9758
10289
|
result.push(currentUserMsg);
|
|
9759
10290
|
return result;
|
|
9760
10291
|
};
|
|
@@ -9818,7 +10349,8 @@ var init_subagent = __esm({
|
|
|
9818
10349
|
parentSystemPrompt
|
|
9819
10350
|
].join("\n");
|
|
9820
10351
|
const allTools = getGlobalTools();
|
|
9821
|
-
const
|
|
10352
|
+
const wantsMcp = manifest?.tools.some((t) => t === "mcp_call" || t === "mcp_list_tools" || t.startsWith("mcp__")) ?? false;
|
|
10353
|
+
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));
|
|
9822
10354
|
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)}..."`);
|
|
9823
10355
|
try {
|
|
9824
10356
|
const subMessages = await buildContextMessages(subSessionId, { role: "user", content: task }, subSystem);
|
|
@@ -9884,7 +10416,7 @@ var init_subagent = __esm({
|
|
|
9884
10416
|
// ../core/src/hooks/loader.ts
|
|
9885
10417
|
import fs27 from "fs/promises";
|
|
9886
10418
|
import path29 from "path";
|
|
9887
|
-
var readHooksConfig, appendValidated, validateRule, parseAgentDecision, compileRule2, loadHooks, initHooks;
|
|
10419
|
+
var readHooksConfig, appendValidated, validateRule, parseStdoutDecision, parseAgentDecision, compileRule2, loadHooks, initHooks;
|
|
9888
10420
|
var init_loader4 = __esm({
|
|
9889
10421
|
"../core/src/hooks/loader.ts"() {
|
|
9890
10422
|
"use strict";
|
|
@@ -10028,6 +10560,24 @@ var init_loader4 = __esm({
|
|
|
10028
10560
|
requireApproval: raw.requireApproval === true ? true : void 0
|
|
10029
10561
|
};
|
|
10030
10562
|
};
|
|
10563
|
+
parseStdoutDecision = (stdout) => {
|
|
10564
|
+
const s = (stdout ?? "").trim();
|
|
10565
|
+
if (!s || !s.startsWith("{")) return void 0;
|
|
10566
|
+
try {
|
|
10567
|
+
const parsed = JSON.parse(s);
|
|
10568
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
10569
|
+
const out = {};
|
|
10570
|
+
if (parsed.deny === true) {
|
|
10571
|
+
out.deny = true;
|
|
10572
|
+
if (typeof parsed.reason === "string" && parsed.reason) out.reason = parsed.reason;
|
|
10573
|
+
}
|
|
10574
|
+
if (parsed.argsOverride !== void 0) out.argsOverride = parsed.argsOverride;
|
|
10575
|
+
if (typeof parsed.resultOverride === "string" && parsed.resultOverride) out.resultOverride = parsed.resultOverride;
|
|
10576
|
+
return out.deny !== void 0 || out.argsOverride !== void 0 || out.resultOverride !== void 0 ? out : void 0;
|
|
10577
|
+
} catch {
|
|
10578
|
+
return void 0;
|
|
10579
|
+
}
|
|
10580
|
+
};
|
|
10031
10581
|
parseAgentDecision = (output) => {
|
|
10032
10582
|
const lines = (output ?? "").split(/\r?\n/);
|
|
10033
10583
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
@@ -10096,9 +10646,15 @@ var init_loader4 = __esm({
|
|
|
10096
10646
|
}
|
|
10097
10647
|
try {
|
|
10098
10648
|
const parsed = JSON.parse(res.responseBody);
|
|
10099
|
-
if (parsed && typeof parsed === "object" && parsed
|
|
10100
|
-
|
|
10101
|
-
|
|
10649
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
10650
|
+
if (parsed.deny === true) {
|
|
10651
|
+
const reason = typeof parsed.reason === "string" ? parsed.reason : `hook http \u62D2\u7EDD\uFF08status ${res.status}\uFF09`;
|
|
10652
|
+
return { deny: true, reason };
|
|
10653
|
+
}
|
|
10654
|
+
const out = {};
|
|
10655
|
+
if (parsed.argsOverride !== void 0) out.argsOverride = parsed.argsOverride;
|
|
10656
|
+
if (typeof parsed.resultOverride === "string" && parsed.resultOverride) out.resultOverride = parsed.resultOverride;
|
|
10657
|
+
if (out.argsOverride !== void 0 || out.resultOverride !== void 0) return out;
|
|
10102
10658
|
}
|
|
10103
10659
|
} catch {
|
|
10104
10660
|
}
|
|
@@ -10127,6 +10683,10 @@ var init_loader4 = __esm({
|
|
|
10127
10683
|
const detail = res.stderr ? `\uFF1A${res.stderr.slice(0, 200)}` : "";
|
|
10128
10684
|
return { deny: true, reason: `hook \u9000\u51FA\u7801 ${res.exitCode}${detail}` };
|
|
10129
10685
|
}
|
|
10686
|
+
if (res.exitCode === 0) {
|
|
10687
|
+
const out = parseStdoutDecision(res.stdout);
|
|
10688
|
+
if (out) return out;
|
|
10689
|
+
}
|
|
10130
10690
|
return { deny: false };
|
|
10131
10691
|
}
|
|
10132
10692
|
};
|
|
@@ -10361,9 +10921,9 @@ var init_loader6 = __esm({
|
|
|
10361
10921
|
);
|
|
10362
10922
|
for (const { item: m, file, source } of picked) {
|
|
10363
10923
|
if (m.tools.length > 0) {
|
|
10364
|
-
const unknown = m.tools.filter((t) => !known.has(t));
|
|
10924
|
+
const unknown = m.tools.filter((t) => !known.has(t) && !t.startsWith("mcp__"));
|
|
10365
10925
|
if (unknown.length) console.warn(`\u26A0\uFE0F [agents] ${m.name} \u58F0\u660E\u4E86\u672A\u77E5\u5DE5\u5177 [${unknown.join(", ")}]\uFF0C\u5DF2\u5254\u9664`);
|
|
10366
|
-
m.tools = m.tools.filter((t) => known.has(t));
|
|
10926
|
+
m.tools = m.tools.filter((t) => known.has(t) || t.startsWith("mcp__"));
|
|
10367
10927
|
}
|
|
10368
10928
|
if (source === "project") {
|
|
10369
10929
|
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`);
|
|
@@ -10564,16 +11124,26 @@ var init_bootstrap = __esm({
|
|
|
10564
11124
|
if (typeof AbortSignal.any !== "function" || typeof AbortSignal.timeout !== "function") {
|
|
10565
11125
|
console.error("\u274C \u5F53\u524D Node \u7248\u672C\u7F3A\u5C11 AbortSignal.any/timeout\uFF08\u9700 Node 20.3+\uFF09\uFF0Cweb_fetch \u76F8\u5173\u80FD\u529B\u5C06\u4E0D\u53EF\u7528\uFF0C\u5EFA\u8BAE\u5347\u7EA7 Node\u3002");
|
|
10566
11126
|
}
|
|
10567
|
-
await
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
11127
|
+
await Promise.all([
|
|
11128
|
+
// P2-13 worktree 孤儿清扫:进程重启 = 上次 run_workflow 未清理的 worktree 全是孤儿。best-effort,失败不阻断。
|
|
11129
|
+
sweepOrphanedWorktrees().catch((e) => console.warn(`worktree \u542F\u52A8\u671F\u6E05\u626B\u5931\u8D25\uFF08\u5DF2\u5FFD\u7565\uFF09: ${e?.message ?? e}`)),
|
|
11130
|
+
// 连接配置的 MCP 服务器并注入其工具(★ 通常最慢:spawn 子进程 + stdio 握手;无配置静默跳过)。仅读全局 mcp.json,不受 includeProject 影响。
|
|
11131
|
+
initMcpTools(into),
|
|
11132
|
+
// 加载声明式 hooks(settings.json;无配置时静默跳过)。未信任时跳过项目级(hooks 会 spawn 执行命令,高风险)
|
|
11133
|
+
initHooks(includeProject),
|
|
11134
|
+
// 加载细粒度权限规则(settings.json permissions.{allow,deny,ask};无配置时静默跳过)。未信任时跳过项目级(防 auto-approve 绕审批)
|
|
11135
|
+
initPermissions(includeProject),
|
|
11136
|
+
// 缓存项目指引(CLAUDE.md/AGENTS.md/AGENT.md)到内存,供每轮自动注入 system prompt。未信任时整体跳过(无全局源,防提示注入)
|
|
11137
|
+
initProjectGuide(includeProject),
|
|
11138
|
+
// 加载斜杠命令(builtin/global/project;用户输入 /<name> 时前置展开)。未信任时跳过项目级
|
|
11139
|
+
initCommands(includeProject),
|
|
11140
|
+
// 加载输出风格(builtin/global/project;用户经 CLI /output-style <name> 选用,runAgent 注入 persona)。未信任时跳过项目级
|
|
11141
|
+
initOutputStyles(includeProject),
|
|
11142
|
+
// 加载持久记忆(global/project;runAgent 注入一行索引,memory_read 按需召回全文)。未信任时跳过项目级(防提示注入)
|
|
11143
|
+
initMemories(includeProject)
|
|
11144
|
+
]);
|
|
10571
11145
|
await initSkills(into, includeProject);
|
|
10572
11146
|
await initAgents(into, includeProject);
|
|
10573
|
-
await initProjectGuide(includeProject);
|
|
10574
|
-
await initCommands(includeProject);
|
|
10575
|
-
await initOutputStyles(includeProject);
|
|
10576
|
-
await initMemories(includeProject);
|
|
10577
11147
|
return () => {
|
|
10578
11148
|
try {
|
|
10579
11149
|
disposeAllMcpClients();
|
|
@@ -11219,6 +11789,124 @@ ${lines.join("\n")}
|
|
|
11219
11789
|
}
|
|
11220
11790
|
});
|
|
11221
11791
|
|
|
11792
|
+
// ../core/src/session/fork.ts
|
|
11793
|
+
import fs37 from "fs/promises";
|
|
11794
|
+
var listForkAnchors, derivePrefix, forkSession;
|
|
11795
|
+
var init_fork = __esm({
|
|
11796
|
+
"../core/src/session/fork.ts"() {
|
|
11797
|
+
"use strict";
|
|
11798
|
+
init_common();
|
|
11799
|
+
init_transcript();
|
|
11800
|
+
init_store();
|
|
11801
|
+
listForkAnchors = (lines) => {
|
|
11802
|
+
const anchors = [];
|
|
11803
|
+
let lastUser = "";
|
|
11804
|
+
for (const l of lines) {
|
|
11805
|
+
if (isEventLine(l)) continue;
|
|
11806
|
+
const row = l;
|
|
11807
|
+
if (row?.role === "user") {
|
|
11808
|
+
lastUser = typeof row.content === "string" ? row.content : "";
|
|
11809
|
+
} else if (row?.role === "assistant") {
|
|
11810
|
+
const content = typeof row.content === "string" ? row.content : "";
|
|
11811
|
+
const names = Array.isArray(row.tool_calls) ? row.tool_calls.map((tc) => tc?.function?.name ?? "").filter(Boolean).join(", ") : "";
|
|
11812
|
+
anchors.push({
|
|
11813
|
+
lineId: row.id,
|
|
11814
|
+
roundNo: anchors.length + 1,
|
|
11815
|
+
userPreview: lastUser,
|
|
11816
|
+
assistantPreview: content || (names ? `\u{1F527} ${names}` : "(\u7A7A\u56DE\u590D)")
|
|
11817
|
+
});
|
|
11818
|
+
}
|
|
11819
|
+
}
|
|
11820
|
+
return anchors;
|
|
11821
|
+
};
|
|
11822
|
+
derivePrefix = (lines, upToLineId) => {
|
|
11823
|
+
let endIdx = lines.length - 1;
|
|
11824
|
+
if (upToLineId !== void 0) {
|
|
11825
|
+
const idx = lines.findIndex((l) => l?.id === upToLineId);
|
|
11826
|
+
if (idx < 0) throw new Error(`upToLineId\uFF08${upToLineId}\uFF09\u5728\u6E90\u4F1A\u8BDD\u8F6C\u5F55\u4E2D\u672A\u627E\u5230`);
|
|
11827
|
+
endIdx = idx;
|
|
11828
|
+
} else {
|
|
11829
|
+
let lastEnd = -1;
|
|
11830
|
+
let lastStart = -1;
|
|
11831
|
+
lines.forEach((l, i) => {
|
|
11832
|
+
if (!isEventLine(l)) return;
|
|
11833
|
+
if (l.dscEvent === "run.end" || l.dscEvent === "run.abandoned") lastEnd = i;
|
|
11834
|
+
else if (l.dscEvent === "run.start") lastStart = i;
|
|
11835
|
+
});
|
|
11836
|
+
if (lastEnd >= 0) endIdx = lastEnd;
|
|
11837
|
+
else if (lastStart >= 0) endIdx = lastStart - 1;
|
|
11838
|
+
}
|
|
11839
|
+
const prefix = endIdx < 0 ? [] : lines.slice(0, endIdx + 1);
|
|
11840
|
+
let archivedMessageCount = 0;
|
|
11841
|
+
let rollingSummary = "";
|
|
11842
|
+
let lastStartRunId;
|
|
11843
|
+
const closed = /* @__PURE__ */ new Set();
|
|
11844
|
+
for (const l of prefix) {
|
|
11845
|
+
if (!isEventLine(l)) continue;
|
|
11846
|
+
if (l.dscEvent === "compaction") {
|
|
11847
|
+
archivedMessageCount = l.archivedMessageCount;
|
|
11848
|
+
rollingSummary = l.summary;
|
|
11849
|
+
} else if (l.dscEvent === "run.start") {
|
|
11850
|
+
lastStartRunId = l.runId;
|
|
11851
|
+
} else if (l.dscEvent === "run.end" || l.dscEvent === "run.abandoned") {
|
|
11852
|
+
closed.add(l.runId);
|
|
11853
|
+
}
|
|
11854
|
+
}
|
|
11855
|
+
const unclosedRunId = lastStartRunId && !closed.has(lastStartRunId) ? lastStartRunId : void 0;
|
|
11856
|
+
return { lines: prefix, archivedMessageCount, rollingSummary, unclosedRunId };
|
|
11857
|
+
};
|
|
11858
|
+
forkSession = async (sourceId, upToLineId) => {
|
|
11859
|
+
assertSafeSessionId(sourceId);
|
|
11860
|
+
const lines = await readTranscriptLines(sourceId);
|
|
11861
|
+
if (lines.length === 0) throw new Error("\u6E90\u4F1A\u8BDD\u4E0D\u5B58\u5728\u6216\u8F6C\u5F55\u4E3A\u7A7A");
|
|
11862
|
+
const prefix = derivePrefix(lines, upToLineId);
|
|
11863
|
+
const newId = createUUID();
|
|
11864
|
+
await ensureSessionsDir(newId);
|
|
11865
|
+
const rawText = await fs37.readFile(getTranscriptPath(sourceId), "utf-8");
|
|
11866
|
+
const kept = [];
|
|
11867
|
+
let good = 0;
|
|
11868
|
+
for (const s of rawText.split("\n")) {
|
|
11869
|
+
if (good >= prefix.lines.length) break;
|
|
11870
|
+
kept.push(s);
|
|
11871
|
+
const t = s.trim();
|
|
11872
|
+
if (!t) continue;
|
|
11873
|
+
try {
|
|
11874
|
+
JSON.parse(t);
|
|
11875
|
+
good++;
|
|
11876
|
+
} catch {
|
|
11877
|
+
}
|
|
11878
|
+
}
|
|
11879
|
+
let payload = kept.join("\n");
|
|
11880
|
+
if (payload.length > 0 && !payload.endsWith("\n")) payload += "\n";
|
|
11881
|
+
await fs37.writeFile(getTranscriptPath(newId), payload, "utf-8");
|
|
11882
|
+
const srcState = await readStore(sourceId);
|
|
11883
|
+
const srcRolling = await getRollingState(sourceId);
|
|
11884
|
+
const legacy = !lines.some(isEventLine);
|
|
11885
|
+
const wholeFile = prefix.lines.length === lines.length;
|
|
11886
|
+
const archivedMessageCount = legacy && wholeFile ? srcRolling.archivedMessageCount : prefix.archivedMessageCount;
|
|
11887
|
+
const rollingSummary = legacy && wholeFile ? srcRolling.rollingSummary : prefix.rollingSummary;
|
|
11888
|
+
const srcTitle = typeof srcState?.title === "string" && srcState.title ? srcState.title : "\u4F1A\u8BDD";
|
|
11889
|
+
await writeStore(newId, {
|
|
11890
|
+
sessionId: newId,
|
|
11891
|
+
createAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11892
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11893
|
+
archivedMessageCount,
|
|
11894
|
+
rollingSummary,
|
|
11895
|
+
consecutiveFailures: 0,
|
|
11896
|
+
title: `${srcTitle}(\u5206\u53C9)`.slice(0, 200),
|
|
11897
|
+
// ★ 校准数据透传:fork 首轮压缩判定不从 1.4 重来(纯收益,语义同源会话续接)
|
|
11898
|
+
calibRatio: srcRolling.calibRatio,
|
|
11899
|
+
lastRealPromptTokens: srcRolling.lastRealPromptTokens,
|
|
11900
|
+
lastCachedTokens: srcRolling.lastCachedTokens
|
|
11901
|
+
});
|
|
11902
|
+
if (prefix.unclosedRunId) {
|
|
11903
|
+
await appendEvent(newId, { dscEvent: "run.abandoned", runId: prefix.unclosedRunId, reason: "forked from interrupted run" });
|
|
11904
|
+
}
|
|
11905
|
+
return { sessionId: newId, copiedLines: prefix.lines.length, archivedMessageCount };
|
|
11906
|
+
};
|
|
11907
|
+
}
|
|
11908
|
+
});
|
|
11909
|
+
|
|
11222
11910
|
// src/cliHost.ts
|
|
11223
11911
|
var createCliRequestApproval, createCliRequestQuestion;
|
|
11224
11912
|
var init_cliHost = __esm({
|
|
@@ -11303,13 +11991,47 @@ var init_util = __esm({
|
|
|
11303
11991
|
|
|
11304
11992
|
// src/replay.ts
|
|
11305
11993
|
var buildReplayRows;
|
|
11306
|
-
var
|
|
11994
|
+
var init_replay2 = __esm({
|
|
11307
11995
|
"src/replay.ts"() {
|
|
11308
11996
|
"use strict";
|
|
11309
|
-
|
|
11997
|
+
init_transcript();
|
|
11998
|
+
buildReplayRows = (lines, nid) => {
|
|
11310
11999
|
const rows = [];
|
|
11311
12000
|
const pending = /* @__PURE__ */ new Map();
|
|
11312
|
-
|
|
12001
|
+
let lastStartRunId;
|
|
12002
|
+
const closedRuns = /* @__PURE__ */ new Set();
|
|
12003
|
+
const attachUsage = (u) => {
|
|
12004
|
+
for (let i = rows.length - 1; i >= 0; i--) {
|
|
12005
|
+
const r = rows[i];
|
|
12006
|
+
if (r.kind === "assistant") {
|
|
12007
|
+
rows[i] = {
|
|
12008
|
+
...r,
|
|
12009
|
+
usage: {
|
|
12010
|
+
...r.usage ?? {},
|
|
12011
|
+
prompt_tokens: u.prompt_tokens,
|
|
12012
|
+
completion_tokens: u.completion_tokens,
|
|
12013
|
+
total_tokens: u.total_tokens,
|
|
12014
|
+
prompt_cache_hit_tokens: u.cached_tokens
|
|
12015
|
+
}
|
|
12016
|
+
};
|
|
12017
|
+
return;
|
|
12018
|
+
}
|
|
12019
|
+
}
|
|
12020
|
+
};
|
|
12021
|
+
for (const line of lines) {
|
|
12022
|
+
if (isEventLine(line)) {
|
|
12023
|
+
if (line.dscEvent === "run.start") lastStartRunId = line.runId;
|
|
12024
|
+
else if (line.dscEvent === "run.end" || line.dscEvent === "run.abandoned") closedRuns.add(line.runId);
|
|
12025
|
+
if ((line.dscEvent === "round.end" || line.dscEvent === "run.end") && line.usage && (line.usage.prompt_tokens != null || line.usage.total_tokens != null)) {
|
|
12026
|
+
const last = [...rows].reverse().find((r) => r.kind === "assistant");
|
|
12027
|
+
if (line.dscEvent === "round.end" || !last?.usage) attachUsage(line.usage);
|
|
12028
|
+
}
|
|
12029
|
+
if (line.dscEvent === "run.abandoned") {
|
|
12030
|
+
rows.push({ id: nid(), kind: "info", text: "\u26A0\uFE0F \u6B64\u56DE\u5408\u88AB\u4E2D\u65AD\uFF0C\u672A\u5B8C\u6210" });
|
|
12031
|
+
}
|
|
12032
|
+
continue;
|
|
12033
|
+
}
|
|
12034
|
+
const m = line;
|
|
11313
12035
|
const role = m?.role;
|
|
11314
12036
|
if (role === "user") {
|
|
11315
12037
|
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("") : "";
|
|
@@ -11359,6 +12081,9 @@ var init_replay = __esm({
|
|
|
11359
12081
|
rows[idx] = { ...r, result: r.result ?? "", ok: false, status: "done" };
|
|
11360
12082
|
}
|
|
11361
12083
|
}
|
|
12084
|
+
if (lastStartRunId && !closedRuns.has(lastStartRunId)) {
|
|
12085
|
+
rows.push({ id: nid(), kind: "info", text: "\u26A0\uFE0F \u6B64\u56DE\u5408\u88AB\u4E2D\u65AD\uFF0C\u672A\u5B8C\u6210" });
|
|
12086
|
+
}
|
|
11362
12087
|
return rows;
|
|
11363
12088
|
};
|
|
11364
12089
|
}
|
|
@@ -11373,13 +12098,15 @@ var init_useChatState = __esm({
|
|
|
11373
12098
|
init_chatProcessing();
|
|
11374
12099
|
init_store();
|
|
11375
12100
|
init_transcript();
|
|
12101
|
+
init_fork();
|
|
12102
|
+
init_inbox();
|
|
11376
12103
|
init_contextCore();
|
|
11377
12104
|
init_createModel();
|
|
11378
12105
|
init_tool();
|
|
11379
12106
|
init_cliHost();
|
|
11380
12107
|
init_strings();
|
|
11381
12108
|
init_util();
|
|
11382
|
-
|
|
12109
|
+
init_replay2();
|
|
11383
12110
|
FLUSH_MS = 120;
|
|
11384
12111
|
ABORT_GRACE_MS = 8e3;
|
|
11385
12112
|
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";
|
|
@@ -11397,6 +12124,7 @@ var init_useChatState = __esm({
|
|
|
11397
12124
|
const [pendingQuestion, setPendingQuestion] = useState(null);
|
|
11398
12125
|
const [pendingPlan, setPendingPlan] = useState(null);
|
|
11399
12126
|
const [pendingSessions, setPendingSessions] = useState(null);
|
|
12127
|
+
const [pendingFork, setPendingFork] = useState(null);
|
|
11400
12128
|
const nextId = useRef(1);
|
|
11401
12129
|
const assistantStreamingId = useRef(null);
|
|
11402
12130
|
const thinkingStreamingId = useRef(null);
|
|
@@ -11409,6 +12137,7 @@ var init_useChatState = __esm({
|
|
|
11409
12137
|
const currentAcRef = useRef(null);
|
|
11410
12138
|
const turnGenRef = useRef(0);
|
|
11411
12139
|
const abortGuardRef = useRef(null);
|
|
12140
|
+
const queuedUnclaimedRef = useRef(0);
|
|
11412
12141
|
const proposedPlanRef = useRef(null);
|
|
11413
12142
|
const enterPlanReasonRef = useRef(null);
|
|
11414
12143
|
const modelRef = useRef("");
|
|
@@ -11423,8 +12152,8 @@ var init_useChatState = __esm({
|
|
|
11423
12152
|
if (!initialSessionId) return;
|
|
11424
12153
|
void (async () => {
|
|
11425
12154
|
try {
|
|
11426
|
-
const
|
|
11427
|
-
const seeded = buildReplayRows(
|
|
12155
|
+
const lines = await readTranscriptLines(initialSessionId);
|
|
12156
|
+
const seeded = buildReplayRows(lines, newRowId);
|
|
11428
12157
|
if (seeded.length) setRows(seeded);
|
|
11429
12158
|
} catch {
|
|
11430
12159
|
}
|
|
@@ -11607,10 +12336,18 @@ var init_useChatState = __esm({
|
|
|
11607
12336
|
}
|
|
11608
12337
|
case "approval_request":
|
|
11609
12338
|
break;
|
|
12339
|
+
case "inbox.claimed": {
|
|
12340
|
+
const n = Array.isArray(obj.texts) ? obj.texts.length : 0;
|
|
12341
|
+
if (n > 0) {
|
|
12342
|
+
queuedUnclaimedRef.current = Math.max(0, queuedUnclaimedRef.current - n);
|
|
12343
|
+
pushInfo(S.inboxClaimed(n));
|
|
12344
|
+
}
|
|
12345
|
+
break;
|
|
12346
|
+
}
|
|
11610
12347
|
default:
|
|
11611
12348
|
break;
|
|
11612
12349
|
}
|
|
11613
|
-
}, [closeStreaming, flush, scheduleFlush]);
|
|
12350
|
+
}, [closeStreaming, flush, scheduleFlush, pushInfo]);
|
|
11614
12351
|
const askApproval = useCallback((detail, toolName) => new Promise((resolve) => setPendingApproval({ detail, toolName, resolve })), []);
|
|
11615
12352
|
const resolveApproval = useCallback((v) => {
|
|
11616
12353
|
setPendingApproval((prev) => {
|
|
@@ -11690,9 +12427,13 @@ var init_useChatState = __esm({
|
|
|
11690
12427
|
clearTimeout(abortGuardRef.current);
|
|
11691
12428
|
abortGuardRef.current = null;
|
|
11692
12429
|
}
|
|
12430
|
+
if (queuedUnclaimedRef.current > 0) {
|
|
12431
|
+
pushInfo(S.inboxCarryover(queuedUnclaimedRef.current));
|
|
12432
|
+
queuedUnclaimedRef.current = 0;
|
|
12433
|
+
}
|
|
11693
12434
|
}
|
|
11694
12435
|
}
|
|
11695
|
-
}, [askApproval, autoRequestApproval, flush, onTrace, pushEvent]);
|
|
12436
|
+
}, [askApproval, autoRequestApproval, flush, onTrace, pushEvent, pushInfo]);
|
|
11696
12437
|
const approveAndImplement = useCallback(async (sid, plan) => {
|
|
11697
12438
|
const res = await setPlan(plan);
|
|
11698
12439
|
if (res.action === "accept") {
|
|
@@ -11710,6 +12451,15 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11710
12451
|
const plan = takeProposedPlan();
|
|
11711
12452
|
if (plan != null) await approveAndImplement(sid, plan);
|
|
11712
12453
|
}, [runOnce, takeProposedPlan, approveAndImplement]);
|
|
12454
|
+
const queueInput = useCallback((content) => {
|
|
12455
|
+
const text = content.trim();
|
|
12456
|
+
const sid = sessionIdRef.current;
|
|
12457
|
+
if (!text || !sid || !pushSessionInbox(sid, text)) return false;
|
|
12458
|
+
pushUser(text);
|
|
12459
|
+
pushInfo(S.inboxQueued);
|
|
12460
|
+
queuedUnclaimedRef.current++;
|
|
12461
|
+
return true;
|
|
12462
|
+
}, [pushUser, pushInfo]);
|
|
11713
12463
|
const submit = useCallback(async (content) => {
|
|
11714
12464
|
const text = content.trim();
|
|
11715
12465
|
if (!text || busy) return;
|
|
@@ -11770,8 +12520,8 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11770
12520
|
sessionIdRef.current = id;
|
|
11771
12521
|
clearRows();
|
|
11772
12522
|
try {
|
|
11773
|
-
const
|
|
11774
|
-
const seeded = buildReplayRows(
|
|
12523
|
+
const lines = await readTranscriptLines(id);
|
|
12524
|
+
const seeded = buildReplayRows(lines, newRowId);
|
|
11775
12525
|
if (seeded.length) setRows(seeded);
|
|
11776
12526
|
} catch {
|
|
11777
12527
|
}
|
|
@@ -11792,6 +12542,37 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11792
12542
|
const picked = await new Promise((resolve) => setPendingSessions({ sessions: sessions2, resolve }));
|
|
11793
12543
|
if (picked) await loadSession(picked);
|
|
11794
12544
|
}, [pushInfo, loadSession]);
|
|
12545
|
+
const resolveFork = useCallback((anchor) => {
|
|
12546
|
+
setPendingFork((prev) => {
|
|
12547
|
+
prev?.resolve(anchor);
|
|
12548
|
+
return null;
|
|
12549
|
+
});
|
|
12550
|
+
}, []);
|
|
12551
|
+
const openForkPicker = useCallback(async () => {
|
|
12552
|
+
const sid = sessionIdRef.current;
|
|
12553
|
+
if (!sid) {
|
|
12554
|
+
pushInfo(S.forkEmpty);
|
|
12555
|
+
return;
|
|
12556
|
+
}
|
|
12557
|
+
let anchors = [];
|
|
12558
|
+
try {
|
|
12559
|
+
anchors = listForkAnchors(await readTranscriptLines(sid));
|
|
12560
|
+
} catch {
|
|
12561
|
+
}
|
|
12562
|
+
if (anchors.length === 0) {
|
|
12563
|
+
pushInfo(S.forkEmpty);
|
|
12564
|
+
return;
|
|
12565
|
+
}
|
|
12566
|
+
const picked = await new Promise((resolve) => setPendingFork({ anchors, resolve }));
|
|
12567
|
+
if (!picked) return;
|
|
12568
|
+
try {
|
|
12569
|
+
const r = await forkSession(sid, picked.lineId);
|
|
12570
|
+
await loadSession(r.sessionId);
|
|
12571
|
+
pushInfo(S.forkDone(truncateMiddle(r.sessionId, 12), picked.roundNo));
|
|
12572
|
+
} catch (e) {
|
|
12573
|
+
pushInfo(S.forkFailed(e?.message ?? String(e)));
|
|
12574
|
+
}
|
|
12575
|
+
}, [pushInfo, loadSession]);
|
|
11795
12576
|
const setModelOverride = useCallback((m) => {
|
|
11796
12577
|
modelRef.current = m;
|
|
11797
12578
|
}, []);
|
|
@@ -11821,9 +12602,11 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11821
12602
|
pendingQuestion,
|
|
11822
12603
|
pendingPlan,
|
|
11823
12604
|
pendingSessions,
|
|
12605
|
+
pendingFork,
|
|
11824
12606
|
sessionIdRef,
|
|
11825
12607
|
// 动作
|
|
11826
12608
|
submit,
|
|
12609
|
+
queueInput,
|
|
11827
12610
|
abortCurrent,
|
|
11828
12611
|
pushUser,
|
|
11829
12612
|
pushInfo,
|
|
@@ -11846,7 +12629,9 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
11846
12629
|
getOutputStyle: getOutputStyle2,
|
|
11847
12630
|
openSessionPicker,
|
|
11848
12631
|
resolveSession,
|
|
11849
|
-
loadSession
|
|
12632
|
+
loadSession,
|
|
12633
|
+
openForkPicker,
|
|
12634
|
+
resolveFork
|
|
11850
12635
|
};
|
|
11851
12636
|
};
|
|
11852
12637
|
}
|
|
@@ -12448,9 +13233,45 @@ var init_SessionPicker = __esm({
|
|
|
12448
13233
|
}
|
|
12449
13234
|
});
|
|
12450
13235
|
|
|
12451
|
-
// src/components/
|
|
13236
|
+
// src/components/ForkPicker.tsx
|
|
12452
13237
|
import { Box as Box11, Text as Text13 } from "ink";
|
|
12453
13238
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
13239
|
+
var PAGE_SIZE2, ForkPicker;
|
|
13240
|
+
var init_ForkPicker = __esm({
|
|
13241
|
+
"src/components/ForkPicker.tsx"() {
|
|
13242
|
+
"use strict";
|
|
13243
|
+
init_theme();
|
|
13244
|
+
init_strings();
|
|
13245
|
+
init_util();
|
|
13246
|
+
PAGE_SIZE2 = 8;
|
|
13247
|
+
ForkPicker = ({ anchors, selectedIndex, wrapW }) => {
|
|
13248
|
+
const start = Math.floor(selectedIndex / PAGE_SIZE2) * PAGE_SIZE2;
|
|
13249
|
+
const visible = anchors.slice(start, start + PAGE_SIZE2);
|
|
13250
|
+
const contentW = Math.max(24, wrapW);
|
|
13251
|
+
const userW = Math.max(10, Math.floor(contentW * 0.45));
|
|
13252
|
+
const replyW = Math.max(10, contentW - userW - 4);
|
|
13253
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: THEME.blue, paddingX: 1, paddingY: 1, marginTop: 1, children: [
|
|
13254
|
+
/* @__PURE__ */ jsx13(Text13, { color: THEME.blue, bold: true, children: S.forkTitle }),
|
|
13255
|
+
/* @__PURE__ */ jsx13(Text13, { color: THEME.grayDim, children: S.forkPrompt }),
|
|
13256
|
+
/* @__PURE__ */ jsx13(Box11, { flexDirection: "column", marginTop: 0.5, children: visible.map((a, i) => {
|
|
13257
|
+
const active = start + i === selectedIndex;
|
|
13258
|
+
const user = truncateMiddle(a.userPreview || "(\u65E0\u63D0\u95EE)", userW);
|
|
13259
|
+
const reply = truncateMiddle(a.assistantPreview, replyW);
|
|
13260
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", children: [
|
|
13261
|
+
/* @__PURE__ */ jsx13(Text13, { color: active ? THEME.coralBright : void 0, bold: true, children: active ? "\u203A " : " " }),
|
|
13262
|
+
/* @__PURE__ */ jsx13(Text13, { color: active ? THEME.white : THEME.gray, bold: active, children: `#${a.roundNo} ${user}` }),
|
|
13263
|
+
/* @__PURE__ */ jsx13(Text13, { color: THEME.grayDim, children: ` \u2192 ${reply}` })
|
|
13264
|
+
] }, a.lineId);
|
|
13265
|
+
}) }),
|
|
13266
|
+
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
|
|
13267
|
+
] });
|
|
13268
|
+
};
|
|
13269
|
+
}
|
|
13270
|
+
});
|
|
13271
|
+
|
|
13272
|
+
// src/components/SlashMenu.tsx
|
|
13273
|
+
import { Box as Box12, Text as Text14 } from "ink";
|
|
13274
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
12454
13275
|
var MAX_ROWS, SlashMenu;
|
|
12455
13276
|
var init_SlashMenu = __esm({
|
|
12456
13277
|
"src/components/SlashMenu.tsx"() {
|
|
@@ -12462,22 +13283,22 @@ var init_SlashMenu = __esm({
|
|
|
12462
13283
|
const more = entries.length > MAX_ROWS;
|
|
12463
13284
|
const cmdW = Math.min(22, Math.max(8, ...visible.map((e) => e.name.length)) + 1);
|
|
12464
13285
|
const descMax = Math.max(12, cols - cmdW - 6);
|
|
12465
|
-
return /* @__PURE__ */
|
|
13286
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: THEME.coral, paddingX: 1, paddingY: 0, marginTop: 1, children: [
|
|
12466
13287
|
visible.map((e, i) => {
|
|
12467
13288
|
const active = i === selectedIndex;
|
|
12468
13289
|
const desc = e.description.length > descMax ? `${e.description.slice(0, descMax - 1)}\u2026` : e.description;
|
|
12469
13290
|
const gap = Math.max(1, cmdW - e.name.length);
|
|
12470
|
-
return /* @__PURE__ */
|
|
12471
|
-
/* @__PURE__ */
|
|
12472
|
-
/* @__PURE__ */
|
|
13291
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
|
|
13292
|
+
/* @__PURE__ */ jsx14(Text14, { color: active ? THEME.coralBright : void 0, bold: true, children: active ? "\u276F " : " " }),
|
|
13293
|
+
/* @__PURE__ */ jsxs12(Text14, { color: active ? THEME.white : THEME.gray, bold: active, children: [
|
|
12473
13294
|
"/",
|
|
12474
13295
|
e.name
|
|
12475
13296
|
] }),
|
|
12476
|
-
/* @__PURE__ */
|
|
12477
|
-
/* @__PURE__ */
|
|
13297
|
+
/* @__PURE__ */ jsx14(Text14, { color: THEME.grayDim, children: " ".repeat(gap) }),
|
|
13298
|
+
/* @__PURE__ */ jsx14(Text14, { color: active ? THEME.gray : THEME.grayDim, children: desc })
|
|
12478
13299
|
] }, e.name);
|
|
12479
13300
|
}),
|
|
12480
|
-
more ? /* @__PURE__ */
|
|
13301
|
+
more ? /* @__PURE__ */ jsxs12(Text14, { color: THEME.coralMuted, children: [
|
|
12481
13302
|
"\u2026 \u8FD8\u6709 ",
|
|
12482
13303
|
entries.length - MAX_ROWS,
|
|
12483
13304
|
" \u6761"
|
|
@@ -12488,8 +13309,8 @@ var init_SlashMenu = __esm({
|
|
|
12488
13309
|
});
|
|
12489
13310
|
|
|
12490
13311
|
// src/components/StatusStrip.tsx
|
|
12491
|
-
import { Box as
|
|
12492
|
-
import { jsx as
|
|
13312
|
+
import { Box as Box13, Text as Text15 } from "ink";
|
|
13313
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
12493
13314
|
var StatusStrip;
|
|
12494
13315
|
var init_StatusStrip = __esm({
|
|
12495
13316
|
"src/components/StatusStrip.tsx"() {
|
|
@@ -12506,18 +13327,18 @@ var init_StatusStrip = __esm({
|
|
|
12506
13327
|
`state: ${stateText}`,
|
|
12507
13328
|
sessionShort ? `session: ${sessionShort}` : ""
|
|
12508
13329
|
].filter(Boolean);
|
|
12509
|
-
return /* @__PURE__ */
|
|
12510
|
-
/* @__PURE__ */
|
|
12511
|
-
/* @__PURE__ */
|
|
12512
|
-
/* @__PURE__ */
|
|
13330
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexShrink: 0, children: [
|
|
13331
|
+
/* @__PURE__ */ jsx15(Text15, { color: THEME.coralMuted, children: customLine && customLine.trim() ? customLine : bits.join(" \xB7 ") }),
|
|
13332
|
+
/* @__PURE__ */ jsx15(Text15, { color: stateColor, children: "" }),
|
|
13333
|
+
/* @__PURE__ */ jsx15(Text15, { color: THEME.grayDim, children: S.cmdHint })
|
|
12513
13334
|
] });
|
|
12514
13335
|
};
|
|
12515
13336
|
}
|
|
12516
13337
|
});
|
|
12517
13338
|
|
|
12518
13339
|
// src/components/TopPanel.tsx
|
|
12519
|
-
import { Box as
|
|
12520
|
-
import { jsx as
|
|
13340
|
+
import { Box as Box14, Text as Text16 } from "ink";
|
|
13341
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
12521
13342
|
var ROBOT, INNER_H, TopPanel;
|
|
12522
13343
|
var init_TopPanel = __esm({
|
|
12523
13344
|
"src/components/TopPanel.tsx"() {
|
|
@@ -12537,36 +13358,36 @@ var init_TopPanel = __esm({
|
|
|
12537
13358
|
const leftW = Math.floor(innerW * 0.33);
|
|
12538
13359
|
const rightW = innerW - leftW - 1;
|
|
12539
13360
|
const ruleLen = Math.max(8, rightW - 2);
|
|
12540
|
-
const VDivider = /* @__PURE__ */
|
|
12541
|
-
return /* @__PURE__ */
|
|
12542
|
-
/* @__PURE__ */
|
|
12543
|
-
/* @__PURE__ */
|
|
12544
|
-
/* @__PURE__ */
|
|
12545
|
-
/* @__PURE__ */
|
|
12546
|
-
/* @__PURE__ */
|
|
12547
|
-
/* @__PURE__ */
|
|
13361
|
+
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)) });
|
|
13362
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: panelW, marginBottom: 1, children: [
|
|
13363
|
+
/* @__PURE__ */ jsxs14(Text16, { children: [
|
|
13364
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "* Welcome to " }),
|
|
13365
|
+
/* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.white, children: "deep" }),
|
|
13366
|
+
/* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.coralBright, children: "Seek" }),
|
|
13367
|
+
/* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.white, children: "Code" }),
|
|
13368
|
+
/* @__PURE__ */ jsxs14(Text16, { color: THEME.coralMuted, children: [
|
|
12548
13369
|
" ",
|
|
12549
13370
|
VERSION
|
|
12550
13371
|
] })
|
|
12551
13372
|
] }),
|
|
12552
|
-
/* @__PURE__ */
|
|
12553
|
-
/* @__PURE__ */
|
|
12554
|
-
/* @__PURE__ */
|
|
12555
|
-
/* @__PURE__ */
|
|
12556
|
-
ROBOT.map((l, i) => /* @__PURE__ */
|
|
12557
|
-
/* @__PURE__ */
|
|
12558
|
-
/* @__PURE__ */
|
|
13373
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: cwd }),
|
|
13374
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", borderStyle: "round", borderColor: THEME.coral, marginTop: 1, paddingX: 0, paddingY: 0, children: [
|
|
13375
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: leftW, height: INNER_H, alignItems: "center", justifyContent: "center", children: [
|
|
13376
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.white, bold: true, children: "Welcome back!" }),
|
|
13377
|
+
ROBOT.map((l, i) => /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, children: l }, i)),
|
|
13378
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "Ctrl+C \u9000\u51FA \xB7 Esc \u4E2D\u6B62" }),
|
|
13379
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "\u8F93\u5165 / \u67E5\u770B\u547D\u4EE4" })
|
|
12559
13380
|
] }),
|
|
12560
13381
|
VDivider,
|
|
12561
|
-
/* @__PURE__ */
|
|
12562
|
-
/* @__PURE__ */
|
|
12563
|
-
/* @__PURE__ */
|
|
12564
|
-
/* @__PURE__ */
|
|
13382
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: rightW, height: INNER_H, justifyContent: "space-between", paddingX: 1, children: [
|
|
13383
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
13384
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "Tips for getting started" }),
|
|
13385
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.white, children: "\u8F93\u5165\u9700\u6C42\u5F00\u59CB\uFF0C\u8F93\u5165 / \u5524\u51FA\u547D\u4EE4\u3002" })
|
|
12565
13386
|
] }),
|
|
12566
|
-
/* @__PURE__ */
|
|
12567
|
-
/* @__PURE__ */
|
|
12568
|
-
/* @__PURE__ */
|
|
12569
|
-
/* @__PURE__ */
|
|
13387
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "\u2500".repeat(ruleLen) }),
|
|
13388
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
13389
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "What's new" }),
|
|
13390
|
+
/* @__PURE__ */ jsx16(Text16, { color: THEME.white, children: "\u5DF2\u5BF9\u63A5\u672C\u5730 Tool Call \u667A\u80FD\u51FD\u6570\u8C03\u7528\u3002" })
|
|
12570
13391
|
] })
|
|
12571
13392
|
] })
|
|
12572
13393
|
] })
|
|
@@ -12576,7 +13397,7 @@ var init_TopPanel = __esm({
|
|
|
12576
13397
|
});
|
|
12577
13398
|
|
|
12578
13399
|
// src/inspect.ts
|
|
12579
|
-
import
|
|
13400
|
+
import fs38 from "fs";
|
|
12580
13401
|
var CWD, fmt, readTrace, inspectUsage, inspectContext, inspectPermissions, inspectMcp, inspectHooks, inspectDebug;
|
|
12581
13402
|
var init_inspect = __esm({
|
|
12582
13403
|
"src/inspect.ts"() {
|
|
@@ -12594,7 +13415,7 @@ var init_inspect = __esm({
|
|
|
12594
13415
|
if (!sessionId) return [];
|
|
12595
13416
|
try {
|
|
12596
13417
|
const p = await getTraceStorePath(sessionId);
|
|
12597
|
-
const text = await
|
|
13418
|
+
const text = await fs38.promises.readFile(p, "utf8");
|
|
12598
13419
|
const out = [];
|
|
12599
13420
|
for (const line of text.split("\n")) {
|
|
12600
13421
|
if (!line.trim()) continue;
|
|
@@ -12717,8 +13538,8 @@ __export(App_exports, {
|
|
|
12717
13538
|
App: () => App
|
|
12718
13539
|
});
|
|
12719
13540
|
import { useCallback as useCallback2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState4 } from "react";
|
|
12720
|
-
import { Box as
|
|
12721
|
-
import { jsx as
|
|
13541
|
+
import { Box as Box15, Static, Text as Text17, useApp, useInput as useInput2, useStdout } from "ink";
|
|
13542
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
12722
13543
|
var KNOWN_MODELS, CWD2, RowView, isDynamicRow, App;
|
|
12723
13544
|
var init_App = __esm({
|
|
12724
13545
|
"src/App.tsx"() {
|
|
@@ -12743,6 +13564,7 @@ var init_App = __esm({
|
|
|
12743
13564
|
init_PlanModal();
|
|
12744
13565
|
init_PlanEditor();
|
|
12745
13566
|
init_SessionPicker();
|
|
13567
|
+
init_ForkPicker();
|
|
12746
13568
|
init_SlashMenu();
|
|
12747
13569
|
init_MultilineInput();
|
|
12748
13570
|
init_StatusStrip();
|
|
@@ -12751,16 +13573,16 @@ var init_App = __esm({
|
|
|
12751
13573
|
KNOWN_MODELS = ["deepseek-v4", "deepseek-v4-flash"];
|
|
12752
13574
|
CWD2 = process.cwd();
|
|
12753
13575
|
RowView = ({ row, wrapW, streamTail, showThinking }) => {
|
|
12754
|
-
if (row.kind === "todos") return /* @__PURE__ */
|
|
12755
|
-
if (row.kind === "tool") return /* @__PURE__ */
|
|
12756
|
-
if (row.kind === "thinking") return /* @__PURE__ */
|
|
13576
|
+
if (row.kind === "todos") return /* @__PURE__ */ jsx17(TodosPanel, { todos: row.todos, wrapW });
|
|
13577
|
+
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 });
|
|
13578
|
+
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 });
|
|
12757
13579
|
if (row.kind === "user") {
|
|
12758
|
-
return /* @__PURE__ */
|
|
12759
|
-
/* @__PURE__ */
|
|
12760
|
-
/* @__PURE__ */
|
|
13580
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
|
|
13581
|
+
/* @__PURE__ */ jsx17(Text17, { color: THEME.grayDim, children: "\u2500".repeat(Math.max(8, wrapW)) }),
|
|
13582
|
+
/* @__PURE__ */ jsx17(MessageBlock, { row, wrapW, streamTail })
|
|
12761
13583
|
] });
|
|
12762
13584
|
}
|
|
12763
|
-
return /* @__PURE__ */
|
|
13585
|
+
return /* @__PURE__ */ jsx17(MessageBlock, { row, wrapW, streamTail });
|
|
12764
13586
|
};
|
|
12765
13587
|
isDynamicRow = (r) => r.kind === "assistant" && !!r.streaming || r.kind === "thinking" && !!r.streaming || r.kind === "tool" && r.status === "running" || r.kind === "todos" && !!r.active;
|
|
12766
13588
|
App = ({ resumeSessionId, initialPlanMode, initialAutoMode, initialIncludeProject }) => {
|
|
@@ -12860,6 +13682,8 @@ var init_App = __esm({
|
|
|
12860
13682
|
return S.cmdOutputStyle;
|
|
12861
13683
|
case "sessions":
|
|
12862
13684
|
return S.cmdSessions;
|
|
13685
|
+
case "fork":
|
|
13686
|
+
return S.cmdFork;
|
|
12863
13687
|
case "usage":
|
|
12864
13688
|
return S.cmdUsage;
|
|
12865
13689
|
case "context":
|
|
@@ -12892,13 +13716,13 @@ var init_App = __esm({
|
|
|
12892
13716
|
const q = input.slice(1).toLowerCase();
|
|
12893
13717
|
return menuEntries.filter((c) => c.name.toLowerCase().startsWith(q));
|
|
12894
13718
|
}, [input, menuEntries]);
|
|
12895
|
-
const menuActive = state.pendingApproval != null || state.pendingQuestion != null || state.pendingPlan != null || state.pendingSessions != null;
|
|
13719
|
+
const menuActive = state.pendingApproval != null || state.pendingQuestion != null || state.pendingPlan != null || state.pendingSessions != null || state.pendingFork != null;
|
|
12896
13720
|
const slashVisible = !menuActive && input.startsWith("/") && filteredCommands.length > 0;
|
|
12897
13721
|
const inputActive = !menuActive;
|
|
12898
13722
|
useEffect4(() => {
|
|
12899
13723
|
setSelectIdx(0);
|
|
12900
13724
|
setPlanEditing(false);
|
|
12901
|
-
}, [state.pendingApproval, state.pendingQuestion, state.pendingPlan, state.pendingSessions, slashVisible, filteredCommands.length]);
|
|
13725
|
+
}, [state.pendingApproval, state.pendingQuestion, state.pendingPlan, state.pendingSessions, state.pendingFork, slashVisible, filteredCommands.length]);
|
|
12902
13726
|
useEffect4(() => {
|
|
12903
13727
|
setQCursor(0);
|
|
12904
13728
|
setQChecked(/* @__PURE__ */ new Set());
|
|
@@ -12917,6 +13741,9 @@ var init_App = __esm({
|
|
|
12917
13741
|
case "/sessions":
|
|
12918
13742
|
void state.openSessionPicker();
|
|
12919
13743
|
return true;
|
|
13744
|
+
case "/fork":
|
|
13745
|
+
void state.openForkPicker();
|
|
13746
|
+
return true;
|
|
12920
13747
|
case "/help":
|
|
12921
13748
|
state.pushInfo(S.helpText(modelDisplay, state.getThinkingLevel(), getLocale()));
|
|
12922
13749
|
return true;
|
|
@@ -13065,7 +13892,12 @@ ${listText}`);
|
|
|
13065
13892
|
const v = inputRef.current.trim();
|
|
13066
13893
|
if (!v) return;
|
|
13067
13894
|
if (busyRef.current) {
|
|
13068
|
-
|
|
13895
|
+
if (!v.startsWith("/") && state.queueInput(v)) {
|
|
13896
|
+
setInput("");
|
|
13897
|
+
setCursor(0);
|
|
13898
|
+
} else {
|
|
13899
|
+
state.pushEvent({ type: "error", message: S.busyBlockSend });
|
|
13900
|
+
}
|
|
13069
13901
|
return;
|
|
13070
13902
|
}
|
|
13071
13903
|
setInput("");
|
|
@@ -13147,6 +13979,16 @@ ${listText}`);
|
|
|
13147
13979
|
} else if (key.escape || key.ctrl && ch === "g") state.resolveSession(null);
|
|
13148
13980
|
return;
|
|
13149
13981
|
}
|
|
13982
|
+
if (state.pendingFork) {
|
|
13983
|
+
const list = state.pendingFork.anchors;
|
|
13984
|
+
if (key.upArrow) setSelectIdx((i) => (i - 1 + list.length) % list.length);
|
|
13985
|
+
else if (key.downArrow) setSelectIdx((i) => (i + 1) % list.length);
|
|
13986
|
+
else if (key.return) {
|
|
13987
|
+
const sel = list[Math.min(selectIdxRef.current, list.length - 1)];
|
|
13988
|
+
state.resolveFork(sel ?? null);
|
|
13989
|
+
} else if (key.escape || key.ctrl && ch === "g") state.resolveFork(null);
|
|
13990
|
+
return;
|
|
13991
|
+
}
|
|
13150
13992
|
if (key.ctrl && ch === "t") {
|
|
13151
13993
|
state.toggleShowThinking();
|
|
13152
13994
|
return;
|
|
@@ -13187,19 +14029,19 @@ ${listText}`);
|
|
|
13187
14029
|
}
|
|
13188
14030
|
});
|
|
13189
14031
|
const sessionShort = state.sessionIdRef.current ? truncateMiddle(state.sessionIdRef.current, 12) : "";
|
|
13190
|
-
return /* @__PURE__ */
|
|
13191
|
-
/* @__PURE__ */
|
|
13192
|
-
/* @__PURE__ */
|
|
13193
|
-
menuActive ? null : /* @__PURE__ */
|
|
13194
|
-
dynamicRows.map((row) => /* @__PURE__ */
|
|
13195
|
-
state.busy ? /* @__PURE__ */
|
|
14032
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: cols, children: [
|
|
14033
|
+
/* @__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) }),
|
|
14034
|
+
/* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: cols, children: [
|
|
14035
|
+
menuActive ? null : /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, children: [
|
|
14036
|
+
dynamicRows.map((row) => /* @__PURE__ */ jsx17(RowView, { row, wrapW, streamTail, showThinking: state.showThinkingText }, row.id)),
|
|
14037
|
+
state.busy ? /* @__PURE__ */ jsx17(Box15, { marginTop: 0.5, children: /* @__PURE__ */ jsxs15(Text17, { color: THEME.coralBright, children: [
|
|
13196
14038
|
"\u25CF ",
|
|
13197
14039
|
S.generating
|
|
13198
14040
|
] }) }) : null
|
|
13199
14041
|
] }),
|
|
13200
|
-
/* @__PURE__ */
|
|
13201
|
-
state.pendingApproval ? /* @__PURE__ */
|
|
13202
|
-
state.pendingQuestion ? /* @__PURE__ */
|
|
14042
|
+
/* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, flexShrink: 0, children: [
|
|
14043
|
+
state.pendingApproval ? /* @__PURE__ */ jsx17(ApprovalModal, { toolName: state.pendingApproval.toolName, detail: state.pendingApproval.detail, selectedIndex: selectIdx, wrapW }) : null,
|
|
14044
|
+
state.pendingQuestion ? /* @__PURE__ */ jsx17(
|
|
13203
14045
|
QuestionModal,
|
|
13204
14046
|
{
|
|
13205
14047
|
question: state.pendingQuestion.req.question,
|
|
@@ -13210,7 +14052,7 @@ ${listText}`);
|
|
|
13210
14052
|
wrapW
|
|
13211
14053
|
}
|
|
13212
14054
|
) : null,
|
|
13213
|
-
state.pendingPlan ? planEditing ? /* @__PURE__ */
|
|
14055
|
+
state.pendingPlan ? planEditing ? /* @__PURE__ */ jsx17(
|
|
13214
14056
|
PlanEditor,
|
|
13215
14057
|
{
|
|
13216
14058
|
value: planDraft,
|
|
@@ -13221,13 +14063,14 @@ ${listText}`);
|
|
|
13221
14063
|
},
|
|
13222
14064
|
onSubmit: confirmPlanEdit
|
|
13223
14065
|
}
|
|
13224
|
-
) : /* @__PURE__ */
|
|
13225
|
-
state.pendingSessions ? /* @__PURE__ */
|
|
13226
|
-
|
|
14066
|
+
) : /* @__PURE__ */ jsx17(PlanModal, { selectedIndex: selectIdx }) : null,
|
|
14067
|
+
state.pendingSessions ? /* @__PURE__ */ jsx17(SessionPicker, { sessions: state.pendingSessions.sessions, selectedIndex: selectIdx, wrapW }) : null,
|
|
14068
|
+
state.pendingFork ? /* @__PURE__ */ jsx17(ForkPicker, { anchors: state.pendingFork.anchors, selectedIndex: selectIdx, wrapW }) : null,
|
|
14069
|
+
slashVisible ? /* @__PURE__ */ jsx17(SlashMenu, { entries: filteredCommands, selectedIndex: selectIdx, cols }) : null
|
|
13227
14070
|
] }),
|
|
13228
|
-
/* @__PURE__ */
|
|
13229
|
-
/* @__PURE__ */
|
|
13230
|
-
/* @__PURE__ */
|
|
14071
|
+
/* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, marginTop: 1, flexShrink: 0, children: [
|
|
14072
|
+
/* @__PURE__ */ jsx17(Text17, { dimColor: true, color: THEME.gray, children: dimRule(cols) }),
|
|
14073
|
+
/* @__PURE__ */ jsx17(
|
|
13231
14074
|
MultilineInput,
|
|
13232
14075
|
{
|
|
13233
14076
|
value: input,
|
|
@@ -13245,13 +14088,88 @@ ${listText}`);
|
|
|
13245
14088
|
}
|
|
13246
14089
|
)
|
|
13247
14090
|
] }),
|
|
13248
|
-
/* @__PURE__ */
|
|
14091
|
+
/* @__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 }) })
|
|
13249
14092
|
] })
|
|
13250
14093
|
] });
|
|
13251
14094
|
};
|
|
13252
14095
|
}
|
|
13253
14096
|
});
|
|
13254
14097
|
|
|
14098
|
+
// src/updateCheck.ts
|
|
14099
|
+
var updateCheck_exports = {};
|
|
14100
|
+
__export(updateCheck_exports, {
|
|
14101
|
+
getCachedLatestIfNewer: () => getCachedLatestIfNewer,
|
|
14102
|
+
readLocalVersion: () => readLocalVersion,
|
|
14103
|
+
refreshUpdateCache: () => refreshUpdateCache
|
|
14104
|
+
});
|
|
14105
|
+
import { readFileSync as readFileSync4, writeFileSync, mkdirSync } from "node:fs";
|
|
14106
|
+
import path39 from "node:path";
|
|
14107
|
+
import os4 from "os";
|
|
14108
|
+
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
14109
|
+
var PKG_NAME, REGISTRY, CACHE_TTL_MS, FETCH_TIMEOUT_MS2, cacheFile, readLocalVersion, parseSemver, compareVersion, readCache, writeCache, getCachedLatestIfNewer, refreshUpdateCache;
|
|
14110
|
+
var init_updateCheck = __esm({
|
|
14111
|
+
"src/updateCheck.ts"() {
|
|
14112
|
+
"use strict";
|
|
14113
|
+
PKG_NAME = "deepseeker-code";
|
|
14114
|
+
REGISTRY = "https://registry.npmjs.org";
|
|
14115
|
+
CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
14116
|
+
FETCH_TIMEOUT_MS2 = 3e3;
|
|
14117
|
+
cacheFile = () => path39.join(os4.homedir(), ".deepseeker-code", "update-check.json");
|
|
14118
|
+
readLocalVersion = () => {
|
|
14119
|
+
try {
|
|
14120
|
+
const here = path39.dirname(fileURLToPath6(import.meta.url));
|
|
14121
|
+
return JSON.parse(readFileSync4(path39.join(here, "..", "package.json"), "utf8")).version ?? "0.0.0";
|
|
14122
|
+
} catch {
|
|
14123
|
+
return "0.0.0";
|
|
14124
|
+
}
|
|
14125
|
+
};
|
|
14126
|
+
parseSemver = (v) => {
|
|
14127
|
+
const m = String(v ?? "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
14128
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : [0, 0, 0];
|
|
14129
|
+
};
|
|
14130
|
+
compareVersion = (a, b) => {
|
|
14131
|
+
const [a1, a2, a3] = parseSemver(a);
|
|
14132
|
+
const [b1, b2, b3] = parseSemver(b);
|
|
14133
|
+
return a1 - b1 || a2 - b2 || a3 - b3;
|
|
14134
|
+
};
|
|
14135
|
+
readCache = () => {
|
|
14136
|
+
try {
|
|
14137
|
+
const obj = JSON.parse(readFileSync4(cacheFile(), "utf8"));
|
|
14138
|
+
return typeof obj.latestVersion === "string" && typeof obj.lastCheck === "number" ? obj : null;
|
|
14139
|
+
} catch {
|
|
14140
|
+
return null;
|
|
14141
|
+
}
|
|
14142
|
+
};
|
|
14143
|
+
writeCache = (latestVersion) => {
|
|
14144
|
+
try {
|
|
14145
|
+
mkdirSync(path39.dirname(cacheFile()), { recursive: true });
|
|
14146
|
+
writeFileSync(cacheFile(), JSON.stringify({ lastCheck: Date.now(), latestVersion }), "utf8");
|
|
14147
|
+
} catch {
|
|
14148
|
+
}
|
|
14149
|
+
};
|
|
14150
|
+
getCachedLatestIfNewer = (currentVersion) => {
|
|
14151
|
+
const cache = readCache();
|
|
14152
|
+
if (!cache) return null;
|
|
14153
|
+
return compareVersion(cache.latestVersion, currentVersion) > 0 ? cache.latestVersion : null;
|
|
14154
|
+
};
|
|
14155
|
+
refreshUpdateCache = () => {
|
|
14156
|
+
const cache = readCache();
|
|
14157
|
+
if (cache && Date.now() - cache.lastCheck < CACHE_TTL_MS) return;
|
|
14158
|
+
void (async () => {
|
|
14159
|
+
try {
|
|
14160
|
+
const res = await fetch(`${REGISTRY}/${PKG_NAME}/latest`, {
|
|
14161
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
14162
|
+
});
|
|
14163
|
+
if (!res.ok) return;
|
|
14164
|
+
const info = await res.json();
|
|
14165
|
+
if (info.version) writeCache(info.version);
|
|
14166
|
+
} catch {
|
|
14167
|
+
}
|
|
14168
|
+
})();
|
|
14169
|
+
};
|
|
14170
|
+
}
|
|
14171
|
+
});
|
|
14172
|
+
|
|
13255
14173
|
// src/preload-config.ts
|
|
13256
14174
|
import { readFileSync } from "node:fs";
|
|
13257
14175
|
import path from "node:path";
|
|
@@ -13301,10 +14219,10 @@ init_strings();
|
|
|
13301
14219
|
init_prefs();
|
|
13302
14220
|
init_trust();
|
|
13303
14221
|
import { render } from "ink";
|
|
13304
|
-
import
|
|
13305
|
-
import
|
|
14222
|
+
import os5 from "os";
|
|
14223
|
+
import path40 from "path";
|
|
13306
14224
|
import { emitKeypressEvents } from "node:readline";
|
|
13307
|
-
import { jsx as
|
|
14225
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
13308
14226
|
var parseArgs = (argv) => {
|
|
13309
14227
|
const out = {};
|
|
13310
14228
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -13314,6 +14232,7 @@ var parseArgs = (argv) => {
|
|
|
13314
14232
|
else if (a === "--auto" || a === "-a") out.auto = true;
|
|
13315
14233
|
else if (a === "--continue" || a === "-c") out.continue = true;
|
|
13316
14234
|
else if (a === "--trust") out.trust = true;
|
|
14235
|
+
else if (a === "--no-update-check") out.noUpdateCheck = true;
|
|
13317
14236
|
}
|
|
13318
14237
|
return out;
|
|
13319
14238
|
};
|
|
@@ -13428,19 +14347,26 @@ var main = async () => {
|
|
|
13428
14347
|
process.stdout.write("\x1B[2J\x1B[3J\x1B[1;1H");
|
|
13429
14348
|
const cwdIsHome = () => {
|
|
13430
14349
|
try {
|
|
13431
|
-
return
|
|
14350
|
+
return path40.resolve(cwd).toLowerCase() === path40.resolve(os5.homedir()).toLowerCase();
|
|
13432
14351
|
} catch {
|
|
13433
14352
|
return false;
|
|
13434
14353
|
}
|
|
13435
14354
|
};
|
|
13436
14355
|
process.stdout.write(S.startupBanner(cwd, appConfig2.userWorkspaceDir, cwdIsHome()));
|
|
14356
|
+
if (!args.noUpdateCheck) {
|
|
14357
|
+
const { readLocalVersion: readLocalVersion2, getCachedLatestIfNewer: getCachedLatestIfNewer2, refreshUpdateCache: refreshUpdateCache2 } = await Promise.resolve().then(() => (init_updateCheck(), updateCheck_exports));
|
|
14358
|
+
const current = readLocalVersion2();
|
|
14359
|
+
const latest = getCachedLatestIfNewer2(current);
|
|
14360
|
+
if (latest) process.stdout.write(S.updateAvailable(latest, current));
|
|
14361
|
+
refreshUpdateCache2();
|
|
14362
|
+
}
|
|
13437
14363
|
let resumeId = args.resume;
|
|
13438
14364
|
if (!resumeId && args.continue) {
|
|
13439
14365
|
const { getMostRecentSessionId: getMostRecentSessionId2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
13440
14366
|
resumeId = await getMostRecentSessionId2() ?? void 0;
|
|
13441
14367
|
}
|
|
13442
14368
|
const { waitUntilExit } = render(
|
|
13443
|
-
/* @__PURE__ */
|
|
14369
|
+
/* @__PURE__ */ jsx18(App2, { resumeSessionId: resumeId, initialPlanMode: args.plan, initialAutoMode: args.auto, initialIncludeProject: includeProject }),
|
|
13444
14370
|
// exitOnCtrlC:false:Ctrl+C 交由 App useInput 处理(统一退出/中止语义);
|
|
13445
14371
|
// patchConsole:false:避免 console 劫持与全屏重绘叠加闪屏。
|
|
13446
14372
|
{ exitOnCtrlC: false, patchConsole: false }
|