deepseeker-code 1.0.60 → 1.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +475 -309
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -4228,7 +4228,7 @@ async function killBackgroundTasksUnder(dirPath) {
4228
4228
  }
4229
4229
  return killed;
4230
4230
  }
4231
- var _winShellCache, resolveWinShell, MAX_BUFFER_CHARS, registry, createBgTask, attachTaskLifecycle, makeTaskExitNotifier, adoptRunningProcess, backgroundTools, killAllBackgroundTasks;
4231
+ var _winShellCache, resolveWinShell, MAX_BUFFER_CHARS, registry, createBgTask, attachTaskLifecycle, makeTaskExitNotifier, adoptRunningProcess, BG_WAIT_SECONDS_CAP, clampWaitSeconds, backgroundTools, killAllBackgroundTasks;
4232
4232
  var init_background = __esm({
4233
4233
  "../core/src/tool/registry/background.ts"() {
4234
4234
  "use strict";
@@ -4393,6 +4393,8 @@ var init_background = __esm({
4393
4393
  void attachTaskLifecycle(task, proc, { signal: meta.signal, codec, onExit: meta.onExit });
4394
4394
  return task.taskId;
4395
4395
  };
4396
+ BG_WAIT_SECONDS_CAP = 90;
4397
+ clampWaitSeconds = (v) => Math.min(Math.max(0, Math.floor(v ?? 0)), BG_WAIT_SECONDS_CAP);
4396
4398
  backgroundTools = [
4397
4399
  {
4398
4400
  type: "function",
@@ -4481,13 +4483,13 @@ task_id: ${taskId}
4481
4483
  type: "function",
4482
4484
  function: {
4483
4485
  name: "get_background_output",
4484
- description: "\u67E5\u770B\u6307\u5B9A\u540E\u53F0\u4EFB\u52A1\u7684\u6700\u8FD1\u8F93\u51FA\u65E5\u5FD7\u4E0E\u8FD0\u884C\u72B6\u6001\uFF08running/exited/killed + \u9000\u51FA\u7801\uFF09\u3002\u7EAF\u8BFB\uFF0C\u514D\u5BA1\u6279\u3002\u7528\u4E8E\u786E\u8BA4 dev server \u662F\u5426\u542F\u52A8\u6210\u529F\u3001\u67E5\u770B\u62A5\u9519\u7B49\u3002\u7B49\u957F\u4EFB\u52A1\uFF08\u6784\u5EFA/\u6D4B\u8BD5\uFF09\u8DD1\u5B8C\uFF1A\u5E26 wait_seconds \u963B\u585E\u7B49\u5F85\u4EFB\u52A1\u9000\u51FA\u540E\u518D\u8FD4\u56DE\uFF08\u4ECD\u5728\u8DD1\u5219\u7B49\u5230\u8D85\u65F6\u8FD4\u56DE\u5F53\u524D\u72B6\u6001\uFF09\u2014\u2014\u7528\u5B83\u7B49\uFF0C\u4E0D\u8981\u4E0D\u5E26 wait \u53CD\u590D\u8F6E\u8BE2\u67E5\u8BE2\u3002",
4486
+ description: "\u67E5\u770B\u6307\u5B9A\u540E\u53F0\u4EFB\u52A1\u7684\u6700\u8FD1\u8F93\u51FA\u65E5\u5FD7\u4E0E\u8FD0\u884C\u72B6\u6001\uFF08running/exited/killed + \u9000\u51FA\u7801\uFF09\u3002\u7EAF\u8BFB\uFF0C\u514D\u5BA1\u6279\u3002\u7528\u4E8E\u786E\u8BA4 dev server \u662F\u5426\u542F\u52A8\u6210\u529F\u3001\u67E5\u770B\u62A5\u9519\u7B49\u3002\u7B49\u957F\u4EFB\u52A1\uFF08\u6784\u5EFA/\u6D4B\u8BD5\uFF09\u8DD1\u5B8C\uFF1A\u5E26 wait_seconds \u963B\u585E\u7B49\u5F85\u4EFB\u52A1\u9000\u51FA\u540E\u518D\u8FD4\u56DE\uFF08\u4ECD\u5728\u8DD1\u5219\u7B49\u6EE1 wait_seconds \u8FD4\u56DE\u5F53\u524D\u5FEB\u7167\uFF09\u2014\u2014\u7528\u5B83\u7B49\uFF0C\u4E0D\u8981\u4E0D\u5E26 wait \u53CD\u590D\u8F6E\u8BE2\u67E5\u8BE2\u3002",
4485
4487
  parameters: {
4486
4488
  type: "object",
4487
4489
  properties: {
4488
4490
  task_id: { type: "string", description: "\u540E\u53F0\u4EFB\u52A1\u7684 task_id\uFF08run_in_background \u8FD4\u56DE\uFF0C\u6216 run_command \u8D85\u65F6\u81EA\u52A8\u8F6C\u540E\u53F0\u8FD4\u56DE\uFF09" },
4489
4491
  tail_lines: { type: "number", description: "\u53EA\u8FD4\u56DE\u6700\u540E N \u884C\u65E5\u5FD7\uFF08\u9ED8\u8BA4 50\uFF0C\u907F\u514D\u4E00\u6B21\u704C\u5165\u8FC7\u591A\uFF09" },
4490
- wait_seconds: { type: "number", description: "\u963B\u585E\u7B49\u5F85\u4EFB\u52A1\u9000\u51FA\uFF08\u6216\u5230\u8FBE\u6B64\u65F6\u957F\uFF09\u540E\u518D\u8FD4\u56DE\uFF0C\u4E0A\u9650 120 \u79D2\uFF1B\u4EFB\u52A1\u5DF2\u5728\u8DD1\u4E14\u9700\u8981\u7B49\u7ED3\u679C\u65F6\u4F7F\u7528\uFF0C\u4E0D\u9700\u8981\u7B49\u5C31\u7701\u7565" }
4492
+ wait_seconds: { type: "number", description: "\u963B\u585E\u7B49\u5F85\u4EFB\u52A1\u9000\u51FA\uFF08\u6216\u5230\u8FBE\u6B64\u65F6\u957F\uFF09\u540E\u518D\u8FD4\u56DE\uFF0C\u4E0A\u9650 90 \u79D2\u2014\u2014\u987B\u4F4E\u4E8E\u8C03\u5EA6\u5C42 120s \u5DE5\u5177\u7194\u65AD\u7EBF\uFF0C\u66F4\u957F\u7684 wait \u4F1A\u88AB\u7194\u65AD\u3001\u771F\u5B9E\u7ED3\u679C\u88AB\u4E22\u5F03\u6362\u6210\u8D85\u65F6\u6587\u6848\u3002\u9884\u8BA1\u66F4\u4E45\u5C31\u4F20 90\uFF0C\u8FD4\u56DE\u4ECD running \u5C31\u518D\u8C03\u4E00\u6B21\u63A5\u7740\u7B49\uFF1B\u53EA\u770B\u5F53\u524D\u65E5\u5FD7\u5C31\u7701\u7565\u6B64\u53C2\u6570" }
4491
4493
  },
4492
4494
  required: ["task_id"]
4493
4495
  },
@@ -4498,7 +4500,7 @@ task_id: ${taskId}
4498
4500
  if (!task || task.sessionId !== ctx?.sessionId) {
4499
4501
  return toolFailure(`[\u67E5\u8BE2\u5931\u8D25]\uFF1A\u672A\u627E\u5230 task_id=${args.task_id}\uFF08\u53EF\u80FD\u5DF2\u968F\u670D\u52A1\u91CD\u542F\u4E22\u5931\uFF0C\u6216\u4E0D\u5C5E\u4E8E\u5F53\u524D\u4F1A\u8BDD\uFF09\u3002`);
4500
4502
  }
4501
- const waitMs = Math.min(Math.max(0, args.wait_seconds ?? 0), 120) * 1e3;
4503
+ const waitMs = clampWaitSeconds(args.wait_seconds) * 1e3;
4502
4504
  if (waitMs > 0 && task.status === "running") {
4503
4505
  const deadline = Date.now() + waitMs;
4504
4506
  while (task.status === "running" && Date.now() < deadline && !ctx?.abortSignal?.aborted) {
@@ -6027,13 +6029,17 @@ var init_toolResultCollect = __esm({
6027
6029
  const idleMs = Number(process.env.DEEP_SEEK_STREAM_IDLE_TIMEOUT_MS) || 12e4;
6028
6030
  while (true) {
6029
6031
  let timer2;
6030
- const outcome = await Promise.race([
6031
- ret.next().then((step) => ({ timedOut: false, step })),
6032
- new Promise((resolve) => {
6033
- timer2 = setTimeout(() => resolve({ timedOut: true }), idleMs);
6034
- })
6035
- ]);
6036
- if (timer2) clearTimeout(timer2);
6032
+ let outcome;
6033
+ try {
6034
+ outcome = await Promise.race([
6035
+ ret.next().then((step) => ({ timedOut: false, step })),
6036
+ new Promise((resolve) => {
6037
+ timer2 = setTimeout(() => resolve({ timedOut: true }), idleMs);
6038
+ })
6039
+ ]);
6040
+ } finally {
6041
+ if (timer2) clearTimeout(timer2);
6042
+ }
6037
6043
  if (outcome.timedOut) {
6038
6044
  full += `
6039
6045
 
@@ -6054,18 +6060,22 @@ var init_toolResultCollect = __esm({
6054
6060
  const timeoutMs2 = Number(process.env.DEEP_SEEK_STREAM_IDLE_TIMEOUT_MS) || 12e4;
6055
6061
  let timer;
6056
6062
  let onAbort;
6057
- const raced = await Promise.race([
6058
- Promise.resolve(ret).then((v2) => ({ kind: "ok", value: v2 })),
6059
- new Promise((resolve) => {
6060
- timer = setTimeout(() => resolve({ kind: "timeout" }), timeoutMs2);
6061
- }),
6062
- ...signal ? [new Promise((resolve) => {
6063
- onAbort = () => resolve({ kind: "abort" });
6064
- signal.addEventListener("abort", onAbort, { once: true });
6065
- })] : []
6066
- ]);
6067
- if (timer) clearTimeout(timer);
6068
- if (onAbort && signal) signal.removeEventListener("abort", onAbort);
6063
+ let raced;
6064
+ try {
6065
+ raced = await Promise.race([
6066
+ Promise.resolve(ret).then((v2) => ({ kind: "ok", value: v2 })),
6067
+ new Promise((resolve) => {
6068
+ timer = setTimeout(() => resolve({ kind: "timeout" }), timeoutMs2);
6069
+ }),
6070
+ ...signal ? [new Promise((resolve) => {
6071
+ onAbort = () => resolve({ kind: "abort" });
6072
+ signal.addEventListener("abort", onAbort, { once: true });
6073
+ })] : []
6074
+ ]);
6075
+ } finally {
6076
+ if (timer) clearTimeout(timer);
6077
+ if (onAbort && signal) signal.removeEventListener("abort", onAbort);
6078
+ }
6069
6079
  if (raced.kind === "timeout") {
6070
6080
  return { content: `[\u23F3 \u5DE5\u5177\u6267\u884C\u8D85\u65F6\uFF08${Math.round(timeoutMs2 / 1e3)}s \u672A\u8FD4\u56DE\uFF09\uFF0C\u5DF2\u7194\u65AD\u8DF3\u8FC7\u3002\u8BE5\u5DE5\u5177\u53EF\u80FD hang \u6216\u4E0D\u54CD\u5E94\u4E2D\u6B62\u4FE1\u53F7\u3002]`, status: "failed", errorCategory: "runtime" };
6071
6081
  }
@@ -7801,9 +7811,15 @@ ${tail}`,
7801
7811
  cwd,
7802
7812
  detached: !isWin,
7803
7813
  // 非 Win 下支持整个进程组独立
7804
- env: scrubCommandEnv(),
7814
+ env: scrubCommandEnv()
7805
7815
  // ★ 剔除 agent 自身凭证(LLM key / 服务端 token / 搜索 key),防 LLM 经 env/printenv 读取外泄
7806
- signal: ctx?.abortSignal
7816
+ // ★ 中止唯一出口 = 下方 onAbort→killTree(2026-10-27 修「■ 终止无效」):
7817
+ // 勿把 signal 交给 spawn——Node 内部 abort 监听先于 onAbort 触发,TerminateProcess
7818
+ // 只杀最外层进程;随后 killTree 的 taskkill /T 对已死根「找不到进程」直接失败,
7819
+ // 孙进程(tsx 的 esbuild、node --test 的每文件子进程)存活并持有继承的 stdout 管道,
7820
+ // close 永不触发 → 工具永不结束(多层进程树命令下点终止永远转圈)。
7821
+ // 根存活时 taskkill /T 才能整树剿灭;进入工具时已 aborted 由上方前置检查拦截,
7822
+ // pre-check 与 addEventListener 之间全同步无 await,无竞态窗口。
7807
7823
  });
7808
7824
  } catch (e) {
7809
7825
  yield toolFailure(`[\u542F\u52A8\u5931\u8D25]\uFF1Aspawn \u629B\u51FA\u5F02\u5E38\uFF08signal \u5DF2\u4E2D\u6B62\u6216\u547D\u4EE4\u975E\u6CD5\uFF09: ${e?.message ?? e}`).content;
@@ -7813,6 +7829,7 @@ ${tail}`,
7813
7829
  const queue = [];
7814
7830
  let settled = false;
7815
7831
  let exitCode = null;
7832
+ let abortedByUser = false;
7816
7833
  let resolveWaiter = null;
7817
7834
  let idleTimer = null;
7818
7835
  const notifyNewData = () => {
@@ -7866,13 +7883,14 @@ ${tail}`,
7866
7883
  notifyNewData();
7867
7884
  });
7868
7885
  proc.on("close", (code) => {
7869
- exitCode ??= code == null ? -1 : code;
7886
+ exitCode ??= abortedByUser ? -1 : code == null ? -1 : code;
7870
7887
  if (decoder) queue.push(decoder.decode());
7871
7888
  queue.push(pendingUtf8.decode());
7872
7889
  settled = true;
7873
7890
  notifyNewData();
7874
7891
  });
7875
7892
  const onAbort = () => {
7893
+ abortedByUser = true;
7876
7894
  void killTree(proc);
7877
7895
  };
7878
7896
  ctx?.abortSignal?.addEventListener("abort", onAbort);
@@ -12033,7 +12051,7 @@ var init_autoPermission = __esm({
12033
12051
 
12034
12052
  // ../core/src/agent/toolExecution.ts
12035
12053
  import path36 from "path";
12036
- var applyPrivacyMasking, scaleTruncBudget, failResult, emitValidationFailed, resolveEarlyOutcome, runSecurityGates, executeTool, finalizeOutcome, processToolCall;
12054
+ var applyPrivacyMasking, scaleTruncBudget, failResult, emitValidationFailed, resolveEarlyOutcome, runSecurityGates, executeTool, finalizeOutcome, previewArgs, processToolCall, processToolCallInner;
12037
12055
  var init_toolExecution = __esm({
12038
12056
  "../core/src/agent/toolExecution.ts"() {
12039
12057
  "use strict";
@@ -12305,7 +12323,9 @@ ${state.result}`;
12305
12323
  const { calledName, calledArgs, matchedTool } = state;
12306
12324
  state.result = applyPrivacyMasking(matchedTool?.function?.privacyMaskingRules, calledArgs, state.result);
12307
12325
  const fill = contextTokensEst !== void 0 && modelWindow > 0 ? contextTokensEst / modelWindow : void 0;
12308
- const truncBudget = scaleTruncBudget(matchedTool?.function?.maxOutputCharacters ?? appConfig.MAX_TOOL_RESULT_CHARS, fill);
12326
+ const baseBudget = matchedTool?.function?.maxOutputCharacters ?? appConfig.MAX_TOOL_RESULT_CHARS;
12327
+ const capped = ctx.batchBudgetChars !== void 0 ? Math.min(baseBudget, ctx.batchBudgetChars) : baseBudget;
12328
+ const truncBudget = scaleTruncBudget(capped, fill);
12309
12329
  const sidecarNote = state.result.length > truncBudget ? await writeSidecarArchive(sessionId, String(toolCall.id), state.result) : void 0;
12310
12330
  state.result = truncateToolResult(state.result, truncBudget, sidecarNote);
12311
12331
  const resultStatus = state.resultStatus;
@@ -12322,7 +12342,7 @@ ${state.result}`;
12322
12342
  }
12323
12343
  if (state.postHookOverride !== void 0) {
12324
12344
  console.log(`\u270F\uFE0F [Post-hook] [${calledName}] \u6A21\u578B\u89C6\u56FE\u7ED3\u679C\u5DF2\u88AB hook \u6539\u5199`);
12325
- const overrideBudget = scaleTruncBudget(matchedTool?.function?.maxOutputCharacters ?? appConfig.MAX_TOOL_RESULT_CHARS, fill);
12345
+ const overrideBudget = scaleTruncBudget(capped, fill);
12326
12346
  const overrideNote = state.postHookOverride.length > overrideBudget ? await writeSidecarArchive(sessionId, String(toolCall.id), state.postHookOverride) : void 0;
12327
12347
  resultForModel = truncateToolResult(state.postHookOverride, overrideBudget, overrideNote);
12328
12348
  }
@@ -12332,7 +12352,36 @@ ${state.result}`;
12332
12352
  }
12333
12353
  return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel, resultForUser, ok, imageAttachments: state.imageAttachments };
12334
12354
  };
12355
+ previewArgs = (raw, max) => raw === void 0 ? void 0 : raw.length > max ? raw.slice(0, max) + `\u2026\uFF08\u5171 ${raw.length} \u5B57\u7B26\uFF09` : raw;
12335
12356
  processToolCall = async (toolCall, ctx) => {
12357
+ try {
12358
+ return await processToolCallInner(toolCall, ctx);
12359
+ } catch (e) {
12360
+ const msg = e instanceof Error ? e.message : String(e);
12361
+ console.error(`\u274C \u5DE5\u5177\u8C03\u7528\u5904\u7406\u5F02\u5E38\uFF08\u5DF2\u9694\u79BB\uFF0C\u4E0D\u5F71\u54CD\u540C\u6279\u5176\u4ED6\u5DE5\u5177\uFF09: ${msg}`);
12362
+ try {
12363
+ ctx.events({
12364
+ sessionId: ctx.sessionId,
12365
+ eventType: "tool.failed",
12366
+ metadata: { depth: ctx.depth, decisionSource: ctx.llmDecisionSource, durationMs: performance.now() - ctx.startTime, round: ctx.round, tools_id: toolCall?.id ?? "", toolName: toolCall?.function?.name ?? "unknown", toolSource: "builtin", ok: false, attempt: ctx.round, errorCategory: "runtime" },
12367
+ payload: { output: `\u5DE5\u5177\u6267\u884C\u5F02\u5E38\uFF1A${msg}` }
12368
+ });
12369
+ } catch {
12370
+ }
12371
+ return {
12372
+ toolCallId: toolCall?.id ?? "",
12373
+ calledName: toolCall?.function?.name ?? "unknown",
12374
+ calledArgs: { _preview: previewArgs(toolCall?.function?.arguments, 300) },
12375
+ // ★ 保留参数上下文(截断预览):否则 tool.failed 排查时看不到模型当时传了什么
12376
+ resultForModel: `\u5DE5\u5177\u6267\u884C\u5F02\u5E38\uFF1A${msg}\uFF08\u672C\u8C03\u7528\u5DF2\u9694\u79BB\uFF0C\u5176\u4ED6\u5DE5\u5177\u7ED3\u679C\u4E0D\u53D7\u5F71\u54CD\uFF09`,
12377
+ resultForUser: `\u274C \u5DE5\u5177\u6267\u884C\u5F02\u5E38\uFF1A${msg}`,
12378
+ ok: false,
12379
+ aborted: ctx.signal?.aborted ? true : void 0
12380
+ // ★ 不吞 abort
12381
+ };
12382
+ }
12383
+ };
12384
+ processToolCallInner = async (toolCall, ctx) => {
12336
12385
  const state = {
12337
12386
  calledName: "",
12338
12387
  calledArgs: {},
@@ -12354,7 +12403,9 @@ ${state.result}`;
12354
12403
  } catch {
12355
12404
  state.parseFailed = true;
12356
12405
  }
12357
- console.log(`\u{1F916} \u6A21\u578B\u8BF7\u6C42\u8C03\u7528\u5DE5\u5177: ${state.calledName}\uFF0C\u53C2\u6570:`, state.calledArgs);
12406
+ const argsLog = JSON.stringify(state.calledArgs) ?? "";
12407
+ const argsPreview = process.env.DSC_DEBUG_TOOL_ARGS === "1" ? argsLog : argsLog.length > 200 ? argsLog.slice(0, 200) + `\u2026\uFF08\u5171 ${argsLog.length} \u5B57\u7B26\uFF09` : argsLog;
12408
+ console.log(`\u{1F916} \u6A21\u578B\u8BF7\u6C42\u8C03\u7528\u5DE5\u5177: ${state.calledName}\uFF0C\u53C2\u6570: ${argsPreview}`);
12358
12409
  }
12359
12410
  state.matchedTool = ctx.rawTools.find((t) => t.function.name === state.calledName);
12360
12411
  const early = resolveEarlyOutcome(ctx, toolCall, state);
@@ -12396,13 +12447,14 @@ ${state.result}`;
12396
12447
  });
12397
12448
 
12398
12449
  // ../core/src/agent/toolScheduling.ts
12399
- var dedupeSameRoundCalls, scheduleToolCalls;
12450
+ var dedupeSameRoundCalls, BATCH_MIN_CHARS, BATCH_WINDOW_SHARE, CHAR_PER_TOKEN, computeBatchBudget, scheduleToolCalls;
12400
12451
  var init_toolScheduling = __esm({
12401
12452
  "../core/src/agent/toolScheduling.ts"() {
12402
12453
  "use strict";
12403
12454
  init_toolExecution();
12404
12455
  init_transcript();
12405
12456
  init_contentParts();
12457
+ init_contextCore();
12406
12458
  init_config();
12407
12459
  init_tool();
12408
12460
  init_permissions();
@@ -12422,6 +12474,14 @@ var init_toolScheduling = __esm({
12422
12474
  }
12423
12475
  return { batch, plan };
12424
12476
  };
12477
+ BATCH_MIN_CHARS = 12e3;
12478
+ BATCH_WINDOW_SHARE = 0.5;
12479
+ CHAR_PER_TOKEN = 4;
12480
+ computeBatchBudget = (modelWindow, compactRatio, contextTokensEst, batchSize) => {
12481
+ const budgetTokensLeft = Math.max(0, modelWindow * compactRatio - (contextTokensEst ?? 0));
12482
+ const batchCapChars = Math.max(BATCH_MIN_CHARS, Math.floor(budgetTokensLeft * CHAR_PER_TOKEN * BATCH_WINDOW_SHARE));
12483
+ return { batchCapChars, perToolCapChars: Math.floor(batchCapChars / batchSize) };
12484
+ };
12425
12485
  scheduleToolCalls = async function* (assistantMessage, message, ctx) {
12426
12486
  const { sessionId, signal, rawTools } = ctx;
12427
12487
  let abortedDuringTools = false;
@@ -12490,7 +12550,10 @@ var init_toolScheduling = __esm({
12490
12550
  const bp = parseTc(p.tc);
12491
12551
  yield { type: "tool.start", toolCallId: p.tc.id, toolName: bp.name, args: bp.args };
12492
12552
  }
12493
- const outcomes = await Promise.all(batch.map((btc) => processToolCall(btc, ctx)));
12553
+ const budget = batch.length >= 2 ? computeBatchBudget(ctx.modelWindow, ctx.compactRatio, ctx.contextTokensEst, batch.length) : void 0;
12554
+ const tokensBefore = budget ? estimateTokens(message) : 0;
12555
+ const batchCtx = budget ? { ...ctx, batchBudgetChars: budget.perToolCapChars } : ctx;
12556
+ const outcomes = await Promise.all(batch.map((btc) => processToolCall(btc, batchCtx)));
12494
12557
  const outcomeByTc = /* @__PURE__ */ new Map();
12495
12558
  batch.forEach((btc, i) => outcomeByTc.set(btc, outcomes[i]));
12496
12559
  const batchEntries = [];
@@ -12514,6 +12577,34 @@ var init_toolScheduling = __esm({
12514
12577
  if (oc.aborted) abortedDuringTools = true;
12515
12578
  }
12516
12579
  await appendMessages(sessionId, batchEntries);
12580
+ if (budget) {
12581
+ try {
12582
+ const tokensAfter = estimateTokens(message);
12583
+ ctx.events({
12584
+ sessionId,
12585
+ eventType: "tool.batch.budget",
12586
+ metadata: {
12587
+ depth: ctx.depth,
12588
+ decisionSource: ctx.llmDecisionSource,
12589
+ ok: true,
12590
+ durationMs: performance.now() - ctx.startTime,
12591
+ round: ctx.round,
12592
+ batchSize: batch.length,
12593
+ batchCapChars: budget.batchCapChars,
12594
+ perToolCapChars: budget.perToolCapChars
12595
+ },
12596
+ payload: {
12597
+ output: JSON.stringify({
12598
+ injectedChars: batch.map((btc) => outcomeByTc.get(btc)?.resultForModel.length ?? 0),
12599
+ tokensBefore,
12600
+ tokensAfter,
12601
+ tokensDelta: tokensAfter - tokensBefore
12602
+ })
12603
+ }
12604
+ });
12605
+ } catch {
12606
+ }
12607
+ }
12517
12608
  } else {
12518
12609
  yield { type: "tool.start", toolCallId: tc.id, toolName: pname, args: pargs };
12519
12610
  const oc = await processToolCall(tc, ctx);
@@ -12644,9 +12735,10 @@ var init_streamInference = __esm({
12644
12735
  const MAX_STREAM_RETRIES = 2;
12645
12736
  const MAX_API_RETRIES = 3;
12646
12737
  let apiRetries = 0;
12738
+ let idleRetries = 0;
12647
12739
  let compactedThisRound = false;
12648
12740
  let visionDegradedThisRound = false;
12649
- for (let streamAttempt = 0; ; streamAttempt++) {
12741
+ for (; ; ) {
12650
12742
  try {
12651
12743
  for await (const chunk of activeProvider.streamChat(inferenceMessages, cleanedToolSchemas, { signal, model, thinkingLevel })) {
12652
12744
  if (signal?.aborted) break;
@@ -12692,10 +12784,11 @@ var init_streamInference = __esm({
12692
12784
  }
12693
12785
  );
12694
12786
  const noOutputYet = !contentBuf && !reasoningBuf && toolCallsBuf.size === 0;
12695
- if (isIdleTimeout && streamAttempt < MAX_STREAM_RETRIES) {
12787
+ if (isIdleTimeout && idleRetries < MAX_STREAM_RETRIES) {
12788
+ idleRetries++;
12696
12789
  if (!noOutputYet) yield { type: "text.reset" };
12697
12790
  const stallShape = noOutputYet ? "\uFF0C\u5C1A\u65E0\u8F93\u51FA" : hasCompleteToolCall ? "\uFF0C\u5DF2\u6709\u5B8C\u6574 tool_call\uFF08\u6D41\u5C3E\u90E8 stall\uFF09" : "\uFF0Ctool_call \u672A\u6D41\u5B8C";
12698
- console.warn(`\u26A0\uFE0F \u6D41\u5F0F stall\uFF08idle \u8D85\u65F6${stallShape}\uFF09\uFF0C\u7B2C ${streamAttempt + 1}/${MAX_STREAM_RETRIES} \u6B21\u91CD\u8BD5...`);
12791
+ console.warn(`\u26A0\uFE0F \u6D41\u5F0F stall\uFF08idle \u8D85\u65F6${stallShape}\uFF09\uFF0C\u7B2C ${idleRetries}/${MAX_STREAM_RETRIES} \u6B21\u91CD\u8BD5...`);
12699
12792
  contentBuf = "";
12700
12793
  reasoningBuf = "";
12701
12794
  toolCallsBuf.clear();
@@ -13365,6 +13458,280 @@ var init_usageLog = __esm({
13365
13458
  }
13366
13459
  });
13367
13460
 
13461
+ // ../core/src/observability/store.ts
13462
+ import path38 from "path";
13463
+ import fs35 from "fs/promises";
13464
+ var getTraceDirPath, getTracePath, tracePathCache, ensuredTraceDirs, ensureTraceDir, getGlobalClockPath, getTraceStorePath;
13465
+ var init_store3 = __esm({
13466
+ "../core/src/observability/store.ts"() {
13467
+ "use strict";
13468
+ init_config();
13469
+ init_traceCalculate();
13470
+ init_common();
13471
+ getTraceDirPath = (mainTraceId) => {
13472
+ assertSafeSessionId(mainTraceId, "traceId");
13473
+ return path38.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
13474
+ };
13475
+ getTracePath = () => {
13476
+ return path38.join(appConfig.dataDir, "trace");
13477
+ };
13478
+ tracePathCache = /* @__PURE__ */ new Map();
13479
+ ensuredTraceDirs = /* @__PURE__ */ new Set();
13480
+ ensureTraceDir = async (mainTraceId) => {
13481
+ const dir = getTraceDirPath(mainTraceId);
13482
+ if (ensuredTraceDirs.has(dir)) return;
13483
+ await fs35.mkdir(dir, { recursive: true });
13484
+ ensuredTraceDirs.add(dir);
13485
+ };
13486
+ getGlobalClockPath = () => {
13487
+ return path38.join(getTracePath(), "trace-cleanup-clock.json");
13488
+ };
13489
+ getTraceStorePath = async (mainTraceId) => {
13490
+ assertSafeSessionId(mainTraceId, "traceId");
13491
+ const rootId = getFileName(mainTraceId);
13492
+ const cached2 = tracePathCache.get(rootId);
13493
+ if (cached2) return cached2;
13494
+ await ensureTraceDir(rootId);
13495
+ const dir = getTraceDirPath(rootId);
13496
+ const files = await fs35.readdir(dir);
13497
+ const existedFile = files.find((f) => f.endsWith(`__${rootId}.jsonl`));
13498
+ let fileName = "";
13499
+ if (existedFile) {
13500
+ fileName = existedFile;
13501
+ } else {
13502
+ const todayStr = getTodayDateString();
13503
+ fileName = `trace-${todayStr}__${rootId}.jsonl`;
13504
+ }
13505
+ const resolved = path38.join(dir, fileName);
13506
+ tracePathCache.set(rootId, resolved);
13507
+ return resolved;
13508
+ };
13509
+ }
13510
+ });
13511
+
13512
+ // ../core/src/observability/trace.ts
13513
+ import fs36 from "fs/promises";
13514
+ import path39 from "path";
13515
+ async function emitTrace(base) {
13516
+ const event = {
13517
+ sessionId: base.sessionId,
13518
+ parentId: base.parentId,
13519
+ eventType: base.eventType,
13520
+ timestamp: base.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
13521
+ usage: base.usage,
13522
+ payload: base.payload,
13523
+ metadata: {
13524
+ ...base.metadata || {}
13525
+ }
13526
+ };
13527
+ if (event.payload) {
13528
+ if (typeof event.payload.input === "string") event.payload.input = truncateTracePayload(event.payload.input);
13529
+ if (typeof event.payload.output === "string") event.payload.output = truncateTracePayload(event.payload.output);
13530
+ }
13531
+ try {
13532
+ await appendTraceEvent(event);
13533
+ } catch (error) {
13534
+ console.warn("\u26A0\uFE0F [Trace] \u4E8B\u4EF6\u843D\u76D8\u5931\u8D25\uFF0C\u5DF2\u9632\u5FA1\u6027\u8DF3\u8FC7\uFF08\u4E0D\u5F71\u54CD\u4E3B\u4E1A\u52A1\uFF09:", error);
13535
+ }
13536
+ }
13537
+ async function appendTraceEvent(event) {
13538
+ const line = JSON.stringify(event) + "\n";
13539
+ const arr = traceBuf.get(event.sessionId);
13540
+ if (arr) arr.push(line);
13541
+ else traceBuf.set(event.sessionId, [line]);
13542
+ if (needImmediateFlush(event)) {
13543
+ await flushTraceBuffer(event.sessionId);
13544
+ return;
13545
+ }
13546
+ if ((traceBuf.get(event.sessionId)?.length ?? 0) >= TRACE_BATCH_LINES) {
13547
+ await flushTraceBuffer(event.sessionId);
13548
+ return;
13549
+ }
13550
+ scheduleTraceTimer(event.sessionId);
13551
+ }
13552
+ async function maybeCleanupAfterAppend(sessionId) {
13553
+ if (cleanupInProgress2) return;
13554
+ cleanupInProgress2 = true;
13555
+ try {
13556
+ await ensureClockLoaded2();
13557
+ const now = Date.now();
13558
+ const isTimeExpired = now - diskLastCleanupAt2 > CLEANUP_INTERVAL_MS2;
13559
+ const isSizeOverflow = workspaceTraceBytes > MAX_TRACE_FOLDER_BYTES;
13560
+ if (!isTimeExpired && !isSizeOverflow) return;
13561
+ if (isSizeOverflow && !isTimeExpired && now - lastSizeCleanupAt2 < SIZE_CLEANUP_COOLDOWN_MS2) {
13562
+ return;
13563
+ }
13564
+ const reason = isTimeExpired && isSizeOverflow ? "\u5BB9\u91CF+\u65F6\u95F4\u53CC\u95F8" : isSizeOverflow ? "\u5BB9\u91CF\u8D8A\u8FC750MB\u5927\u95F8" : "3\u5929\u51B7\u5374\u5468\u671F\u5DF2\u6EE1";
13565
+ console.log(`\u{1F9F9} [Trace\u8FD0\u7EF4] \u89E6\u53D1\u81EA\u9002\u5E94\u6E05\u7406\uFF08\u539F\u56E0: ${reason}\uFF09`);
13566
+ let deletedCount = 0;
13567
+ deletedCount += await cleanupOldTraceFiles();
13568
+ workspaceTraceBytes = await getDirBytes(getTracePath());
13569
+ if (workspaceTraceBytes > MAX_TRACE_FOLDER_BYTES) {
13570
+ const targetBytes = Math.floor(MAX_TRACE_FOLDER_BYTES * SIZE_RECLAIM_TARGET_RATIO2);
13571
+ deletedCount += await evictOldestForSize2(targetBytes);
13572
+ workspaceTraceBytes = await getDirBytes(getTracePath());
13573
+ }
13574
+ lastSizeCleanupAt2 = now;
13575
+ diskLastCleanupAt2 = now;
13576
+ const clockPath = getGlobalClockPath();
13577
+ await fs36.mkdir(path39.dirname(clockPath), { recursive: true });
13578
+ await fs36.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
13579
+ if (deletedCount > 0) {
13580
+ console.log(`\u2728 [Trace\u8FD0\u7EF4] \u5171\u9500\u6BC1 ${deletedCount} \u4E2A\u4F1A\u8BDD\u65E5\u5FD7\uFF08\u8F6F\u89C4\u5219\u8FC7\u671F\u6E05\u7406 + \u5BB9\u91CF\u786C\u9A71\u9010\uFF09\uFF0C\u78C1\u76D8\u6C34\u4F4D\u56DE\u843D\u3002`);
13581
+ }
13582
+ } catch (error) {
13583
+ console.warn("\u26A0\uFE0F [Trace\u8FD0\u7EF4] \u81EA\u52A8\u6E05\u7406\u53D1\u751F\u8F7B\u5FAE\u5F02\u5E38\uFF0C\u5DF2\u9632\u5FA1\u6027\u8DF3\u8FC7:", error);
13584
+ } finally {
13585
+ cleanupInProgress2 = false;
13586
+ }
13587
+ }
13588
+ async function cleanupOldTraceFiles() {
13589
+ const dir = getTracePath();
13590
+ const retentionDays = Math.max(1, appConfig.traceRetentionDays || 7);
13591
+ const cutoff = /* @__PURE__ */ new Date();
13592
+ cutoff.setHours(0, 0, 0, 0);
13593
+ cutoff.setDate(cutoff.getDate() - retentionDays);
13594
+ const now = Date.now();
13595
+ let deleted = 0;
13596
+ let relativePaths;
13597
+ try {
13598
+ relativePaths = await fs36.readdir(dir, { recursive: true });
13599
+ } catch {
13600
+ return 0;
13601
+ }
13602
+ const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
13603
+ for (const relativePath of relativePaths) {
13604
+ const fileName = path39.basename(relativePath);
13605
+ const m = fileName.match(re);
13606
+ if (!m) continue;
13607
+ const fileBornDay = /* @__PURE__ */ new Date(`${m[1]}T00:00:00`);
13608
+ if (fileBornDay >= cutoff) continue;
13609
+ const fullPath = path39.join(dir, relativePath);
13610
+ try {
13611
+ const st = await fs36.stat(fullPath);
13612
+ if (now - st.mtimeMs < ACTIVE_GRACE_MS2) continue;
13613
+ await fs36.unlink(fullPath);
13614
+ deleted += 1;
13615
+ } catch {
13616
+ }
13617
+ }
13618
+ return deleted;
13619
+ }
13620
+ async function evictOldestForSize2(targetBytes) {
13621
+ const dir = getTracePath();
13622
+ let relativePaths;
13623
+ try {
13624
+ relativePaths = await fs36.readdir(dir, { recursive: true });
13625
+ } catch {
13626
+ return 0;
13627
+ }
13628
+ const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
13629
+ const candidates = [];
13630
+ for (const relativePath of relativePaths) {
13631
+ const fileName = path39.basename(relativePath);
13632
+ if (!re.test(fileName)) continue;
13633
+ try {
13634
+ const st = await fs36.stat(path39.join(dir, relativePath));
13635
+ candidates.push({ mtime: st.mtimeMs, fullPath: path39.join(dir, relativePath), size: st.size });
13636
+ } catch {
13637
+ }
13638
+ }
13639
+ candidates.sort((a, b) => a.mtime - b.mtime);
13640
+ let totalBytes = candidates.reduce((sum, c) => sum + c.size, 0);
13641
+ let deleted = 0;
13642
+ for (const c of candidates) {
13643
+ if (totalBytes <= targetBytes) break;
13644
+ try {
13645
+ await fs36.unlink(c.fullPath);
13646
+ totalBytes -= c.size;
13647
+ deleted += 1;
13648
+ } catch {
13649
+ }
13650
+ }
13651
+ if (deleted > 0) {
13652
+ console.warn(`\u26A0\uFE0F [Trace\u8FD0\u7EF4] \u5BB9\u91CF\u786C\u9A71\u9010\uFF1A\u8D8A\u8FC7\u6D3B\u8DC3\u4FDD\u62A4\u5F3A\u5220 ${deleted} \u4E2A\u6700\u65E7 trace \u6587\u4EF6\uFF08\u78C1\u76D8\u538B\u529B\u515C\u5E95\uFF09\u3002`);
13653
+ }
13654
+ return deleted;
13655
+ }
13656
+ var CLEANUP_INTERVAL_MS2, ACTIVE_GRACE_MS2, MAX_TRACE_FOLDER_BYTES, SIZE_RECLAIM_TARGET_RATIO2, SIZE_CLEANUP_COOLDOWN_MS2, workspaceTraceBytes, diskLastCleanupAt2, clockLoaded2, lastSizeCleanupAt2, cleanupInProgress2, TRACE_BATCH_LINES, TRACE_BATCH_MS, traceBuf, traceTimers, cleanupTriggerCount, needImmediateFlush, scheduleTraceTimer, flushTraceBuffer, ensureClockLoaded2, tracePayloadMaxChars, truncateTracePayload;
13657
+ var init_trace = __esm({
13658
+ "../core/src/observability/trace.ts"() {
13659
+ "use strict";
13660
+ init_config();
13661
+ init_store3();
13662
+ init_traceCalculate();
13663
+ CLEANUP_INTERVAL_MS2 = 3 * 24 * 60 * 60 * 1e3;
13664
+ ACTIVE_GRACE_MS2 = 24 * 60 * 60 * 1e3;
13665
+ MAX_TRACE_FOLDER_BYTES = 50 * 1024 * 1024;
13666
+ SIZE_RECLAIM_TARGET_RATIO2 = 0.8;
13667
+ SIZE_CLEANUP_COOLDOWN_MS2 = 60 * 1e3;
13668
+ workspaceTraceBytes = -1;
13669
+ diskLastCleanupAt2 = 0;
13670
+ clockLoaded2 = false;
13671
+ lastSizeCleanupAt2 = 0;
13672
+ cleanupInProgress2 = false;
13673
+ TRACE_BATCH_LINES = 50;
13674
+ TRACE_BATCH_MS = 200;
13675
+ traceBuf = /* @__PURE__ */ new Map();
13676
+ traceTimers = /* @__PURE__ */ new Map();
13677
+ cleanupTriggerCount = 0;
13678
+ needImmediateFlush = (ev) => ev.metadata?.ok === false || ev.eventType === "user.aborted" || ev.eventType === "tool.repeat_break" || ev.eventType === "session.end";
13679
+ scheduleTraceTimer = (sessionId) => {
13680
+ if (traceTimers.has(sessionId)) return;
13681
+ const t = setTimeout(() => {
13682
+ traceTimers.delete(sessionId);
13683
+ void flushTraceBuffer(sessionId);
13684
+ }, TRACE_BATCH_MS);
13685
+ t.unref?.();
13686
+ traceTimers.set(sessionId, t);
13687
+ };
13688
+ flushTraceBuffer = async (sessionId) => {
13689
+ const ids = sessionId !== void 0 ? [sessionId] : [...traceBuf.keys()];
13690
+ for (const id of ids) {
13691
+ const arr = traceBuf.get(id);
13692
+ if (!arr || arr.length === 0) {
13693
+ traceBuf.delete(id);
13694
+ continue;
13695
+ }
13696
+ traceBuf.set(id, []);
13697
+ const timer = traceTimers.get(id);
13698
+ if (timer) {
13699
+ clearTimeout(timer);
13700
+ traceTimers.delete(id);
13701
+ }
13702
+ try {
13703
+ const joined = arr.join("");
13704
+ const p = await getTraceStorePath(id);
13705
+ await fs36.appendFile(p, joined, "utf-8");
13706
+ if (workspaceTraceBytes < 0) {
13707
+ workspaceTraceBytes = await getDirBytes(getTracePath());
13708
+ }
13709
+ workspaceTraceBytes += Buffer.byteLength(joined, "utf-8");
13710
+ cleanupTriggerCount++;
13711
+ void maybeCleanupAfterAppend(id);
13712
+ } catch (error) {
13713
+ console.warn("\u26A0\uFE0F [Trace] \u6279\u91CF\u843D\u76D8\u5931\u8D25\uFF0C\u4E22\u5F03\u8BE5\u6279\uFF08\u4E0D\u5F71\u54CD\u4E3B\u4E1A\u52A1\uFF09:", error);
13714
+ }
13715
+ }
13716
+ };
13717
+ ensureClockLoaded2 = async () => {
13718
+ if (clockLoaded2) return;
13719
+ clockLoaded2 = true;
13720
+ try {
13721
+ const rawClock = await fs36.readFile(getGlobalClockPath(), "utf-8");
13722
+ diskLastCleanupAt2 = JSON.parse(rawClock).lastCleanupAt || 0;
13723
+ } catch {
13724
+ diskLastCleanupAt2 = 0;
13725
+ }
13726
+ };
13727
+ tracePayloadMaxChars = () => Number(process.env.TRACE_PAYLOAD_MAX_CHARS) || 2e3;
13728
+ truncateTracePayload = (s) => {
13729
+ const max = tracePayloadMaxChars();
13730
+ return s.length > max ? s.slice(0, max) + `\u2026[trace \u622A\u65AD ${s.length - max} \u5B57\u7B26\uFF08\u5171 ${s.length} \u5B57\u7B26\uFF09]` : s;
13731
+ };
13732
+ }
13733
+ });
13734
+
13368
13735
  // ../core/src/agent/runAgent.ts
13369
13736
  async function* runAgent(message, options) {
13370
13737
  const sessionId = options.sessionId;
@@ -13633,7 +14000,10 @@ async function* runAgent(message, options) {
13633
14000
  nudges.notePlanWriteRejected(planWriteRej);
13634
14001
  },
13635
14002
  // ★ P1-5 子任务预算熔断:runSubagent 经 toolCtx.budgetCheck 拿到探测闭包,子 runAgent 每轮边界自检
13636
- budgetCheck: inheritedBudgetCheck
14003
+ budgetCheck: inheritedBudgetCheck,
14004
+ // ★ A 批批级预算:主循环不设(undefined);仅并行批 ≥2 时由调度层浅拷贝下发(R4/R5:
14005
+ // required 字段,构造处显式对齐,漏写即 tsc 打红)
14006
+ batchBudgetChars: void 0
13637
14007
  };
13638
14008
  const scheduleResult = yield* scheduleToolCalls(assistantMessage, message, toolCallCtx);
13639
14009
  if (scheduleResult.kind === "aborted") {
@@ -13673,6 +14043,10 @@ async function* runAgent(message, options) {
13673
14043
  await appendEvent(sessionId, { dscEvent: "run.end", runId, stopReason: signal?.aborted ? "aborted" : stopReason, rounds: round, usage: ledger.usageSummary() });
13674
14044
  } catch {
13675
14045
  }
14046
+ try {
14047
+ await flushTraceBuffer();
14048
+ } catch {
14049
+ }
13676
14050
  try {
13677
14051
  const us = ledger.usageSummary();
13678
14052
  void recordUsageRun({
@@ -13751,6 +14125,7 @@ var init_runAgent = __esm({
13751
14125
  init_agentNudges();
13752
14126
  init_runLedger();
13753
14127
  init_usageLog();
14128
+ init_trace();
13754
14129
  init_createModel();
13755
14130
  CALIB_EMA_KEEP = 0.6;
13756
14131
  CALIB_EMA_NEW = 0.4;
@@ -13770,7 +14145,7 @@ var init_runAgent = __esm({
13770
14145
  });
13771
14146
 
13772
14147
  // ../core/src/session/lineage.ts
13773
- import fs35 from "node:fs";
14148
+ import fs37 from "node:fs";
13774
14149
  var parentOfSubsession, stringAncestorsOf, readForkedFromSync, lineageClosureOf, ownerCanApprove;
13775
14150
  var init_lineage = __esm({
13776
14151
  "../core/src/session/lineage.ts"() {
@@ -13793,7 +14168,7 @@ var init_lineage = __esm({
13793
14168
  };
13794
14169
  readForkedFromSync = (sessionId) => {
13795
14170
  try {
13796
- const raw = fs35.readFileSync(getStatePath(sessionId), "utf-8");
14171
+ const raw = fs37.readFileSync(getStatePath(sessionId), "utf-8");
13797
14172
  const v = JSON.parse(raw)?.forkedFrom;
13798
14173
  return typeof v === "string" && v.length > 0 ? v : void 0;
13799
14174
  } catch {
@@ -13922,6 +14297,7 @@ var init_subagent = __esm({
13922
14297
  sessionId: ""
13923
14298
  };
13924
14299
  }
14300
+ const SUBAGENT_REPORT_REQ = `\u3010\u6C47\u62A5\u8981\u6C42\u3011\u6700\u7EC8\u6C47\u62A5\u63A7\u5236\u5728\u4E00\u5C4F\u5185\uFF1A\u5DF2\u5B8C\u6210/\u6539\u52A8\u70B9\uFF08\u6587\u4EF6\u8DEF\u5F84\uFF09/\u9A8C\u8BC1\u7ED3\u679C/\u672A\u5B8C\u6210\u9879\u3002\u4E0D\u8981\u590D\u8FF0\u8FC7\u7A0B\u4E0E\u5DE5\u5177\u8F93\u51FA\u2014\u2014\u7236\u7EA7\u53EF\u76F4\u63A5\u7ECF resume \u8FFD\u95EE\u7EC6\u8282\u3002`;
13925
14301
  const subSystem = manifest ? [
13926
14302
  `# \u5B50 Agent \u8EAB\u4EFD\uFF1A${manifest.name}`,
13927
14303
  manifest.body,
@@ -13930,7 +14306,8 @@ var init_subagent = __esm({
13930
14306
  `\u5F53\u524D\u6240\u5904\u7684\u4EFB\u52A1\u6267\u884C\u5D4C\u5957\u6DF1\u5EA6: Depth ${ctx.depth + 1} / ${MAX_AGENT_DEPTH}`,
13931
14307
  `
13932
14308
  # \u3010\u7EE7\u627F\u7684\u5168\u5C40\u4EE3\u7801\u89C4\u8303\u3011`,
13933
- parentSystemPrompt
14309
+ parentSystemPrompt,
14310
+ SUBAGENT_REPORT_REQ
13934
14311
  ].filter(Boolean).join("\n") : [
13935
14312
  `# \u4EFB\u52A1\u4E0A\u4E0B\u6587`,
13936
14313
  `\u5F53\u524D\u6240\u5904\u7684\u4EFB\u52A1\u6267\u884C\u5D4C\u5957\u6DF1\u5EA6: Depth ${ctx.depth + 1} / ${MAX_AGENT_DEPTH}`,
@@ -13939,7 +14316,8 @@ var init_subagent = __esm({
13939
14316
  `\u4F60\u76F4\u63A5\u5171\u4EAB\u5E76\u64CD\u4F5C\u672C\u5730\u6587\u4EF6\u7CFB\u7EDF\u3002\u5F53\u4F60\u5BF9\u6587\u4EF6\u5168\u91CF\u5199\u5165\u6216\u5C40\u90E8\u4FEE\u6539\u65F6\uFF0C\u5FC5\u987B\u786E\u4FDD\u64CD\u4F5C\u7684\u7EDD\u5BF9\u7CBE\u51C6\u3002\u5B8C\u6210\u6307\u5B9A\u5B50\u4EFB\u52A1\u540E\uFF0C\u8BF7\u4F7F\u7528\u6700\u7EC8\u7684\u6587\u672C\u603B\u7ED3\u5411\u7236\u7EA7 Agent \u4EA4\u4ED8\u7ED3\u679C\u3002`,
13940
14317
  `
13941
14318
  # \u3010\u7EE7\u627F\u7684\u5168\u5C40\u4EE3\u7801\u89C4\u8303\u3011`,
13942
- parentSystemPrompt
14319
+ parentSystemPrompt,
14320
+ SUBAGENT_REPORT_REQ
13943
14321
  ].join("\n");
13944
14322
  const subTaskPrompt = [
13945
14323
  role ? manifest ? `# \u672C\u6B21\u89D2\u8272\u8865\u5145: ${role}` : `\u3010\u4F60\u7684\u4E13\u5C5E\u89D2\u8272\u3011: ${role}` : manifest ? "" : `\u3010\u4F60\u7684\u4E13\u5C5E\u89D2\u8272\u3011: \u4E13\u6CE8\u6267\u884C\u7279\u5B9A\u5C40\u90E8\u5B50\u4EFB\u52A1\u7684\u72EC\u7ACB\u667A\u80FD\u4F53\u52A9\u624B`,
@@ -14033,15 +14411,15 @@ var init_subagent = __esm({
14033
14411
  });
14034
14412
 
14035
14413
  // ../core/src/hooks/trust.ts
14036
- import path38 from "path";
14037
- import fs36 from "fs/promises";
14414
+ import path40 from "path";
14415
+ import fs38 from "fs/promises";
14038
14416
  var TRUSTED_HOOKS_FILE, approved, loaded, ensureLoaded, isHookCommandApproved, approveHookCommand;
14039
14417
  var init_trust2 = __esm({
14040
14418
  "../core/src/hooks/trust.ts"() {
14041
14419
  "use strict";
14042
14420
  init_config();
14043
14421
  init_common();
14044
- TRUSTED_HOOKS_FILE = path38.join(appConfig.dataDir, "trusted_hooks.json");
14422
+ TRUSTED_HOOKS_FILE = path40.join(appConfig.dataDir, "trusted_hooks.json");
14045
14423
  approved = /* @__PURE__ */ new Set();
14046
14424
  loaded = false;
14047
14425
  ensureLoaded = async () => {
@@ -14061,7 +14439,7 @@ var init_trust2 = __esm({
14061
14439
  if (approved.has(ident)) return;
14062
14440
  approved.add(ident);
14063
14441
  try {
14064
- await fs36.mkdir(appConfig.dataDir, { recursive: true });
14442
+ await fs38.mkdir(appConfig.dataDir, { recursive: true });
14065
14443
  await atomicWriteJSON(TRUSTED_HOOKS_FILE, [...approved]);
14066
14444
  } catch (e) {
14067
14445
  console.warn(`\u26A0\uFE0F [hooks] \u5BA1\u6279\u8BB0\u5FC6\u843D\u76D8\u5931\u8D25\uFF08\u672C\u6B21\u5DF2\u653E\u884C\uFF0C\u4E0B\u6B21\u9996\u8DD1\u4F1A\u518D\u95EE\uFF09: ${e?.message ?? e}`);
@@ -14071,8 +14449,8 @@ var init_trust2 = __esm({
14071
14449
  });
14072
14450
 
14073
14451
  // ../core/src/hooks/loader.ts
14074
- import fs37 from "fs/promises";
14075
- import path39 from "path";
14452
+ import fs39 from "fs/promises";
14453
+ import path41 from "path";
14076
14454
  var slimHookContext, readHooksConfig, appendValidated, validateRule, parseStdoutDecision, parseAgentDecision, gateSeq, firstRunGate, compileRule2, loadHooks, initHooks;
14077
14455
  var init_loader4 = __esm({
14078
14456
  "../core/src/hooks/loader.ts"() {
@@ -14101,15 +14479,15 @@ var init_loader4 = __esm({
14101
14479
  readHooksConfig = async (includeProject) => {
14102
14480
  const merged = {};
14103
14481
  const paths = [
14104
- path39.join(appConfig.dataDir, "settings.json"),
14482
+ path41.join(appConfig.dataDir, "settings.json"),
14105
14483
  // 全局用户级
14106
- ...includeProject ? [path39.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
14484
+ ...includeProject ? [path41.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
14107
14485
  // 项目级(叠加);未信任时省略
14108
14486
  ];
14109
14487
  for (const configPath of paths) {
14110
14488
  let raw;
14111
14489
  try {
14112
- raw = await fs37.readFile(configPath, "utf-8");
14490
+ raw = await fs39.readFile(configPath, "utf-8");
14113
14491
  } catch {
14114
14492
  continue;
14115
14493
  }
@@ -14482,8 +14860,8 @@ ${m.context}`;
14482
14860
  });
14483
14861
 
14484
14862
  // ../core/src/skills/loader.ts
14485
- import fs38 from "fs/promises";
14486
- import path40 from "path";
14863
+ import fs40 from "fs/promises";
14864
+ import path42 from "path";
14487
14865
  import { fileURLToPath as fileURLToPath2 } from "url";
14488
14866
  var BUILTIN_DIR, SOURCES2, MAX_SKILL_BODY_BYTES, splitList, parseSkillAt, loadSkills, initSkills;
14489
14867
  var init_loader5 = __esm({
@@ -14494,18 +14872,18 @@ var init_loader5 = __esm({
14494
14872
  init_registry3();
14495
14873
  init_skill();
14496
14874
  init_registry2();
14497
- BUILTIN_DIR = path40.join(path40.dirname(fileURLToPath2(import.meta.url)), "builtin");
14875
+ BUILTIN_DIR = path42.join(path42.dirname(fileURLToPath2(import.meta.url)), "builtin");
14498
14876
  SOURCES2 = [
14499
14877
  { dir: BUILTIN_DIR, source: "builtin" },
14500
- { dir: path40.join(appConfig.dataDir, "skills"), source: "global" },
14501
- { dir: path40.join(process.cwd(), ".deepseeker-code", "skills"), source: "project" }
14878
+ { dir: path42.join(appConfig.dataDir, "skills"), source: "global" },
14879
+ { dir: path42.join(process.cwd(), ".deepseeker-code", "skills"), source: "project" }
14502
14880
  ];
14503
14881
  MAX_SKILL_BODY_BYTES = 64 * 1024;
14504
14882
  splitList = (raw) => (raw ?? "").split(",").map((s) => s.trim()).filter(Boolean);
14505
14883
  parseSkillAt = async (skillFile, dir, source) => {
14506
14884
  let raw;
14507
14885
  try {
14508
- raw = await fs38.readFile(skillFile, "utf-8");
14886
+ raw = await fs40.readFile(skillFile, "utf-8");
14509
14887
  } catch {
14510
14888
  return null;
14511
14889
  }
@@ -14544,7 +14922,7 @@ var init_loader5 = __esm({
14544
14922
  loadSkills = async (includeProject) => {
14545
14923
  const picked = await scanSources(
14546
14924
  filterSources(SOURCES2, includeProject),
14547
- (e, dir) => e.isDirectory() ? path40.join(dir, e.name, "SKILL.md") : void 0,
14925
+ (e, dir) => e.isDirectory() ? path42.join(dir, e.name, "SKILL.md") : void 0,
14548
14926
  parseSkillAt
14549
14927
  );
14550
14928
  for (const { item } of picked) registerSkill(item);
@@ -14575,8 +14953,8 @@ var init_loader5 = __esm({
14575
14953
  });
14576
14954
 
14577
14955
  // ../core/src/agents/loader.ts
14578
- import fs39 from "fs/promises";
14579
- import path41 from "path";
14956
+ import fs41 from "fs/promises";
14957
+ import path43 from "path";
14580
14958
  import { fileURLToPath as fileURLToPath3 } from "url";
14581
14959
  var BUILTIN_DIR2, SOURCES3, parseAgentAt, initAgents;
14582
14960
  var init_loader6 = __esm({
@@ -14586,16 +14964,16 @@ var init_loader6 = __esm({
14586
14964
  init_frontmatter();
14587
14965
  init_registry4();
14588
14966
  init_registry2();
14589
- BUILTIN_DIR2 = path41.join(path41.dirname(fileURLToPath3(import.meta.url)), "builtin");
14967
+ BUILTIN_DIR2 = path43.join(path43.dirname(fileURLToPath3(import.meta.url)), "builtin");
14590
14968
  SOURCES3 = [
14591
14969
  { dir: BUILTIN_DIR2, source: "builtin" },
14592
- { dir: path41.join(appConfig.dataDir, "agents"), source: "global" },
14593
- { dir: path41.join(process.cwd(), ".deepseeker-code", "agents"), source: "project" }
14970
+ { dir: path43.join(appConfig.dataDir, "agents"), source: "global" },
14971
+ { dir: path43.join(process.cwd(), ".deepseeker-code", "agents"), source: "project" }
14594
14972
  ];
14595
14973
  parseAgentAt = async (file, dir, source) => {
14596
14974
  let raw;
14597
14975
  try {
14598
- raw = await fs39.readFile(file, "utf-8");
14976
+ raw = await fs41.readFile(file, "utf-8");
14599
14977
  } catch {
14600
14978
  return null;
14601
14979
  }
@@ -14630,7 +15008,7 @@ var init_loader6 = __esm({
14630
15008
  const known = new Set(into.map((t) => t.function.name));
14631
15009
  const picked = await scanSources(
14632
15010
  filterSources(SOURCES3, includeProject),
14633
- (e, dir) => e.isFile() && e.name.endsWith(".agent.md") ? path41.join(dir, e.name) : void 0,
15011
+ (e, dir) => e.isFile() && e.name.endsWith(".agent.md") ? path43.join(dir, e.name) : void 0,
14634
15012
  parseAgentAt
14635
15013
  );
14636
15014
  for (const { item: m, file, source } of picked) {
@@ -14667,8 +15045,8 @@ var init_registry7 = __esm({
14667
15045
  });
14668
15046
 
14669
15047
  // ../core/src/commands/loader.ts
14670
- import fs40 from "fs/promises";
14671
- import path42 from "path";
15048
+ import fs42 from "fs/promises";
15049
+ import path44 from "path";
14672
15050
  import { fileURLToPath as fileURLToPath4 } from "url";
14673
15051
  var BUILTIN_DIR3, SOURCES4, MAX_COMMAND_BODY_BYTES, parseCommandAt, loadCommands, initCommands;
14674
15052
  var init_loader7 = __esm({
@@ -14678,17 +15056,17 @@ var init_loader7 = __esm({
14678
15056
  init_frontmatter();
14679
15057
  init_registry7();
14680
15058
  init_registry2();
14681
- BUILTIN_DIR3 = path42.join(path42.dirname(fileURLToPath4(import.meta.url)), "builtin");
15059
+ BUILTIN_DIR3 = path44.join(path44.dirname(fileURLToPath4(import.meta.url)), "builtin");
14682
15060
  SOURCES4 = [
14683
15061
  { dir: BUILTIN_DIR3, source: "builtin" },
14684
- { dir: path42.join(appConfig.dataDir, "commands"), source: "global" },
14685
- { dir: path42.join(process.cwd(), ".deepseeker-code", "commands"), source: "project" }
15062
+ { dir: path44.join(appConfig.dataDir, "commands"), source: "global" },
15063
+ { dir: path44.join(process.cwd(), ".deepseeker-code", "commands"), source: "project" }
14686
15064
  ];
14687
15065
  MAX_COMMAND_BODY_BYTES = 64 * 1024;
14688
15066
  parseCommandAt = async (file, _dir, source) => {
14689
15067
  let raw;
14690
15068
  try {
14691
- raw = await fs40.readFile(file, "utf-8");
15069
+ raw = await fs42.readFile(file, "utf-8");
14692
15070
  } catch {
14693
15071
  return null;
14694
15072
  }
@@ -14699,7 +15077,7 @@ var init_loader7 = __esm({
14699
15077
  }
14700
15078
  const name = parsed.frontmatter.name;
14701
15079
  const description = parsed.frontmatter.description;
14702
- const fallbackName = path42.basename(file, ".md");
15080
+ const fallbackName = path44.basename(file, ".md");
14703
15081
  const finalName = name || fallbackName;
14704
15082
  if (!description) {
14705
15083
  console.warn(`\u26A0\uFE0F [commands] \u7F3A\u5C11 description\uFF08${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
@@ -14725,7 +15103,7 @@ var init_loader7 = __esm({
14725
15103
  loadCommands = async (includeProject) => {
14726
15104
  const picked = await scanSources(
14727
15105
  filterSources(SOURCES4, includeProject),
14728
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path42.join(dir, e.name) : void 0,
15106
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path44.join(dir, e.name) : void 0,
14729
15107
  parseCommandAt
14730
15108
  );
14731
15109
  for (const { item } of picked) registerCommand(item);
@@ -14743,8 +15121,8 @@ var init_loader7 = __esm({
14743
15121
  });
14744
15122
 
14745
15123
  // ../core/src/outputStyles/loader.ts
14746
- import fs41 from "fs/promises";
14747
- import path43 from "path";
15124
+ import fs43 from "fs/promises";
15125
+ import path45 from "path";
14748
15126
  import { fileURLToPath as fileURLToPath5 } from "url";
14749
15127
  var BUILTIN_DIR4, MAX_STYLE_BODY_BYTES, SOURCES5, parseStyleAt, loadOutputStyles, initOutputStyles;
14750
15128
  var init_loader8 = __esm({
@@ -14754,17 +15132,17 @@ var init_loader8 = __esm({
14754
15132
  init_frontmatter();
14755
15133
  init_registry5();
14756
15134
  init_registry2();
14757
- BUILTIN_DIR4 = path43.join(path43.dirname(fileURLToPath5(import.meta.url)), "builtin");
15135
+ BUILTIN_DIR4 = path45.join(path45.dirname(fileURLToPath5(import.meta.url)), "builtin");
14758
15136
  MAX_STYLE_BODY_BYTES = 64 * 1024;
14759
15137
  SOURCES5 = [
14760
15138
  { dir: BUILTIN_DIR4, source: "builtin" },
14761
- { dir: path43.join(appConfig.dataDir, "output-styles"), source: "global" },
14762
- { dir: path43.join(process.cwd(), ".deepseeker-code", "output-styles"), source: "project" }
15139
+ { dir: path45.join(appConfig.dataDir, "output-styles"), source: "global" },
15140
+ { dir: path45.join(process.cwd(), ".deepseeker-code", "output-styles"), source: "project" }
14763
15141
  ];
14764
15142
  parseStyleAt = async (file, _dir, source) => {
14765
15143
  let raw;
14766
15144
  try {
14767
- raw = await fs41.readFile(file, "utf-8");
15145
+ raw = await fs43.readFile(file, "utf-8");
14768
15146
  } catch {
14769
15147
  return null;
14770
15148
  }
@@ -14796,7 +15174,7 @@ var init_loader8 = __esm({
14796
15174
  loadOutputStyles = async (includeProject) => {
14797
15175
  const picked = await scanSources(
14798
15176
  filterSources(SOURCES5, includeProject),
14799
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path43.join(dir, e.name) : void 0,
15177
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path45.join(dir, e.name) : void 0,
14800
15178
  parseStyleAt
14801
15179
  );
14802
15180
  for (const { item } of picked) registerOutputStyle(item);
@@ -14877,8 +15255,8 @@ var init_bootstrap = __esm({
14877
15255
  });
14878
15256
 
14879
15257
  // ../core/src/statusLine/config.ts
14880
- import fs42 from "fs/promises";
14881
- import path44 from "path";
15258
+ import fs44 from "fs/promises";
15259
+ import path46 from "path";
14882
15260
  var parseBlock, readStatusLineConfig;
14883
15261
  var init_config2 = __esm({
14884
15262
  "../core/src/statusLine/config.ts"() {
@@ -14894,16 +15272,16 @@ var init_config2 = __esm({
14894
15272
  };
14895
15273
  readStatusLineConfig = async (includeProject) => {
14896
15274
  const paths = [
14897
- path44.join(appConfig.dataDir, "settings.json"),
15275
+ path46.join(appConfig.dataDir, "settings.json"),
14898
15276
  // 全局用户级
14899
- ...includeProject ? [path44.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
15277
+ ...includeProject ? [path46.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
14900
15278
  // 项目级(覆盖);未信任时省略
14901
15279
  ];
14902
15280
  let result = null;
14903
15281
  for (const configPath of paths) {
14904
15282
  let raw;
14905
15283
  try {
14906
- raw = await fs42.readFile(configPath, "utf-8");
15284
+ raw = await fs44.readFile(configPath, "utf-8");
14907
15285
  } catch {
14908
15286
  continue;
14909
15287
  }
@@ -14923,8 +15301,8 @@ var init_config2 = __esm({
14923
15301
 
14924
15302
  // ../core/src/statusLine/runner.ts
14925
15303
  import { spawn as spawn5 } from "child_process";
14926
- import fs43 from "fs";
14927
- import path45 from "path";
15304
+ import fs45 from "fs";
15305
+ import path47 from "path";
14928
15306
  import { fileURLToPath as fileURLToPath6 } from "url";
14929
15307
  var STATUSLINE_TIMEOUT_MS, cachedVersion, runStatusLine;
14930
15308
  var init_runner = __esm({
@@ -14933,16 +15311,16 @@ var init_runner = __esm({
14933
15311
  init_guard();
14934
15312
  STATUSLINE_TIMEOUT_MS = 3e3;
14935
15313
  try {
14936
- const here = path45.dirname(fileURLToPath6(import.meta.url));
15314
+ const here = path47.dirname(fileURLToPath6(import.meta.url));
14937
15315
  const candidates = [
14938
- path45.join(here, "../../../package.json"),
15316
+ path47.join(here, "../../../package.json"),
14939
15317
  // src/core/package.json
14940
- path45.join(here, "../../../../package.json")
15318
+ path47.join(here, "../../../../package.json")
14941
15319
  // 仓库根 package.json
14942
15320
  ];
14943
15321
  for (const p of candidates) {
14944
15322
  try {
14945
- const pkg = JSON.parse(fs43.readFileSync(p, "utf-8"));
15323
+ const pkg = JSON.parse(fs45.readFileSync(p, "utf-8"));
14946
15324
  if (typeof pkg.version === "string" && pkg.version) {
14947
15325
  cachedVersion = pkg.version;
14948
15326
  break;
@@ -14992,222 +15370,6 @@ var init_runner = __esm({
14992
15370
  }
14993
15371
  });
14994
15372
 
14995
- // ../core/src/observability/store.ts
14996
- import path46 from "path";
14997
- import fs44 from "fs/promises";
14998
- var getTraceDirPath, getTracePath, tracePathCache, ensuredTraceDirs, ensureTraceDir, getGlobalClockPath, getTraceStorePath;
14999
- var init_store3 = __esm({
15000
- "../core/src/observability/store.ts"() {
15001
- "use strict";
15002
- init_config();
15003
- init_traceCalculate();
15004
- init_common();
15005
- getTraceDirPath = (mainTraceId) => {
15006
- assertSafeSessionId(mainTraceId, "traceId");
15007
- return path46.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
15008
- };
15009
- getTracePath = () => {
15010
- return path46.join(appConfig.dataDir, "trace");
15011
- };
15012
- tracePathCache = /* @__PURE__ */ new Map();
15013
- ensuredTraceDirs = /* @__PURE__ */ new Set();
15014
- ensureTraceDir = async (mainTraceId) => {
15015
- const dir = getTraceDirPath(mainTraceId);
15016
- if (ensuredTraceDirs.has(dir)) return;
15017
- await fs44.mkdir(dir, { recursive: true });
15018
- ensuredTraceDirs.add(dir);
15019
- };
15020
- getGlobalClockPath = () => {
15021
- return path46.join(getTracePath(), "trace-cleanup-clock.json");
15022
- };
15023
- getTraceStorePath = async (mainTraceId) => {
15024
- assertSafeSessionId(mainTraceId, "traceId");
15025
- const rootId = getFileName(mainTraceId);
15026
- const cached2 = tracePathCache.get(rootId);
15027
- if (cached2) return cached2;
15028
- await ensureTraceDir(rootId);
15029
- const dir = getTraceDirPath(rootId);
15030
- const files = await fs44.readdir(dir);
15031
- const existedFile = files.find((f) => f.endsWith(`__${rootId}.jsonl`));
15032
- let fileName = "";
15033
- if (existedFile) {
15034
- fileName = existedFile;
15035
- } else {
15036
- const todayStr = getTodayDateString();
15037
- fileName = `trace-${todayStr}__${rootId}.jsonl`;
15038
- }
15039
- const resolved = path46.join(dir, fileName);
15040
- tracePathCache.set(rootId, resolved);
15041
- return resolved;
15042
- };
15043
- }
15044
- });
15045
-
15046
- // ../core/src/observability/trace.ts
15047
- import fs45 from "fs/promises";
15048
- import path47 from "path";
15049
- async function emitTrace(base) {
15050
- const event = {
15051
- sessionId: base.sessionId,
15052
- parentId: base.parentId,
15053
- eventType: base.eventType,
15054
- timestamp: base.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
15055
- usage: base.usage,
15056
- payload: base.payload,
15057
- metadata: {
15058
- ...base.metadata || {}
15059
- }
15060
- };
15061
- try {
15062
- await appendTraceEvent(event);
15063
- } catch (error) {
15064
- console.warn("\u26A0\uFE0F [Trace] \u4E8B\u4EF6\u843D\u76D8\u5931\u8D25\uFF0C\u5DF2\u9632\u5FA1\u6027\u8DF3\u8FC7\uFF08\u4E0D\u5F71\u54CD\u4E3B\u4E1A\u52A1\uFF09:", error);
15065
- }
15066
- }
15067
- async function appendTraceEvent(event) {
15068
- const p = await getTraceStorePath(event.sessionId);
15069
- const line = JSON.stringify(event) + "\n";
15070
- await fs45.appendFile(p, line, "utf-8");
15071
- if (workspaceTraceBytes < 0) {
15072
- workspaceTraceBytes = await getDirBytes(getTracePath());
15073
- }
15074
- workspaceTraceBytes += Buffer.byteLength(line, "utf-8");
15075
- void maybeCleanupAfterAppend(event.sessionId);
15076
- }
15077
- async function maybeCleanupAfterAppend(sessionId) {
15078
- if (cleanupInProgress2) return;
15079
- cleanupInProgress2 = true;
15080
- try {
15081
- await ensureClockLoaded2();
15082
- const now = Date.now();
15083
- const isTimeExpired = now - diskLastCleanupAt2 > CLEANUP_INTERVAL_MS2;
15084
- const isSizeOverflow = workspaceTraceBytes > MAX_TRACE_FOLDER_BYTES;
15085
- if (!isTimeExpired && !isSizeOverflow) return;
15086
- if (isSizeOverflow && !isTimeExpired && now - lastSizeCleanupAt2 < SIZE_CLEANUP_COOLDOWN_MS2) {
15087
- return;
15088
- }
15089
- const reason = isTimeExpired && isSizeOverflow ? "\u5BB9\u91CF+\u65F6\u95F4\u53CC\u95F8" : isSizeOverflow ? "\u5BB9\u91CF\u8D8A\u8FC750MB\u5927\u95F8" : "3\u5929\u51B7\u5374\u5468\u671F\u5DF2\u6EE1";
15090
- console.log(`\u{1F9F9} [Trace\u8FD0\u7EF4] \u89E6\u53D1\u81EA\u9002\u5E94\u6E05\u7406\uFF08\u539F\u56E0: ${reason}\uFF09`);
15091
- let deletedCount = 0;
15092
- deletedCount += await cleanupOldTraceFiles();
15093
- workspaceTraceBytes = await getDirBytes(getTracePath());
15094
- if (workspaceTraceBytes > MAX_TRACE_FOLDER_BYTES) {
15095
- const targetBytes = Math.floor(MAX_TRACE_FOLDER_BYTES * SIZE_RECLAIM_TARGET_RATIO2);
15096
- deletedCount += await evictOldestForSize2(targetBytes);
15097
- workspaceTraceBytes = await getDirBytes(getTracePath());
15098
- }
15099
- lastSizeCleanupAt2 = now;
15100
- diskLastCleanupAt2 = now;
15101
- const clockPath = getGlobalClockPath();
15102
- await fs45.mkdir(path47.dirname(clockPath), { recursive: true });
15103
- await fs45.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
15104
- if (deletedCount > 0) {
15105
- console.log(`\u2728 [Trace\u8FD0\u7EF4] \u5171\u9500\u6BC1 ${deletedCount} \u4E2A\u4F1A\u8BDD\u65E5\u5FD7\uFF08\u8F6F\u89C4\u5219\u8FC7\u671F\u6E05\u7406 + \u5BB9\u91CF\u786C\u9A71\u9010\uFF09\uFF0C\u78C1\u76D8\u6C34\u4F4D\u56DE\u843D\u3002`);
15106
- }
15107
- } catch (error) {
15108
- console.warn("\u26A0\uFE0F [Trace\u8FD0\u7EF4] \u81EA\u52A8\u6E05\u7406\u53D1\u751F\u8F7B\u5FAE\u5F02\u5E38\uFF0C\u5DF2\u9632\u5FA1\u6027\u8DF3\u8FC7:", error);
15109
- } finally {
15110
- cleanupInProgress2 = false;
15111
- }
15112
- }
15113
- async function cleanupOldTraceFiles() {
15114
- const dir = getTracePath();
15115
- const retentionDays = Math.max(1, appConfig.traceRetentionDays || 7);
15116
- const cutoff = /* @__PURE__ */ new Date();
15117
- cutoff.setHours(0, 0, 0, 0);
15118
- cutoff.setDate(cutoff.getDate() - retentionDays);
15119
- const now = Date.now();
15120
- let deleted = 0;
15121
- let relativePaths;
15122
- try {
15123
- relativePaths = await fs45.readdir(dir, { recursive: true });
15124
- } catch {
15125
- return 0;
15126
- }
15127
- const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
15128
- for (const relativePath of relativePaths) {
15129
- const fileName = path47.basename(relativePath);
15130
- const m = fileName.match(re);
15131
- if (!m) continue;
15132
- const fileBornDay = /* @__PURE__ */ new Date(`${m[1]}T00:00:00`);
15133
- if (fileBornDay >= cutoff) continue;
15134
- const fullPath = path47.join(dir, relativePath);
15135
- try {
15136
- const st = await fs45.stat(fullPath);
15137
- if (now - st.mtimeMs < ACTIVE_GRACE_MS2) continue;
15138
- await fs45.unlink(fullPath);
15139
- deleted += 1;
15140
- } catch {
15141
- }
15142
- }
15143
- return deleted;
15144
- }
15145
- async function evictOldestForSize2(targetBytes) {
15146
- const dir = getTracePath();
15147
- let relativePaths;
15148
- try {
15149
- relativePaths = await fs45.readdir(dir, { recursive: true });
15150
- } catch {
15151
- return 0;
15152
- }
15153
- const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
15154
- const candidates = [];
15155
- for (const relativePath of relativePaths) {
15156
- const fileName = path47.basename(relativePath);
15157
- if (!re.test(fileName)) continue;
15158
- try {
15159
- const st = await fs45.stat(path47.join(dir, relativePath));
15160
- candidates.push({ mtime: st.mtimeMs, fullPath: path47.join(dir, relativePath), size: st.size });
15161
- } catch {
15162
- }
15163
- }
15164
- candidates.sort((a, b) => a.mtime - b.mtime);
15165
- let totalBytes = candidates.reduce((sum, c) => sum + c.size, 0);
15166
- let deleted = 0;
15167
- for (const c of candidates) {
15168
- if (totalBytes <= targetBytes) break;
15169
- try {
15170
- await fs45.unlink(c.fullPath);
15171
- totalBytes -= c.size;
15172
- deleted += 1;
15173
- } catch {
15174
- }
15175
- }
15176
- if (deleted > 0) {
15177
- console.warn(`\u26A0\uFE0F [Trace\u8FD0\u7EF4] \u5BB9\u91CF\u786C\u9A71\u9010\uFF1A\u8D8A\u8FC7\u6D3B\u8DC3\u4FDD\u62A4\u5F3A\u5220 ${deleted} \u4E2A\u6700\u65E7 trace \u6587\u4EF6\uFF08\u78C1\u76D8\u538B\u529B\u515C\u5E95\uFF09\u3002`);
15178
- }
15179
- return deleted;
15180
- }
15181
- var CLEANUP_INTERVAL_MS2, ACTIVE_GRACE_MS2, MAX_TRACE_FOLDER_BYTES, SIZE_RECLAIM_TARGET_RATIO2, SIZE_CLEANUP_COOLDOWN_MS2, workspaceTraceBytes, diskLastCleanupAt2, clockLoaded2, lastSizeCleanupAt2, cleanupInProgress2, ensureClockLoaded2;
15182
- var init_trace = __esm({
15183
- "../core/src/observability/trace.ts"() {
15184
- "use strict";
15185
- init_config();
15186
- init_store3();
15187
- init_traceCalculate();
15188
- CLEANUP_INTERVAL_MS2 = 3 * 24 * 60 * 60 * 1e3;
15189
- ACTIVE_GRACE_MS2 = 24 * 60 * 60 * 1e3;
15190
- MAX_TRACE_FOLDER_BYTES = 50 * 1024 * 1024;
15191
- SIZE_RECLAIM_TARGET_RATIO2 = 0.8;
15192
- SIZE_CLEANUP_COOLDOWN_MS2 = 60 * 1e3;
15193
- workspaceTraceBytes = -1;
15194
- diskLastCleanupAt2 = 0;
15195
- clockLoaded2 = false;
15196
- lastSizeCleanupAt2 = 0;
15197
- cleanupInProgress2 = false;
15198
- ensureClockLoaded2 = async () => {
15199
- if (clockLoaded2) return;
15200
- clockLoaded2 = true;
15201
- try {
15202
- const rawClock = await fs45.readFile(getGlobalClockPath(), "utf-8");
15203
- diskLastCleanupAt2 = JSON.parse(rawClock).lastCleanupAt || 0;
15204
- } catch {
15205
- diskLastCleanupAt2 = 0;
15206
- }
15207
- };
15208
- }
15209
- });
15210
-
15211
15373
  // ../core/src/tool/approvalGate.ts
15212
15374
  var approvalGate_exports = {};
15213
15375
  __export(approvalGate_exports, {
@@ -16923,7 +17085,7 @@ var init_StreamingCursor = __esm({
16923
17085
  // src/components/MessageBlock.tsx
16924
17086
  import { Box, Text as Text3 } from "ink";
16925
17087
  import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
16926
- var UsageFooter, listPrefix, AssistantLine, isFenceMark, isMdRow, isMdSep, mdCells, parseBlocks, fitCell, tableWidths, buildVLines, AssistantVLine, MessageBlock;
17088
+ var UsageFooter, listPrefix, AssistantLine, fenceLen, isMdRow, isMdSep, mdCells, parseBlocks, fitCell, tableWidths, buildVLines, AssistantVLine, MessageBlock;
16927
17089
  var init_MessageBlock = __esm({
16928
17090
  "src/components/MessageBlock.tsx"() {
16929
17091
  "use strict";
@@ -16962,7 +17124,10 @@ var init_MessageBlock = __esm({
16962
17124
  }
16963
17125
  return /* @__PURE__ */ jsx3(RichText, { text: line });
16964
17126
  };
16965
- isFenceMark = (l) => /^\s*```/.test(l);
17127
+ fenceLen = (l, bareOnly) => {
17128
+ const m = l.match(/^\s*(`{3,})([a-z0-9_-]*)\s*$/);
17129
+ return m && (!bareOnly || !m[2]) ? m[1].length : 0;
17130
+ };
16966
17131
  isMdRow = (l) => l.includes("|");
16967
17132
  isMdSep = (l) => /^[ \t|:-]+$/.test(l) && l.includes("-") && l.includes("|");
16968
17133
  mdCells = (l) => l.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
@@ -16971,10 +17136,11 @@ var init_MessageBlock = __esm({
16971
17136
  const blocks = [];
16972
17137
  let i = 0;
16973
17138
  while (i < src.length) {
16974
- if (isFenceMark(src[i])) {
17139
+ const openLen = fenceLen(src[i], false);
17140
+ if (openLen) {
16975
17141
  const body = [];
16976
17142
  i++;
16977
- while (i < src.length && !isFenceMark(src[i])) body.push(src[i++]);
17143
+ while (i < src.length && fenceLen(src[i], true) < openLen) body.push(src[i++]);
16978
17144
  if (i < src.length) i++;
16979
17145
  blocks.push({ kind: "fence", lines: body });
16980
17146
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepseeker-code",
3
- "version": "1.0.60",
3
+ "version": "1.0.61",
4
4
  "description": "DeepSeeker-Code 终端客户端(React Ink,in-process 直驱 runAgent)",
5
5
  "homepage": "https://github.com/xknk/deepSeekCode#readme",
6
6
  "repository": {