deepseeker-code 1.0.48 → 1.0.50

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 (3) hide show
  1. package/README.md +4 -3
  2. package/dist/cli.mjs +857 -276
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -161,7 +161,8 @@ ${dim} \u8FD0\u884C npm i -g deepseeker-code@latest \u66F4\u65B0${reset}
161
161
  cmdStatus: "\u67E5\u770B\u5F53\u524D\u6A21\u578B/\u4F1A\u8BDD/\u6A21\u5F0F",
162
162
  cmdPlan: "\u5207\u6362\u8BA1\u5212\u6A21\u5F0F\uFF08\u53EA\u8BFB\u8C03\u7814\u2192\u5BA1\u6279\u2192\u5B9E\u73B0\uFF09",
163
163
  cmdAuto: "\u5207\u6362\u81EA\u52A8\u6A21\u5F0F\uFF08\u6587\u4EF6\u7F16\u8F91\u5206\u7C7B\u5668\u81EA\u52A8\u653E\u884C\uFF0C\u9AD8\u5371\u8F6C\u4EBA\u5DE5\uFF09",
164
- cmdModel: "\u5207\u6362\u6A21\u578B\uFF1A/model <deepseek-v4|deepseek-v4-flash|\u2026>",
164
+ cmdModel: "\u5207\u6362\u6A21\u578B\uFF08\u76F4\u8F93\uFF09\uFF1A/model <\u6A21\u578Bid>\uFF0C\u65E0\u53C2\u67E5\u770B\u5F53\u524D\u6A21\u578B",
165
+ cmdSwitch: "\u5F39\u51FA\u5019\u9009\u6A21\u578B\u9009\u62E9\u5668\uFF08\u2191\u2193 \u9009\u62E9\uFF09",
165
166
  cmdThinking: "\u5207\u6362\u601D\u8003\u7B49\u7EA7\uFF1A/thinking <off|high|max>",
166
167
  cmdLang: "\u5207\u6362\u754C\u9762\u8BED\u8A00\uFF1A/lang <zh|en>",
167
168
  cmdOutputStyle: "\u5207\u6362\u8F93\u51FA\u98CE\u683C\uFF1A/output-style <name|off>",
@@ -185,6 +186,12 @@ ${dim} \u8FD0\u884C npm i -g deepseeker-code@latest \u66F4\u65B0${reset}
185
186
  forkEmpty: "\uFF08\u5F53\u524D\u4F1A\u8BDD\u6682\u65E0\u53EF\u5206\u53C9\u7684\u68C0\u67E5\u70B9\uFF09",
186
187
  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`,
187
188
  forkFailed: (e) => `\u5206\u53C9\u5931\u8D25\uFF1A${e}`,
189
+ modelUsage: (current) => `\u5F53\u524D\u6A21\u578B\uFF1A${current || "\u9ED8\u8BA4\uFF08DEEP_SEEK_MODEL\uFF09"}
190
+ \u7528\u6CD5\uFF1A/model <\u6A21\u578Bid> \u76F4\u8F93\u5207\u6362\uFF0C\u6216 /switch \u5F39\u51FA\u5019\u9009\u9009\u62E9\u5668`,
191
+ modelPickerTitle: (current) => `\u{1F9E0} \u9009\u62E9\u6A21\u578B\uFF08\u5F53\u524D\uFF1A${current || "\u9ED8\u8BA4"}\uFF09`,
192
+ modelPickerPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u5207\u6362 \xB7 Esc \u53D6\u6D88\uFF08\u5176\u5B83\u6A21\u578B\uFF1A/model <\u6A21\u578Bid>\uFF09",
193
+ modelCurrentTag: "\u5F53\u524D",
194
+ modelSwitched: (m) => `\u6A21\u578B\u5DF2\u5207\u6362\uFF1A${m}\uFF08\u4E0B\u6B21\u56DE\u590D\u751F\u6548\uFF0C\u91CD\u542F\u540E\u4FDD\u6301\uFF09`,
188
195
  relTime: (iso) => {
189
196
  const t = Date.parse(iso);
190
197
  if (!t) return "";
@@ -216,7 +223,8 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
216
223
  helpText: (model2, thinking, locale2) => [
217
224
  "/help \xB7 /status \xB7 /clear \xB7 /exit",
218
225
  "/plan \u2014 \u5207\u6362\u8BA1\u5212\u6A21\u5F0F\uFF08\u53EA\u8BFB\u8C03\u7814 \u2192 \u65B9\u6848\u5BA1\u6279 \u2192 \u5B9E\u73B0\uFF09",
219
- `/model [deepseek-v4|deepseek-v4-flash|<\u4EFB\u610F>] \u2014 \u5207\u6362\u6A21\u578B\uFF08\u5F53\u524D ${model2}\uFF09`,
226
+ `/model <\u6A21\u578Bid> \u2014 \u5207\u6362\u6A21\u578B\uFF08\u76F4\u8F93\uFF0C\u5F53\u524D ${model2}\uFF09`,
227
+ "/switch \u2014 \u5F39\u51FA\u5019\u9009\u6A21\u578B\u9009\u62E9\u5668",
220
228
  `/thinking [off|high|max] \u2014 \u5207\u6362\u601D\u8003\u7B49\u7EA7\uFF08\u5F53\u524D ${thinking}\uFF09`,
221
229
  `/lang [zh|en] \u2014 \u5207\u6362\u754C\u9762\u8BED\u8A00\uFF08\u5F53\u524D ${locale2}\uFF09`,
222
230
  "/sessions \u2014 \u9009\u62E9\u5E76\u8F7D\u5165\u5386\u53F2\u4F1A\u8BDD\uFF08\u7EED\u63A5\u5BF9\u8BDD\uFF09",
@@ -301,7 +309,8 @@ ${dim} Run npm i -g deepseeker-code@latest to update${reset}
301
309
  cmdStatus: "Show current model/session/mode",
302
310
  cmdPlan: "Toggle plan mode (read-only research \u2192 review \u2192 implement)",
303
311
  cmdAuto: "Toggle auto mode (classifier auto-approves file edits, escalates risky)",
304
- cmdModel: "Switch model: /model <deepseek-v4|deepseek-v4-flash|\u2026>",
312
+ cmdModel: "Switch model (direct): /model <model-id>; no arg shows current",
313
+ cmdSwitch: "Open the model picker (\u2191\u2193 to pick)",
305
314
  cmdThinking: "Switch thinking level: /thinking <off|high|max>",
306
315
  cmdLang: "Switch interface language: /lang <zh|en>",
307
316
  cmdOutputStyle: "Switch output style: /output-style <name|off>",
@@ -325,6 +334,12 @@ ${dim} Run npm i -g deepseeker-code@latest to update${reset}
325
334
  forkEmpty: "(no checkpoints to fork from in this session)",
326
335
  forkDone: (id, roundNo) => `Forked from round ${roundNo} \u2192 new session ${id} (loaded; new messages go to the fork, source untouched)`,
327
336
  forkFailed: (e) => `Fork failed: ${e}`,
337
+ modelUsage: (current) => `Current model: ${current || "default (DEEP_SEEK_MODEL)"}
338
+ Usage: /model <model-id> to switch directly, or /switch for the picker`,
339
+ modelPickerTitle: (current) => `\u{1F9E0} Pick a model (current: ${current || "default"})`,
340
+ modelPickerPrompt: "\u2191\u2193 pick \xB7 Enter switch \xB7 Esc cancel (any other model: /model <id>)",
341
+ modelCurrentTag: "current",
342
+ modelSwitched: (m) => `Model switched: ${m} (takes effect on next reply, persists across restarts)`,
328
343
  relTime: (iso) => {
329
344
  const t = Date.parse(iso);
330
345
  if (!t) return "";
@@ -356,7 +371,8 @@ DeepSeeker-Code will read, edit, and execute files here.`,
356
371
  helpText: (model2, thinking, locale2) => [
357
372
  "/help \xB7 /status \xB7 /clear \xB7 /exit",
358
373
  "/plan \u2014 Toggle plan mode (read-only research \u2192 review \u2192 implement)",
359
- `/model [deepseek-v4|deepseek-v4-flash|<any>] \u2014 Switch model (current ${model2})`,
374
+ `/model <model-id> \u2014 Switch model (direct input; current ${model2})`,
375
+ "/switch \u2014 Open the model picker",
360
376
  `/thinking [off|high|max] \u2014 Switch thinking level (current ${thinking})`,
361
377
  `/lang [zh|en] \u2014 Switch interface language (current ${locale2})`,
362
378
  "/sessions \u2014 Pick a past session to resume",
@@ -381,7 +397,7 @@ DeepSeeker-Code will read, edit, and execute files here.`,
381
397
  S = new Proxy({}, {
382
398
  get: (_t, k) => typeof k === "string" ? STRINGS[locale][k] : void 0
383
399
  });
384
- LOCAL_COMMAND_NAMES = ["help", "status", "plan", "auto", "model", "thinking", "lang", "output-style", "sessions", "fork", "usage", "context", "permissions", "mcp", "hooks", "trust", "debug", "clear", "exit"];
400
+ LOCAL_COMMAND_NAMES = ["help", "status", "plan", "auto", "model", "switch", "thinking", "lang", "output-style", "sessions", "fork", "usage", "context", "permissions", "mcp", "hooks", "trust", "debug", "clear", "exit"];
385
401
  }
386
402
  });
387
403
 
@@ -666,7 +682,7 @@ ${body}`;
666
682
  const oldBody = next?.index !== void 0 ? after.slice(0, next.index) : after;
667
683
  if (oldBody === `
668
684
  ${body}`) return;
669
- 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`);
685
+ console.warn(`\u26A0\uFE0F ${fence} \u5DF2\u9501\u5B9A\uFF08run \u5185\u4E0D\u53D8\u4EE5\u4FDD\u524D\u7F00\u7F13\u5B58\uFF09\uFF0C\u5185\u5BB9\u53D8\u5316\u5C06\u4E8E\u4E0B\u8F6E\u91CD\u5EFA message[0] \u65F6\u751F\u6548\u3002`);
670
686
  };
671
687
  decodeProcessOutput = (buf) => {
672
688
  const utf8 = buf.toString("utf8");
@@ -690,7 +706,7 @@ ${body}`) return;
690
706
  // src/prefs.ts
691
707
  import path4 from "path";
692
708
  import fs2 from "fs/promises";
693
- var PREFS_FILE, readPrefs, readLocale, writePrefs, writeLocale;
709
+ var PREFS_FILE, readPrefs, readModelPref, readLocale, writePrefs, writeLocale;
694
710
  var init_prefs = __esm({
695
711
  "src/prefs.ts"() {
696
712
  "use strict";
@@ -701,6 +717,10 @@ var init_prefs = __esm({
701
717
  const p = await readJSONFile(PREFS_FILE);
702
718
  return p && typeof p === "object" ? p : {};
703
719
  };
720
+ readModelPref = async () => {
721
+ const { model: model2 } = await readPrefs();
722
+ return typeof model2 === "string" && model2.trim() ? model2.trim() : null;
723
+ };
704
724
  readLocale = async () => {
705
725
  const { locale: locale2 } = await readPrefs();
706
726
  return locale2 === "zh" || locale2 === "en" ? locale2 : null;
@@ -792,8 +812,9 @@ var init_client = __esm({
792
812
  baseURL: process.env.DEEP_SEEK_API_URL || "https://api.deepseek.com",
793
813
  apiKey: process.env.DEEP_SEEK_API_KEY,
794
814
  // ★ 瞬态错误自动指数退避重试(SDK 内置:408/409/429/500/502/503/504 + 连接错误),
795
- // 避免单次 429 限流 / 网关抖动 / 网络超时直接终止整轮 agent(长任务几十轮工具调用体验极差)。
796
- // 注:SDK 重试已覆盖瞬态错误,runAgent 不再叠加第二层重试(否则会放大负载)。
815
+ // 覆盖非流式 helper(summarize / classifyRisk)。★ 流式对话不在此列:stream.ts 按
816
+ // maxRetries: 0 关掉 SDK 层,瞬态重试单层归 streamInference 应用层(Retry-After 感知 +
817
+ // text.reset/abort/超长降级语义,SDK 层不具备)——两层同开会把 429 放大成 5×3=15 次请求。
797
818
  maxRetries: 4,
798
819
  timeout: 12e4
799
820
  // 单次请求 120s 兜底(长上下文 / 长生成场景)
@@ -808,18 +829,37 @@ var init_client = __esm({
808
829
  });
809
830
 
810
831
  // ../core/src/llm/providers/deepseek/stream.ts
811
- var STREAM_IDLE_TIMEOUT_MS, streamChat;
832
+ var STREAM_IDLE_TIMEOUT_MS, stripHistoricalReasoning, streamChat;
812
833
  var init_stream = __esm({
813
834
  "../core/src/llm/providers/deepseek/stream.ts"() {
814
835
  "use strict";
815
836
  init_client();
816
837
  STREAM_IDLE_TIMEOUT_MS = Number(process.env.DEEP_SEEK_STREAM_IDLE_TIMEOUT_MS) || 12e4;
838
+ stripHistoricalReasoning = (messages) => {
839
+ if (process.env.DEEP_SEEK_REASONING_PASSTHROUGH === "1") return messages;
840
+ let lastNonSystem = null;
841
+ for (let i = messages.length - 1; i >= 0; i--) {
842
+ if (messages[i]?.role !== "system") {
843
+ lastNonSystem = messages[i];
844
+ break;
845
+ }
846
+ }
847
+ if (lastNonSystem?.role === "assistant") return messages;
848
+ return messages.map((m) => {
849
+ const wire = m;
850
+ if (wire?.role !== "assistant" || typeof wire.reasoning_content !== "string") return m;
851
+ const copy = { ...wire };
852
+ delete copy.reasoning_content;
853
+ return copy;
854
+ });
855
+ };
817
856
  streamChat = async function* (messages, tools, opts) {
818
857
  const level = opts.thinkingLevel;
819
858
  const thinkingType = (level === void 0 ? MODEL_THINKING_ENABLED : level !== "off") ? "enabled" : "disabled";
820
859
  const effort = level === "max" ? "max" : level === "high" ? "high" : level === "off" ? "high" : MODEL_REASONING_EFFORT;
821
860
  const requestBody = {
822
- messages,
861
+ messages: stripHistoricalReasoning(messages),
862
+ // ★ 出口剥离历史思考记录(见函数注释;默认开)
823
863
  model: opts.model ?? MODEL_NAME,
824
864
  // per-agent 覆盖(声明式子 Agent);缺省回退全局
825
865
  tool_choice: "auto",
@@ -836,7 +876,8 @@ var init_stream = __esm({
836
876
  const extSignal = opts.signal;
837
877
  const combinedSignal = extSignal ? AbortSignal.any([idleAc.signal, extSignal]) : idleAc.signal;
838
878
  const stream = await model.chat.completions.create(requestBody, {
839
- signal: combinedSignal
879
+ signal: combinedSignal,
880
+ maxRetries: 0
840
881
  });
841
882
  const reader = stream[Symbol.asyncIterator]();
842
883
  try {
@@ -903,7 +944,8 @@ var init_deepseek = __esm({
903
944
  summarize = async (messages, tools, opts) => {
904
945
  try {
905
946
  const requestBody = {
906
- messages,
947
+ messages: stripHistoricalReasoning(messages),
948
+ // ★ 出口剥离历史思考记录(压缩输入全价计费,省得最实)
907
949
  model: AUX_MODEL_NAME,
908
950
  tool_choice: "auto",
909
951
  tools,
@@ -980,11 +1022,22 @@ var init_deepseek = __esm({
980
1022
  }
981
1023
  });
982
1024
 
1025
+ // ../core/src/llm/createModel.ts
1026
+ var SELECTABLE_MODELS;
1027
+ var init_createModel = __esm({
1028
+ "../core/src/llm/createModel.ts"() {
1029
+ "use strict";
1030
+ init_client();
1031
+ SELECTABLE_MODELS = ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-v4-flash-vision-exp"];
1032
+ }
1033
+ });
1034
+
983
1035
  // ../core/src/session/contentParts.ts
984
- var MAX_IMAGE_BYTES, msgText, imageUrlsOf, hasImagePart, isVisionEnabled, estimateImageTokens, toWireUserContent, replaceImageParts, collapseToText, degradeImagesForAux;
1036
+ var MAX_IMAGE_BYTES, msgText, imageUrlsOf, hasImagePart, modelSupportsVision, isVisionEnabled, estimateImageTokens, toWireUserContent, toIngestContents, replaceImageParts, collapseToText, degradeImagesForAux;
985
1037
  var init_contentParts = __esm({
986
1038
  "../core/src/session/contentParts.ts"() {
987
1039
  "use strict";
1040
+ init_createModel();
988
1041
  MAX_IMAGE_BYTES = 8 * 1024 * 1024;
989
1042
  msgText = (content) => {
990
1043
  if (typeof content === "string") return content;
@@ -998,9 +1051,13 @@ var init_contentParts = __esm({
998
1051
  return content.filter((p) => p?.type === "image_url" && typeof p?.image_url?.url === "string").map((p) => p.image_url.url);
999
1052
  };
1000
1053
  hasImagePart = (content) => imageUrlsOf(content).length > 0;
1001
- isVisionEnabled = () => {
1054
+ modelSupportsVision = (modelId) => /vision|vlm|(^|[-_.])vl([-_.0-9]|$)/i.test(modelId || "");
1055
+ isVisionEnabled = (modelId) => {
1002
1056
  const v = process.env.DEEP_SEEK_VISION;
1003
- return v === "1" || v === "true";
1057
+ if (v === "1" || v === "true") return true;
1058
+ if (v === "0" || v === "false") return false;
1059
+ const effective = typeof modelId === "string" && modelId.trim() ? modelId.trim() : MODEL_NAME;
1060
+ return modelSupportsVision(effective);
1004
1061
  };
1005
1062
  estimateImageTokens = () => {
1006
1063
  const n = Number(process.env.DEEP_SEEK_IMAGE_TOKENS);
@@ -1039,6 +1096,22 @@ ${footer.join("\n")}` : text;
1039
1096
  ];
1040
1097
  return parts;
1041
1098
  };
1099
+ toIngestContents = (text, attachments, modelId) => {
1100
+ const archive = toWireUserContent(text, attachments);
1101
+ if (!Array.isArray(attachments) || attachments.length === 0) return { wire: archive, archive };
1102
+ if (isVisionEnabled(modelId)) return { wire: archive, archive };
1103
+ const names = attachments.map((a) => a?.name || "image").join("\u3001");
1104
+ const paths = attachments.map((a) => typeof a?.path === "string" && a.path ? ` ${a?.name || "image"} \u2192 ${a.path}` : "").filter(Boolean);
1105
+ const relay = paths.length ? `\u56FE\u7247\u5DF2\u5B58\u5DE5\u4F5C\u533A\uFF1A
1106
+ ${paths.join("\n")}
1107
+ \u82E5\u5DF2\u914D\u7F6E\u56FE\u50CF\u8BC6\u522B MCP \u5DE5\u5177\uFF0C\u53EF\u8BFB\u53D6\u4E0A\u8FF0\u8DEF\u5F84\u7406\u89E3\u56FE\u7247\u5185\u5BB9\u3002` : "\u82E5\u6D88\u606F\u4E2D\u5305\u542B\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84\u4E14\u5DF2\u914D\u7F6E\u56FE\u50CF\u8BC6\u522B MCP \u5DE5\u5177\uFF0C\u53EF\u8BFB\u53D6\u8BE5\u8DEF\u5F84\u7406\u89E3\u56FE\u7247\u3002";
1108
+ return {
1109
+ wire: `${text}
1110
+
1111
+ \u{1F5BC} \u6536\u5230\u56FE\u7247\u9644\u4EF6\uFF08${names}\uFF09\uFF1A\u5F53\u524D\u6A21\u578B\u65E0\u89C6\u89C9\u80FD\u529B\uFF0C\u65E0\u6CD5\u76F4\u63A5\u67E5\u770B\u56FE\u7247\u5185\u5BB9\uFF08\u53EF\u5207\u6362 vision \u6A21\u578B\u6216\u8BBE DEEP_SEEK_VISION=1 \u5F3A\u5F00\uFF09\uFF1B${relay}`,
1112
+ archive
1113
+ };
1114
+ };
1042
1115
  replaceImageParts = (m, note) => {
1043
1116
  if (!m || !Array.isArray(m.content)) return m;
1044
1117
  let touched = false;
@@ -1719,7 +1792,7 @@ var init_shellExecutor = __esm({
1719
1792
  };
1720
1793
  executeHookCommand = (input) => {
1721
1794
  return new Promise((resolve) => {
1722
- const timeoutMs = Math.min(input.timeoutMs ?? DEFAULT_TIMEOUT_MS, HARD_TIMEOUT_CAP_MS);
1795
+ const timeoutMs2 = Math.min(input.timeoutMs ?? DEFAULT_TIMEOUT_MS, HARD_TIMEOUT_CAP_MS);
1723
1796
  const childEnv = {};
1724
1797
  for (const k of ENV_WHITELIST) {
1725
1798
  const v = process.env[k];
@@ -1755,7 +1828,7 @@ var init_shellExecutor = __esm({
1755
1828
  const timer = setTimeout(() => {
1756
1829
  timedOut = true;
1757
1830
  void killTree(child);
1758
- }, timeoutMs);
1831
+ }, timeoutMs2);
1759
1832
  child.stdout?.on("data", (d) => {
1760
1833
  if (stdout.length < MAX_OUTPUT) stdout += d.toString();
1761
1834
  });
@@ -1787,7 +1860,7 @@ var init_shellExecutor = __esm({
1787
1860
  });
1788
1861
 
1789
1862
  // ../core/src/hooks/registry.ts
1790
- var rules, matches, registerHooks, listHooks, isPlainObject, dispatch, runPreHooks, HOOK_RESULT_MAX, truncateForHook, runPostHooks;
1863
+ var rules, matches, DECLARATIVE_RULE, replaceDeclarativeHooks, listHooks, isPlainObject, dispatch, runPreHooks, HOOK_RESULT_MAX, truncateForHook, runPostHooks;
1791
1864
  var init_registry = __esm({
1792
1865
  "../core/src/hooks/registry.ts"() {
1793
1866
  "use strict";
@@ -1796,7 +1869,12 @@ var init_registry = __esm({
1796
1869
  init_config();
1797
1870
  rules = [];
1798
1871
  matches = (matcher, toolName) => {
1799
- if (typeof matcher === "string") return matcher === "*" || matcher === toolName;
1872
+ if (typeof matcher === "string") {
1873
+ if (matcher === "*") return true;
1874
+ if (matcher === "mcp_call") return toolName.startsWith("mcp__");
1875
+ if (matcher.endsWith("*")) return toolName.startsWith(matcher.slice(0, -1));
1876
+ return matcher === toolName;
1877
+ }
1800
1878
  if (matcher instanceof RegExp) return matcher.test(toolName);
1801
1879
  try {
1802
1880
  return matcher(toolName);
@@ -1804,8 +1882,15 @@ var init_registry = __esm({
1804
1882
  return false;
1805
1883
  }
1806
1884
  };
1807
- registerHooks = (rs) => {
1808
- for (const r of rs) rules.push(r);
1885
+ DECLARATIVE_RULE = Symbol("dsc.hook.declarative");
1886
+ replaceDeclarativeHooks = (rs) => {
1887
+ for (let i = rules.length - 1; i >= 0; i--) {
1888
+ if (rules[i][DECLARATIVE_RULE]) rules.splice(i, 1);
1889
+ }
1890
+ for (const r of rs) {
1891
+ r[DECLARATIVE_RULE] = true;
1892
+ rules.push(r);
1893
+ }
1809
1894
  };
1810
1895
  listHooks = () => {
1811
1896
  const strMatcher = (m) => {
@@ -1923,15 +2008,14 @@ function stripAnsi(text) {
1923
2008
  }
1924
2009
  function microcompactTextContent(raw) {
1925
2010
  let s = stripAnsi(raw || "");
1926
- s = s.replace(/<!--[\s\S]*?-->/g, "");
1927
2011
  s = relativizeWorkspacePathsInText(s);
1928
- s = s.replace(/\n{3,}/g, "\n\n").replace(/[ \t]{3,}/g, " ").trim();
2012
+ s = s.replace(/\n{3,}/g, "\n\n").trim();
1929
2013
  return s;
1930
2014
  }
1931
2015
  function isAsyncGenerator(x) {
1932
2016
  return x != null && typeof x[Symbol.asyncIterator] === "function";
1933
2017
  }
1934
- var ANSI_ESCAPE, getFileAccessRoots, relativizeWorkspacePathsInText, truncateToolResult, truncateApprovalDetail, compactBatch, ARCHIVE_INDEX_MAX_ENTRIES, ARCHIVE_INDEX_BATCH_CAP, extractArchiveEntities, parseSummarySlot, mergeSummarySlot, compactSlotNarrative, compactToLine, ensureSummarySlot, SUMMARY_SELF_COMPACT_THRESHOLD, ensureFitsWindow, collectToolResult;
2018
+ var ANSI_ESCAPE, getFileAccessRoots, relativizeWorkspacePathsInText, truncateToolResult, truncateApprovalDetail, batchSummaryPrompt, compactBatch, ARCHIVE_INDEX_MAX_ENTRIES, ARCHIVE_INDEX_BATCH_CAP, extractArchiveEntities, parseSummarySlot, mergeSummarySlot, CHECKPOINT_MAX_CHARS, SLOT_PLACEHOLDER, CHECKPOINT_FORMAT, checkpointRules, checkpointPrompt, checkpointDirectPrompt, assembleSlot, parseSlotNarrativeState, synthesizeSlotNarrative, synthesizeSlotNarrativeFromBatch, compactSlotNarrative, splitIntoBatches, compactBatches, ensureSummarySlot, SUMMARY_SELF_COMPACT_THRESHOLD, ensureFitsWindow, collectToolResult;
1935
2019
  var init_truncate = __esm({
1936
2020
  "../core/src/agent/truncate.ts"() {
1937
2021
  "use strict";
@@ -2003,10 +2087,11 @@ var init_truncate = __esm({
2003
2087
 
2004
2088
  ${tail}`;
2005
2089
  };
2006
- compactBatch = async (batch, signal) => {
2090
+ batchSummaryPrompt = (tailContext) => "\u6982\u62EC\u4EE5\u4E0A\u5BF9\u8BDD\u4E0E\u5DE5\u5177\u8C03\u7528\uFF0C\u6309\u300C\u5B8C\u6210\u4E86\u4EC0\u4E48 \u2192 \u6B63\u5728\u505A\u4EC0\u4E48 \u2192 \u4E0B\u4E00\u6B65/\u53D7\u963B\u300D\u7684\u987A\u5E8F\u5199\u6210\u4E00\u6BB5\u3002\u5FC5\u987B\u539F\u6837\u4FDD\u7559\u5173\u952E\u5B9E\u4F53\u540D\uFF08\u6587\u4EF6\u8DEF\u5F84\u3001\u51FD\u6570/\u7C7B\u540D\u3001\u62A5\u9519\u5173\u952E\u8BCD\uFF09\u4EE5\u4FBF\u540E\u7EED\u68C0\u7D22\uFF1B" + (tailContext ? "\u8FD9\u6279\u6458\u8981\u7D27\u90BB\u672A\u538B\u7F29\u7684\u4FDD\u7559\u533A\uFF0C\u8BF7\u989D\u5916\u5199\u660E\u5176\u4E2D\u5BF9\u7D27\u968F\u5176\u540E\u7684\u8FD1\u671F\u5DE5\u4F5C\u6709\u7528\u7684\u80CC\u666F\uFF08\u5DF2\u786E\u8BA4\u7684\u7EA6\u675F\u3001\u6570\u636E\u3001\u7ED3\u8BBA\uFF09\u3002" : "") + '\u5BF9\u8BB0\u4E0D\u51C6\u7684\u7EC6\u8282\u4E0D\u8981\u81C6\u6D4B\uFF0C\u6807\u6CE8"(\u7EC6\u8282\u5DF2\u5F52\u6863)"\u5373\u53EF\u3002\u4E0D\u8981\u8C03\u7528\u5DE5\u5177\u3002';
2091
+ compactBatch = async (batch, signal, tailContext) => {
2007
2092
  const resp = await chatWithModelWithSummary(
2008
2093
  // ★ 辅助模型是 text-only:送前把 image part 降级为占位符——base64 绝不能进摘要批(烧钱且无意义)
2009
- [...batch.map(degradeImagesForAux), { role: "user", content: '\u7528\u4E00\u884C\u8BDD\u6982\u62EC\u4EE5\u4E0A\u5BF9\u8BDD\u4E0E\u5DE5\u5177\u8C03\u7528\uFF1A\u4EFB\u52A1\u76EE\u6807\u3001\u5173\u952E\u51B3\u7B56\u3001\u52A8\u8FC7\u7684\u6587\u4EF6\u3001\u5F53\u524D\u8FDB\u5EA6\u3002\u5FC5\u987B\u539F\u6837\u4FDD\u7559\u5173\u952E\u5B9E\u4F53\u540D\uFF08\u6587\u4EF6\u8DEF\u5F84\u3001\u51FD\u6570/\u7C7B\u540D\u3001\u62A5\u9519\u5173\u952E\u8BCD\uFF09\u4EE5\u4FBF\u540E\u7EED\u68C0\u7D22\u3002\u5BF9\u8BB0\u4E0D\u51C6\u7684\u7EC6\u8282\u4E0D\u8981\u81C6\u6D4B\uFF0C\u6807\u6CE8"(\u7EC6\u8282\u5DF2\u5F52\u6863)"\u5373\u53EF\u3002\u4E0D\u8981\u8C03\u7528\u5DE5\u5177\u3002' }],
2094
+ [...batch.map(degradeImagesForAux), { role: "user", content: batchSummaryPrompt(tailContext) }],
2010
2095
  [],
2011
2096
  { signal }
2012
2097
  );
@@ -2026,6 +2111,8 @@ ${tail}`;
2026
2111
  const push = (raw) => {
2027
2112
  const s = raw.trim();
2028
2113
  if (!s || s.length < 3 || s.length > 60 || seen.has(s)) return;
2114
+ const lastSeg = s.split(/[\\/]/).pop() ?? "";
2115
+ if (/^[\d.]+$/.test(lastSeg)) return;
2029
2116
  seen.add(s);
2030
2117
  found.push(s);
2031
2118
  };
@@ -2054,8 +2141,8 @@ ${tail}`;
2054
2141
  merged.push(e);
2055
2142
  if (merged.length >= ARCHIVE_INDEX_MAX_ENTRIES) break;
2056
2143
  }
2057
- const newNotes = notes ? `${notes}
2058
- ${noteLine}` : noteLine;
2144
+ const newNotes = noteLine ? notes ? `${notes}
2145
+ ${noteLine}` : noteLine : notes;
2059
2146
  return [
2060
2147
  "\u27E6DSC:ARCHIVE-INDEX\u27E7 \u7CBE\u786E\u7EC6\u8282\u53EF\u7528 recall \u5DE5\u5177\u68C0\u7D22\u672C\u4F1A\u8BDD\u5168\u91CF\u5386\u53F2\uFF1B\u4EE5\u4E0B\u4E3A\u5F52\u6863\u5B9E\u4F53\u7D22\u5F15\uFF08\u68C0\u7D22\u5173\u952E\u8BCD\u7EBF\u7D22\uFF09\uFF1A",
2061
2148
  merged.join(" | "),
@@ -2063,17 +2150,57 @@ ${noteLine}` : noteLine;
2063
2150
  newNotes
2064
2151
  ].join("\n");
2065
2152
  };
2066
- compactSlotNarrative = async (slotContent, modelWindow, signal) => {
2067
- const { index } = parseSummarySlot(slotContent);
2068
- const compactedNotes = await compactToLine([{ role: "system", content: slotContent }], modelWindow, signal);
2069
- return [
2070
- "\u27E6DSC:ARCHIVE-INDEX\u27E7 \u7CBE\u786E\u7EC6\u8282\u53EF\u7528 recall \u5DE5\u5177\u68C0\u7D22\u672C\u4F1A\u8BDD\u5168\u91CF\u5386\u53F2\uFF1B\u4EE5\u4E0B\u4E3A\u5F52\u6863\u5B9E\u4F53\u7D22\u5F15\uFF08\u68C0\u7D22\u5173\u952E\u8BCD\u7EBF\u7D22\uFF09\uFF1A",
2071
- index.join(" | "),
2072
- "\u27E6DSC:ARCHIVE-NOTES\u27E7",
2073
- compactedNotes
2074
- ].join("\n");
2153
+ CHECKPOINT_MAX_CHARS = 800;
2154
+ SLOT_PLACEHOLDER = "SYSTEM_ROLLING_SUMMARY_SLOT";
2155
+ CHECKPOINT_FORMAT = '\u4E25\u683C\u6309\u4EE5\u4E0B\u683C\u5F0F\u8F93\u51FA\uFF1A\n\n## \u76EE\u6807\n[\u7528\u6237\u8981\u5B8C\u6210\u4EC0\u4E48\uFF1B\u591A\u4EFB\u52A1\u5206\u6BB5\u5217\u51FA]\n## \u7EA6\u675F\u4E0E\u504F\u597D\n- [\u7528\u6237\u660E\u793A\u7684\u7EA6\u675F\u3001\u504F\u597D\u4E0E\u6280\u672F\u8981\u6C42\uFF1B\u65E0\u5219\u5199"(\u65E0)"]\n## \u8FDB\u5EA6\n### \u5DF2\u5B8C\u6210\n- [x] [\u5DF2\u5B8C\u6210\u7684\u4E8B\u9879]\n### \u8FDB\u884C\u4E2D\n- [ ] [\u8FDB\u884C\u4E2D\u7684\u4E8B\u9879\u53CA\u5176\u6700\u65B0\u72B6\u6001]\n### \u53D7\u963B\n- [\u5361\u70B9\uFF1B\u65E0\u5219\u5199"(\u65E0)"]\n## \u5173\u952E\u51B3\u7B56\n- **[\u51B3\u7B56]**: [\u7B80\u8981\u7406\u7531]\n## \u4E0B\u4E00\u6B65\n1. [\u6309\u987A\u5E8F\u5217\u51FA\u63A5\u4E0B\u6765\u8BE5\u505A\u4EC0\u4E48]\n## \u5173\u952E\u4E0A\u4E0B\u6587\n- [\u7EED\u63A5\u6240\u9700\u7684\u6570\u636E\u3001\u7ED3\u8BBA\u4E0E\u53C2\u7167\uFF1B\u65E0\u5219\u5199"(\u65E0)"]\n\n';
2156
+ checkpointRules = (hasPrevious, isRaw = false) => "\u89C4\u5219\uFF1A" + (hasPrevious ? `\u4FDD\u7559\u65E2\u6709\u68C0\u67E5\u70B9\u4E0E\u65B0\u5F52\u6863${isRaw ? "\u539F\u6587" : "\u884C"}\u4E2D\u7684\u5168\u90E8\u6709\u6548\u4FE1\u606F\uFF0C\u53EA\u6574\u7406\u3001\u4E0D\u6539\u5199\u4E8B\u5B9E\uFF1B\u5DF2\u5B8C\u6210\u4E8B\u9879\u79FB\u5165"\u5DF2\u5B8C\u6210"\uFF0C\u8FDB\u884C\u4E2D\u4E8B\u9879\u5237\u65B0\u5230\u6700\u65B0\u72B6\u6001\uFF1B\u88AB\u53D6\u4EE3\u7684\u8FC7\u671F\u7EC6\u8282\u53EF\u5220\u9664\uFF08\u7EC6\u8282\u53EF\u7ECF recall \u68C0\u7D22\uFF0C\u65E0\u9700\u604B\u6218\uFF09\uFF1B` : '\u5BF9\u8BB0\u4E0D\u51C6\u7684\u7EC6\u8282\u4E0D\u8981\u81C6\u6D4B\uFF0C\u6807\u6CE8"(\u7EC6\u8282\u5DF2\u5F52\u6863)"\u5373\u53EF\uFF08\u7EC6\u8282\u53EF\u7ECF recall \u68C0\u7D22\uFF09\uFF1B') + "\u539F\u6837\u4FDD\u7559\u6587\u4EF6\u8DEF\u5F84\u3001\u51FD\u6570/\u7C7B\u540D\u3001\u62A5\u9519\u5173\u952E\u8BCD\u7B49\u5B9E\u4F53\u540D\uFF1B\u5168\u6587\u4E0D\u8D85\u8FC7 " + CHECKPOINT_MAX_CHARS + " \u5B57\uFF1B\u76F4\u63A5\u8F93\u51FA\u68C0\u67E5\u70B9\uFF0C\u4E0D\u8981\u4EFB\u4F55\u89E3\u91CA\u3002";
2157
+ checkpointPrompt = (hasPrevious) => (hasPrevious ? "\u4EE5\u4E0A\u662F\u672C\u4F1A\u8BDD\u7684\u5F52\u6863\u6863\u6848\uFF1A\u27E6DSC:ARCHIVE-INDEX\u27E7 \u5B9E\u4F53\u7D22\u5F15\uFF08\u68C0\u7D22\u7EBF\u7D22\uFF0C\u4E0D\u8981\u6539\u52A8\u5176\u5185\u5BB9\uFF09\u4E0E \u27E6DSC:ARCHIVE-NOTES\u27E7 \u65E2\u6709\u68C0\u67E5\u70B9\u3002\u8BF7\u628A\u65E2\u6709\u68C0\u67E5\u70B9\u4E0E\u7528\u6237\u6D88\u606F\u4E2D\u7684\u672C\u8F6E\u65B0\u5F52\u6863\u6458\u8981\u884C\u5408\u5E76\u6539\u5199\u4E3A\u4E00\u4EFD\u65B0\u7684\u7ED3\u6784\u5316\u68C0\u67E5\u70B9\uFF0C\u4F9B\u540E\u7EED\u6A21\u578B\u7EED\u63A5\u5DE5\u4F5C\u3002" : "\u7528\u6237\u6D88\u606F\u662F\u672C\u4F1A\u8BDD\u672C\u8F6E\u5F52\u6863\u51FA\u7684\u6458\u8981\u884C\u3002\u8BF7\u628A\u5B83\u4EEC\u6574\u7406\u4E3A\u4E00\u4EFD\u7ED3\u6784\u5316\u68C0\u67E5\u70B9\uFF0C\u4F9B\u540E\u7EED\u6A21\u578B\u7EED\u63A5\u5DE5\u4F5C\uFF08\u5B9E\u4F53\u7D22\u5F15\u7531\u7CFB\u7EDF\u53E6\u884C\u786E\u5B9A\u6027\u7EF4\u62A4\uFF0C\u65E0\u9700\u4F60\u8F93\u51FA\uFF09\u3002") + CHECKPOINT_FORMAT + checkpointRules(hasPrevious);
2158
+ checkpointDirectPrompt = (hasPrevious) => (hasPrevious ? "system \u6D88\u606F\u662F\u672C\u4F1A\u8BDD\u7684\u5F52\u6863\u6863\u6848\uFF1A\u27E6DSC:ARCHIVE-INDEX\u27E7 \u5B9E\u4F53\u7D22\u5F15\uFF08\u68C0\u7D22\u7EBF\u7D22\uFF0C\u4E0D\u8981\u6539\u52A8\u5176\u5185\u5BB9\uFF09\u4E0E \u27E6DSC:ARCHIVE-NOTES\u27E7 \u65E2\u6709\u68C0\u67E5\u70B9\uFF1B\u5176\u540E\u7684\u5BF9\u8BDD\u6D88\u606F\u662F\u672C\u8F6E\u65B0\u5F52\u6863\u7684\u4F1A\u8BDD\u539F\u6587\uFF08\u672A\u7ECF\u884C\u5F0F\u538B\u7F29\uFF09\u3002\u8BF7\u628A\u65E2\u6709\u68C0\u67E5\u70B9\u4E0E\u8FD9\u4E9B\u539F\u6587\u5408\u5E76\u6539\u5199\u4E3A\u4E00\u4EFD\u65B0\u7684\u7ED3\u6784\u5316\u68C0\u67E5\u70B9\uFF0C\u4F9B\u540E\u7EED\u6A21\u578B\u7EED\u63A5\u5DE5\u4F5C\u3002" : "\u672C\u8F6E\u5F52\u6863\u51FA\u7684\u4F1A\u8BDD\u539F\u6587\u4EE5\u5BF9\u8BDD\u6D88\u606F\u5F62\u5F0F\u9644\u540E\uFF08\u672A\u7ECF\u884C\u5F0F\u538B\u7F29\uFF09\u3002\u8BF7\u628A\u5B83\u4EEC\u6574\u7406\u4E3A\u4E00\u4EFD\u7ED3\u6784\u5316\u68C0\u67E5\u70B9\uFF0C\u4F9B\u540E\u7EED\u6A21\u578B\u7EED\u63A5\u5DE5\u4F5C\uFF08\u5B9E\u4F53\u7D22\u5F15\u7531\u7CFB\u7EDF\u53E6\u884C\u786E\u5B9A\u6027\u7EF4\u62A4\uFF0C\u65E0\u9700\u4F60\u8F93\u51FA\uFF09\u3002") + "\u8FD9\u6279\u539F\u6587\u7D27\u90BB\u672A\u538B\u7F29\u7684\u4FDD\u7559\u533A\uFF0C\u8BF7\u989D\u5916\u5199\u660E\u5176\u4E2D\u5BF9\u7D27\u968F\u5176\u540E\u7684\u8FD1\u671F\u5DE5\u4F5C\u6709\u7528\u7684\u80CC\u666F\uFF08\u5DF2\u786E\u8BA4\u7684\u7EA6\u675F\u3001\u6570\u636E\u3001\u7ED3\u8BBA\uFF09\u3002" + CHECKPOINT_FORMAT + checkpointRules(hasPrevious, true);
2159
+ assembleSlot = (index, newNotes) => [
2160
+ "\u27E6DSC:ARCHIVE-INDEX\u27E7 \u7CBE\u786E\u7EC6\u8282\u53EF\u7528 recall \u5DE5\u5177\u68C0\u7D22\u672C\u4F1A\u8BDD\u5168\u91CF\u5386\u53F2\uFF1B\u4EE5\u4E0B\u4E3A\u5F52\u6863\u5B9E\u4F53\u7D22\u5F15\uFF08\u68C0\u7D22\u5173\u952E\u8BCD\u7EBF\u7D22\uFF09\uFF1A",
2161
+ index.join(" | "),
2162
+ "\u27E6DSC:ARCHIVE-NOTES\u27E7",
2163
+ newNotes
2164
+ ].join("\n");
2165
+ parseSlotNarrativeState = (slotContent) => {
2166
+ const { index, notes } = parseSummarySlot(slotContent);
2167
+ const trimmedNotes = notes.trim();
2168
+ const hasPrevious = trimmedNotes.length > 0 && trimmedNotes !== SLOT_PLACEHOLDER;
2169
+ return { index, hasPrevious };
2170
+ };
2171
+ synthesizeSlotNarrative = async (slotContent, newLines, signal) => {
2172
+ const { index, hasPrevious } = parseSlotNarrativeState(slotContent);
2173
+ const lines = newLines.trim();
2174
+ const resp = await chatWithModelWithSummary(
2175
+ [
2176
+ { role: "system", content: slotContent },
2177
+ { role: "user", content: `${lines ? `\u672C\u8F6E\u65B0\u5F52\u6863\u7684\u6458\u8981\u884C\uFF1A
2178
+ ${lines}
2179
+
2180
+ ` : ""}${checkpointPrompt(hasPrevious)}` }
2181
+ ],
2182
+ [],
2183
+ { signal }
2184
+ );
2185
+ const newNotes = (resp.choices[0].message.content || "").trim();
2186
+ return assembleSlot(index, newNotes);
2187
+ };
2188
+ synthesizeSlotNarrativeFromBatch = async (slotContent, batch, signal) => {
2189
+ const { index, hasPrevious } = parseSlotNarrativeState(slotContent);
2190
+ const resp = await chatWithModelWithSummary(
2191
+ [
2192
+ { role: "system", content: slotContent },
2193
+ ...batch.map(degradeImagesForAux),
2194
+ { role: "user", content: checkpointDirectPrompt(hasPrevious) }
2195
+ ],
2196
+ [],
2197
+ { signal }
2198
+ );
2199
+ const newNotes = (resp.choices[0].message.content || "").trim();
2200
+ return assembleSlot(index, newNotes);
2075
2201
  };
2076
- compactToLine = async (toCompact, _modelWindow, signal) => {
2202
+ compactSlotNarrative = async (slotContent, _modelWindow, signal) => synthesizeSlotNarrative(slotContent, "", signal);
2203
+ splitIntoBatches = (toCompact) => {
2077
2204
  const MAX_BATCH_TOKENS = 16e3;
2078
2205
  const units = groupUnits(toCompact);
2079
2206
  const batches = [];
@@ -2090,7 +2217,10 @@ ${noteLine}` : noteLine;
2090
2217
  batchTokens += size;
2091
2218
  }
2092
2219
  if (batch.length > 0) batches.push(batch);
2093
- const lines = await Promise.all(batches.map((b) => compactBatch(b, signal)));
2220
+ return batches;
2221
+ };
2222
+ compactBatches = async (batches, signal) => {
2223
+ const lines = await Promise.all(batches.map((b, i) => compactBatch(b, signal, i === batches.length - 1)));
2094
2224
  return lines.join("\n");
2095
2225
  };
2096
2226
  ensureSummarySlot = (messageArr) => {
@@ -2098,13 +2228,14 @@ ${noteLine}` : noteLine;
2098
2228
  messageArr.unshift({ role: "system", content: "SYSTEM_META_CONTEXT_START" });
2099
2229
  }
2100
2230
  if (messageArr.length < 2 || messageArr[1]?.role !== "system") {
2101
- messageArr.splice(1, 0, { role: "system", content: "SYSTEM_ROLLING_SUMMARY_SLOT" });
2231
+ messageArr.splice(1, 0, { role: "system", content: SLOT_PLACEHOLDER });
2102
2232
  }
2103
2233
  };
2104
2234
  SUMMARY_SELF_COMPACT_THRESHOLD = 2e3;
2105
2235
  ensureFitsWindow = async (event) => {
2106
2236
  const correctionRatio = event.correctionRatio ?? 1.4;
2107
- const estReal = (arr) => estimateTokens(arr) * correctionRatio;
2237
+ const toolsTokens = event.toolsTokens ?? 0;
2238
+ const estReal = (arr) => estimateTokens(arr) * correctionRatio + toolsTokens;
2108
2239
  const hitRate = event.lastRealPromptTokens && event.lastCachedTokens != null && event.lastRealPromptTokens > 0 ? event.lastCachedTokens / event.lastRealPromptTokens : null;
2109
2240
  const cacheFactor = hitRate == null ? 1 : Math.min(1.1, Math.max(0.9, 0.9 + hitRate * 0.2));
2110
2241
  const effectiveRatio = Math.min(event.compactRatio * cacheFactor, 0.82);
@@ -2126,8 +2257,9 @@ ${noteLine}` : noteLine;
2126
2257
  const { toCompact, keepRecent } = splitUntils(active, keep);
2127
2258
  try {
2128
2259
  if (toCompact.length > 0) {
2129
- const line = await compactToLine(toCompact, event.modelWindow, event.signal);
2130
- summaryMsg.content = mergeSummarySlot(summaryMsg?.content || "", line, extractArchiveEntities(toCompact));
2260
+ summaryMsg.content = mergeSummarySlot(summaryMsg?.content || "", "", extractArchiveEntities(toCompact));
2261
+ const batches = splitIntoBatches(toCompact);
2262
+ summaryMsg.content = batches.length === 1 ? await synthesizeSlotNarrativeFromBatch(summaryMsg.content, batches[0], event.signal) : await synthesizeSlotNarrative(summaryMsg.content, await compactBatches(batches, event.signal), event.signal);
2131
2263
  if (estimateTokens([summaryMsg]) > SUMMARY_SELF_COMPACT_THRESHOLD) {
2132
2264
  summaryMsg.content = await compactSlotNarrative(summaryMsg.content, event.modelWindow, event.signal);
2133
2265
  }
@@ -2263,12 +2395,12 @@ ${noteLine}` : noteLine;
2263
2395
  }
2264
2396
  return full;
2265
2397
  }
2266
- const timeoutMs = Number(process.env.DEEP_SEEK_STREAM_IDLE_TIMEOUT_MS) || 12e4;
2398
+ const timeoutMs2 = Number(process.env.DEEP_SEEK_STREAM_IDLE_TIMEOUT_MS) || 12e4;
2267
2399
  let timer;
2268
2400
  const raced = await Promise.race([
2269
2401
  Promise.resolve(ret).then((v) => ({ kind: "ok", value: typeof v === "string" ? v : JSON.stringify(v) })),
2270
2402
  new Promise((resolve) => {
2271
- timer = setTimeout(() => resolve({ kind: "timeout" }), timeoutMs);
2403
+ timer = setTimeout(() => resolve({ kind: "timeout" }), timeoutMs2);
2272
2404
  }),
2273
2405
  ...signal ? [new Promise((resolve) => {
2274
2406
  signal.addEventListener("abort", () => resolve({ kind: "abort" }), { once: true });
@@ -2276,7 +2408,7 @@ ${noteLine}` : noteLine;
2276
2408
  ]);
2277
2409
  if (timer) clearTimeout(timer);
2278
2410
  if (raced.kind === "timeout") {
2279
- return `[\u23F3 \u5DE5\u5177\u6267\u884C\u8D85\u65F6\uFF08${Math.round(timeoutMs / 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]`;
2411
+ return `[\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]`;
2280
2412
  }
2281
2413
  if (raced.kind === "abort") {
2282
2414
  throw new Error("aborted");
@@ -4038,19 +4170,19 @@ var init_httpExecutor = __esm({
4038
4170
  };
4039
4171
  executeHttpHook = async (input) => {
4040
4172
  const method = (input.method || "POST").toUpperCase();
4041
- const timeoutMs = input.timeoutMs ?? 3e4;
4173
+ const timeoutMs2 = input.timeoutMs ?? 3e4;
4042
4174
  try {
4043
4175
  const res = await fetch(input.url, {
4044
4176
  method,
4045
4177
  headers: { "content-type": "application/json", ...input.headers ?? {} },
4046
4178
  body: input.body !== void 0 ? JSON.stringify(input.body) : void 0,
4047
- signal: AbortSignal.timeout(timeoutMs)
4179
+ signal: AbortSignal.timeout(timeoutMs2)
4048
4180
  });
4049
4181
  const text = await res.text();
4050
4182
  return { ok: true, status: res.status, responseBody: truncateBody(text) };
4051
4183
  } catch (e) {
4052
4184
  const name = e?.name ?? "";
4053
- if (name === "TimeoutError") return { ok: false, status: 0, responseBody: "", error: `\u8BF7\u6C42\u8D85\u65F6\uFF08>${timeoutMs}ms\uFF09` };
4185
+ if (name === "TimeoutError") return { ok: false, status: 0, responseBody: "", error: `\u8BF7\u6C42\u8D85\u65F6\uFF08>${timeoutMs2}ms\uFF09` };
4054
4186
  if (name === "AbortError") return { ok: false, status: 0, responseBody: "", error: "\u8BF7\u6C42\u88AB\u4E2D\u6B62" };
4055
4187
  return { ok: false, status: 0, responseBody: "", error: e?.message ?? String(e) };
4056
4188
  }
@@ -4351,7 +4483,7 @@ var init_registry3 = __esm({
4351
4483
  getSkillCatalog = () => {
4352
4484
  const all = listSkills();
4353
4485
  if (all.length === 0) return "";
4354
- return all.map((s) => `- ${s.name}\uFF1A${s.description}${s.triggers.length ? `\uFF08\u89E6\u53D1\uFF1A${s.triggers.join("\u3001 ")}\uFF09` : ""}`).join("\n");
4486
+ return all.slice().sort((a, b) => a.name.localeCompare(b.name)).map((s) => `- ${s.name}\uFF1A${s.description}${s.triggers.length ? `\uFF08\u89E6\u53D1\uFF1A${s.triggers.join("\u3001 ")}\uFF09` : ""}`).join("\n");
4355
4487
  };
4356
4488
  }
4357
4489
  });
@@ -4391,7 +4523,7 @@ var init_registry4 = __esm({
4391
4523
  getAgentCatalog = () => {
4392
4524
  const all = listAgents();
4393
4525
  if (all.length === 0) return "";
4394
- return all.map((a) => `- ${a.name}\uFF1A${a.description}${a.role ? `\uFF08\u89D2\u8272\uFF1A${a.role}\uFF09` : ""}`).join("\n");
4526
+ return all.slice().sort((a, b) => a.name.localeCompare(b.name)).map((a) => `- ${a.name}\uFF1A${a.description}${a.role ? `\uFF08\u89D2\u8272\uFF1A${a.role}\uFF09` : ""}`).join("\n");
4395
4527
  };
4396
4528
  }
4397
4529
  });
@@ -4593,6 +4725,7 @@ var init_systemInjections = __esm({
4593
4725
  type: t.type,
4594
4726
  function: { name: t.function.name, description: t.function.description, parameters: t.function.parameters }
4595
4727
  }));
4728
+ const toolsTokens = Math.round(JSON.stringify(cleanedToolSchemas).length / 4);
4596
4729
  ensureSummarySlot(message);
4597
4730
  const LOCALE_HINTS = {
4598
4731
  zh: "\u59CB\u7EC8\u7528\u4E2D\u6587\u8F93\u51FA\u6240\u6709\u9762\u5411\u7528\u6237\u7684\u5185\u5BB9\uFF1A\u4F60\u7684\u56DE\u590D\u3001\u4E2D\u95F4\u53D9\u8FF0\u3001todo \u4EFB\u52A1\u9879\u6807\u9898\u3001\u901A\u8FC7 exit_plan_mode \u63D0\u4EA4\u7684\u65B9\u6848\u6587\u672C\u3001\u4EE3\u7801\u6CE8\u91CA\u4E0E\u63D0\u4EA4\u4FE1\u606F\u3002\u4EE3\u7801\u6807\u8BC6\u7B26\u4FDD\u6301\u539F\u6837\uFF1B\u5DE5\u5177\u7ED3\u679C\u4E0E\u7CFB\u7EDF\u6307\u4EE4\u53EF\u80FD\u5939\u6742\u5176\u4ED6\u8BED\u8A00\u2014\u2014\u5FC5\u8981\u65F6\u7167\u5F15\u539F\u6587\uFF0C\u4F46\u4F60\u81EA\u5DF1\u7684\u53D9\u8FF0\u4E0E\u89E3\u91CA\u4E00\u5F8B\u7528\u4E2D\u6587\u3002",
@@ -4616,7 +4749,7 @@ var init_systemInjections = __esm({
4616
4749
  injectAgentCatalog(message);
4617
4750
  injectProjectGuide(message);
4618
4751
  injectMemory(message);
4619
- return { rawTools, cleanedToolSchemas };
4752
+ return { rawTools, cleanedToolSchemas, toolsTokens };
4620
4753
  };
4621
4754
  }
4622
4755
  });
@@ -4633,14 +4766,14 @@ var init_agent = __esm({
4633
4766
  type: "function",
4634
4767
  function: {
4635
4768
  name: "spawn_agent",
4636
- description: "\u521B\u5EFA\u4E00\u4E2A\u62E5\u6709\u72EC\u7ACB\u6267\u884C\u73AF\u5883\u7684\u5B50 agent \u5904\u7406\u9694\u79BB\u7684\u7279\u5B9A\u5B50\u4EFB\u52A1\uFF0C\u5B50\u4EFB\u52A1\u5B8C\u6210\u540E\u81EA\u52A8\u6C47\u603B\u6539\u52A8\u70B9\u4E0E\u7ED3\u8BBA\u8FD4\u56DE\u3002\u53EF\u901A\u8FC7 name \u6307\u5B9A\u58F0\u660E\u5F0F\u5B50 Agent\uFF08\u89C1\u7CFB\u7EDF\u63D0\u793A\u8BCD\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\uFF09\u4EE5\u5957\u7528\u5176\u4E13\u957F\u7CFB\u7EDF\u8BCD/\u5DE5\u5177\u767D\u540D\u5355/model\uFF1B\u4E0D\u4F20 name \u8D70\u9ED8\u8BA4\u901A\u7528\u5B50 agent\u3002\u652F\u6301\u7EED\u8DD1\uFF1A\u4F20 resume_session_id\uFF08\u6B64\u524D\u8FD4\u56DE\u7684 agent_id\uFF09\u590D\u7528\u8BE5\u5B50 Agent \u7684\u5B8C\u6574\u5386\u53F2\u8BB0\u5FC6\uFF0C\u9002\u5408\u8FFD\u95EE\u3001\u7EE7\u7EED\u672A\u5B8C\u6210\u7684\u4EFB\u52A1\u3002",
4769
+ description: "\u6D3E\u751F\u62E5\u6709\u72EC\u7ACB\u6267\u884C\u73AF\u5883\u7684\u5B50 agent \u5904\u7406\u9694\u79BB\u5B50\u4EFB\u52A1\uFF0C\u5B8C\u6210\u540E\u81EA\u52A8\u6C47\u62A5\u6539\u52A8\u70B9\u4E0E\u7ED3\u8BBA\u3002name \u53EF\u6307\u5B9A\u58F0\u660E\u5F0F\u5B50 Agent\uFF08\u89C1\u7CFB\u7EDF\u63D0\u793A\u8BCD\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\uFF0C\u5957\u7528\u5176\u7CFB\u7EDF\u8BCD/\u5DE5\u5177\u767D\u540D\u5355/model\uFF09\uFF1B\u7F3A\u7701\u8D70\u901A\u7528\u6A21\u677F\u3002\u7EED\u8DD1\uFF1A\u4F20 resume_session_id\uFF08\u6B64\u524D\u8FD4\u56DE\u7684 agent_id\uFF09\u590D\u7528\u8BE5\u5B50 Agent \u5B8C\u6574\u5386\u53F2\u8BB0\u5FC6\uFF0C\u9002\u5408\u8FFD\u95EE/\u7EE7\u7EED\u672A\u5B8C\u4EFB\u52A1\u3002",
4637
4770
  parameters: {
4638
4771
  type: "object",
4639
4772
  properties: {
4640
- task: { type: "string", description: "\u4EA4\u7ED9\u5B50 agent \u7684\u5177\u4F53\u5FAE\u89C2\u4EFB\u52A1\u63CF\u8FF0\uFF08\u5982 '\u7F16\u5199 Button \u7EC4\u4EF6\u7684\u5355\u5143\u6D4B\u8BD5'\uFF09\uFF1B\u7EED\u8DD1\u65F6\u4E3A\u65B0\u6307\u4EE4\uFF08\u5982 '\u7EE7\u7EED\u5B8C\u6210\u5269\u4F59\u7528\u4F8B'\uFF09" },
4641
- name: { type: "string", description: "\u58F0\u660E\u5F0F\u5B50 Agent \u540D\u79F0\uFF08\u987B\u4E0E\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E2D\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\u4E00\u81F4\uFF09\u3002\u63D0\u4F9B\u65F6\u6309\u5176\u58F0\u660E\u52A0\u8F7D\u7CFB\u7EDF\u8BCD/\u5DE5\u5177\u767D\u540D\u5355/model\uFF1B\u4E0D\u63D0\u4F9B\u5219\u8D70\u9ED8\u8BA4\u901A\u7528\u5B50 agent\u3002" },
4642
- role: { type: "string", description: "\u5B50 agent \u7684\u89D2\u8272/\u4E13\u957F\uFF08\u53EF\u9009\uFF0C\u5982 '\u6D4B\u8BD5\u4E13\u5BB6'\u3001'\u91CD\u6784\u5148\u950B'\uFF09\u3002\u58F0\u660E\u5F0F agent \u81EA\u5E26 role \u65F6\u4F5C\u8865\u5145\u3002" },
4643
- resume_session_id: { type: "string", description: "\u7EED\u8DD1\u65E2\u6709\u5B50 Agent\uFF1A\u4F20\u6B64\u524D spawn_agent \u8FD4\u56DE\u7684 agent_id\uFF0C\u5176\u78C1\u76D8\u4E0A\u7684\u5386\u53F2\u4E0E\u8BB0\u5FC6\u5C06\u5B8C\u6574\u6062\u590D\u3002\u6CE8\u610F\uFF1A\u5B50 Agent \u72B6\u6001\u4E0D\u968F\u4E3B\u4F1A\u8BDD fork \u56DE\u6EDA\u2014\u2014fork \u53EA\u5206\u53C9\u5BF9\u8BDD\uFF0C\u7EED\u8DD1\u62FF\u5230\u7684\u662F\u5B50\u4F1A\u8BDD\u78C1\u76D8\u6700\u65B0\u72B6\u6001\u3002\u7F3A\u7701\u5219\u65B0\u5EFA\u5B50 Agent\u3002" }
4773
+ task: { type: "string", description: "\u5B50 agent \u7684\u5177\u4F53\u4EFB\u52A1\uFF08\u5982 '\u7F16\u5199 Button \u7EC4\u4EF6\u7684\u5355\u5143\u6D4B\u8BD5'\uFF09\uFF1B\u7EED\u8DD1\u65F6\u4E3A\u65B0\u6307\u4EE4" },
4774
+ name: { type: "string", description: "\u58F0\u660E\u5F0F\u5B50 Agent \u540D\uFF08\u987B\u4E0E\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\u4E00\u81F4\uFF09\uFF1B\u7F3A\u7701\u901A\u7528\u5B50 agent" },
4775
+ role: { type: "string", description: "\u89D2\u8272/\u4E13\u957F\u8865\u5145\uFF08\u53EF\u9009\uFF09\uFF1B\u58F0\u660E\u5F0F agent \u81EA\u5E26 role \u65F6\u4F5C\u8865\u5145" },
4776
+ resume_session_id: { type: "string", description: "\u7EED\u8DD1\u65E2\u6709\u5B50 Agent\uFF1A\u4F20\u6B64\u524D\u8FD4\u56DE\u7684 agent_id\uFF08\u6062\u590D\u5176\u78C1\u76D8\u5386\u53F2\u4E0E\u8BB0\u5FC6\uFF09\u3002\u6CE8\u610F\u5B50 Agent \u72B6\u6001\u4E0D\u968F\u4E3B\u4F1A\u8BDD fork \u56DE\u6EDA\u3002\u7F3A\u7701\u65B0\u5EFA" }
4644
4777
  },
4645
4778
  required: ["task"]
4646
4779
  },
@@ -4907,13 +5040,9 @@ var init_workflow = __esm({
4907
5040
  function: {
4908
5041
  name: "run_workflow",
4909
5042
  description: [
4910
- "\u591A\u5B50 agent \u5E76\u884C\u7F16\u6392\uFF08P0-3\uFF09\uFF1A\u628A\u4E00\u4E2A\u53EF\u5206\u89E3\u7684\u5927\u4EFB\u52A1\u4E00\u6B21\u6027\u6D3E\u7ED9\u591A\u4E2A\u72EC\u7ACB\u5B50 agent \u5E76\u53D1\u6267\u884C\uFF0C\u6216\u4E32\u6210\u6570\u636E\u6D41\u6C34\u7EBF\u9010\u7EA7\u7CBE\u70BC\u3002\u7A81\u7834 spawn_agent \u53EA\u80FD\u4E32\u884C\u5355\u6D3E\u751F\u7684\u4E0A\u9650\uFF0C\u9002\u7528\u4E8E\u5927\u89C4\u6A21\u4EE3\u7801\u5BA1\u67E5\u3001\u8FC1\u79FB\u5206\u6790\u3001\u591A\u65B9\u6848\u5E76\u884C\u8C03\u7814\u7B49\u3002",
4911
- "\u4E24\u79CD\u6A21\u5F0F\uFF1A",
4912
- "\u2022 parallel\uFF08\u9ED8\u8BA4\uFF09\uFF1A\u5404\u6B65\u9AA4\u4E92\u4E0D\u4F9D\u8D56\u3001\u5E76\u53D1\u6267\u884C\uFF0C\u7ED3\u679C\u6309\u5E8F\u805A\u5408\u3002\u9002\u5408\u4E92\u76F8\u72EC\u7ACB\u7684\u53EA\u8BFB/\u5206\u6790\u4EFB\u52A1\uFF08\u5982\u5BA1\u67E5 5 \u4E2A\u6A21\u5757\u3001\u5BF9 3 \u4E2A\u6280\u672F\u65B9\u6848\u5404\u6D3E\u4E00\u4E2A\u8C03\u7814 agent\uFF09\u3002\u5F3A\u70C8\u5EFA\u8BAE parallel \u7528\u4E8E\u8BFB/\u5206\u6790\u7C7B\u4EFB\u52A1\uFF08\u5E76\u884C\u6539\u540C\u4E00\u6279\u6587\u4EF6\u6613\u51B2\u7A81\uFF09\u3002",
4913
- "\u2022 pipeline\uFF1A\u6B65\u9AA4\u4E32\u884C\uFF0C\u9636\u6BB5 N \u81EA\u52A8\u63A5\u6536\u9636\u6BB5 N-1 \u7684\u4EA7\u51FA\u4F5C\u4E3A\u8F93\u5165\u4E0A\u4E0B\u6587\uFF0C\u9010\u7EA7\u7CBE\u70BC\u3002\u9002\u5408\u5206\u9636\u6BB5\u52A0\u5DE5\uFF08\u5982\uFF1A\u9636\u6BB51 \u62BD\u53D6\u8981\u70B9 \u2192 \u9636\u6BB52 \u5F52\u7C7B \u2192 \u9636\u6BB53 \u6C47\u603B\u7ED3\u8BBA\uFF09\u3002",
4914
- "\u6BCF\u4E2A\u6B65\u9AA4\u53EF\u6307\u5B9A name \u5957\u7528\u58F0\u660E\u5F0F\u5B50 Agent\uFF08\u89C1\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\uFF09\u3001role \u8865\u5145\u89D2\u8272\u3001key \u4F5C\u4E3A\u7ED3\u679C\u6807\u7B7E\u3002",
4915
- '\u5E76\u884C\u5199\u5B89\u5168\uFF1Aparallel \u6A21\u5F0F\u9ED8\u8BA4\u5171\u4EAB\u5DE5\u4F5C\u533A\uFF08\u5E76\u884C\u6539\u540C\u4E00\u6279\u6587\u4EF6\u4F1A\u51B2\u7A81\uFF0C\u5EFA\u8BAE\u4EC5\u7528\u4E8E\u8BFB/\u5206\u6790\uFF09\u3002\u8BBE isolation="worktree" \u540E\uFF0C\u6BCF\u4E2A\u6B65\u9AA4\u5728\u72EC\u7ACB git worktree \u91CC\u6267\u884C\uFF0C\u4E92\u4E0D\u6C61\u67D3\u2014\u2014\u7ED3\u675F\u540E\u6536\u5272\u5404 worktree \u7684 diff \u4F9B\u5408\u5E76\uFF0C\u5B9E\u73B0\u5B89\u5168\u7684\u5E76\u884C\u8FC1\u79FB/\u6539\u9020\u3002',
4916
- "\u4E0E spawn_agent \u7684\u5173\u7CFB\uFF1Aspawn_agent = \u4E32\u884C\u6D3E\u751F\u5355\u4E2A\uFF1Brun_workflow = \u5E76\u884C/\u6D41\u6C34\u7EBF\u7F16\u6392\u591A\u4E2A\u3002\u4EFB\u52A1\u53EF\u5206\u89E3\u3001\u5F7C\u6B64\u72EC\u7ACB\u6216\u5448\u6D41\u6C34\u7EBF\u65F6\u7528\u672C\u5DE5\u5177\uFF0C\u5426\u5219\u7528 spawn_agent\u3002"
5043
+ "\u591A\u5B50 agent \u7F16\u6392\uFF1A\u628A\u53EF\u5206\u89E3\u7684\u5927\u4EFB\u52A1\u6D3E\u7ED9\u591A\u4E2A\u72EC\u7ACB\u5B50 agent\u3002parallel\uFF08\u9ED8\u8BA4\uFF09=\u5404\u6B65\u9AA4\u5E76\u53D1\u6267\u884C\u3001\u7ED3\u679C\u6309\u5E8F\u805A\u5408\uFF0C\u9002\u5408\u4E92\u76F8\u72EC\u7ACB\u7684\u53EA\u8BFB/\u5206\u6790\u4EFB\u52A1\uFF1Bpipeline=\u6B65\u9AA4\u4E32\u884C\uFF0C\u524D\u9636\u6BB5\u4EA7\u51FA\u81EA\u52A8\u4F5C\u4E3A\u540E\u9636\u6BB5\u8F93\u5165\uFF0C\u9002\u5408\u5206\u9636\u6BB5\u52A0\u5DE5\uFF08\u62BD\u53D6\u2192\u5F52\u7C7B\u2192\u6C47\u603B\uFF09\u3002",
5044
+ '\u6B65\u9AA4\u53EF\u7528 name \u5957\u7528\u58F0\u660E\u5F0F\u5B50 Agent\uFF08\u89C1\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\uFF09\u3001key \u4F5C\u7ED3\u679C\u6807\u7B7E\u3002parallel \u9ED8\u8BA4\u5171\u4EAB\u5DE5\u4F5C\u533A\uFF0C\u4EC5\u9002\u5408\u5E76\u884C\u8BFB/\u5206\u6790\uFF1B\u5E76\u884C\u5199/\u8FC1\u79FB\u7528 isolation="worktree"\uFF08\u6BCF\u6B65\u72EC\u7ACB git worktree\uFF0C\u7ED3\u675F\u540E\u6536\u5272\u5404\u6B65 diff\uFF09\u3002',
5045
+ "\u4E0E spawn_agent \u7684\u5206\u5DE5\uFF1A\u5355\u4EFB\u52A1\u4E32\u884C\u59D4\u6D3E\u7528 spawn_agent\uFF1B\u4EFB\u52A1\u53EF\u5206\u89E3\u3001\u591A\u5206\u652F\u6216\u6D41\u6C34\u7EBF\u5F0F\u65F6\u7528\u672C\u5DE5\u5177\u3002"
4917
5046
  ].join("\n"),
4918
5047
  parameters: {
4919
5048
  type: "object",
@@ -4921,18 +5050,18 @@ var init_workflow = __esm({
4921
5050
  mode: {
4922
5051
  type: "string",
4923
5052
  enum: ["parallel", "pipeline"],
4924
- description: "\u7F16\u6392\u6A21\u5F0F\uFF1Aparallel=\u5E76\u53D1\u6247\u51FA\uFF08\u9ED8\u8BA4\uFF0C\u4E92\u4E0D\u4F9D\u8D56\u7684\u4EFB\u52A1\uFF09\uFF1Bpipeline=\u4E32\u884C\u6D41\u6C34\u7EBF\uFF08\u9636\u6BB5\u95F4\u6709\u6570\u636E\u4F9D\u8D56\uFF0C\u9010\u7EA7\u7CBE\u70BC\uFF09\u3002"
5053
+ description: "parallel=\u5E76\u53D1\u6247\u51FA\uFF08\u9ED8\u8BA4\uFF0C\u6B65\u9AA4\u4E92\u4E0D\u4F9D\u8D56\uFF09\uFF1Bpipeline=\u4E32\u884C\u6D41\u6C34\u7EBF\uFF08\u524D\u9636\u6BB5\u4EA7\u51FA\u4F5C\u540E\u9636\u6BB5\u8F93\u5165\uFF09\u3002"
4925
5054
  },
4926
5055
  steps: {
4927
5056
  type: "array",
4928
- description: "\u7F16\u6392\u6B65\u9AA4\u5217\u8868\uFF08parallel\uFF1A\u6BCF\u4E2A\u662F\u4E00\u4E2A\u72EC\u7ACB\u5B50 agent \u4EFB\u52A1\uFF1Bpipeline\uFF1A\u6309\u987A\u5E8F\u4E3A\u5404\u9636\u6BB5\uFF0C\u524D\u9636\u6BB5\u4EA7\u51FA\u81EA\u52A8\u4F5C\u4E3A\u540E\u9636\u6BB5\u8F93\u5165\uFF09\u3002",
5057
+ description: "\u6B65\u9AA4\u5217\u8868\uFF08parallel=\u6BCF\u4E2A\u662F\u72EC\u7ACB\u5B50 agent \u4EFB\u52A1\uFF1Bpipeline=\u6309\u5E8F\u5404\u9636\u6BB5\uFF09\u3002",
4929
5058
  items: {
4930
5059
  type: "object",
4931
5060
  properties: {
4932
- task: { type: "string", description: "\u4EA4\u7ED9\u8BE5\u5B50 agent \u7684\u5177\u4F53\u4EFB\u52A1\u63CF\u8FF0\uFF08parallel \u5FC5\u987B\u81EA\u5305\u542B\u3001\u4E0D\u4F9D\u8D56\u5176\u5B83\u6B65\u9AA4\uFF1Bpipeline \u53EA\u5199\u672C\u9636\u6BB5\u804C\u8D23\uFF0C\u524D\u9636\u6BB5\u4EA7\u51FA\u4F1A\u81EA\u52A8\u62FC\u5165\uFF09" },
4933
- name: { type: "string", description: "\u58F0\u660E\u5F0F\u5B50 Agent \u540D\u79F0\uFF08\u53EF\u9009\uFF0C\u5957\u7528\u5176\u4E13\u957F\u7CFB\u7EDF\u8BCD/\u5DE5\u5177\u767D\u540D\u5355/model\uFF09" },
4934
- role: { type: "string", description: "\u89D2\u8272/\u4E13\u957F\u8865\u5145\uFF08\u53EF\u9009\uFF09" },
4935
- key: { type: "string", description: "\u7ED3\u679C\u6807\u7B7E\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u7528\u4EFB\u52A1\u9996\u53E5\uFF1Bparallel \u7ED3\u679C\u6309\u6B64\u6807\u8BC6\u5404\u5B50 agent \u4EA7\u51FA\uFF09" }
5061
+ task: { type: "string", description: "\u5B50 agent \u4EFB\u52A1\u63CF\u8FF0\uFF08parallel \u987B\u81EA\u5305\u542B\uFF1Bpipeline \u53EA\u5199\u672C\u9636\u6BB5\u804C\u8D23\uFF09" },
5062
+ name: { type: "string", description: "\u58F0\u660E\u5F0F\u5B50 Agent \u540D\uFF08\u53EF\u9009\uFF0C\u5957\u7528\u5176\u7CFB\u7EDF\u8BCD/\u5DE5\u5177\u767D\u540D\u5355/model\uFF09" },
5063
+ role: { type: "string", description: "\u89D2\u8272\u8865\u5145\uFF08\u53EF\u9009\uFF09" },
5064
+ key: { type: "string", description: "\u7ED3\u679C\u6807\u7B7E\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u53D6\u4EFB\u52A1\u9996\u53E5\uFF09" }
4936
5065
  },
4937
5066
  required: ["task"]
4938
5067
  },
@@ -4940,12 +5069,12 @@ var init_workflow = __esm({
4940
5069
  },
4941
5070
  concurrency: {
4942
5071
  type: "number",
4943
- description: "parallel \u6A21\u5F0F\u6700\u5927\u5E76\u53D1\u5B50 agent \u6570\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4 4\uFF0C\u4E0A\u9650\u53D7\u5168\u5C40\u914D\u7F6E\u7EA6\u675F\uFF09\u3002\u4EFB\u52A1\u5F7C\u6B64\u72EC\u7ACB\u65F6\u8C03\u5927\u53EF\u52A0\u901F\uFF1B\u4E3A 1 \u5219\u9000\u5316\u4E3A\u4E32\u884C\u3002"
5072
+ description: "parallel \u6700\u5927\u5E76\u53D1\u6570\uFF08\u9ED8\u8BA4 4\uFF0C\u53D7\u5168\u5C40\u4E0A\u9650\u7EA6\u675F\uFF1B1=\u4E32\u884C\uFF09\u3002"
4944
5073
  },
4945
5074
  isolation: {
4946
5075
  type: "string",
4947
5076
  enum: ["none", "worktree"],
4948
- description: "\u9694\u79BB\u6A21\u5F0F\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4 none\uFF09\uFF1Anone=\u5171\u4EAB\u5DE5\u4F5C\u533A\uFF08\u4EC5\u9002\u5408\u8BFB/\u5206\u6790\uFF09\uFF1Bworktree=\u6BCF\u6B65\u72EC\u7ACB git worktree\uFF08\u9002\u5408\u5E76\u884C\u5199/\u8FC1\u79FB\uFF0C\u4E92\u4E0D\u6C61\u67D3\uFF0C\u7ED3\u675F\u540E\u6536\u5272\u5404 worktree diff\uFF09\u3002\u4EC5 parallel \u6A21\u5F0F\u652F\u6301 worktree\u3002"
5077
+ description: "none=\u5171\u4EAB\u5DE5\u4F5C\u533A\uFF08\u9ED8\u8BA4\uFF0C\u53EA\u8BFB/\u5206\u6790\uFF09\uFF1Bworktree=\u6BCF\u6B65\u72EC\u7ACB git worktree\uFF08\u5E76\u884C\u5199/\u8FC1\u79FB\uFF09\u3002\u4EC5 parallel \u652F\u6301\u3002"
4949
5078
  }
4950
5079
  },
4951
5080
  required: ["steps"]
@@ -5068,7 +5197,7 @@ var init_workflow = __esm({
5068
5197
  // ../core/src/tool/tsHost.ts
5069
5198
  import fsSync3 from "fs";
5070
5199
  import path15 from "path";
5071
- var _ts, _tsTried, getTs, buildDefaultOptions, findTsConfigBounded, resolveTsConfig, createProjectHost, lsCache, getLanguageService, realpathNative, posToLineCol, lineColToPos;
5200
+ var _ts, _tsTried, getTs, buildDefaultOptions, findTsConfigBounded, resolveTsConfig, createProjectHost, lsCache, getLanguageService, realpathNative, posToLineCol, SUPPORTED_SOURCE_EXTS, checkSupportedSourceExt, lineColToPos;
5072
5201
  var init_tsHost = __esm({
5073
5202
  "../core/src/tool/tsHost.ts"() {
5074
5203
  "use strict";
@@ -5214,6 +5343,12 @@ var init_tsHost = __esm({
5214
5343
  const { line, character } = ts.getLineAndCharacterOfPosition(sf, pos);
5215
5344
  return { line: line + 1, column: character + 1 };
5216
5345
  };
5346
+ SUPPORTED_SOURCE_EXTS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
5347
+ checkSupportedSourceExt = (displayPath) => {
5348
+ const ext = path15.extname(displayPath).toLowerCase();
5349
+ if (SUPPORTED_SOURCE_EXTS.has(ext)) return null;
5350
+ return `\u274C [\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301]\uFF1A[${displayPath}] \u7684\u6269\u5C55\u540D ${ext || "(\u65E0)"} \u4E0D\u5728 TS \u5F15\u64CE\u652F\u6301\u8303\u56F4\uFF08\u4EC5 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF09\u3002\u8BF7\u6539\u7528 read_file/grep \u67E5\u770B\u5185\u5BB9\uFF1B\u7F16\u8BD1/\u7C7B\u578B\u7C7B\u9A8C\u8BC1\u7528 run_command \u8DD1\u5BF9\u5E94\u8BED\u8A00\u5DE5\u5177\u94FE\uFF08\u5982 mvn compile / tsc --noEmit\uFF09\u3002`;
5351
+ };
5217
5352
  lineColToPos = (ts, sf, line1, col1) => ts.getPositionOfLineAndCharacter(sf, Math.max(0, line1 - 1), Math.max(0, col1 - 1));
5218
5353
  }
5219
5354
  });
@@ -5596,23 +5731,23 @@ ${treeResult}`;
5596
5731
  type: "function",
5597
5732
  function: {
5598
5733
  name: "edit_file",
5599
- description: "\u9488\u5BF9\u6307\u5B9A\u7684\u6587\u4EF6\u8FDB\u884C\u5C40\u90E8\u7CBE\u51C6\u4FEE\u6539\u3002\u2605 \u540C\u4E00\u6587\u4EF6\u6709\u591A\u5904\u8981\u6539\u65F6\uFF0C\u52A1\u5FC5\u4E00\u6B21\u8C03\u7528\u4F20 edits \u6570\u7EC4\u5168\u90E8\u5B8C\u6210\uFF08\u6309\u5E8F\u5E94\u7528\u3001\u6574\u4F53\u539F\u5B50\uFF1A\u4EFB\u4E00\u5904\u5931\u8D25\u5219\u5168\u90E8\u4E0D\u5199\u5165\uFF09\uFF0C\u52FF\u9010\u5904\u591A\u6B21\u8C03\u7528\u3002old_str \u5FC5\u987B\u4E0E\u6587\u4EF6\u4E2D\u7684\u539F\u59CB\u4EE3\u7801\u9010\u5B57\u7B26\u4E00\u81F4\uFF1A\u8BF7\u53BB\u6389 read_file \u8FD4\u56DE\u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF0C\u5E76\u4FDD\u7559\u539F\u6709\u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0E\u884C\u5C3E\u7A7A\u767D\uFF1B\u9ED8\u8BA4\u8981\u6C42\u5728\u5168\u6587\u4E2D\u552F\u4E00\uFF0C\u82E5\u8BBE replace_all=true \u5219\u66FF\u6362\u5168\u90E8\u5339\u914D\u5904\uFF08\u9002\u5408\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\uFF09\u3002",
5734
+ description: "\u5BF9\u6587\u4EF6\u505A\u5C40\u90E8\u7CBE\u51C6\u4FEE\u6539\u3002\u2605 \u540C\u4E00\u6587\u4EF6\u591A\u5904\u8981\u6539\u65F6\u4E00\u6B21\u4F20 edits \u6570\u7EC4\u5168\u90E8\u5B8C\u6210\uFF08\u6309\u5E8F\u5E94\u7528\u3001\u6574\u4F53\u539F\u5B50\uFF1A\u4EFB\u4E00\u5904\u5931\u8D25\u5168\u90E8\u4E0D\u5199\u5165\uFF09\uFF0C\u52FF\u9010\u5904\u591A\u6B21\u8C03\u7528\u3002old_str \u987B\u4E0E\u6587\u4EF6\u539F\u6587\u9010\u5B57\u7B26\u4E00\u81F4\uFF1A\u53BB\u6389 read_file \u8FD4\u56DE\u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF0C\u4FDD\u7559\u539F\u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0E\u884C\u5C3E\u7A7A\u767D\u3002\u9ED8\u8BA4\u987B\u5168\u6587\u552F\u4E00\uFF1Breplace_all=true \u66FF\u6362\u5168\u90E8\u5339\u914D\uFF08\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\uFF09\u3002",
5600
5735
  parameters: {
5601
5736
  type: "object",
5602
5737
  properties: {
5603
- path: { type: "string", description: "\u51C6\u5907\u4FEE\u6539\u7684\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84" },
5604
- old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF1B\u591A\u5904\u4FEE\u6539\u8BF7\u6539\u7528 edits \u6570\u7EC4\u4E00\u6B21\u5B8C\u6210\uFF09" },
5605
- new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF09" },
5606
- replace_all: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\u5904\uFF08\u9ED8\u8BA4 false \u4EC5\u66FF\u6362\u552F\u4E00\u5339\u914D\uFF1B\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\u65F6\u8BBE true\uFF09\u3002\u9876\u5C42\u53C2\u6570\u4EC5\u4F5C\u7528\u4E8E\u5355\u6761 old_str/new_str\uFF1Bedits \u5185\u6BCF\u6761\u53EF\u72EC\u7ACB\u8BBE\u7F6E" },
5738
+ path: { type: "string", description: "\u76EE\u6807\u6587\u4EF6\u8DEF\u5F84" },
5739
+ old_str: { type: "string", description: "\u73B0\u6709\u65E7\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF1B\u591A\u5904\u6539\u7528 edits\uFF09" },
5740
+ new_str: { type: "string", description: "\u66FF\u6362\u540E\u7684\u65B0\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF09" },
5741
+ replace_all: { type: "boolean", description: "\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\uFF08\u9ED8\u8BA4 false \u4EC5\u552F\u4E00\u5339\u914D\uFF09\u3002\u9876\u5C42\u4EC5\u4F5C\u7528\u5355\u6761 old_str/new_str\uFF1Bedits \u5185\u6BCF\u6761\u53EF\u72EC\u7ACB\u8BBE\u7F6E" },
5607
5742
  edits: {
5608
5743
  type: "array",
5609
- description: "\u2605 \u540C\u4E00\u6587\u4EF6\u591A\u5904\u4FEE\u6539\u65F6\u4F18\u5148\u4F7F\u7528\uFF1A\u4E00\u6B21\u8C03\u7528\u6309\u5E8F\u5B8C\u6210\u5168\u90E8\u66FF\u6362\uFF0C\u7701\u53BB\u9010\u5904\u5F80\u8FD4\u3002\u7B2C N \u6761\u7684 old_str \u987B\u57FA\u4E8E\u524D N-1 \u6761\u5E94\u7528\u540E\u7684\u6587\u4EF6\u5185\u5BB9\u6784\u9020\uFF1B\u4EFB\u4E00\u6761\u672A\u547D\u4E2D\u5219\u6574\u4F53\u4E0D\u5199\u5165\uFF08\u539F\u5B50\uFF09\uFF0C\u4FEE\u6B63\u8BE5\u6761\u540E\u6574\u7EC4\u91CD\u8BD5",
5744
+ description: "\u2605 \u540C\u6587\u4EF6\u591A\u5904\u4FEE\u6539\u9996\u9009\uFF1A\u4E00\u6B21\u6309\u5E8F\u5B8C\u6210\u5168\u90E8\u66FF\u6362\u3002\u7B2C N \u6761 old_str \u57FA\u4E8E\u524D N-1 \u6761\u5E94\u7528\u540E\u7684\u5185\u5BB9\u6784\u9020\uFF1B\u4EFB\u4E00\u6761\u672A\u547D\u4E2D\u5219\u6574\u7EC4\u4E0D\u5199\u5165\uFF08\u539F\u5B50\uFF09\uFF0C\u4FEE\u6B63\u540E\u6574\u7EC4\u91CD\u8BD5",
5610
5745
  items: {
5611
5746
  type: "object",
5612
5747
  properties: {
5613
- old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757" },
5614
- new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757" },
5615
- replace_all: { type: "boolean", description: "\u8BE5\u6761\u662F\u5426\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\u5904\uFF08\u9ED8\u8BA4 false\uFF09" }
5748
+ old_str: { type: "string", description: "\u73B0\u6709\u65E7\u4EE3\u7801\u5757" },
5749
+ new_str: { type: "string", description: "\u65B0\u4EE3\u7801\u5757" },
5750
+ replace_all: { type: "boolean", description: "\u66FF\u6362\u5168\u90E8\u5339\u914D\uFF08\u9ED8\u8BA4 false\uFF09" }
5616
5751
  },
5617
5752
  required: ["old_str", "new_str"]
5618
5753
  }
@@ -5778,7 +5913,7 @@ ${summaries.join("\n")}`;
5778
5913
  type: "function",
5779
5914
  function: {
5780
5915
  name: "write_file",
5781
- description: "\u5C06\u5B8C\u6574\u5185\u5BB9\u5168\u91CF\u5199\u5165\u6307\u5B9A\u6587\u4EF6\uFF08\u8986\u76D6\uFF09\u3002\u6587\u4EF6\u4E0D\u5B58\u5728\u5219\u65B0\u5EFA\uFF08\u542B\u7236\u76EE\u5F55\uFF09\uFF1B\u5DF2\u5B58\u5728\u5219\u6574\u4F53\u8986\u76D6\u3002\u2605 \u4EC5\u7528\u4E8E\u3010\u65B0\u5EFA\u6587\u4EF6\u3011\u6216\u3010\u5F7B\u5E95\u91CD\u5199\u6574\u4E2A\u6587\u4EF6\u3011\u2014\u2014\u4FEE\u6539\u65E2\u6709\u6587\u4EF6\u4E00\u5F8B\u6539\u7528 edit_file\uFF08\u7CBE\u51C6\u5C40\u90E8\u66FF\u6362\u3001\u4FDD\u7559\u539F\u7F29\u8FDB\u3001\u6700\u5C0F diff\uFF09\u3002\u7528 write_file \u8986\u76D6\u65E2\u6709\u6587\u4EF6\u4F1A\u4E22\u5931\u539F\u6709 Tab/\u7A7A\u683C\u7F29\u8FDB\uFF0C\u4EA7\u751F\u5927\u91CF\u65E0\u5173 diff\uFF0C\u7528\u6237\u5F3A\u70C8\u53CD\u611F\u3002",
5916
+ description: "\u5C06\u5B8C\u6574\u5185\u5BB9\u5168\u91CF\u5199\u5165\u6307\u5B9A\u6587\u4EF6\uFF08\u8986\u76D6\uFF09\u3002\u6587\u4EF6\u4E0D\u5B58\u5728\u5219\u65B0\u5EFA\uFF08\u542B\u7236\u76EE\u5F55\uFF09\uFF1B\u5DF2\u5B58\u5728\u5219\u6574\u4F53\u8986\u76D6\u3002\u2605 \u4EC5\u7528\u4E8E\u3010\u65B0\u5EFA\u6587\u4EF6\u3011\u6216\u3010\u5F7B\u5E95\u91CD\u5199\u6574\u4E2A\u6587\u4EF6\u3011\uFF1B\u4FEE\u6539\u65E2\u6709\u6587\u4EF6\u4E00\u5F8B\u6539\u7528 edit_file\uFF08\u5C40\u90E8\u7CBE\u51C6\u66FF\u6362\u3001\u6700\u5C0F diff\uFF09\u3002",
5782
5917
  parameters: {
5783
5918
  type: "object",
5784
5919
  properties: {
@@ -5816,7 +5951,7 @@ ${summaries.join("\n")}`;
5816
5951
  type: "function",
5817
5952
  function: {
5818
5953
  name: "view_symbol_outline",
5819
- description: "\u901A\u8FC7\u62BD\u8C61\u8BED\u6CD5\u6811(AST)\u5FEB\u901F\u63D0\u53D6\u6307\u5B9A\u6587\u4EF6\u4E2D\u7684\u7B26\u53F7\u5927\u7EB2\uFF08\u7C7B\u3001\u63A5\u53E3\u3001\u51FD\u6570\u540D\u3001\u5BFC\u51FA\u9879\u3001\u5165\u53C2\u7B7E\u540D\u7B49\uFF09\u3002\u9002\u5408\u5728\u4E0D\u8BFB\u53D6\u51E0\u5343\u884C\u5177\u4F53\u4EE3\u7801\u7684\u524D\u63D0\u4E0B\uFF0C\u5B8F\u89C2\u4E86\u89E3\u6587\u4EF6\u67B6\u6784\u3002",
5954
+ description: "\u901A\u8FC7\u62BD\u8C61\u8BED\u6CD5\u6811(AST)\u5FEB\u901F\u63D0\u53D6\u6307\u5B9A TS/JS \u6E90\u6587\u4EF6\u4E2D\u7684\u7B26\u53F7\u5927\u7EB2\uFF08\u7C7B\u3001\u63A5\u53E3\u3001\u51FD\u6570\u540D\u3001\u5BFC\u51FA\u9879\u3001\u5165\u53C2\u7B7E\u540D\u7B49\uFF09\u3002\u9002\u5408\u5728\u4E0D\u8BFB\u53D6\u51E0\u5343\u884C\u5177\u4F53\u4EE3\u7801\u7684\u524D\u63D0\u4E0B\uFF0C\u5B8F\u89C2\u4E86\u89E3\u6587\u4EF6\u67B6\u6784\u3002\u4EC5\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B\u5176\u4ED6\u7C7B\u578B\u6587\u4EF6\uFF08.java/.vue/.py \u7B49\uFF09\u76F4\u63A5\u62D2\u7EDD\uFF0C\u8BF7\u6539\u7528 read_file\u3002",
5820
5955
  parameters: {
5821
5956
  type: "object",
5822
5957
  properties: {
@@ -5832,6 +5967,8 @@ ${summaries.join("\n")}`;
5832
5967
  const absPath = resolveReadablePath(args.path);
5833
5968
  const readBlock = await assertReadable(absPath, args.path);
5834
5969
  if (readBlock) return readBlock;
5970
+ const extBlock = checkSupportedSourceExt(args.path);
5971
+ if (extBlock) return extBlock;
5835
5972
  const statForSize = await fs12.stat(absPath);
5836
5973
  if (statForSize.size > 1024 * 1024) {
5837
5974
  return `\u26A0\uFE0F [\u6587\u4EF6\u8FC7\u5927]\uFF1A[${args.path}] \u7EA6 ${Math.round(statForSize.size / 1024)}KB\uFF0C\u8D85\u8FC7\u7B26\u53F7\u5927\u7EB2\u5206\u6790\u7684 1MB \u4E0A\u9650\uFF08\u9632\u5168\u91CF readFile + AST \u9A7B\u7559\u5403\u5185\u5B58\uFF09\u3002\u8BF7\u6539\u7528 read_file \u5206\u7247\u67E5\u770B\uFF0C\u6216\u7F29\u5C0F\u76EE\u6807\u6587\u4EF6\u3002`;
@@ -5962,14 +6099,14 @@ var init_search = __esm({
5962
6099
  type: "function",
5963
6100
  function: {
5964
6101
  name: "search_grep",
5965
- description: "\u5728\u5DE5\u4F5C\u533A\u7684\u6240\u6709\u6587\u4EF6\u4E2D\u68C0\u7D22\u5339\u914D\u7684\u4EE3\u7801\u884C\uFF0C\u6BCF\u4E2A\u547D\u4E2D\u9ED8\u8BA4\u5E26\u524D\u540E\u5404 2 \u884C\u4E0A\u4E0B\u6587\uFF08\u53EF\u76F4\u63A5\u5224\u65AD\u7528\u6CD5\u3001\u514D\u7D27\u8DDF\u4E00\u6B21 read_file\uFF1B\u6784\u9020 edit_file \u7684 old_str \u524D\u53EF\u7528 context \u53C2\u6570\u8C03\u5927\u4E00\u6B21\u62FF\u8DB3\uFF09\uFF1B\u9ED8\u8BA4\u6309\u5B57\u9762\u91CF\u5173\u952E\u8BCD\u5339\u914D\uFF0C\u5982\u9700\u6B63\u5219\u4F20 is_regex=true\u3002\u2605 \u68C0\u7D22\u591A\u4E2A\u5173\u952E\u8BCD\u65F6\uFF0C\u7528 is_regex=true \u4EE5 | \u5408\u5E76\uFF08\u5982 'uploadVisible|uploadTip'\uFF09\u4E00\u6B21\u67E5\u5B8C\uFF0C\u52FF\u9010\u4E2A\u5173\u952E\u8BCD\u591A\u6B21\u8C03\u7528\u3002path \u53EF\u9650\u5B9A\u5230\u76EE\u5F55\u6216\u5177\u4F53\u6587\u4EF6\uFF08\u5728\u5355\u4E2A\u5927\u6587\u4EF6\u5185\u591A\u5904\u5B9A\u4F4D\u65F6\u4F20\u6587\u4EF6\u8DEF\u5F84\u6700\u9AD8\u6548\uFF09\u3002\u591A\u6839\u5DE5\u4F5C\u533A\u4E0B\uFF1A\u53EF\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF0C\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../\u5144\u5F1F\u76EE\u5F55\u3002\u2605 \u5F53\u7528\u6237\u5728\u5BF9\u8BDD\u91CC\u6307\u660E\u4E86\u67D0\u4E2A\u9879\u76EE\u65F6\uFF0C\u52A1\u5FC5\u628A\u8BE5\u9879\u76EE\u4F5C\u4E3A path \u4F20\u5165\u2014\u2014\u5426\u5219\u53EA\u4F1A\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u7684\u6D3B\u52A8\u6839\uFF0C\u5E38\u4E0E\u7528\u6237\u610F\u56FE\u4E0D\u7B26\u3002",
6102
+ description: "\u5728\u5DE5\u4F5C\u533A\u6587\u4EF6\u4E2D\u68C0\u7D22\u5339\u914D\u7684\u4EE3\u7801\u884C\uFF0C\u6BCF\u4E2A\u547D\u4E2D\u9ED8\u8BA4\u5E26\u524D\u540E\u5404 2 \u884C\u4E0A\u4E0B\u6587\uFF08\u53EF\u76F4\u63A5\u5224\u65AD\u7528\u6CD5\uFF1B\u6784\u9020 edit_file \u7684 old_str \u524D\u53EF\u7528 context \u8C03\u5927\u4E00\u6B21\u62FF\u8DB3\uFF09\u3002\u9ED8\u8BA4\u5B57\u9762\u91CF\u5339\u914D\uFF0C\u6B63\u5219\u4F20 is_regex=true\u3002\u2605 \u591A\u5173\u952E\u8BCD\u7528 is_regex=true \u4EE5 | \u5408\u5E76\uFF08\u5982 'uploadVisible|uploadTip'\uFF09\u4E00\u6B21\u67E5\u5B8C\uFF0C\u52FF\u9010\u8BCD\u591A\u6B21\u8C03\u7528\u3002path \u53EF\u9650\u5B9A\u76EE\u5F55\u6216\u6587\u4EF6\uFF08\u5355\u5927\u6587\u4EF6\u591A\u5904\u5B9A\u4F4D\u4F20\u6587\u4EF6\u8DEF\u5F84\u6700\u9AD8\u6548\uFF09\u3002\u591A\u6839\u5DE5\u4F5C\u533A\uFF1Apath \u53EF\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u3001\u7EDD\u5BF9\u8DEF\u5F84\u6216 ../\u5144\u5F1F\u76EE\u5F55\u3002\u2605 \u7528\u6237\u6307\u660E\u4E86\u9879\u76EE\u65F6\u52A1\u5FC5\u628A\u8BE5\u9879\u76EE\u4F5C\u4E3A path \u4F20\u5165\u2014\u2014\u7F3A\u7701\u53EA\u641C\u6D3B\u52A8\u6839\uFF0C\u5E38\u4E0E\u610F\u56FE\u4E0D\u7B26\u3002",
5966
6103
  parameters: {
5967
6104
  type: "object",
5968
6105
  properties: {
5969
- query: { type: "string", description: "\u68C0\u7D22\u5185\u5BB9\u3002\u9ED8\u8BA4\u4E3A\u5B57\u9762\u91CF\u5173\u952E\u8BCD\uFF08\u5982 'function runAgent'\uFF09\uFF1Bis_regex=true \u65F6\u6309\u6B63\u5219\u89E3\u6790\uFF08\u5982 'function\\s+runAgent'\uFF0C\u591A\u5173\u952E\u8BCD\u7528 | \u5408\u5E76\uFF09" },
5970
- is_regex: { type: "boolean", description: "\u662F\u5426\u5C06 query \u4F5C\u4E3A\u6B63\u5219\u8868\u8FBE\u5F0F\u89E3\u6790\uFF0C\u9ED8\u8BA4 false\uFF08\u5B57\u9762\u91CF\u5339\u914D\uFF0C\u81EA\u52A8\u8F6C\u4E49\u7279\u6B8A\u5B57\u7B26\uFF09" },
5971
- path: { type: "string", description: "\u9650\u5B9A\u641C\u7D22\u7684\u76EE\u5F55\u6216\u5177\u4F53\u6587\u4EF6\uFF08\u53EF\u9009\uFF09\u3002\u4F20\u5177\u4F53\u6587\u4EF6\u8DEF\u5F84\u65F6\u76F8\u5F53\u4E8E\u8BE5\u6587\u4EF6\u5185\u5168\u6587\u68C0\u7D22\uFF08\u5927\u6587\u4EF6\u591A\u5904\u5B9A\u4F4D\u9996\u9009\uFF09\u3002\u9ED8\u8BA4\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u6D3B\u52A8\u6839\u3002\u591A\u6839\u573A\u666F\u4E0B\uFF1A\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF1B\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../<\u5144\u5F1F\u76EE\u5F55>\uFF1B\u5747\u7ECF\u6C99\u7BB1\u6821\u9A8C\u3002\u7528\u6237\u63D0\u5230\u5177\u4F53\u9879\u76EE\u65F6\u5FC5\u586B\u3002" },
5972
- context: { type: "number", description: "\u6BCF\u4E2A\u547D\u4E2D\u9644\u5E26\u7684\u524D\u540E\u4E0A\u4E0B\u6587\u884C\u6570\uFF080-10\uFF0C\u9ED8\u8BA4 2\uFF09\u3002\u9700\u8981\u62FF\u8DB3\u4E00\u6BB5\u5B8C\u6574\u4EE3\u7801\u4F5C edit_file \u7684 old_str \u65F6\u53EF\u8C03\u5927\uFF08\u5982 5-8\uFF09\uFF0C\u514D\u5F97\u4E8C\u6B21\u68C0\u7D22" }
6106
+ query: { type: "string", description: "\u68C0\u7D22\u8BCD\u3002\u9ED8\u8BA4\u5B57\u9762\u91CF\uFF08\u5982 'function runAgent'\uFF09\uFF1Bis_regex=true \u65F6\u6309\u6B63\u5219\uFF08\u591A\u5173\u952E\u8BCD\u7528 | \u5408\u5E76\uFF09" },
6107
+ is_regex: { type: "boolean", description: "query \u6309\u6B63\u5219\u89E3\u6790\uFF08\u9ED8\u8BA4 false\uFF0C\u5B57\u9762\u91CF\u81EA\u52A8\u8F6C\u4E49\u7279\u6B8A\u5B57\u7B26\uFF09" },
6108
+ path: { type: "string", description: "\u9650\u5B9A\u641C\u7D22\u7684\u76EE\u5F55\u6216\u6587\u4EF6\uFF08\u53EF\u9009\uFF09\u3002\u4F20\u6587\u4EF6=\u8BE5\u6587\u4EF6\u5185\u68C0\u7D22\uFF08\u5927\u6587\u4EF6\u591A\u5904\u5B9A\u4F4D\u9996\u9009\uFF09\u3002\u9ED8\u8BA4\u6D3B\u52A8\u6839\uFF1B\u591A\u6839\u4E0B\u53EF\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09/\u7EDD\u5BF9\u8DEF\u5F84/../\u5144\u5F1F\u76EE\u5F55\u3002\u7528\u6237\u63D0\u5230\u5177\u4F53\u9879\u76EE\u65F6\u5FC5\u586B\u3002" },
6109
+ context: { type: "number", description: "\u6BCF\u547D\u4E2D\u9644\u5E26\u4E0A\u4E0B\u6587\u884C\u6570\uFF080-10\uFF0C\u9ED8\u8BA4 2\uFF09\u3002\u8981\u62FF\u8DB3\u5B8C\u6574\u4EE3\u7801\u4F5C old_str \u65F6\u8C03\u5927\uFF08\u5982 5-8\uFF09" }
5973
6110
  },
5974
6111
  required: ["query"]
5975
6112
  },
@@ -6113,7 +6250,7 @@ ${content}`;
6113
6250
 
6114
6251
  // ../core/src/tool/registry/command.ts
6115
6252
  import { spawn as spawn4 } from "child_process";
6116
- var EXIT_SENTINEL, EXIT_SENTINEL_RE, RUN_COMMAND_MAX_CHARS, commandTools;
6253
+ var EXIT_SENTINEL, EXIT_SENTINEL_RE, AUTO_BG_NOTICE, AUTO_BG_SENTINEL_RE, RUN_COMMAND_MAX_CHARS, commandTools;
6117
6254
  var init_command = __esm({
6118
6255
  "../core/src/tool/registry/command.ts"() {
6119
6256
  "use strict";
@@ -6124,6 +6261,8 @@ var init_command = __esm({
6124
6261
  EXIT_SENTINEL = (code) => `
6125
6262
  \u27E6DSC_EXIT:${code}\u27E7`;
6126
6263
  EXIT_SENTINEL_RE = /⟦DSC_EXIT:(-?\d+)⟧/g;
6264
+ AUTO_BG_NOTICE = "\u27E6DSC_BG\u27E7";
6265
+ AUTO_BG_SENTINEL_RE = /⟦DSC_BG⟧\s*$/;
6127
6266
  RUN_COMMAND_MAX_CHARS = 2e4;
6128
6267
  commandTools = [
6129
6268
  {
@@ -6148,8 +6287,13 @@ var init_command = __esm({
6148
6287
  // 💡 我们将在 execute 内部真正落地这个长度限制
6149
6288
  verifyResult: (rawOutput) => {
6150
6289
  const matches2 = [...rawOutput.matchAll(EXIT_SENTINEL_RE)];
6151
- const code = matches2.length ? parseInt(matches2[matches2.length - 1][1], 10) : 0;
6290
+ const last = matches2[matches2.length - 1];
6291
+ const code = last ? parseInt(last[1], 10) : null;
6152
6292
  if (code === 0) return { status: "success" /* SUCCESS */ };
6293
+ if (code === null) {
6294
+ if (AUTO_BG_SENTINEL_RE.test(rawOutput.trimEnd())) return { status: "success" /* SUCCESS */ };
6295
+ return { status: "failed" /* FAILED */, summary: "\u8F93\u51FA\u4E2D\u7F3A\u5C11\u9000\u51FA\u7801\u54E8\u5175\u2014\u2014\u8FDB\u7A0B\u88AB\u5F3A\u5236\u7EC8\u6B62\u6216\u8F93\u51FA\u4E0D\u5B8C\u6574\uFF0C\u7ED3\u679C\u4E0D\u53EF\u4FE1\uFF0C\u6309\u5931\u8D25\u5904\u7406\u3002" };
6296
+ }
6153
6297
  const hint = code === 9009 ? "\uFF08Windows\uFF1A\u547D\u4EE4\u672A\u88AB\u8BC6\u522B\u2014\u2014\u547D\u4EE4\u4E0D\u5B58\u5728\u6216 PATH \u7F3A\u5931\uFF09" : code === 127 ? "\uFF08\u547D\u4EE4\u672A\u627E\u5230\u2014\u2014\u68C0\u67E5\u547D\u4EE4\u540D/PATH\uFF09" : code === 255 ? "\uFF08255 \u5E38\u89C1\u4E8E Unix \u547D\u4EE4\u5728\u975E POSIX shell \u4E0B\u7F3A\u5931\uFF0C\u6216\u8FDB\u7A0B\u663E\u5F0F exit(-1/255)\u3001\u8FDE\u63A5\u5931\u8D25\uFF09" : code === 4294967295 || code === -1 ? "\uFF08\u8FDB\u7A0B\u9000\u51FA\u7801 -1/\u672A\u6355\u83B7\u5F02\u5E38\u88AB\u6740\uFF09" : "";
6154
6298
  return { status: "failed" /* FAILED */, summary: `\u547D\u4EE4\u9000\u51FA\u7801\u975E\u96F6\uFF1A${code}${hint}` };
6155
6299
  },
@@ -6338,6 +6482,7 @@ ${tail}`,
6338
6482
  \u23F3 [\u81EA\u52A8\u8F6C\u540E\u53F0]\uFF1A\u547D\u4EE4 [${args.command}] ${why}\uFF0C\u5DF2\u81EA\u52A8\u8F6C\u4E3A\u540E\u53F0\u4EFB\u52A1\uFF08\u524D\u53F0\u6D41\u5F0F\u7ED3\u675F\uFF0C\u672A\u6D88\u8D39\u7684\u5269\u4F59\u8F93\u51FA\u5DF2\u5E76\u5165\u540E\u53F0\u7F13\u51B2\uFF09\u3002
6339
6483
  task_id: ${taskId}
6340
6484
  \u26A0\uFE0F \u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF0C\u9000\u51FA\u7801\u672A\u77E5\uFF08\u4E0D\u5224\u5B9A\u6210\u529F/\u5931\u8D25\uFF09\u2014\u2014\u7528 get_background_output(task_id="${taskId}", wait_seconds=\u2026) \u7B49\u5F85/\u67E5\u770B\u7ED3\u679C\uFF1B\u82E5\u786E\u8BA4\u65E0\u9700\u7EE7\u7EED\uFF0C\u7528 stop_background_task(task_id="${taskId}") \u7EC8\u6B62\u3002
6485
+ ${AUTO_BG_NOTICE}
6341
6486
  `;
6342
6487
  } else if (overLimit) {
6343
6488
  yield EXIT_SENTINEL(-1);
@@ -7259,9 +7404,9 @@ var init_http = __esm({
7259
7404
  function: {
7260
7405
  name: "http_request",
7261
7406
  description: [
7262
- "\u5168\u65B9\u6CD5 HTTP \u5BA2\u6237\u7AEF\uFF0C\u7528\u4E8E\u672C\u5730\u524D\u540E\u7AEF\u8054\u8C03\u3001API \u6D4B\u8BD5\u3001\u8C03\u7528 REST \u63A5\u53E3\u3002\u652F\u6301 GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS\uFF0C\u53EF\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\u4E0E\u8BF7\u6C42\u4F53\uFF0C\u8FD4\u56DE\u539F\u59CB\u54CD\u5E94\uFF08HTTP \u72B6\u6001\u7801 + \u54CD\u5E94\u5934 + body \u539F\u6587\uFF0C\u4E0D\u8F6C Markdown\uFF09\u3002",
7263
- "\u4E0E web_fetch \u7684\u533A\u522B\uFF1Aweb_fetch \u662F GET \u6293\u7F51\u9875\u8F6C Markdown\uFF08\u67E5\u6587\u6863\u7528\u3001\u9ED8\u8BA4\u62E6\u5185\u7F51\uFF09\uFF1B\u672C\u5DE5\u5177\u662F\u8C03\u63A5\u53E3\u53D6\u539F\u59CB\u54CD\u5E94\uFF08\u8054\u8C03\u7528\u3001\u9ED8\u8BA4\u653E\u884C localhost/\u5185\u7F51\uFF09\u3002",
7264
- "SSRF\uFF1A\u9ED8\u8BA4\u653E\u884C loopback \u4E0E\u5185\u7F51\u6BB5\uFF08\u672C\u5730\u8054\u8C03\u5FC5\u9700\uFF0C\u542B docker/k8s \u5185\u7F51\uFF09\uFF0C\u4F46\u59CB\u7EC8\u62E6\u622A\u4E91\u5143\u6570\u636E\u7AEF\u70B9 169.254.169.254\uFF1B\u4EC5 http/https\u3002"
7407
+ "\u5168\u65B9\u6CD5 HTTP \u5BA2\u6237\u7AEF\uFF1A\u672C\u5730\u524D\u540E\u7AEF\u8054\u8C03\u3001API \u6D4B\u8BD5\u3001\u8C03 REST \u63A5\u53E3\u3002\u8FD4\u56DE\u539F\u59CB\u54CD\u5E94\uFF08\u72B6\u6001\u7801+\u54CD\u5E94\u5934+body \u539F\u6587\uFF0C\u4E0D\u8F6C Markdown\uFF09\u3002",
7408
+ "\u4E0E web_fetch \u533A\u522B\uFF1Aweb_fetch GET \u6293\u7F51\u9875\u8F6C Markdown\uFF08\u67E5\u6587\u6863\u3001\u9ED8\u8BA4\u62E6\u5185\u7F51\uFF09\uFF1B\u672C\u5DE5\u5177\u8C03\u63A5\u53E3\u53D6\u539F\u59CB\u54CD\u5E94\uFF08\u8054\u8C03\u3001\u9ED8\u8BA4\u653E\u884C localhost/\u5185\u7F51\uFF09\u3002",
7409
+ "SSRF\uFF1A\u59CB\u7EC8\u62E6\u4E91\u5143\u6570\u636E\u7AEF\u70B9 169.254.169.254\uFF1B\u4EC5 http/https\u3002"
7265
7410
  ].join(" "),
7266
7411
  parameters: {
7267
7412
  type: "object",
@@ -7357,7 +7502,7 @@ var init_http = __esm({
7357
7502
  // ../core/src/tool/registry/typescript.ts
7358
7503
  import fs16 from "fs/promises";
7359
7504
  import path20 from "path";
7360
- var MAX_FILE_BYTES, toDisplayPath, precheck, MAX_DIAG_ENTRIES, MAX_DIAG_FILES, diagnoseOneFile, typescriptTools;
7505
+ var MAX_FILE_BYTES, toDisplayPath, isLibFile, precheck, MAX_DIAG_ENTRIES, MAX_DIAG_FILES, MAX_REF_ENTRIES, REF_SNIPPET_MAX, diagnoseOneFile, typescriptTools;
7361
7506
  var init_typescript = __esm({
7362
7507
  "../core/src/tool/registry/typescript.ts"() {
7363
7508
  "use strict";
@@ -7371,9 +7516,12 @@ var init_typescript = __esm({
7371
7516
  if (rel && !rel.startsWith("..") && !path20.isAbsolute(rel)) return rel.replace(/\\/g, "/");
7372
7517
  return abs.replace(/\\/g, "/").split("/").slice(-3).join("/");
7373
7518
  };
7519
+ isLibFile = (abs) => /(?:^|\/)node_modules\//.test(abs.replace(/\\/g, "/")) || /\.d\.ts$/i.test(abs);
7374
7520
  precheck = async (displayPath, absPath) => {
7375
7521
  const readBlock = await assertReadable(absPath, displayPath);
7376
7522
  if (readBlock) return readBlock;
7523
+ const extBlock = checkSupportedSourceExt(displayPath);
7524
+ if (extBlock) return extBlock;
7377
7525
  const stat = await fs16.stat(absPath);
7378
7526
  if (stat.size > MAX_FILE_BYTES) {
7379
7527
  return `\u26A0\uFE0F [\u6587\u4EF6\u8FC7\u5927]\uFF1A[${displayPath}] \u7EA6 ${Math.round(stat.size / 1024)}KB\uFF0C\u8D85\u8FC7 ${MAX_FILE_BYTES / 1024}KB \u4E0A\u9650\uFF08\u9632\u5168\u91CF type-check \u5403\u5185\u5B58\uFF09\u3002`;
@@ -7382,6 +7530,8 @@ var init_typescript = __esm({
7382
7530
  };
7383
7531
  MAX_DIAG_ENTRIES = 300;
7384
7532
  MAX_DIAG_FILES = 20;
7533
+ MAX_REF_ENTRIES = 200;
7534
+ REF_SNIPPET_MAX = 160;
7385
7535
  diagnoseOneFile = async (TS, displayPath, checkJs) => {
7386
7536
  try {
7387
7537
  const absPath = realpathNative(resolveReadablePath(displayPath));
@@ -7436,7 +7586,7 @@ ${body}${tail}` };
7436
7586
  type: "function",
7437
7587
  function: {
7438
7588
  name: "get_diagnostics",
7439
- description: "\u5BF9\u4E00\u4E2A\u6216\u591A\u4E2A TS/JS \u6587\u4EF6\u53D6 TypeScript \u8BED\u6CD5 + \u8BED\u4E49\u8BCA\u65AD\uFF08\u7C7B\u578B\u9519\u8BEF\u3001\u672A\u7528\u53D8\u91CF\u3001\u4E0D\u53EF\u8FBE\u4EE3\u7801\u7B49\uFF09\uFF0C\u8F93\u51FA\u5E26\u884C\u53F7/\u5217/\u4E25\u91CD\u5EA6/TS \u9519\u8BEF\u7801\uFF0C\u683C\u5F0F\u5BF9\u9F50 tsc\u3002\u7528\u4E8E\u7CBE\u51C6\u5B9A\u4F4D\u7F16\u8BD1/\u7C7B\u578B\u95EE\u9898\uFF0C\u66FF\u4EE3\u624B\u52A8\u8DD1 tsc \u518D\u89E3\u6790\u8F93\u51FA\u3002\u2605 \u6539\u5B8C\u591A\u4E2A\u6587\u4EF6\u540E\u9A8C\u8BC1\uFF1A\u4F20 paths \u6570\u7EC4\u4E00\u6B21\u8BCA\u65AD\u5168\u90E8\uFF08\u6700\u591A 20 \u4E2A\uFF09\uFF0C\u52FF\u9010\u6587\u4EF6\u591A\u6B21\u8C03\u7528\u3002\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B.vue SFC \u4E0D\u652F\u6301\uFF08\u9700 vue-tsc\uFF09\u3002\u9879\u76EE\u7EA7\u5168\u91CF\u8BCA\u65AD\u8BF7\u7528 run_command \u8DD1 `tsc --noEmit`\u3002\u4F9D\u8D56 typescript \u6A21\u5757\uFF08VSCode \u6269\u5C55\u5185\u53EF\u7528\uFF1B\u7F3A\u5931\u5219\u672C\u5DE5\u5177\u81EA\u52A8\u9690\u85CF\uFF09\u3002",
7589
+ description: "\u5BF9\u4E00\u4E2A\u6216\u591A\u4E2A TS/JS \u6587\u4EF6\u53D6\u7C7B\u578B+\u8BED\u4E49\u8BCA\u65AD\uFF08\u7C7B\u578B\u9519\u8BEF/\u672A\u7528\u53D8\u91CF/\u4E0D\u53EF\u8FBE\u4EE3\u7801\uFF09\uFF0C\u8F93\u51FA\u884C:\u5217/\u4E25\u91CD\u5EA6/TS \u9519\u8BEF\u7801\uFF0C\u683C\u5F0F\u5BF9\u9F50 tsc\u3002\u2605 \u6539\u5B8C\u591A\u4E2A\u6587\u4EF6\u540E\u9A8C\u8BC1\uFF1A\u4F20 paths \u6570\u7EC4\u4E00\u6B21\u8BCA\u65AD\u5168\u90E8\uFF08\u6700\u591A 20 \u4E2A\uFF09\uFF0C\u52FF\u9010\u6587\u4EF6\u591A\u6B21\u8C03\u7528\u3002\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B.vue SFC \u4E0E\u5176\u4ED6\u8BED\u8A00\u6269\u5C55\u540D\uFF08.java/.py \u7B49\uFF09\u76F4\u63A5\u62D2\u7EDD\u3001\u52FF\u4F20\u5165\u3002\u9879\u76EE\u7EA7\u5168\u91CF\u8BCA\u65AD\u7528 run_command \u8DD1 `tsc --noEmit`\u3002",
7440
7590
  parameters: {
7441
7591
  type: "object",
7442
7592
  properties: {
@@ -7491,7 +7641,7 @@ ${sections.join("\n\n")}`;
7491
7641
  type: "function",
7492
7642
  function: {
7493
7643
  name: "goto_definition",
7494
- description: "\u8DF3\u8F6C\u5230\u6307\u5B9A TS/JS \u6587\u4EF6\u67D0\u884C\u67D0\u5217\u7B26\u53F7\u7684\u5B9A\u4E49\u4F4D\u7F6E\uFF0C\u8FD4\u56DE rel/path:line:col\uFF08\u53EF\u591A\u5904\uFF09\u3002\u7528\u4E8E\u8DE8\u6587\u4EF6\u8FFD\u8E2A\u51FD\u6570/\u7C7B\u578B/\u53D8\u91CF\u7684\u6765\u6E90\uFF0C\u66FF\u4EE3 grep \u731C\u6D4B\u3002\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B.vue SFC \u4E0D\u652F\u6301\u3002\u843D\u70B9\u5728 node_modules \u6216 .d.ts \u65F6\u6807\u6CE8 (declaration/library)\u3002\u884C/\u5217\u4E3A 1-based\uFF08\u4E0E\u7F16\u8F91\u5668\u4E00\u81F4\uFF09\u3002\u4F9D\u8D56 typescript \u6A21\u5757\uFF08VSCode \u6269\u5C55\u5185\u53EF\u7528\uFF1B\u7F3A\u5931\u5219\u672C\u5DE5\u5177\u81EA\u52A8\u9690\u85CF\uFF09\u3002",
7644
+ description: "\u8DF3\u8F6C\u5230 TS/JS \u6587\u4EF6\u67D0\u884C\u67D0\u5217\u7B26\u53F7\u7684\u5B9A\u4E49\u4F4D\u7F6E\uFF0C\u8FD4\u56DE rel/path:line:col\uFF08\u53EF\u591A\u5904\uFF09\u3002\u8DE8\u6587\u4EF6\u8FFD\u8E2A\u51FD\u6570/\u7C7B\u578B/\u53D8\u91CF\u7684\u6765\u6E90\uFF0C\u66FF\u4EE3 grep \u731C\u6D4B\u3002\u843D\u70B9\u5728 node_modules/.d.ts \u65F6\u6807\u6CE8 (declaration/library)\u3002\u884C\u5217 1-based\u3002\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B.vue SFC \u4E0E\u5176\u4ED6\u8BED\u8A00\u6269\u5C55\u540D\u76F4\u63A5\u62D2\u7EDD\u3001\u52FF\u4F20\u5165\u3002",
7495
7645
  parameters: {
7496
7646
  type: "object",
7497
7647
  properties: {
@@ -7531,7 +7681,7 @@ ${sections.join("\n\n")}`;
7531
7681
  const lc = posToLineCol(TS, defSf, def.textSpan.start);
7532
7682
  loc = `${toDisplayPath(wsRoot, def.fileName)}:${lc.line}:${lc.column}`;
7533
7683
  }
7534
- const isLib = /(?:^|\/)node_modules\//.test(def.fileName.replace(/\\/g, "/")) || /\.d\.ts$/i.test(def.fileName);
7684
+ const isLib = isLibFile(def.fileName);
7535
7685
  const name = def.name || "(anonymous)";
7536
7686
  const kind = def.kind ? ` [${def.kind}]` : "";
7537
7687
  return `${name}${kind} \u2192 ${loc}${isLib ? " (declaration/library)" : ""}`;
@@ -7543,6 +7693,97 @@ ${out.join("\n")}`;
7543
7693
  }
7544
7694
  }
7545
7695
  }
7696
+ },
7697
+ {
7698
+ type: "function",
7699
+ function: {
7700
+ name: "find_references",
7701
+ description: "\u67E5\u627E TS/JS \u6587\u4EF6\u67D0\u884C\u67D0\u5217\u7B26\u53F7\u7684\u5168\u9879\u76EE\u5F15\u7528\uFF08\u8C03\u7528/\u5BFC\u5165/\u8BFB\u5199\uFF09\uFF0C\u8F93\u51FA rel/path:line:col + \u8BFB\u5199\u6807\u6CE8 + \u884C\u6458\u5F55\u3002\u7C7B\u578B\u611F\u77E5\uFF1A\u53EA\u8FD4\u56DE\u771F\u5B9E\u7ED1\u5B9A\uFF0C\u4E0D\u542B\u6CE8\u91CA/\u5B57\u7B26\u4E32\u91CC\u7684\u540C\u540D\u8BCD\uFF08grep \u6838\u5FC3\u8BEF\u62A5\u6E90\uFF09\u3002\u7528\u4E8E\u6539\u7B7E\u540D/\u91CD\u547D\u540D\u524D\u7684\u5F71\u54CD\u9762\u6392\u67E5\u3001\u8FFD\u8E2A\u8C03\u7528\u65B9\uFF1B\u4E0E goto_definition \u4E92\u4E3A\u53CD\u5411\u3002\u8986\u76D6\u4EE5 program \u5185\u6587\u4EF6\u4E3A\u754C\uFF08tsconfig include + import \u94FE\uFF09\uFF1B\u5355\u7B26\u53F7\u8D85 200 \u5904\u5F15\u7528\u622A\u65AD\u3002\u884C\u5217 1-based\u3002\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B.vue SFC \u4E0E\u5176\u4ED6\u8BED\u8A00\u6269\u5C55\u540D\u76F4\u63A5\u62D2\u7EDD\u3001\u52FF\u4F20\u5165\u3002",
7702
+ parameters: {
7703
+ type: "object",
7704
+ properties: {
7705
+ path: { type: "string", description: "\u76EE\u6807\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84\uFF08\u5982 'src/index.ts'\uFF09" },
7706
+ line: { type: "integer", description: "\u7B26\u53F7\u6240\u5728\u884C\u53F7\uFF081-based\uFF09" },
7707
+ column: { type: "integer", description: "\u7B26\u53F7\u6240\u5728\u5217\u53F7\uFF081-based\uFF09" }
7708
+ },
7709
+ required: ["path", "line", "column"]
7710
+ },
7711
+ safetyLevel: "safe" /* SAFE */,
7712
+ isSync: true,
7713
+ maxOutputCharacters: 48e3,
7714
+ // 200 条引用 × ~160 字符摘录的理论上界之内;中心 truncateToolResult 仍是最终兜底
7715
+ privacyMaskingRules: maskSecretsInContent,
7716
+ validateEnvironment: async () => !!await getTs(),
7717
+ async execute(args, _ctx) {
7718
+ const { path: displayPath, line, column } = args;
7719
+ try {
7720
+ const TS = await getTs();
7721
+ if (!TS) return `\u26A0\uFE0F [\u67E5\u627E\u5F15\u7528\u4E0D\u53EF\u7528]\uFF1Atypescript \u6A21\u5757\u672A\u52A0\u8F7D\uFF08VSCode \u6269\u5C55\u5185\u53EF\u7528\uFF1BCLI \u73AF\u5883\u672A\u5FC5\u5B89\u88C5 typescript\uFF09\u3002`;
7722
+ const absPath = realpathNative(resolveReadablePath(displayPath));
7723
+ const block = await precheck(displayPath, absPath);
7724
+ if (block) return block;
7725
+ const { ls } = await getLanguageService(TS, absPath);
7726
+ const program = ls.getProgram();
7727
+ if (!program) return `\u274C \u65E0\u6CD5\u53D6\u5F97 TS program\uFF08\u5185\u90E8\u9519\u8BEF\uFF09\u3002`;
7728
+ const sf = program.getSourceFile(absPath);
7729
+ if (!sf) return `\u274C \u6587\u4EF6\u672A\u7EB3\u5165 program\uFF1A${displayPath}\uFF08\u53EF\u80FD\u65E0\u5BF9\u5E94 tsconfig \u6216\u89E3\u6790\u5931\u8D25\uFF09\u3002`;
7730
+ const pos = lineColToPos(TS, sf, line, column);
7731
+ const groups = ls.findReferences(absPath, pos);
7732
+ if (!groups || groups.length === 0) {
7733
+ return `No references found at ${displayPath}:${line}:${column}\uFF08\u786E\u8BA4\u5B9A\u4F4D\u5728\u6807\u8BC6\u7B26\u4E0A\uFF0C\u975E\u7A7A\u767D/\u5B57\u9762\u91CF/\u5173\u952E\u5B57\uFF09\u3002`;
7734
+ }
7735
+ const wsRoot = getContainingRoot(absPath);
7736
+ const lineTextCache = /* @__PURE__ */ new Map();
7737
+ const lineSnippet = async (abs, line1) => {
7738
+ let lines = lineTextCache.get(abs);
7739
+ if (!lines) {
7740
+ try {
7741
+ lines = (await fs16.readFile(abs, "utf-8")).split(/\r?\n/);
7742
+ } catch {
7743
+ lines = [];
7744
+ }
7745
+ lineTextCache.set(abs, lines);
7746
+ }
7747
+ const text = (lines[line1 - 1] ?? "").trim();
7748
+ if (!text) return "";
7749
+ return " " + (text.length > REF_SNIPPET_MAX ? text.slice(0, REF_SNIPPET_MAX) + "\u2026" : text);
7750
+ };
7751
+ const sections = [];
7752
+ let shown = 0, overflow = 0;
7753
+ for (const g of groups) {
7754
+ const defSf = program.getSourceFile(g.definition.fileName);
7755
+ let defLoc = toDisplayPath(wsRoot, g.definition.fileName);
7756
+ if (defSf && g.definition.textSpan) {
7757
+ const lc = posToLineCol(TS, defSf, g.definition.textSpan.start);
7758
+ defLoc = `${defLoc}:${lc.line}:${lc.column}`;
7759
+ }
7760
+ const defLib = isLibFile(g.definition.fileName) ? " (declaration/library)" : "";
7761
+ const defName = (g.definition.name || "(anonymous)").replace(/\s+/g, " ");
7762
+ const header = `${defName}${g.definition.kind ? ` [${g.definition.kind}]` : ""} \u2014 ${g.references.length} \u5904\u5F15\u7528\uFF08\u58F0\u660E ${defLoc}\uFF09${defLib}`;
7763
+ const bodyLines = [];
7764
+ for (const r of g.references) {
7765
+ if (shown >= MAX_REF_ENTRIES) {
7766
+ overflow++;
7767
+ continue;
7768
+ }
7769
+ shown++;
7770
+ const refSf = program.getSourceFile(r.fileName);
7771
+ const lc = refSf ? posToLineCol(TS, refSf, r.textSpan.start) : { line: 0, column: 0 };
7772
+ const tag = r.isDefinition ? "[def]" : r.isWriteAccess ? "(write)" : "(read)";
7773
+ const snippet = r.isDefinition ? "" : await lineSnippet(r.fileName, lc.line);
7774
+ bodyLines.push(` ${toDisplayPath(wsRoot, r.fileName)}:${lc.line}:${lc.column} ${tag}${snippet}`);
7775
+ }
7776
+ sections.push([header, ...bodyLines].join("\n"));
7777
+ }
7778
+ const tail = overflow > 0 ? `
7779
+ \u2026(\u53E6\u6709 ${overflow} \u5904\u5F15\u7528\u672A\u663E\u793A\uFF1B\u7B26\u53F7\u8FC7\u70ED\u53EF\u6539\u7528 grep \u6309\u8C03\u7528\u540D\u626B\u63CF\uFF0C\u6216\u5206\u6587\u4EF6\u7F29\u5C0F\u8303\u56F4)\u2026` : "";
7780
+ return `[References: ${displayPath}:${line}:${column}]
7781
+ ${sections.join("\n")}${tail}`;
7782
+ } catch (e) {
7783
+ return `\u274C \u67E5\u627E\u5F15\u7528\u5931\u8D25 [${displayPath}:${line}:${column}]: ${e?.message ?? e}`;
7784
+ }
7785
+ }
7786
+ }
7546
7787
  }
7547
7788
  ];
7548
7789
  }
@@ -8518,10 +8759,9 @@ var init_ask = __esm({
8518
8759
  function: {
8519
8760
  name: "ask_question",
8520
8761
  description: [
8521
- "\u5411\u7528\u6237\u63D0\u51FA\u4E00\u4E2A\u591A\u9009\u95EE\u9898\u5E76\u7B49\u5F85\u4F5C\u7B54\u3002\u7528\u4E8E\u9700\u8981\u7528\u6237\u62CD\u677F\u7684\u51B3\u7B56\uFF08\u5982\u6280\u672F\u65B9\u6848\u4E8C\u9009\u4E00\u3001\u5B9E\u73B0\u8DEF\u5F84\u53D6\u820D\u3001\u8303\u56F4\u786E\u8BA4\uFF09\u6216\u6F84\u6E05\u6B67\u4E49\u2014\u2014\u5207\u52FF\u7528\u4E8E\u80FD\u4ECE\u4EE3\u7801/\u4E0A\u4E0B\u6587\u81EA\u884C\u786E\u5B9A\u7684\u95EE\u9898\u3002",
8522
- "\u63D0\u4F9B 2-4 \u4E2A\u9009\u9879\uFF0C\u6BCF\u4E2A\u542B\u7B80\u77ED label \u4E0E\u53EF\u9009 description\u3002multiSelect=true \u5141\u8BB8\u591A\u9009\uFF08\u9ED8\u8BA4\u5355\u9009\uFF09\u3002",
8523
- "\u7528\u6237\u7684\u9009\u62E9\u4F1A\u4F5C\u4E3A\u7ED3\u679C\u8FD4\u56DE\uFF1B\u82E5\u7528\u6237\u53D6\u6D88\uFF0C\u8FD4\u56DE\u7A7A\u9009\u62E9\uFF08\u6B64\u65F6\u5E94\u6539\u7528\u9ED8\u8BA4\u6216\u91CD\u65B0\u63D0\u95EE\uFF09\u3002",
8524
- "\u6CE8\u610F\uFF1A\u4EC5\u5728\u4EA4\u4E92\u5F0F\u73AF\u5883\u53EF\u7528\uFF1B\u82E5\u7ED3\u679C\u63D0\u793A\u300C\u4E0D\u652F\u6301\u300D\uFF0C\u6539\u7528\u7EAF\u6587\u672C\u5411\u7528\u6237\u63D0\u95EE\u3002"
8762
+ "\u5411\u7528\u6237\u63D0\u51FA\u591A\u9009\u95EE\u9898\u5E76\u7B49\u5F85\u4F5C\u7B54\uFF1A\u6280\u672F\u65B9\u6848\u4E8C\u9009\u4E00\u3001\u8DEF\u5F84\u53D6\u820D\u3001\u8303\u56F4\u786E\u8BA4\u7B49\u9700\u7528\u6237\u62CD\u677F\u7684\u51B3\u7B56\u6216\u6B67\u4E49\u6F84\u6E05\u2014\u2014\u52FF\u7528\u4E8E\u80FD\u4ECE\u4EE3\u7801/\u4E0A\u4E0B\u6587\u81EA\u884C\u786E\u5B9A\u7684\u95EE\u9898\u3002",
8763
+ "2-4 \u4E2A\u9009\u9879\uFF08label + \u53EF\u9009 description\uFF09\uFF1BmultiSelect=true \u591A\u9009\uFF08\u9ED8\u8BA4\u5355\u9009\uFF09\u3002\u7528\u6237\u53D6\u6D88\u8FD4\u56DE\u7A7A\u9009\u62E9\uFF08\u6539\u7528\u9ED8\u8BA4\u6216\u91CD\u65B0\u63D0\u95EE\uFF09\u3002",
8764
+ "\u4EC5\u4EA4\u4E92\u5F0F\u73AF\u5883\u53EF\u7528\uFF1B\u7ED3\u679C\u63D0\u793A\u300C\u4E0D\u652F\u6301\u300D\u65F6\u6539\u7528\u7EAF\u6587\u672C\u63D0\u95EE\u3002"
8525
8765
  ].join("\n"),
8526
8766
  parameters: {
8527
8767
  type: "object",
@@ -8964,30 +9204,30 @@ ${body.trim()}
8964
9204
  type: "function",
8965
9205
  function: {
8966
9206
  name: "memory_save",
8967
- description: "\u4FDD\u5B58\u4E00\u6761\u6301\u4E45\u8BB0\u5FC6\uFF08\u8DE8\u4F1A\u8BDD\u4FDD\u7559\uFF09\u3002\u7528\u4E8E\u8BB0\u5F55\u975E\u663E\u7136\u7684\u4E8B\u5B9E\u3001\u7528\u6237\u504F\u597D\u3001\u5DE5\u4F5C\u65B9\u5F0F\u53CD\u9988\u3001\u9879\u76EE\u7EA6\u675F\u6216\u5916\u90E8\u8D44\u6E90\u6307\u9488\u2014\u2014\u5373\u90A3\u4E9B\u300C\u4E0D\u5E94\u6BCF\u6B21\u91CD\u65B0\u53D1\u73B0\u300D\u300C\u4EE3\u7801/git \u4E0D\u4F1A\u76F4\u63A5\u544A\u8BC9\u4F60\u300D\u7684\u4FE1\u606F\u3002\u52FF\u4FDD\u5B58\u4F1A\u8BDD\u5185\u5373\u629B\u7684\u4E34\u65F6\u4FE1\u606F\u3002\u4FDD\u5B58\u540E\u7CFB\u7EDF\u63D0\u793A\u8BCD\u7684\u8BB0\u5FC6\u7D22\u5F15\u4F1A\u81EA\u52A8\u66F4\u65B0\u3002\u540C\u540D\u8BB0\u5FC6\u4F1A\u88AB\u8986\u76D6\u3002",
9207
+ description: "\u4FDD\u5B58\u4E00\u6761\u6301\u4E45\u8BB0\u5FC6\uFF08\u8DE8\u4F1A\u8BDD\u4FDD\u7559\uFF09\uFF1A\u975E\u663E\u7136\u7684\u4E8B\u5B9E\u3001\u7528\u6237\u504F\u597D\u3001\u5DE5\u4F5C\u65B9\u5F0F\u53CD\u9988\u3001\u9879\u76EE\u7EA6\u675F\u3001\u5916\u90E8\u8D44\u6E90\u6307\u9488\u2014\u2014\u300C\u4E0D\u5E94\u6BCF\u6B21\u91CD\u65B0\u53D1\u73B0\u300D\u300C\u4EE3\u7801/git \u4E0D\u4F1A\u76F4\u63A5\u544A\u8BC9\u4F60\u300D\u7684\u4FE1\u606F\u3002\u52FF\u5B58\u4F1A\u8BDD\u5185\u5373\u629B\u7684\u4E34\u65F6\u4FE1\u606F\u3002\u4FDD\u5B58\u540E\u8BB0\u5FC6\u7D22\u5F15\u81EA\u52A8\u66F4\u65B0\uFF1B\u540C\u540D\u8BB0\u5FC6\u88AB\u8986\u76D6\u3002",
8968
9208
  parameters: {
8969
9209
  type: "object",
8970
9210
  properties: {
8971
9211
  name: {
8972
9212
  type: "string",
8973
- description: "\u8BB0\u5FC6\u552F\u4E00\u952E\uFF0C\u4EC5\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF08\u5982 user-prefers-arrow-fns\uFF09\u3002\u5EFA\u8BAE\u5177\u63CF\u8FF0\u6027\u7684 kebab-case\u3002"
9213
+ description: "\u552F\u4E00\u952E\uFF0C\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF08\u63CF\u8FF0\u6027 kebab-case\uFF0C\u5982 user-prefers-arrow-fns\uFF09"
8974
9214
  },
8975
9215
  description: {
8976
9216
  type: "string",
8977
- description: "\u4E00\u53E5\u8BDD\u6982\u62EC\u672C\u6761\u8BB0\u5FC6\u5185\u5BB9\uFF08\u6CE8\u5165\u8BB0\u5FC6\u7D22\u5F15\u65F6\u5C55\u793A\uFF0C\u4F9B\u65E5\u540E\u5224\u65AD\u662F\u5426\u9700\u8981\u53EC\u56DE\uFF09\u3002\u52FF\u6362\u884C\u3002"
9217
+ description: "\u4E00\u53E5\u8BDD\u6982\u62EC\uFF08\u6CE8\u5165\u7D22\u5F15\u4F9B\u65E5\u540E\u5224\u65AD\u662F\u5426\u53EC\u56DE\uFF09\u3002\u52FF\u6362\u884C"
8978
9218
  },
8979
9219
  body: {
8980
9220
  type: "string",
8981
- description: "\u8BB0\u5FC6\u6B63\u6587\uFF08\u4E8B\u5B9E\u672C\u8EAB\uFF09\u3002\u53EF\u591A\u884C\u3002\u4E0A\u9650 64KB\u3002"
9221
+ description: "\u8BB0\u5FC6\u6B63\u6587\uFF0C\u53EF\u591A\u884C\uFF0C\u4E0A\u9650 64KB"
8982
9222
  },
8983
9223
  type: {
8984
9224
  type: "string",
8985
9225
  enum: ["user", "feedback", "project", "reference"],
8986
- description: "user=\u7528\u6237\u753B\u50CF/\u504F\u597D\uFF1Bfeedback=\u5DE5\u4F5C\u65B9\u5F0F\u53CD\u9988\uFF08\u542B\u539F\u56E0\u4E0E\u505A\u6CD5\uFF09\uFF1Bproject=\u9879\u76EE\u76EE\u6807/\u7EA6\u675F\uFF1Breference=\u5916\u90E8\u8D44\u6E90\u6307\u9488\uFF08URL/dashboard/ticket\uFF09\u3002\u9ED8\u8BA4 reference\u3002"
9226
+ description: "user=\u7528\u6237\u753B\u50CF/\u504F\u597D\uFF1Bfeedback=\u5DE5\u4F5C\u65B9\u5F0F\u53CD\u9988\uFF08\u542B\u539F\u56E0\u4E0E\u505A\u6CD5\uFF09\uFF1Bproject=\u9879\u76EE\u76EE\u6807/\u7EA6\u675F\uFF1Breference=\u5916\u90E8\u8D44\u6E90\u6307\u9488\u3002\u9ED8\u8BA4 reference"
8987
9227
  },
8988
9228
  project: {
8989
9229
  type: "boolean",
8990
- description: "\u662F\u5426\u5199\u5165\u9879\u76EE\u8BB0\u5FC6\u76EE\u5F55\uFF08<\u9879\u76EE>/.deepseeker-code/memory\uFF0C\u53EF\u63D0\u4EA4 git \u56E2\u961F\u5171\u4EAB\uFF09\u3002\u9ED8\u8BA4 false\uFF08\u5199\u5168\u5C40 ~/.deepseeker-code/memory\uFF0C\u4EC5\u672C\u673A\uFF09\u3002"
9230
+ description: "true=\u5199\u5165\u9879\u76EE .deepseeker-code/memory\uFF08\u53EF\u63D0\u4EA4 git \u5171\u4EAB\uFF09\uFF1B\u9ED8\u8BA4 false\uFF08\u5168\u5C40\uFF0C\u4EC5\u672C\u673A\uFF09"
8991
9231
  }
8992
9232
  },
8993
9233
  required: ["name", "description", "body"]
@@ -9140,7 +9380,7 @@ var init_recall = __esm({
9140
9380
  type: "function",
9141
9381
  function: {
9142
9382
  name: "recall",
9143
- description: "\u68C0\u7D22\u3010\u672C\u4F1A\u8BDD\u3011\u5168\u91CF\u5386\u53F2\u8F6C\u5F55\uFF08transcript\uFF09\uFF0C\u5305\u62EC\u5DF2\u88AB\u4E0A\u4E0B\u6587\u538B\u7F29\u5F52\u6863\u7684\u539F\u59CB\u6D88\u606F\u4E0E\u5DE5\u5177\u7ED3\u679C\u3002\u4F7F\u7528\u65F6\u673A\uFF1A\u6EDA\u52A8\u6458\u8981\uFF08\u27E6DSC:ARCHIVE-INDEX\u27E7/\u27E6DSC:ARCHIVE-NOTES\u27E7\uFF09\u4E0D\u8DB3\u4EE5\u56DE\u7B54\u7EC6\u8282\u65F6\u2014\u2014\u5982\u5F52\u6863\u524D\u7684\u6587\u4EF6\u5185\u5BB9\u3001\u62A5\u9519\u539F\u6587\u3001\u7528\u6237\u65E9\u524D\u7684\u8981\u6C42\u2014\u2014\u5148\u7528\u672C\u5DE5\u5177\u68C0\u7D22\uFF0C\u4E0D\u8981\u51ED\u6458\u8981\u81C6\u6D4B\uFF0C\u4E5F\u4E0D\u8981\u91CD\u8DD1\u5DE5\u5177\u3002\u2605 \u9996\u67E5\u7B56\u7565\uFF1Aquery \u5FC5\u987B\u7528\u5177\u4F53\u5B9E\u4F53\u8BCD\u2014\u2014\u62A5\u9519\u5173\u952E\u8BCD\uFF08\u5982 TypeError\uFF09\u3001\u6587\u4EF6\u8DEF\u5F84\u3001\u51FD\u6570/\u7B26\u53F7\u540D\uFF08\u6458\u8981\u5B9E\u4F53\u7D22\u5F15\u91CC\u51FA\u73B0\u8FC7\u4EC0\u4E48\u5C31\u7528\u4EC0\u4E48\uFF09\uFF1B\u4E0D\u8981\u7528\u5DE5\u5177\u540D\uFF08read_file \u7B49\uFF09\u6216\u6CDB\u8BCD\uFF08\u4EE3\u7801/\u6587\u4EF6/\u95EE\u9898\uFF09\u4F5C query\uFF0C\u4F1A\u547D\u4E2D\u5927\u91CF\u65E0\u5173\u5DE5\u5177\u884C\u3002\u4E00\u6B21\u6CA1\u4E2D\u5C31\u6362\u66F4\u5177\u4F53\u7684\u8BCD\u6216\u7528 is_regex \u4EE5 | \u5408\u5E76\u591A\u4E2A\u5019\u9009\u8BCD\uFF0C\u901A\u5E38 1-2 \u6B21\u5185\u547D\u4E2D\u3002\u8FD4\u56DE\u6309\u65F6\u95F4\u65E7\u2192\u65B0\uFF08\u4F18\u5148\u5F52\u6863\u533A\uFF09\uFF1B\u6587\u4EF6\u7C7B\u5DE5\u5177\u7ED3\u679C\u9644\u5B9E\u65F6\u6821\u9A8C\uFF1A\u26A0\uFE0F \u5DF2\u4FEE\u6539/\u5DF2\u4E0D\u5B58\u5728 \u7684\u5FC5\u987B\u91CD\u65B0 read_file \u9A8C\u8BC1\u540E\u624D\u80FD\u636E\u4EE5\u4FEE\u6539\uFF0C\u2713 \u672A\u53D8 \u65B9\u53EF\u76F4\u63A5\u5F15\u7528\u3002\u7ED3\u679C\u66FE\u88AB\u622A\u65AD\u7684\u4F1A\u6807\u6CE8 with_full \u53EF\u53D6\u5B58\u6863\u5168\u6587\u3002\u6458\u8981\u5DF2\u591F\u7528\u65F6\u52FF\u8C03\u7528\uFF08\u7701 token\uFF09\u3002",
9383
+ description: "\u68C0\u7D22\u3010\u672C\u4F1A\u8BDD\u3011\u5168\u91CF\u5386\u53F2\uFF08\u542B\u5DF2\u88AB\u538B\u7F29\u5F52\u6863\u7684\u539F\u59CB\u6D88\u606F\u4E0E\u5DE5\u5177\u7ED3\u679C\uFF09\u3002\u65F6\u673A\uFF1A\u6EDA\u52A8\u6458\u8981\u4E0D\u8DB3\u4EE5\u56DE\u7B54\u7EC6\u8282\u65F6\uFF08\u5F52\u6863\u524D\u7684\u6587\u4EF6\u5185\u5BB9/\u62A5\u9519\u539F\u6587/\u7528\u6237\u65E9\u524D\u8981\u6C42\uFF09\u2014\u2014\u5148\u68C0\u7D22\uFF0C\u4E0D\u8981\u51ED\u6458\u8981\u81C6\u6D4B\uFF0C\u4E5F\u4E0D\u8981\u91CD\u8DD1\u5DE5\u5177\u3002query \u7528\u5177\u4F53\u5B9E\u4F53\u8BCD\uFF1A\u62A5\u9519\u5173\u952E\u8BCD\u3001\u6587\u4EF6\u8DEF\u5F84\u3001\u51FD\u6570/\u7B26\u53F7\u540D\uFF08\u4F18\u5148\u53D6\u6458\u8981\u5B9E\u4F53\u7D22\u5F15 \u27E6DSC:ARCHIVE-INDEX\u27E7 \u91CC\u51FA\u73B0\u8FC7\u7684\uFF09\uFF1B\u5FCC\u7528\u5DE5\u5177\u540D\u6216\u6CDB\u8BCD\uFF08\u4EE3\u7801/\u6587\u4EF6/\u95EE\u9898\uFF09\u3002\u672A\u547D\u4E2D\u5C31\u6362\u66F4\u5177\u4F53\u7684\u8BCD\uFF0C\u6216 is_regex=true \u7528 | \u5408\u5E76\u591A\u5019\u9009\u8BCD\uFF0C\u901A\u5E38 1-2 \u6B21\u5185\u547D\u4E2D\u3002\u8FD4\u56DE\u6309\u65F6\u95F4\u65E7\u2192\u65B0\uFF1B\u6587\u4EF6\u7C7B\u7ED3\u679C\u9644\u5B9E\u65F6\u6821\u9A8C\uFF1A\u26A0\uFE0F \u5DF2\u4FEE\u6539/\u5DF2\u4E0D\u5B58\u5728\u5FC5\u987B\u91CD\u65B0 read_file \u540E\u624D\u80FD\u636E\u4EE5\u4FEE\u6539\uFF0C\u2713 \u672A\u53D8\u53EF\u76F4\u63A5\u5F15\u7528\u3002\u66FE\u88AB\u622A\u65AD\u7684\u7ED3\u679C\u4F1A\u6807\u6CE8 with_full \u53D6\u5B58\u6863\u5168\u6587\u3002\u6458\u8981\u5DF2\u591F\u65F6\u52FF\u8C03\u7528\uFF08\u7701 token\uFF09\u3002",
9144
9384
  parameters: {
9145
9385
  type: "object",
9146
9386
  properties: {
@@ -9620,7 +9860,8 @@ async function runBackgroundTool(gen, lockKey, toolName, signal) {
9620
9860
  if (lockKey && !acquireLock(lockKey)) {
9621
9861
  try {
9622
9862
  await gen.return(void 0);
9623
- } catch {
9863
+ } catch (e) {
9864
+ console.warn("\u26A0\uFE0F \u5173\u95ED\u672A\u6D88\u8D39\u7684\u540E\u53F0 generator \u5931\u8D25:", e instanceof Error ? e.message : e);
9624
9865
  }
9625
9866
  return `\u{1F512} [\u4E92\u65A5\u9501\u963B\u585E]\uFF1A\u9501 [${lockKey}] \u5DF2\u88AB\u5360\u7528\uFF0C[${toolName}] \u672A\u542F\u52A8\u3002`;
9626
9867
  }
@@ -9671,7 +9912,7 @@ var init_backgroundTool = __esm({
9671
9912
 
9672
9913
  // ../core/src/tool/autoPermission.ts
9673
9914
  import path30 from "path";
9674
- var AUTO_SCOPE, AUTO_DEFAULT_EXTRA, AUTO_AGGRESSIVE_EXTRA, isMcpTool, BUILTIN_AUTO_DENY, matchBuiltinDeny, COMMAND_DENY, matchCommandDeny, hasShellMetachars, READONLY_HEADS, hasWriteModifier, SENSITIVE_FILE_ARG_RE, hasSensitiveFileArg, isReadOnlyCommand, isWithinWorkspace, runAutoCheck;
9915
+ var AUTO_SCOPE, AUTO_DEFAULT_EXTRA, AUTO_AGGRESSIVE_EXTRA, isMcpTool, BUILTIN_AUTO_DENY, matchBuiltinDeny, COMMAND_DENY, matchCommandDeny, hasShellMetachars, READONLY_HEADS, PKG_MGR, SCRIPT_RUNNER_HEADS, SCRIPT_RUNNER_READONLY, isScriptRunnerCommand, hasWriteModifier, SENSITIVE_FILE_ARG_RE, hasSensitiveFileArg, isReadOnlyCommand, isWithinWorkspace, runAutoCheck;
9675
9916
  var init_autoPermission = __esm({
9676
9917
  "../core/src/tool/autoPermission.ts"() {
9677
9918
  "use strict";
@@ -9778,12 +10019,25 @@ var init_autoPermission = __esm({
9778
10019
  // —— 版本号 ——
9779
10020
  /^(node|npm|pnpm|npx|git|tsc|python|python3)\s+(-v|-V|--version)\b/,
9780
10021
  // —— 验证类(跑项目代码但不改源码)——
9781
- /^npm test\b/,
9782
- /^npm run (test|lint|typecheck|type-check)\b/,
9783
- /^pnpm (test|lint|typecheck)\b/,
9784
- /^npx (vitest|jest|eslint|tsc)\b/,
10022
+ // ★ npm/pnpm/npx/yarn 系「跑脚本」命令已整类移出免审清单(isScriptRunnerCommand 单独治理,见下方):
10023
+ // package.json scripts 是仓库作者的任意代码、npx 未装包时还会从 registry 拉取执行——
10024
+ // hasShellMetachars 检查的是命令串本身,拦不到脚本内容(恶意 repo 投毒面)。
10025
+ // 改走「首次人工确认 + allow-always 按精确命令串记住」路径(toolExecution 的 scriptRunnerBlocked 门)。
9785
10026
  /^tsc --noEmit\b/
9786
10027
  ];
10028
+ PKG_MGR = String.raw`\s*([^\s"'\`]*[\\/])?(npx|npm|pnpm|yarn|corepack)(\.cmd|\.exe|\.ps1|\.bat)?\b`;
10029
+ SCRIPT_RUNNER_HEADS = [
10030
+ new RegExp(`^${PKG_MGR}`, "i")
10031
+ ];
10032
+ SCRIPT_RUNNER_READONLY = [
10033
+ new RegExp(`^${PKG_MGR}\\s+(-v|-V|--version)\\b`, "i")
10034
+ ];
10035
+ isScriptRunnerCommand = (cmd) => {
10036
+ const c = (cmd || "").trim();
10037
+ if (!c || hasShellMetachars(c)) return false;
10038
+ if (SCRIPT_RUNNER_READONLY.some((re) => re.test(c))) return false;
10039
+ return SCRIPT_RUNNER_HEADS.some((re) => re.test(c));
10040
+ };
9787
10041
  hasWriteModifier = (cmd) => {
9788
10042
  if (!cmd) return false;
9789
10043
  if (/^sed\b/.test(cmd) && /(^|\s)-i\b/.test(cmd)) return true;
@@ -9940,7 +10194,7 @@ var init_toolExecution = __esm({
9940
10194
  preHooksAdvanced = true;
9941
10195
  let veto;
9942
10196
  try {
9943
- veto = await runPreHooks(calledName, calledArgs, toolCtx);
10197
+ veto = await runPreHooks(resolveMcpPermissionName(calledName, calledArgs), calledArgs, toolCtx);
9944
10198
  } catch (e) {
9945
10199
  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` };
9946
10200
  }
@@ -9972,7 +10226,20 @@ var init_toolExecution = __esm({
9972
10226
  } catch {
9973
10227
  perm = null;
9974
10228
  }
9975
- if (perm === null && needApproval && !denied && calledName === "run_command" && isReadOnlyCommand(typeof calledArgs?.command === "string" ? calledArgs.command : "")) {
10229
+ const cmdIsScriptRunner = (calledName === "run_command" || calledName === "run_in_background") && isScriptRunnerCommand(typeof calledArgs?.command === "string" ? calledArgs.command : "");
10230
+ const argCwd = typeof calledArgs?.cwd === "string" ? calledArgs.cwd.trim() : "";
10231
+ const samePath = (a, b) => {
10232
+ try {
10233
+ const ra = path31.resolve(a), rb = path31.resolve(b);
10234
+ return process.platform === "win32" ? ra.toLowerCase() === rb.toLowerCase() : ra === rb;
10235
+ } catch {
10236
+ return false;
10237
+ }
10238
+ };
10239
+ const scriptRunnerCwdDrift = cmdIsScriptRunner && argCwd !== "" && !samePath(argCwd, toolCtx.cwd);
10240
+ const scriptRunnerBlocked = cmdIsScriptRunner && (perm === null || scriptRunnerCwdDrift);
10241
+ if (scriptRunnerCwdDrift) needApproval = true;
10242
+ if (perm === null && needApproval && !denied && !scriptRunnerBlocked && calledName === "run_command" && isReadOnlyCommand(typeof calledArgs?.command === "string" ? calledArgs.command : "")) {
9976
10243
  needApproval = false;
9977
10244
  }
9978
10245
  if ((calledName === "run_command" || calledName === "run_in_background") && matchCommandDeny(typeof calledArgs?.command === "string" ? calledArgs.command : "")) {
@@ -9985,7 +10252,7 @@ var init_toolExecution = __esm({
9985
10252
  denied = true;
9986
10253
  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`;
9987
10254
  }
9988
- if (needApproval && !denied) {
10255
+ if (needApproval && !denied && !scriptRunnerBlocked) {
9989
10256
  const auto = await runAutoCheck(resolveMcpPermissionName(calledName, calledArgs), calledArgs, toolCtx, permissionMode === "auto");
9990
10257
  if (auto === "allow") {
9991
10258
  needApproval = false;
@@ -10020,7 +10287,7 @@ var init_toolExecution = __esm({
10020
10287
  if (!denied && !preHooksAdvanced) {
10021
10288
  let veto;
10022
10289
  try {
10023
- veto = await runPreHooks(calledName, calledArgs, toolCtx);
10290
+ veto = await runPreHooks(resolveMcpPermissionName(calledName, calledArgs), calledArgs, toolCtx);
10024
10291
  } catch (e) {
10025
10292
  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` };
10026
10293
  }
@@ -10062,7 +10329,7 @@ ${result}`;
10062
10329
  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 } });
10063
10330
  }
10064
10331
  try {
10065
- const post = await runPostHooks(calledName, calledArgs, result, toolCtx);
10332
+ const post = await runPostHooks(resolveMcpPermissionName(calledName, calledArgs), calledArgs, result, toolCtx);
10066
10333
  postHookOverride = post?.resultOverride;
10067
10334
  } catch (e) {
10068
10335
  console.warn(`\u26A0\uFE0F post-hook [${calledName}] \u5F02\u5E38\uFF08\u5DF2\u5FFD\u7565\uFF09:`, e?.message ?? e);
@@ -10222,7 +10489,8 @@ var init_toolScheduling = __esm({
10222
10489
  });
10223
10490
 
10224
10491
  // ../core/src/agent/streamInference.ts
10225
- var streamInference;
10492
+ import { createHash as createHash2 } from "node:crypto";
10493
+ var sha1short, RETRY_BACKOFF_CAP_MS, extractRetryAfterMs, withNudgeTail, streamInference;
10226
10494
  var init_streamInference = __esm({
10227
10495
  "../core/src/agent/streamInference.ts"() {
10228
10496
  "use strict";
@@ -10231,6 +10499,32 @@ var init_streamInference = __esm({
10231
10499
  init_transcript();
10232
10500
  init_contextCore();
10233
10501
  init_contentParts();
10502
+ sha1short = (s) => createHash2("sha1").update(s).digest("hex").slice(0, 10);
10503
+ RETRY_BACKOFF_CAP_MS = 3e4;
10504
+ extractRetryAfterMs = (e) => {
10505
+ try {
10506
+ const h = e?.headers;
10507
+ if (!h) return null;
10508
+ const get = (k) => typeof h.get === "function" ? h.get(k) ?? void 0 : h[k] ?? h[k.toLowerCase()];
10509
+ const ms = get("retry-after-ms");
10510
+ if (ms != null) {
10511
+ const n = Number(ms);
10512
+ if (Number.isFinite(n) && n >= 0) return n;
10513
+ }
10514
+ const sec = get("retry-after");
10515
+ if (sec != null) {
10516
+ const n = Number(sec);
10517
+ if (Number.isFinite(n) && n >= 0) return n * 1e3;
10518
+ }
10519
+ } catch {
10520
+ }
10521
+ return null;
10522
+ };
10523
+ withNudgeTail = (base, nudge) => {
10524
+ if (!nudge) return base;
10525
+ const lastRole = base[base.length - 1]?.role;
10526
+ return [...base, lastRole === "assistant" ? { ...nudge, role: "user" } : nudge];
10527
+ };
10234
10528
  streamInference = async function* (ctx) {
10235
10529
  const {
10236
10530
  message,
@@ -10248,16 +10542,24 @@ var init_streamInference = __esm({
10248
10542
  events,
10249
10543
  keepRecentUnits,
10250
10544
  compactRatio,
10251
- modelWindow
10545
+ modelWindow,
10546
+ toolsTokens = 0
10252
10547
  } = ctx;
10253
- let inferenceMessages = nudgeMsg ? [...message, nudgeMsg] : message;
10548
+ let inferenceMessages = withNudgeTail(message, nudgeMsg);
10254
10549
  let assistantMessage = { role: "assistant", content: null };
10255
10550
  try {
10551
+ const prefixFingerprint = {
10552
+ toolsHash: sha1short(JSON.stringify(cleanedToolSchemas)),
10553
+ sysHash: sha1short(String(message[0]?.content ?? "")),
10554
+ sumHash: sha1short(String(message[1]?.content ?? "")),
10555
+ msgCount: message.length
10556
+ };
10256
10557
  events({
10257
10558
  sessionId,
10258
10559
  eventType: "llm.request",
10259
- metadata: { depth, decisionSource: userDecisionSource, ok: true, durationMs: performance.now() - startTime, round },
10260
- usage: { prompt_tokens: estimateTokens(inferenceMessages) },
10560
+ metadata: { depth, decisionSource: userDecisionSource, ok: true, durationMs: performance.now() - startTime, round, ...prefixFingerprint },
10561
+ // ★ P2 口径:估算加上工具 schema 常数项(与 API 真实 prompt_tokens 同口径,trace 里 est/real 才可比)
10562
+ usage: { prompt_tokens: estimateTokens(inferenceMessages) + toolsTokens },
10261
10563
  payload: { input: msgText(message[message.length - 1].content) }
10262
10564
  // ★ 多模态:trace 只记文本视图
10263
10565
  });
@@ -10267,7 +10569,7 @@ var init_streamInference = __esm({
10267
10569
  const toolCallsBuf = /* @__PURE__ */ new Map();
10268
10570
  let lastUsage;
10269
10571
  const MAX_STREAM_RETRIES = 2;
10270
- const MAX_API_RETRIES = 2;
10572
+ const MAX_API_RETRIES = 3;
10271
10573
  let apiRetries = 0;
10272
10574
  let compactedThisRound = false;
10273
10575
  for (let streamAttempt = 0; ; streamAttempt++) {
@@ -10327,10 +10629,15 @@ var init_streamInference = __esm({
10327
10629
  }
10328
10630
  if (activeProvider.isTransientError(streamErr) && apiRetries < MAX_API_RETRIES && !signal?.aborted) {
10329
10631
  apiRetries++;
10330
- const backoffMs = 1e3 * Math.pow(2, apiRetries - 1);
10632
+ const retryAfterMs = extractRetryAfterMs(streamErr);
10633
+ const backoffMs = Math.min(
10634
+ Math.max(1e3 * Math.pow(2, apiRetries - 1), retryAfterMs ?? 0),
10635
+ RETRY_BACKOFF_CAP_MS
10636
+ );
10331
10637
  if (!noOutputYet) yield { type: "text.reset" };
10332
10638
  const statusHint = streamErr?.status ? `${streamErr.status} ` : "";
10333
- console.warn(`\u26A0\uFE0F API \u77AC\u65F6\u9519\u8BEF\uFF08${statusHint}${streamErr instanceof Error ? streamErr.message : String(streamErr)}\uFF09\uFF0C${backoffMs}ms \u540E\u7B2C ${apiRetries}/${MAX_API_RETRIES} \u6B21\u91CD\u8BD5...`);
10639
+ const raHint = retryAfterMs != null ? `\uFF0C\u9075 Retry-After=${retryAfterMs}ms` : "";
10640
+ console.warn(`\u26A0\uFE0F API \u77AC\u65F6\u9519\u8BEF\uFF08${statusHint}${streamErr instanceof Error ? streamErr.message : String(streamErr)}\uFF09\uFF0C${backoffMs}ms \u540E\u7B2C ${apiRetries}/${MAX_API_RETRIES} \u6B21\u91CD\u8BD5${raHint}...`);
10334
10641
  await new Promise((resolve, reject) => {
10335
10642
  const t = setTimeout(resolve, backoffMs);
10336
10643
  signal?.addEventListener("abort", () => {
@@ -10354,9 +10661,10 @@ var init_streamInference = __esm({
10354
10661
  modelWindow,
10355
10662
  events,
10356
10663
  depth,
10357
- signal
10664
+ signal,
10665
+ toolsTokens
10358
10666
  });
10359
- inferenceMessages = nudgeMsg ? [...message, nudgeMsg] : message;
10667
+ inferenceMessages = withNudgeTail(message, nudgeMsg);
10360
10668
  compactedThisRound = true;
10361
10669
  contentBuf = "";
10362
10670
  reasoningBuf = "";
@@ -10437,12 +10745,12 @@ var init_agentNudges = __esm({
10437
10745
  GREP_REPEAT_THRESHOLD = 2;
10438
10746
  REPEAT_NUDGE_MAX = 3;
10439
10747
  PHANTOM_TEXT = "\u4F60\u7684\u4E0A\u4E00\u6761\u56DE\u590D\u6CA1\u6709\u4EFB\u4F55\u5185\u5BB9\u3001\u4E5F\u6CA1\u6709\u8C03\u7528\u4EFB\u4F55\u5DE5\u5177\uFF0C\u4F46\u4EFB\u52A1\u5C1A\u672A\u5B8C\u6210\u3002\u8BF7\u7EE7\u7EED\u63A8\u8FDB\uFF08\u8C03\u7528\u5DE5\u5177\u6216\u7ED9\u51FA\u5B9E\u8D28\u56DE\u7B54\uFF09\uFF1B\u82E5\u786E\u5B9E\u53D7\u963B\u3001\u9700\u8981\u7528\u6237\u51B3\u7B56\uFF0C\u7528 ask_question \u8BF4\u660E\u5177\u4F53\u963B\u585E\u70B9\u3002\u4E0D\u8981\u8FD4\u56DE\u7A7A\u56DE\u590D\u3002";
10440
- EARLY_FINAL_TEXT = (round) => `\u4F60\u4EC5\u8FDB\u884C\u4E86 ${round} \u8F6E\u5DE5\u5177\u8C03\u7528\u5C31\u51C6\u5907\u6536\u5C3E\uFF0C\u4E14\u56DE\u7B54\u4E2D\u6CA1\u6709\u660E\u786E\u7684\u5B8C\u6210\u58F0\u660E\u3002\u8BF7\u4E25\u683C\u81EA\u68C0\uFF1A\u7528\u6237\u7684\u6BCF\u4E00\u4E2A\u5B50\u76EE\u6807\u662F\u5426\u90FD\u5DF2\u771F\u6B63\u843D\u5730\uFF08\u6240\u9700\u4FE1\u606F\u5DF2\u83B7\u53D6 / \u8BE5\u6539\u7684\u6587\u4EF6\u5DF2\u6539\u5B8C / \u5DF2\u9A8C\u8BC1\u901A\u8FC7\uFF09\uFF1F\u82E5\u786E\u5B9E\u5168\u90E8\u5B8C\u6210\uFF0C\u8BF7\u660E\u786E\u56DE\u590D"\u5DF2\u5B8C\u6210"\u5E76\u7B80\u8FF0\u6210\u679C\uFF1B\u82E5\u8FD8\u6709\u4EFB\u4F55\u672A\u843D\u5730\u7684\u5B50\u76EE\u6807\uFF0C\u7ACB\u5373\u7EE7\u7EED\u8C03\u7528\u5DE5\u5177\u63A8\u8FDB\uFF0C\u4E0D\u8981\u7528\u81EA\u7136\u8BED\u8A00\u8349\u7387\u603B\u7ED3\u6536\u5C3E\u3002`;
10748
+ EARLY_FINAL_TEXT = (round) => `\u4F60\u4EC5 ${round} \u8F6E\u5C31\u51C6\u5907\u6536\u5C3E\uFF0C\u4E14\u56DE\u7B54\u4E2D\u6CA1\u6709\u660E\u786E\u7684\u5B8C\u6210\u58F0\u660E\u3002\u8BF7\u81EA\u68C0\uFF1A\u82E5\u7528\u6237\u8F93\u5165\u672C\u5C31\u65E0\u9700\u5DE5\u5177\uFF08\u5BD2\u6684/\u95F2\u804A/\u7EAF\u95EE\u7B54\uFF09\u3001\u6216\u4F60\u5728\u7B49\u7528\u6237\u6F84\u6E05\u51B3\u7B56\uFF0C\u76F4\u63A5\u6B63\u5E38\u56DE\u5E94\u5373\u53EF\uFF0C\u5FFD\u7565\u672C\u81EA\u68C0\u3001\u4E0D\u8981\u8F93\u51FA\u4EFB\u4F55\u81EA\u68C0\u8BF4\u660E\uFF1B\u82E5\u786E\u6709\u4EFB\u52A1\u672A\u843D\u5730\uFF08\u6240\u9700\u4FE1\u606F\u672A\u83B7\u53D6\u9F50 / \u8BE5\u6539\u7684\u6587\u4EF6\u672A\u6539\u5B8C / \u672A\u9A8C\u8BC1\uFF09\uFF0C\u7ACB\u5373\u7EE7\u7EED\u8C03\u7528\u5DE5\u5177\u63A8\u8FDB\uFF0C\u4E0D\u8981\u8349\u7387\u603B\u7ED3\u6536\u5C3E\uFF1B\u82E5\u786E\u5DF2\u5168\u90E8\u5B8C\u6210\uFF0C\u8BF7\u660E\u786E\u56DE\u590D\u300C\u5DF2\u5B8C\u6210\u300D\u5E76\u7B80\u8FF0\u6210\u679C\u3002`;
10441
10749
  TOOL_DIGEST_TEXT = "\u4F60\u521A\u6267\u884C\u5B8C\u5DE5\u5177\u62FF\u5230\u7ED3\u679C\uFF0C\u5374\u672A\u57FA\u4E8E\u8BE5\u7ED3\u679C\u7ED9\u51FA\u5B9E\u8D28\u56DE\u5E94\u5C31\u51C6\u5907\u6536\u5C3E\u3002\u8BF7\u7ED3\u5408\u5DE5\u5177\u8FD4\u56DE\u7ED3\u679C\u7EE7\u7EED\u63A8\u8FDB\uFF1B\u82E5\u7ED3\u679C\u8868\u660E\u4EFB\u52A1\u5C1A\u672A\u5B8C\u6210\uFF08\u5982\u4ECD\u5728\u7F16\u8BD1/\u8FD0\u884C\u3001\u9700\u7EE7\u7EED\u8F6E\u8BE2\uFF09\uFF0C\u7ACB\u5373\u91C7\u53D6\u4E0B\u4E00\u6B65\u884C\u52A8\uFF0C\u4E0D\u8981\u7A7A\u624B\u6536\u5C3E\u3002\u82E5\u786E\u5DF2\u5168\u90E8\u5B8C\u6210\uFF0C\u8BF7\u660E\u786E\u56DE\u590D\u300C\u5DF2\u5B8C\u6210\u300D\u5E76\u7B80\u8FF0\u6210\u679C\u3002";
10442
10750
  NUDGE_TEXT = (round) => `\u4F60\u5DF2\u6267\u884C\u7EA6 ${round} \u8F6E\u5DE5\u5177\u8C03\u7528\u3002\u8BF7\u81EA\u8BC4\uFF1A\u82E5\u4EFB\u52A1\u5DF2\u53EF\u5B8C\u6210\uFF0C\u7ACB\u5373\u7ED9\u51FA\u6700\u7EC8\u7B54\u6848\u3001\u4E0D\u518D\u8C03\u7528\u5DE5\u5177\uFF1B\u82E5\u786E\u9700\u66F4\u591A\u6B65\u9AA4\uFF0C\u7EE7\u7EED\uFF0C\u4F46\u786E\u4FDD\u6BCF\u6B65\u90FD\u5728\u5B9E\u8D28\u63A8\u8FDB\u4EFB\u52A1\u3001\u4E0D\u91CD\u590D\u68C0\u7D22\u3002`;
10443
- COMPLEX_VERBS = /实现|新增|添加|重构|改造|迁移|重写|拆分|升级|开发|编写|构建|集成|支持|完善/;
10444
- COMPLEX_OBJECTS = /功能|模块|系统|架构|流程|机制|组件|服务|页面|接口|能力|特性|面板/;
10445
- COMPLEX_MARKERS = /多个文件|多文件|整体|全套|端到端|从零|重新设计|一整套|跨[^,。\s]{1,6}/;
10751
+ COMPLEX_VERBS = /实现|新增|添加|重构|改造|迁移|重写|拆分|升级|开发|编写|构建|集成|支持|完善|implement|refactor|migrate|rewrite|rebuild|restructure|split|upgrade|integrate|develop/i;
10752
+ COMPLEX_OBJECTS = /功能|模块|系统|架构|流程|机制|组件|服务|页面|接口|能力|特性|面板|feature|module|system|architecture|pipeline|component|service|page|api\b|interface|panel|workflow|endpoint/i;
10753
+ COMPLEX_MARKERS = /多个文件|多文件|整体|全套|端到端|从零|重新设计|一整套|跨[^,。\s]{1,6}|multiple files|multi-file|end-to-end|from scratch|across\s+\S+/i;
10446
10754
  QUERY_LEAD = /^(请)?\s*(解释|说明|查(一下|询)?|搜索|搜一下|怎么看|如何(用|使用|配置|启动)|怎么用|为什么|是什么|帮我看看|分析一下|检查|review|对比|评价)/i;
10447
10755
  looksComplex = (text) => {
10448
10756
  const t = (text || "").trim();
@@ -10470,7 +10778,7 @@ var init_agentNudges = __esm({
10470
10778
  return s;
10471
10779
  };
10472
10780
  normQuery = (q) => String(q ?? "").trim().toLowerCase().replace(/\s+/g, " ");
10473
- REPEAT_READ_TEXT = (p, n) => `\u4F60\u5DF2\u7B2C ${n} \u6B21\u8BFB\u53D6\u300C${p}\u300D\u2014\u2014\u8BE5\u6587\u4EF6\u5185\u5BB9\u4F60\u65E9\u5DF2\u62E5\u6709\uFF0C\u65E0\u9700\u6574\u6587\u4EF6\u91CD\u8BFB\u3002\u5982\u9700\u67D0\u5904\u7EC6\u8282\u8BF7\u56DE\u770B\u4E4B\u524D\u7684\u5DE5\u5177\u7ED3\u679C\uFF1B\u82E5\u8BE5\u6587\u4EF6\u521A\u88AB\u6539\u52A8\u3001\u786E\u9700\u786E\u8BA4\uFF0C\u53EA\u8BFB\u6539\u52A8\u9644\u8FD1\u51E0\u884C\u5373\u53EF\uFF0C\u4E0D\u8981\u6574\u6587\u4EF6\u91CD\u8BFB\u3002`;
10781
+ REPEAT_READ_TEXT = (p, n) => `\u4F60\u5DF2\u7B2C ${n} \u6B21\u8BFB\u53D6\u300C${p}\u300D\u2014\u2014\u8BE5\u6587\u4EF6\u5185\u5BB9\u4F60\u65E9\u5DF2\u62E5\u6709\uFF0C\u65E0\u9700\u6574\u6587\u4EF6\u91CD\u8BFB\u3002\u5982\u9700\u67D0\u5904\u7EC6\u8282\u8BF7\u56DE\u770B\u4E4B\u524D\u7684\u5DE5\u5177\u7ED3\u679C\uFF08\u65E9\u524D\u8BFB\u53D6\u53EF\u80FD\u5DF2\u88AB\u5F52\u6863\uFF0C\u53EF\u7528 recall \u5DE5\u5177\u68C0\u7D22\u53D6\u56DE\u539F\u6587\uFF09\uFF1B\u82E5\u8BE5\u6587\u4EF6\u521A\u88AB\u6539\u52A8\u3001\u786E\u9700\u786E\u8BA4\uFF0C\u53EA\u8BFB\u6539\u52A8\u9644\u8FD1\u51E0\u884C\u5373\u53EF\uFF0C\u4E0D\u8981\u6574\u6587\u4EF6\u91CD\u8BFB\u3002`;
10474
10782
  REPEAT_GREP_TEXT = (q, n) => `\u4F60\u5DF2\u7B2C ${n} \u6B21\u68C0\u7D22\u300C${q}\u300D\u2014\u2014\u4E4B\u524D\u7684\u7ED3\u679C\u4F60\u5DF2\u62E5\u6709\u3002\u8BF7\u6539\u7528 read_file \u8BFB\u5B8C\u6574\u76EE\u6807\u6587\u4EF6\u7406\u89E3\u4E0A\u4E0B\u6587\uFF0C\u6216\u7F29\u5C0F/\u8C03\u6574\u68C0\u7D22\u8303\u56F4\uFF0C\u4E0D\u8981\u91CD\u590D\u540C\u4E00\u68C0\u7D22\u3002`;
10475
10783
  createNudgeScheduler = (opts = {}) => {
10476
10784
  const firstPrompt = opts.firstPrompt ?? "";
@@ -10538,7 +10846,7 @@ ${TOOL_DIGEST_TEXT}` };
10538
10846
  ${PHANTOM_TEXT}` };
10539
10847
  return true;
10540
10848
  }
10541
- if (!noEarlyFinal && text !== "" && round <= EARLY_FINAL_TURN_THRESHOLD && earlyFinalNudges < EARLY_FINAL_MAX && !looksComplete(finalText)) {
10849
+ if (!noEarlyFinal && (lastToolCallRound > 0 || looksComplex(firstPrompt)) && text !== "" && round <= EARLY_FINAL_TURN_THRESHOLD && earlyFinalNudges < EARLY_FINAL_MAX && !looksComplete(finalText)) {
10542
10850
  earlyFinalNudges++;
10543
10851
  earlyFinalPending = { role: "system", content: `${EARLY_FINAL_FENCE}
10544
10852
  ${EARLY_FINAL_TEXT(round)}` };
@@ -10598,10 +10906,11 @@ ${REPEAT_GREP_TEXT(q, n)}` };
10598
10906
  // ../core/src/agent/runAgent.ts
10599
10907
  async function* runAgent(message, options) {
10600
10908
  const sessionId = options.sessionId;
10909
+ const runId = createUUID();
10601
10910
  const rawEvents = options.events;
10602
10911
  const events = async (base) => {
10603
10912
  try {
10604
- await rawEvents(base);
10913
+ await rawEvents({ ...base, metadata: { ...base.metadata, runId } });
10605
10914
  } catch (e) {
10606
10915
  console.warn("\u26A0\uFE0F \u57CB\u70B9\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u63A8\u7406\uFF09:", e instanceof Error ? e.message : e);
10607
10916
  }
@@ -10613,7 +10922,7 @@ async function* runAgent(message, options) {
10613
10922
  const keepRecentUnits = options.keepRecentUnits;
10614
10923
  const compactRatio = options.compactRatio;
10615
10924
  const parentSystemPrompt = options.parentSystemPrompt;
10616
- const { rawTools, cleanedToolSchemas } = await prepareToolsAndInjections(message, options, events);
10925
+ const { rawTools, cleanedToolSchemas, toolsTokens } = await prepareToolsAndInjections(message, options, events);
10617
10926
  let round = 0;
10618
10927
  let lastContent = "";
10619
10928
  let stopReason = "normal";
@@ -10632,7 +10941,6 @@ async function* runAgent(message, options) {
10632
10941
  let lastRealPromptTokens = persistedCalib.lastRealPromptTokens;
10633
10942
  let lastCachedTokens = persistedCalib.lastCachedTokens;
10634
10943
  const breaker = createRepeatBreaker({ sessionId, depth, llmDecisionSource, startTime, events });
10635
- const runId = createUUID();
10636
10944
  let usageSum;
10637
10945
  const addUsage = (u) => {
10638
10946
  if (!u) return;
@@ -10693,7 +11001,8 @@ async function* runAgent(message, options) {
10693
11001
  signal,
10694
11002
  correctionRatio: calibRatio,
10695
11003
  lastRealPromptTokens,
10696
- lastCachedTokens
11004
+ lastCachedTokens,
11005
+ toolsTokens
10697
11006
  }
10698
11007
  );
10699
11008
  } catch (e) {
@@ -10725,7 +11034,8 @@ async function* runAgent(message, options) {
10725
11034
  events,
10726
11035
  keepRecentUnits,
10727
11036
  compactRatio,
10728
- modelWindow
11037
+ modelWindow,
11038
+ toolsTokens
10729
11039
  });
10730
11040
  if (infResult.kind === "aborted") {
10731
11041
  yield { type: "final", text: infResult.partialText || lastContent || "\uFF08\u5DF2\u4E2D\u6B62\uFF09" };
@@ -10737,7 +11047,7 @@ async function* runAgent(message, options) {
10737
11047
  return;
10738
11048
  }
10739
11049
  if (infResult.usage?.prompt_tokens) {
10740
- const estAtInfer = estimateTokens(message);
11050
+ const estAtInfer = estimateTokens(message) + toolsTokens;
10741
11051
  if (estAtInfer > 1e3) {
10742
11052
  const observed = infResult.usage.prompt_tokens / estAtInfer;
10743
11053
  calibRatio = calibRatio * 0.6 + observed * 0.4;
@@ -10827,11 +11137,13 @@ async function* runAgent(message, options) {
10827
11137
  try {
10828
11138
  const reason = signal?.aborted ? "aborted" : stopReason;
10829
11139
  await dispatch("Stop", { sessionId, cwd, lastText: lastContent || "", reason });
10830
- } catch {
11140
+ } catch (e) {
11141
+ console.warn("\u26A0\uFE0F Stop hook \u5916\u5C42\u515C\u5E95\uFF08dispatch \u5185\u90E8\u5BB9\u9519\u5931\u6548\uFF0C\u5C5E\u5F02\u5E38\u4FE1\u53F7\uFF09:", e instanceof Error ? e.message : e);
10831
11142
  }
10832
11143
  try {
10833
11144
  await updateCalibration(sessionId, { calibRatio, lastRealPromptTokens, lastCachedTokens });
10834
- } catch {
11145
+ } catch (e) {
11146
+ console.warn("\u26A0\uFE0F \u538B\u7F29\u6821\u51C6\u72B6\u6001\u843D\u76D8\u5931\u8D25\uFF08\u4E0B run \u6821\u51C6\u91CD\u96F6\uFF0C\u7F13\u5B58\u611F\u77E5\u538B\u7F29\u9000\u5316\u56DE\u7F3A\u7701 1.4\uFF09:", e instanceof Error ? e.message : e);
10835
11147
  }
10836
11148
  }
10837
11149
  }
@@ -10974,9 +11286,9 @@ var init_content = __esm({
10974
11286
  return replaceImageParts(mm, "[\u5386\u53F2\u56FE\u7247\u5DF2\u6298\u53E0\uFF1A\u539F\u56FE\u4ECD\u5728\u4F1A\u8BDD\u5F52\u6863\u4E2D\uFF0C\u5982\u9700\u518D\u6B21\u67E5\u770B\u8BF7\u91CD\u65B0\u63D0\u4F9B\u8BE5\u56FE\u7247]");
10975
11287
  });
10976
11288
  };
10977
- NO_VISION_IMAGE_NOTE = "[\u56FE\u7247\u672A\u9001\u8FBE\uFF1A\u5F53\u524D\u672A\u5F00\u542F\u89C6\u89C9\u80FD\u529B\uFF08DEEP_SEEK_VISION\uFF09\uFF0C\u6A21\u578B\u770B\u4E0D\u5230\u8BE5\u56FE\uFF1B\u539F\u56FE\u4FDD\u7559\u5728\u4F1A\u8BDD\u5F52\u6863\u4E2D\uFF0C\u5982\u9700\u5206\u6790\u8BF7\u8BA9\u7528\u6237\u91CD\u65B0\u63D0\u4F9B]";
10978
- enforceVisionGate = (msgs) => isVisionEnabled() ? msgs : msgs.map((m) => collapseToText(m, NO_VISION_IMAGE_NOTE));
10979
- buildContextMessages = async (sessionId, currentUserMsg, systemPrompt) => {
11289
+ NO_VISION_IMAGE_NOTE = "[\u56FE\u7247\u672A\u9001\u8FBE\uFF1A\u5F53\u524D\u6A21\u578B\u65E0\u89C6\u89C9\u80FD\u529B\uFF0C\u770B\u4E0D\u5230\u8BE5\u56FE\uFF1B\u539F\u56FE\u4FDD\u7559\u5728\u4F1A\u8BDD\u5F52\u6863\u4E2D\uFF0C\u5982\u9700\u5206\u6790\u8BF7\u8BA9\u7528\u6237\u91CD\u65B0\u63D0\u4F9B\u6216\u5207\u6362 vision \u6A21\u578B]";
11290
+ enforceVisionGate = (msgs, modelId) => isVisionEnabled(modelId) ? msgs : msgs.map((m) => collapseToText(m, NO_VISION_IMAGE_NOTE));
11291
+ buildContextMessages = async (sessionId, currentUserMsg, systemPrompt, modelId) => {
10980
11292
  const lines = await readTranscriptLines(sessionId);
10981
11293
  const store = await getRollingState(sessionId);
10982
11294
  const eventAware = appConfig.transcriptEvents || lines.some(isEventLine);
@@ -10995,12 +11307,12 @@ var init_content = __esm({
10995
11307
  const messageAll = all.slice(archivedMessageCount);
10996
11308
  if (messageAll.length === 0) {
10997
11309
  result.push(currentUserMsg);
10998
- return enforceVisionGate(result);
11310
+ return enforceVisionGate(result, modelId);
10999
11311
  }
11000
11312
  const repair = repairOrphanToolCalls(messageAll, recovery.interruption.kind === "crashed");
11001
11313
  result.push(...decayOldToolResults(repair.msgs));
11002
11314
  result.push(currentUserMsg);
11003
- return enforceVisionGate(result);
11315
+ return enforceVisionGate(result, modelId);
11004
11316
  };
11005
11317
  }
11006
11318
  });
@@ -11161,7 +11473,7 @@ var init_subagent = __esm({
11161
11473
  console.log(`${resuming ? "\u{1F501} \u7EED\u8DD1" : "\u{1F423} \u6D3E\u751F"}\u5B50 Agent [\u6DF1\u5EA6: ${ctx.depth + 1}/${MAX_AGENT_DEPTH}][${subSessionId}]${manifest ? ` \u58F0\u660E\u5F0F=${manifest.name}` : ""} \u4EFB\u52A1: "${task.slice(0, 50)}..."`);
11162
11474
  activeSubagents.add(subSessionId);
11163
11475
  try {
11164
- const subMessages = await buildContextMessages(subSessionId, { role: "user", content: task }, subSystem);
11476
+ const subMessages = await buildContextMessages(subSessionId, { role: "user", content: task }, subSystem, manifest?.model);
11165
11477
  await appendMessage({ sessionId: subSessionId, role: "user", content: task });
11166
11478
  let subResult = "";
11167
11479
  let hasFinalResult = false;
@@ -11338,7 +11650,7 @@ var init_loader4 = __esm({
11338
11650
  console.warn(`\u26A0\uFE0F [hooks] ${where} \u975E\u5DE5\u5177\u4E8B\u4EF6\u4E0D\u652F\u6301 matcher\uFF0C\u5DF2\u5FFD\u7565`);
11339
11651
  }
11340
11652
  const matcher = TOOL_EVENTS.has(event) && typeof raw.matcher === "string" ? raw.matcher : void 0;
11341
- const timeoutMs = typeof raw.timeoutMs === "number" && raw.timeoutMs > 0 ? raw.timeoutMs : void 0;
11653
+ const timeoutMs2 = typeof raw.timeoutMs === "number" && raw.timeoutMs > 0 ? raw.timeoutMs : void 0;
11342
11654
  let denyOnNonZero = typeof raw.denyOnNonZero === "boolean" ? raw.denyOnNonZero : void 0;
11343
11655
  if (denyOnNonZero === true && !INTERCEPTABLE_EVENTS.has(event)) {
11344
11656
  console.warn(`\u26A0\uFE0F [hooks] ${where} \u975E\u62E6\u622A\u4E8B\u4EF6\uFF0CdenyOnNonZero \u4E0D\u751F\u6548\uFF08\u4EC5 PreToolUse/UserPromptSubmit \u53EF\u62E6\u622A\uFF09\uFF0C\u5DF2\u5FFD\u7565`);
@@ -11366,7 +11678,7 @@ var init_loader4 = __esm({
11366
11678
  text: type === "prompt" && typeof raw.text === "string" ? raw.text : void 0,
11367
11679
  task: type === "agent" && typeof raw.task === "string" ? raw.task : void 0,
11368
11680
  matcher,
11369
- timeoutMs,
11681
+ timeoutMs: timeoutMs2,
11370
11682
  denyOnNonZero,
11371
11683
  onError,
11372
11684
  requireApproval: raw.requireApproval === true ? true : void 0
@@ -11374,9 +11686,12 @@ var init_loader4 = __esm({
11374
11686
  };
11375
11687
  parseStdoutDecision = (stdout) => {
11376
11688
  const s = (stdout ?? "").trim();
11377
- if (!s || !s.startsWith("{")) return void 0;
11689
+ if (!s) return void 0;
11690
+ const match = s.match(/\{[\s\S]*\}$/);
11691
+ if (!match) return void 0;
11692
+ const jsonStr = match[0];
11378
11693
  try {
11379
- const parsed = JSON.parse(s);
11694
+ const parsed = JSON.parse(jsonStr);
11380
11695
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
11381
11696
  const out = {};
11382
11697
  if (parsed.deny === true) {
@@ -11406,7 +11721,7 @@ var init_loader4 = __esm({
11406
11721
  };
11407
11722
  compileRule2 = (event, raw) => {
11408
11723
  const denyOnNonZero = raw.denyOnNonZero ?? event === "PreToolUse";
11409
- const timeoutMs = raw.timeoutMs ?? DEFAULT_TIMEOUT_BY_EVENT[event];
11724
+ const timeoutMs2 = raw.timeoutMs ?? DEFAULT_TIMEOUT_BY_EVENT[event];
11410
11725
  const base = { event, matcher: raw.matcher, source: "config", onError: raw.onError };
11411
11726
  if (raw.type === "prompt") {
11412
11727
  const text = raw.text;
@@ -11451,7 +11766,7 @@ var init_loader4 = __esm({
11451
11766
  headers: raw.headers,
11452
11767
  body: ctx,
11453
11768
  // 整个 hook 上下文 JSON 化发出(含 sessionId/toolName/args/prompt 等)
11454
- timeoutMs
11769
+ timeoutMs: timeoutMs2
11455
11770
  });
11456
11771
  if (!res.ok) {
11457
11772
  return denyOnNonZero ? { deny: true, reason: `hook http \u8BF7\u6C42\u5931\u8D25\uFF1A${res.error}` } : { deny: false };
@@ -11485,11 +11800,11 @@ var init_loader4 = __esm({
11485
11800
  command,
11486
11801
  cwd: ctx?.cwd,
11487
11802
  env: ctx?.env,
11488
- timeoutMs,
11803
+ timeoutMs: timeoutMs2,
11489
11804
  stdinPayload: ctx
11490
11805
  });
11491
11806
  if (res.timedOut) {
11492
- return denyOnNonZero ? { deny: true, reason: `hook \u6267\u884C\u8D85\u65F6\uFF08>${timeoutMs}ms\uFF09` } : { deny: false };
11807
+ return denyOnNonZero ? { deny: true, reason: `hook \u6267\u884C\u8D85\u65F6\uFF08>${timeoutMs2}ms\uFF09` } : { deny: false };
11493
11808
  }
11494
11809
  if (denyOnNonZero && res.exitCode !== 0) {
11495
11810
  const detail = res.stderr ? `\uFF1A${res.stderr.slice(0, 200)}` : "";
@@ -11511,9 +11826,7 @@ var init_loader4 = __esm({
11511
11826
  if (!list || list.length === 0) continue;
11512
11827
  for (const raw of list) compiled.push(compileRule2(event, raw));
11513
11828
  }
11514
- if (compiled.length > 0) {
11515
- registerHooks(compiled);
11516
- }
11829
+ replaceDeclarativeHooks(compiled);
11517
11830
  return compiled.length;
11518
11831
  };
11519
11832
  initHooks = async (includeProject) => {
@@ -12090,14 +12403,6 @@ var init_runner = __esm({
12090
12403
  }
12091
12404
  });
12092
12405
 
12093
- // ../core/src/llm/createModel.ts
12094
- var init_createModel = __esm({
12095
- "../core/src/llm/createModel.ts"() {
12096
- "use strict";
12097
- init_client();
12098
- }
12099
- });
12100
-
12101
12406
  // ../core/src/observability/store.ts
12102
12407
  import path39 from "path";
12103
12408
  import fs37 from "fs/promises";
@@ -12414,11 +12719,12 @@ var init_systemPrompt = __esm({
12414
12719
  - \u88AB\u95EE"\u4F60\u662F\u8C01"\u65F6\u636E\u5B9E\u56DE\u7B54\uFF1A\u4F60\u662F ${p.displayName}\u3002\u5207\u52FF\u81EA\u79F0 ChatGPT\u3001GPT \u6216\u4EFB\u4F55\u5176\u4ED6\u516C\u53F8\u7684\u5927\u6A21\u578B/AI \u4EA7\u54C1\u3002
12415
12720
 
12416
12721
  \u3010\u56DE\u7B54\u51C6\u5219 / \u5B8C\u6210\u5224\u5B9A\u3011
12417
- - \u4EFB\u52A1\u5B8C\u6210\u540E\u76F4\u63A5\u7528\u81EA\u7136\u8BED\u8A00\u7ED9\u51FA\u6700\u7EC8\u7B54\u6848\uFF0C\u4E0D\u8981\u518D\u8C03\u7528\u5DE5\u5177\u3002
12418
- - **"\u8C03\u7528\u4E86\u4E00\u4E2A\u5DE5\u5177"\u4E0D\u7B49\u4E8E\u4EFB\u52A1\u5B8C\u6210**\uFF1A\u6BCF\u5B8C\u6210\u4E00\u6B65\u90FD\u8981\u5BF9\u7167\u7528\u6237\u539F\u59CB\u8BF7\u6C42\u4E0E todo \u6E05\u5355\uFF08\u82E5\u6709\uFF09\u9010\u9879\u6838\u5BF9\uFF0C\u786E\u8BA4\u5168\u90E8\u5B50\u76EE\u6807\u90FD\u5DF2\u843D\u5730\u3001\u4E14\u672A\u5F15\u5165\u65B0\u95EE\u9898\u540E\uFF0C\u624D\u7ED9\u51FA\u6700\u7EC8\u7B54\u6848\u3002\u4E0D\u8981\u5728\u53EA\u5B8C\u6210\u4E00\u90E8\u5206\u65F6\u5C31\u6536\u5C3E\u3002
12419
- - \u5DE5\u5177**\u6267\u884C\u5931\u8D25\u6216\u88AB\u7528\u6237\u62D2\u7EDD**\u65F6\uFF0C\u7EDD\u4E0D\u80FD\u9053\u6B49\u4E00\u4E24\u53E5\u5C31\u505C\u4E0B\u3002\u5148\u8BFB\u8FD4\u56DE\u7ED3\u679C\u5B9A\u4F4D\u5931\u8D25\u539F\u56E0\uFF0C\u4FEE\u6B63\u53C2\u6570\u91CD\u8BD5\uFF0C\u6216\u6362\u7B49\u6548\u5DE5\u5177/\u65B9\u6848\u7EE7\u7EED\u63A8\u8FDB\uFF1B\u786E\u5B9E\u53D7\u963B\u3001\u9700\u8981\u7528\u6237\u51B3\u7B56\u65F6\uFF0C\u7528 ask_question \u8BF4\u660E**\u5177\u4F53**\u7684\u963B\u585E\u70B9\u8BF7\u7528\u6237\u62CD\u677F\uFF0C\u800C\u4E0D\u662F\u7A7A\u6CDB\u5730\u8BF4"\u65E0\u6CD5\u5B8C\u6210"\u7136\u540E\u7ED3\u675F\u3002
12420
- - **\u4E25\u7981**\u5728\u672A\u771F\u6B63\u6267\u884C\u6216\u672A\u9A8C\u8BC1\u7684\u60C5\u51B5\u4E0B\u58F0\u79F0"\u5DF2\u5B8C\u6210/\u5DF2\u4FEE\u6539/\u5DF2\u4FEE\u590D"\u3002\u6539\u52A8\u540E\u82E5\u53EF\u9A8C\u8BC1\uFF08\u91CD\u65B0\u8BFB\u53D6\u786E\u8BA4\u3001\u8DD1\u6D4B\u8BD5\u3001\u7C7B\u578B\u68C0\u67E5\u7B49\uFF09\uFF0C\u5E94\u4E3B\u52A8\u9A8C\u8BC1\u518D\u6536\u5C3E\u3002
12421
- - **\u5DE5\u5177\u8FD4\u56DE\u540E\u5148\u81EA\u68C0\u518D\u51B3\u5B9A\u6536\u5C3E**\uFF1A\u6BCF\u6B21\u5DE5\u5177\u8FD4\u56DE\u7ED3\u679C\uFF0C\u5148\u5224\u65AD\u7528\u6237\u7684\u6BCF\u4E00\u4E2A\u5B50\u76EE\u6807\u662F\u5426\u90FD\u5DF2\u6709\u843D\u5730\u4EA7\u7269\uFF08\u5DF2\u8BFB\u5230\u6240\u9700\u4FE1\u606F / \u5DF2\u6539\u5B8C\u8BE5\u6539\u7684\u6587\u4EF6 / \u5DF2\u9A8C\u8BC1\u901A\u8FC7\uFF09\u3002\u53EA\u8981\u8FD8\u6709\u672A\u843D\u5730\u7684\u5B50\u76EE\u6807\uFF0C\u5C31\u7EE7\u7EED\u8C03\u7528\u5DE5\u5177\u63A8\u8FDB\u2014\u2014**\u4E0D\u8981\u5728\u62FF\u5230\u90E8\u5206\u68C0\u7D22\u6216\u8BFB\u53D6\u7ED3\u679C\u540E\u5C31\u7528\u81EA\u7136\u8BED\u8A00\u603B\u7ED3\u6536\u5C3E**\u3002\u590D\u6742\u4EFB\u52A1\u7528 todo_write \u62C6\u89E3\u5E76\u9010\u9879\u52FE\u9009\uFF0C\u6BCF\u8F6E\u5BF9\u7167\u6E05\u5355\u6838\u5BF9\u8FDB\u5EA6\u3002
12722
+ - \u4EFB\u52A1\u5B8C\u6210\u540E\u76F4\u63A5\u7528\u81EA\u7136\u8BED\u8A00\u7ED9\u51FA\u6700\u7EC8\u7B54\u6848\uFF0C\u4E0D\u8981\u518D\u8C03\u7528\u5DE5\u5177\u3002**\u5B8C\u6210\u5224\u636E = \u7528\u6237\u7684\u6BCF\u4E2A\u5B50\u76EE\u6807\u90FD\u6709\u843D\u5730\u4EA7\u7269**\uFF08\u6240\u9700\u4FE1\u606F\u5DF2\u5230\u624B / \u8BE5\u6539\u7684\u6587\u4EF6\u5DF2\u6539\u5B8C / \u5DF2\u9A8C\u8BC1\u901A\u8FC7\uFF09\uFF0C\u800C\u975E"\u8C03\u7528\u8FC7\u5DE5\u5177"\u3002\u6BCF\u8F6E\u5DE5\u5177\u8FD4\u56DE\u540E\u5BF9\u7167\u539F\u59CB\u8BF7\u6C42\u4E0E todo \u6E05\u5355\uFF08\u82E5\u6709\uFF09\u9010\u9879\u6838\u5BF9\uFF1A\u8FD8\u6709\u672A\u843D\u5730\u9879\u5C31\u7EE7\u7EED\u63A8\u8FDB\uFF0C\u4E0D\u8981\u62FF\u90E8\u5206\u68C0\u7D22/\u8BFB\u53D6\u7ED3\u679C\u603B\u7ED3\u6536\u5C3E\u3002\u590D\u6742\u4EFB\u52A1\u7528 todo_write \u62C6\u89E3\u5E76\u9010\u9879\u52FE\u9009\uFF0C\u6BCF\u8F6E\u5BF9\u7167\u6E05\u5355\u6838\u5BF9\u8FDB\u5EA6\u3002
12723
+ - \u5DE5\u5177**\u6267\u884C\u5931\u8D25\u6216\u88AB\u7528\u6237\u62D2\u7EDD**\u65F6\uFF0C\u8BFB\u8FD4\u56DE\u7ED3\u679C\u5B9A\u4F4D\u539F\u56E0\uFF0C\u4FEE\u6B63\u53C2\u6570\u6216\u6362\u7B49\u6548\u65B9\u6848\u7EE7\u7EED\uFF0C\u4E0D\u8981\u9053\u6B49\u4E00\u4E24\u53E5\u5C31\u505C\u4E0B\uFF1B\u786E\u5B9E\u53D7\u963B\u9700\u8981\u7528\u6237\u51B3\u7B56\u65F6\uFF0C\u7528 ask_question \u8BF4\u660E**\u5177\u4F53**\u963B\u585E\u70B9\u3002**\u4E25\u7981**\u5728\u672A\u771F\u6B63\u6267\u884C\u6216\u672A\u9A8C\u8BC1\u7684\u60C5\u51B5\u4E0B\u58F0\u79F0"\u5DF2\u5B8C\u6210/\u5DF2\u4FEE\u6539/\u5DF2\u4FEE\u590D"\u2014\u2014\u6539\u52A8\u82E5\u53EF\u9A8C\u8BC1\uFF08\u91CD\u8BFB\u786E\u8BA4\u3001\u8DD1\u6D4B\u8BD5\u3001\u7C7B\u578B\u68C0\u67E5\uFF09\uFF0C\u5148\u9A8C\u8BC1\u518D\u6536\u5C3E\u3002
12724
+
12725
+ \u3010\u56DE\u7B54\u5F62\u5F0F\u3011
12726
+ - **\u5148\u7ED3\u8BBA\u540E\u7EC6\u8282**\uFF1A\u5148\u76F4\u63A5\u56DE\u7B54\u6216\u6C47\u62A5\u7ED3\u679C\uFF0C\u518D\u5C55\u5F00\u5FC5\u8981\u7684\u89E3\u91CA\uFF1B\u6536\u5C3E\u603B\u7ED3\u7B80\u77ED\uFF08\u51E0\u884C\u4EE5\u5185\uFF09\uFF0C\u4E0D\u9010\u6587\u4EF6\u6D41\u6C34\u8D26\u3002
12727
+ - **\u4E0D\u56DE\u8D34\u5927\u6BB5\u4EE3\u7801**\uFF1A\u6539\u52A8\u5185\u5BB9\u7528\u6237\u5728\u7F16\u8F91\u5668/diff \u91CC\u770B\u5F97\u5230\uFF0C\u6B63\u6587\u53EA\u9700\u4E00\u53E5\u8BDD\u8BF4\u660E\u6539\u4E86\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\uFF0C\u6216\u5F15\u7528\u5173\u952E\u51E0\u884C\u3002
12422
12728
 
12423
12729
  \u3010\u5DE5\u5177\u4F7F\u7528\u51C6\u5219\u3011
12424
12730
  - \u4FEE\u6539\u6587\u4EF6**\u53EA\u80FD**\u7528 edit_file / create_file / write_file\u3002**\u4E25\u7981**\u7528 run_command \u901A\u8FC7 python/node/sed/awk/perl \u7B49\u811A\u672C\u8BFB\u5199\u6216\u4FEE\u6539\u6587\u4EF6\u2014\u2014\u811A\u672C\u8F6C\u4E49\u6781\u6613\u51FA\u9519\u3001\u6BCF\u6761\u547D\u4EE4\u90FD\u8981\u7528\u6237\u5BA1\u6279\u3001\u6548\u7387\u6781\u4F4E\uFF0C\u662F\u88AB\u660E\u786E\u7981\u6B62\u7684\u9000\u8DEF\u3002
@@ -12519,18 +12825,29 @@ ${lines.join("\n")}
12519
12825
  \u2605 \u8DEF\u5F84\u951A\u5B9A\u94C1\u5F8B\uFF1A\u5DE5\u5177\u7F3A\u7701\u53EA\u4F5C\u7528\u4E8E\u9ED8\u8BA4\u6839\uFF08${path41.basename(activeReal) || activeReal} = IDE \u5934\u90E8\u6240\u793A\u6839\uFF09\u3002\u5F53\u7528\u6237\u5728\u5BF9\u8BDD\u4E2D\u6307\u660E\u4E86\u67D0\u4E2A\u9879\u76EE\uFF08\u5982\u300C\u5728 A \u9879\u76EE\u300D\u300C\u6539\u524D\u7AEF\u7684 xxx\u300D\u300C\u641C\u540E\u7AEF\u300D\uFF09\uFF0C\u8BE5\u8F6E\u6240\u6709\u5E26 path \u53C2\u6570\u7684\u5DE5\u5177\u8C03\u7528\uFF08read_file / edit_file / search_grep / glob / list_dir / read_xlsx / read_docx \u7B49\uFF09\u5FC5\u987B\u628A\u5BF9\u5E94\u9879\u76EE\u6839\u4F5C\u4E3A path \u4F20\u5165\uFF08\u7EDD\u5BF9\u8DEF\u5F84\u3001../<\u5144\u5F1F\u76EE\u5F55>\u3001\u6216\u9879\u76EE\u76EE\u5F55\u540D\uFF09\uFF0C\u5426\u5219\u53EA\u4F1A\u8BFB\u5199/\u641C\u7D22\u9ED8\u8BA4\u6839\uFF0C\u4E0E\u7528\u6237\u610F\u56FE\u4E0D\u7B26\u3002
12520
12826
  \u6CE8\u610F\uFF1A\u9879\u76EE\u7EA7\u914D\u7F6E\uFF08.deepseeker-code/\uFF09\u4EC5\u5728\u9ED8\u8BA4\u6839 ${path41.basename(activeReal) || activeReal} \u751F\u6548\u3002`;
12521
12827
  }
12522
- let replyText = "";
12523
- let userContent = inbound.content;
12524
- if (Array.isArray(inbound.attachments) && inbound.attachments.length > 0) {
12525
- userContent = isVisionEnabled() ? toWireUserContent(inbound.content, inbound.attachments) : `${inbound.content}
12828
+ const osName = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
12829
+ const now = /* @__PURE__ */ new Date();
12830
+ const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
12831
+ const shellNote = process.platform === "win32" ? "\u7ECF shell \u6267\u884C\uFF08\u4F18\u5148 Git Bash\uFF0CPOSIX \u8BED\u4E49\uFF1B\u7F3A\u7701\u56DE\u9000 cmd.exe\uFF09" : "\u7ECF POSIX shell\uFF08sh\uFF09\u6267\u884C";
12832
+ const envLines = [
12833
+ ...roots.length > 1 ? [] : [`- \u5DE5\u4F5C\u533A\u6839\uFF08\u5DE5\u5177\u76F8\u5BF9\u8DEF\u5F84\u7684\u57FA\u51C6\uFF09: ${getActiveWorkspaceRoot()}`],
12834
+ `- \u64CD\u4F5C\u7CFB\u7EDF: ${osName}\uFF08${process.platform}\uFF09`,
12835
+ `- \u547D\u4EE4\u6267\u884C: ${shellNote}`,
12836
+ `- \u4ECA\u5929: ${today}`
12837
+ ];
12838
+ sysPrompt = sysPrompt + `
12526
12839
 
12527
- \u{1F5BC} \u6536\u5230\u56FE\u7247\u9644\u4EF6\uFF08${inbound.attachments.map((a) => a?.name || "image").join("\u3001")}\uFF09\uFF1A\u5F53\u524D\u6A21\u578B\u672A\u5F00\u542F\u89C6\u89C9\u80FD\u529B\uFF08DEEP_SEEK_VISION\uFF09\uFF0C\u5DF2\u5FFD\u7565\u56FE\u7247\u5185\u5BB9\u3002`;
12528
- }
12840
+ \u3010\u73AF\u5883\u3011
12841
+ ${envLines.join("\n")}`;
12842
+ let replyText = "";
12843
+ const { wire: userContent, archive: archiveContent } = toIngestContents(inbound.content, inbound.attachments, opts?.model);
12529
12844
  try {
12530
12845
  const fullMessages = await buildContextMessages(
12531
12846
  sessionId,
12532
12847
  { role: "user", content: userContent },
12533
- sysPrompt
12848
+ sysPrompt,
12849
+ opts?.model
12850
+ // ★ vision 自动判定与实际请求模型(opts.model ?? MODEL_NAME)同源
12534
12851
  );
12535
12852
  await emitTrace({
12536
12853
  sessionId,
@@ -12542,7 +12859,7 @@ ${lines.join("\n")}
12542
12859
  });
12543
12860
  void sweepStaleAtomicTmp().catch(() => {
12544
12861
  });
12545
- await appendMessage({ sessionId, role: "user", content: userContent });
12862
+ await appendMessage({ sessionId, role: "user", content: archiveContent });
12546
12863
  let streamedAnyText = false;
12547
12864
  const onUIEvent = opts?.onUIEvent ?? ((evt) => sseWrite?.(evt));
12548
12865
  const requestApproval2 = opts?.requestApproval ?? createWebRequestApproval((evt) => sseWrite?.(evt), abortSignal);
@@ -12731,6 +13048,75 @@ var init_fork = __esm({
12731
13048
  }
12732
13049
  });
12733
13050
 
13051
+ // ../core/src/commands/bashDirect.ts
13052
+ import { exec } from "node:child_process";
13053
+ var OUTPUT_MAX_CHARS, timeoutMs, truncateOutput, decodeBuffer, runBashDirect, formatBashEntry, recordBashEntry;
13054
+ var init_bashDirect = __esm({
13055
+ "../core/src/commands/bashDirect.ts"() {
13056
+ "use strict";
13057
+ init_transcript();
13058
+ init_guard();
13059
+ OUTPUT_MAX_CHARS = 4e3;
13060
+ timeoutMs = () => {
13061
+ const n = Number(process.env.DEEP_SEEK_BANG_TIMEOUT_MS);
13062
+ return Number.isFinite(n) && n > 0 ? n : 6e4;
13063
+ };
13064
+ truncateOutput = (s) => {
13065
+ if (s.length <= OUTPUT_MAX_CHARS) return s;
13066
+ const half = Math.floor(OUTPUT_MAX_CHARS / 2);
13067
+ return `${s.slice(0, half)}
13068
+ \u2026\uFF08\u4E2D\u6BB5\u7701\u7565 ${s.length - OUTPUT_MAX_CHARS} \u5B57\u7B26\uFF09\u2026
13069
+ ${s.slice(-half)}`;
13070
+ };
13071
+ decodeBuffer = (buf) => {
13072
+ const utf8 = buf.toString("utf8");
13073
+ if (!utf8.includes("\uFFFD")) return utf8;
13074
+ try {
13075
+ return new TextDecoder("gbk").decode(buf);
13076
+ } catch {
13077
+ return utf8;
13078
+ }
13079
+ };
13080
+ runBashDirect = (cmd, cwd, signal) => new Promise((resolve) => {
13081
+ let settled = false;
13082
+ const finish = (r) => {
13083
+ if (!settled) {
13084
+ settled = true;
13085
+ resolve(r);
13086
+ }
13087
+ };
13088
+ const start = Date.now();
13089
+ const child = exec(cmd, { cwd, timeout: timeoutMs(), maxBuffer: 4 * 1024 * 1024, windowsHide: true, env: scrubCommandEnv(), encoding: "buffer" }, (err, stdout, stderr) => {
13090
+ const durationMs = Date.now() - start;
13091
+ const out = stdout;
13092
+ const errBuf = stderr;
13093
+ const timedOut = err != null && err.killed === true && signal?.aborted !== true;
13094
+ const combined = errBuf.length ? (out.length ? `${decodeBuffer(out)}
13095
+ ` : "") + decodeBuffer(errBuf) : decodeBuffer(out);
13096
+ const exitCode = err == null ? 0 : typeof err.code === "number" ? err.code : null;
13097
+ finish({ ok: err == null, output: truncateOutput(combined ?? ""), exitCode, timedOut, durationMs });
13098
+ });
13099
+ if (signal) {
13100
+ const onAbort = () => {
13101
+ try {
13102
+ child.kill();
13103
+ } catch {
13104
+ }
13105
+ };
13106
+ if (signal.aborted) onAbort();
13107
+ else signal.addEventListener("abort", onAbort, { once: true });
13108
+ }
13109
+ });
13110
+ formatBashEntry = (cmd, r) => `!bash $ ${cmd}
13111
+ ` + (r.timedOut ? `[\u8D85\u65F6\u4E2D\u6B62\uFF08>${Math.round(r.durationMs / 1e3)}s\uFF09]
13112
+ ` : "") + (r.exitCode != null && r.exitCode !== 0 ? `[\u9000\u51FA\u7801 ${r.exitCode}]
13113
+ ` : "") + (r.output.trim() || "(\u65E0\u8F93\u51FA)");
13114
+ recordBashEntry = async (sessionId, text) => {
13115
+ await appendMessage({ sessionId, role: "user", content: text });
13116
+ };
13117
+ }
13118
+ });
13119
+
12734
13120
  // src/cliHost.ts
12735
13121
  var createCliRequestApproval, createCliRequestQuestion;
12736
13122
  var init_cliHost = __esm({
@@ -12925,9 +13311,12 @@ var init_useChatState = __esm({
12925
13311
  init_fork();
12926
13312
  init_inbox();
12927
13313
  init_contextCore();
13314
+ init_bashDirect();
13315
+ init_guard();
12928
13316
  init_createModel();
12929
13317
  init_tool();
12930
13318
  init_cliHost();
13319
+ init_prefs();
12931
13320
  init_strings();
12932
13321
  init_util();
12933
13322
  init_replay2();
@@ -12949,6 +13338,7 @@ var init_useChatState = __esm({
12949
13338
  const [pendingPlan, setPendingPlan] = useState(null);
12950
13339
  const [pendingSessions, setPendingSessions] = useState(null);
12951
13340
  const [pendingFork, setPendingFork] = useState(null);
13341
+ const [pendingModel, setPendingModel] = useState(null);
12952
13342
  const nextId = useRef(1);
12953
13343
  const assistantStreamingId = useRef(null);
12954
13344
  const thinkingStreamingId = useRef(null);
@@ -13320,6 +13710,22 @@ ${finalPlan}`, false, res.autoExecute);
13320
13710
  if (turnGenRef.current === myGen) setBusy(false);
13321
13711
  }
13322
13712
  }, [busy, initialSessionId, pushUser, pushInfo, runOnce, runPlanStage, takeEnterPlanRequest, takeProposedPlan, approveAndImplement]);
13713
+ const runBangCommand = useCallback(async (raw) => {
13714
+ const cmd = raw.replace(/^!/, "").trim();
13715
+ if (!cmd) {
13716
+ pushInfo("\u7528\u6CD5\uFF1A!<shell \u547D\u4EE4>\uFF08\u5982 !git status\uFF09\uFF1B\u8F93\u51FA\u4F1A\u5E26\u5165\u4E0B\u8F6E\u5BF9\u8BDD\u4E0A\u4E0B\u6587\u3002");
13717
+ return;
13718
+ }
13719
+ pushUser(raw);
13720
+ if (sessionIdRef.current == null) {
13721
+ sessionIdRef.current = await getOrCreateSessionId(initialSessionId ?? void 0);
13722
+ }
13723
+ const r = await runBashDirect(cmd, getActiveWorkspaceRoot());
13724
+ const head = r.timedOut ? `\u23F1 \u8D85\u65F6\u4E2D\u6B62` : r.ok ? `\u2705 \u9000\u51FA\u7801 0` : r.exitCode != null ? `\u274C \u9000\u51FA\u7801 ${r.exitCode}` : `\u274C \u5DF2\u4E2D\u6B62`;
13725
+ pushInfo(`${head} \xB7 ${Math.round(r.durationMs / 100) / 10}s
13726
+ ${r.output.trim() || "(\u65E0\u8F93\u51FA)"}`);
13727
+ await recordBashEntry(sessionIdRef.current, formatBashEntry(cmd, r));
13728
+ }, [initialSessionId, pushUser, pushInfo]);
13323
13729
  const abortCurrent = useCallback(() => {
13324
13730
  const ac = currentAcRef.current;
13325
13731
  if (!ac) return;
@@ -13403,7 +13809,21 @@ ${finalPlan}`, false, res.autoExecute);
13403
13809
  }, [pushInfo, loadSession]);
13404
13810
  const setModelOverride = useCallback((m) => {
13405
13811
  modelRef.current = m;
13812
+ void writePrefs({ model: m });
13406
13813
  }, []);
13814
+ const resolveModel = useCallback((model2) => {
13815
+ setPendingModel((prev) => {
13816
+ prev?.resolve(model2);
13817
+ return null;
13818
+ });
13819
+ }, []);
13820
+ const openModelPicker = useCallback(async () => {
13821
+ const picked = await new Promise((resolve) => setPendingModel({ models: SELECTABLE_MODELS, resolve }));
13822
+ if (picked) {
13823
+ setModelOverride(picked);
13824
+ pushInfo(S.modelSwitched(picked));
13825
+ }
13826
+ }, [pushInfo, setModelOverride]);
13407
13827
  const setPlanMode = useCallback((on) => {
13408
13828
  planModeRef.current = on;
13409
13829
  }, []);
@@ -13431,6 +13851,7 @@ ${finalPlan}`, false, res.autoExecute);
13431
13851
  pendingPlan,
13432
13852
  pendingSessions,
13433
13853
  pendingFork,
13854
+ pendingModel,
13434
13855
  sessionIdRef,
13435
13856
  // 动作
13436
13857
  submit,
@@ -13439,6 +13860,7 @@ ${finalPlan}`, false, res.autoExecute);
13439
13860
  pushUser,
13440
13861
  pushInfo,
13441
13862
  pushEvent,
13863
+ runBangCommand,
13442
13864
  askApproval,
13443
13865
  resolveApproval,
13444
13866
  resolveQuestion,
@@ -13459,7 +13881,9 @@ ${finalPlan}`, false, res.autoExecute);
13459
13881
  resolveSession,
13460
13882
  loadSession,
13461
13883
  openForkPicker,
13462
- resolveFork
13884
+ resolveFork,
13885
+ openModelPicker,
13886
+ resolveModel
13463
13887
  };
13464
13888
  };
13465
13889
  }
@@ -13548,7 +13972,7 @@ var init_StreamingCursor = __esm({
13548
13972
  // src/components/MessageBlock.tsx
13549
13973
  import { Box, Text as Text3 } from "ink";
13550
13974
  import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
13551
- var UsageFooter, listPrefix, AssistantLine, MessageBlock;
13975
+ var UsageFooter, listPrefix, AssistantLine, isFenceMark, isMdRow, isMdSep, mdCells, parseBlocks, fitCell, tableWidths, buildVLines, AssistantVLine, MessageBlock;
13552
13976
  var init_MessageBlock = __esm({
13553
13977
  "src/components/MessageBlock.tsx"() {
13554
13978
  "use strict";
@@ -13587,6 +14011,94 @@ var init_MessageBlock = __esm({
13587
14011
  }
13588
14012
  return /* @__PURE__ */ jsx3(RichText, { text: line });
13589
14013
  };
14014
+ isFenceMark = (l) => /^\s*```/.test(l);
14015
+ isMdRow = (l) => l.includes("|");
14016
+ isMdSep = (l) => /^[ \t|:-]+$/.test(l) && l.includes("-") && l.includes("|");
14017
+ mdCells = (l) => l.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
14018
+ parseBlocks = (text) => {
14019
+ const src = String(text || "").split("\n");
14020
+ const blocks = [];
14021
+ let i = 0;
14022
+ while (i < src.length) {
14023
+ if (isFenceMark(src[i])) {
14024
+ const body = [];
14025
+ i++;
14026
+ while (i < src.length && !isFenceMark(src[i])) body.push(src[i++]);
14027
+ if (i < src.length) i++;
14028
+ blocks.push({ kind: "fence", lines: body });
14029
+ continue;
14030
+ }
14031
+ if (isMdRow(src[i]) && i + 1 < src.length && isMdSep(src[i + 1])) {
14032
+ const header = mdCells(src[i]);
14033
+ const rows = [];
14034
+ i += 2;
14035
+ while (i < src.length && isMdRow(src[i])) rows.push(mdCells(src[i++]));
14036
+ blocks.push({ kind: "table", header, rows });
14037
+ continue;
14038
+ }
14039
+ blocks.push({ kind: "line", text: src[i++] });
14040
+ }
14041
+ return blocks;
14042
+ };
14043
+ fitCell = (s, w) => {
14044
+ if (strWidth(s) <= w) return s + " ".repeat(w - strWidth(s));
14045
+ let out = "";
14046
+ let width = 0;
14047
+ const limit = Math.max(1, w - 1);
14048
+ for (const ch of s) {
14049
+ const cw = strWidth(ch);
14050
+ if (width + cw > limit) break;
14051
+ out += ch;
14052
+ width += cw;
14053
+ }
14054
+ return out + "\u2026";
14055
+ };
14056
+ tableWidths = (header, rows, contentW) => {
14057
+ const n = Math.max(1, header.length);
14058
+ const w = Array.from({ length: n }, (_, c) => {
14059
+ let m = strWidth(header[c] ?? "");
14060
+ for (const r of rows) m = Math.max(m, strWidth(r[c] ?? ""));
14061
+ return Math.min(m, 30);
14062
+ });
14063
+ const total = () => w.reduce((a, b) => a + b, 0) + 2 * (n - 1);
14064
+ while (total() > contentW && Math.max(...w) > 1) {
14065
+ const maxW = Math.max(...w);
14066
+ w[w.indexOf(maxW)] = maxW - 1;
14067
+ }
14068
+ return w;
14069
+ };
14070
+ buildVLines = (text, contentW) => {
14071
+ const out = [];
14072
+ for (const b of parseBlocks(text)) {
14073
+ if (b.kind === "line") {
14074
+ for (const l of wrapText(b.text, contentW)) out.push({ k: "text", s: l });
14075
+ } else if (b.kind === "fence") {
14076
+ for (const l of b.lines) out.push({ k: "code", s: l });
14077
+ } else {
14078
+ const w = tableWidths(b.header, b.rows, contentW);
14079
+ out.push({ k: "thead", cells: b.header, w }, { k: "tsep", w });
14080
+ for (const r of b.rows) out.push({ k: "trow", cells: r, w });
14081
+ }
14082
+ }
14083
+ return out.length ? out : [{ k: "text", s: "" }];
14084
+ };
14085
+ AssistantVLine = ({ v }) => {
14086
+ switch (v.k) {
14087
+ case "text":
14088
+ return /* @__PURE__ */ jsx3(AssistantLine, { line: v.s });
14089
+ case "code":
14090
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
14091
+ /* @__PURE__ */ jsx3(Text3, { color: THEME.divider, children: "\u2502 " }),
14092
+ /* @__PURE__ */ jsx3(Text3, { color: THEME.gray, children: v.s.length ? v.s : " " })
14093
+ ] });
14094
+ case "thead":
14095
+ return /* @__PURE__ */ jsx3(Box, { flexDirection: "row", children: v.w.map((cw, i) => /* @__PURE__ */ jsx3(Box, { width: cw + 2, flexShrink: 0, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "#ffffff", children: fitCell(v.cells[i] ?? "", cw) }) }, i)) });
14096
+ case "tsep":
14097
+ return /* @__PURE__ */ jsx3(Box, { flexDirection: "row", children: v.w.map((cw, i) => /* @__PURE__ */ jsx3(Box, { width: cw + 2, flexShrink: 0, children: /* @__PURE__ */ jsx3(Text3, { color: THEME.divider, children: "\u2500".repeat(cw) }) }, i)) });
14098
+ case "trow":
14099
+ return /* @__PURE__ */ jsx3(Box, { flexDirection: "row", children: v.w.map((cw, i) => /* @__PURE__ */ jsx3(Box, { width: cw + 2, flexShrink: 0, children: /* @__PURE__ */ jsx3(Text3, { color: THEME.body, children: fitCell(v.cells[i] ?? "", cw) }) }, i)) });
14100
+ }
14101
+ };
13590
14102
  MessageBlock = ({ row, wrapW, streamTail }) => {
13591
14103
  if (row.kind === "meta") {
13592
14104
  if (/^第 \d+ 轮$/.test(row.text)) {
@@ -13603,15 +14115,15 @@ var init_MessageBlock = __esm({
13603
14115
  ] }) });
13604
14116
  }
13605
14117
  if (row.kind === "info") {
13606
- const lines2 = wrapText(row.text, Math.max(8, wrapW));
13607
- return /* @__PURE__ */ jsx3(Box, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: lines2.map((line, j) => /* @__PURE__ */ jsxs(Text3, { color: THEME.coralMuted, children: [
14118
+ const lines = wrapText(row.text, Math.max(8, wrapW));
14119
+ return /* @__PURE__ */ jsx3(Box, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: lines.map((line, j) => /* @__PURE__ */ jsxs(Text3, { color: THEME.coralMuted, children: [
13608
14120
  j === 0 ? "\u203A " : " ",
13609
14121
  line
13610
14122
  ] }, j)) });
13611
14123
  }
13612
14124
  if (row.kind === "user") {
13613
- const lines2 = wrapText(row.text, Math.max(8, wrapW - 2));
13614
- return /* @__PURE__ */ jsx3(Box, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: lines2.map((line, j) => /* @__PURE__ */ jsx3(Text3, { children: j === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
14125
+ const lines = wrapText(row.text, Math.max(8, wrapW - 2));
14126
+ return /* @__PURE__ */ jsx3(Box, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: lines.map((line, j) => /* @__PURE__ */ jsx3(Text3, { children: j === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
13615
14127
  /* @__PURE__ */ jsx3(Text3, { color: THEME.coralBright, bold: true, children: "> " }),
13616
14128
  /* @__PURE__ */ jsx3(Text3, { color: THEME.white, children: line })
13617
14129
  ] }) : /* @__PURE__ */ jsxs(Text3, { color: THEME.white, children: [
@@ -13620,19 +14132,19 @@ var init_MessageBlock = __esm({
13620
14132
  ] }) }, j)) });
13621
14133
  }
13622
14134
  if (row.kind === "system") {
13623
- const lines2 = wrapText(row.text, Math.max(8, wrapW - 2));
13624
- return /* @__PURE__ */ jsx3(Box, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: lines2.map((line, j) => /* @__PURE__ */ jsxs(Text3, { color: THEME.warn, children: [
14135
+ const lines = wrapText(row.text, Math.max(8, wrapW - 2));
14136
+ return /* @__PURE__ */ jsx3(Box, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: lines.map((line, j) => /* @__PURE__ */ jsxs(Text3, { color: THEME.warn, children: [
13625
14137
  j === 0 ? "! " : " ",
13626
14138
  line
13627
14139
  ] }, j)) });
13628
14140
  }
13629
14141
  const contentW = Math.max(8, wrapW - 2);
13630
- const allLines = wrapText(row.text, contentW);
13631
- let lines = allLines;
14142
+ const allLines = buildVLines(row.text, contentW);
14143
+ let vlines = allLines;
13632
14144
  let folded = 0;
13633
14145
  if (row.streaming && streamTail && allLines.length > streamTail) {
13634
14146
  folded = allLines.length - streamTail;
13635
- lines = allLines.slice(folded);
14147
+ vlines = allLines.slice(folded);
13636
14148
  }
13637
14149
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: [
13638
14150
  folded > 0 ? /* @__PURE__ */ jsxs(Text3, { color: THEME.grayDim, children: [
@@ -13640,11 +14152,11 @@ var init_MessageBlock = __esm({
13640
14152
  folded,
13641
14153
  " \u884C\u2026"
13642
14154
  ] }) : null,
13643
- lines.map((line, j) => {
13644
- const isLast = j === lines.length - 1;
14155
+ vlines.map((v, j) => {
14156
+ const isLast = j === vlines.length - 1;
13645
14157
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
13646
14158
  /* @__PURE__ */ jsx3(Text3, { bold: true, color: THEME.coralBright, children: j === 0 ? "\u25CF " : " " }),
13647
- /* @__PURE__ */ jsx3(AssistantLine, { line }),
14159
+ /* @__PURE__ */ jsx3(AssistantVLine, { v }),
13648
14160
  isLast && row.streaming ? /* @__PURE__ */ jsx3(StreamingCursor, {}) : null
13649
14161
  ] }, j);
13650
14162
  }),
@@ -14268,9 +14780,44 @@ var init_ForkPicker = __esm({
14268
14780
  }
14269
14781
  });
14270
14782
 
14271
- // src/components/SlashMenu.tsx
14783
+ // src/components/ModelPicker.tsx
14272
14784
  import { Box as Box12, Text as Text14 } from "ink";
14273
14785
  import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
14786
+ var PAGE_SIZE3, ModelPicker;
14787
+ var init_ModelPicker = __esm({
14788
+ "src/components/ModelPicker.tsx"() {
14789
+ "use strict";
14790
+ init_theme();
14791
+ init_strings();
14792
+ init_util();
14793
+ PAGE_SIZE3 = 8;
14794
+ ModelPicker = ({ models, currentModel, selectedIndex, wrapW }) => {
14795
+ const start = Math.floor(Math.max(0, selectedIndex) / PAGE_SIZE3) * PAGE_SIZE3;
14796
+ const visible = models.slice(start, start + PAGE_SIZE3);
14797
+ const contentW = Math.max(24, wrapW);
14798
+ const metaSample = " \xB7 \uFF08\u5F53\u524D\uFF09";
14799
+ const modelW = Math.max(12, contentW - strWidth(metaSample) - 4);
14800
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: THEME.blue, paddingX: 1, paddingY: 1, marginTop: 1, children: [
14801
+ /* @__PURE__ */ jsx14(Text14, { color: THEME.blue, bold: true, children: S.modelPickerTitle(currentModel) }),
14802
+ /* @__PURE__ */ jsx14(Text14, { color: THEME.grayDim, children: S.modelPickerPrompt }),
14803
+ /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", marginTop: 0.5, children: visible.map((m, i) => {
14804
+ const idx = start + i;
14805
+ const active = idx === selectedIndex;
14806
+ const current = m === currentModel;
14807
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
14808
+ /* @__PURE__ */ jsx14(Text14, { color: active ? THEME.coralBright : void 0, bold: true, children: active ? "\u203A " : " " }),
14809
+ /* @__PURE__ */ jsx14(Text14, { color: active ? THEME.white : THEME.gray, bold: active, children: `${current ? "\u25CF " : " "}${truncateMiddle(m, modelW)}` }),
14810
+ current ? /* @__PURE__ */ jsx14(Text14, { color: THEME.grayDim, children: ` \xB7 ${S.modelCurrentTag}` }) : null
14811
+ ] }, m);
14812
+ }) })
14813
+ ] });
14814
+ };
14815
+ }
14816
+ });
14817
+
14818
+ // src/components/SlashMenu.tsx
14819
+ import { Box as Box13, Text as Text15 } from "ink";
14820
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
14274
14821
  var MAX_ROWS, SlashMenu;
14275
14822
  var init_SlashMenu = __esm({
14276
14823
  "src/components/SlashMenu.tsx"() {
@@ -14282,22 +14829,22 @@ var init_SlashMenu = __esm({
14282
14829
  const visible = entries.slice(start, start + MAX_ROWS);
14283
14830
  const cmdW = Math.min(22, Math.max(8, ...visible.map((e) => e.name.length)) + 1);
14284
14831
  const descMax = Math.max(12, cols - cmdW - 6);
14285
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: THEME.coral, paddingX: 1, paddingY: 0, marginTop: 1, children: [
14832
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", borderStyle: "round", borderColor: THEME.coral, paddingX: 1, paddingY: 0, marginTop: 1, children: [
14286
14833
  visible.map((e, i) => {
14287
14834
  const active = i + start === selectedIndex;
14288
14835
  const desc = e.description.length > descMax ? `${e.description.slice(0, descMax - 1)}\u2026` : e.description;
14289
14836
  const gap = Math.max(1, cmdW - e.name.length);
14290
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
14291
- /* @__PURE__ */ jsx14(Text14, { color: active ? THEME.coralBright : void 0, bold: true, children: active ? "\u276F " : " " }),
14292
- /* @__PURE__ */ jsxs12(Text14, { color: active ? THEME.white : THEME.gray, bold: active, children: [
14837
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", children: [
14838
+ /* @__PURE__ */ jsx15(Text15, { color: active ? THEME.coralBright : void 0, bold: true, children: active ? "\u276F " : " " }),
14839
+ /* @__PURE__ */ jsxs13(Text15, { color: active ? THEME.white : THEME.gray, bold: active, children: [
14293
14840
  "/",
14294
14841
  e.name
14295
14842
  ] }),
14296
- /* @__PURE__ */ jsx14(Text14, { color: THEME.grayDim, children: " ".repeat(gap) }),
14297
- /* @__PURE__ */ jsx14(Text14, { color: active ? THEME.gray : THEME.grayDim, children: desc })
14843
+ /* @__PURE__ */ jsx15(Text15, { color: THEME.grayDim, children: " ".repeat(gap) }),
14844
+ /* @__PURE__ */ jsx15(Text15, { color: active ? THEME.gray : THEME.grayDim, children: desc })
14298
14845
  ] }, e.name);
14299
14846
  }),
14300
- entries.length > MAX_ROWS ? /* @__PURE__ */ jsxs12(Text14, { color: THEME.coralMuted, children: [
14847
+ entries.length > MAX_ROWS ? /* @__PURE__ */ jsxs13(Text15, { color: THEME.coralMuted, children: [
14301
14848
  "\u2191\u2193 \u6EDA\u52A8 \xB7 ",
14302
14849
  selectedIndex + 1,
14303
14850
  "/",
@@ -14310,8 +14857,8 @@ var init_SlashMenu = __esm({
14310
14857
  });
14311
14858
 
14312
14859
  // src/components/StatusStrip.tsx
14313
- import { Box as Box13, Text as Text15 } from "ink";
14314
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
14860
+ import { Box as Box14, Text as Text16 } from "ink";
14861
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
14315
14862
  var StatusStrip;
14316
14863
  var init_StatusStrip = __esm({
14317
14864
  "src/components/StatusStrip.tsx"() {
@@ -14328,18 +14875,18 @@ var init_StatusStrip = __esm({
14328
14875
  `state: ${stateText}`,
14329
14876
  sessionShort ? `session: ${sessionShort}` : ""
14330
14877
  ].filter(Boolean);
14331
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexShrink: 0, children: [
14332
- /* @__PURE__ */ jsx15(Text15, { color: THEME.coralMuted, children: customLine && customLine.trim() ? customLine : bits.join(" \xB7 ") }),
14333
- /* @__PURE__ */ jsx15(Text15, { color: stateColor, children: "" }),
14334
- /* @__PURE__ */ jsx15(Text15, { color: THEME.grayDim, children: S.cmdHint })
14878
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", flexShrink: 0, children: [
14879
+ /* @__PURE__ */ jsx16(Text16, { color: THEME.coralMuted, children: customLine && customLine.trim() ? customLine : bits.join(" \xB7 ") }),
14880
+ /* @__PURE__ */ jsx16(Text16, { color: stateColor, children: "" }),
14881
+ /* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: S.cmdHint })
14335
14882
  ] });
14336
14883
  };
14337
14884
  }
14338
14885
  });
14339
14886
 
14340
14887
  // src/components/TopPanel.tsx
14341
- import { Box as Box14, Text as Text16 } from "ink";
14342
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
14888
+ import { Box as Box15, Text as Text17 } from "ink";
14889
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
14343
14890
  var ROBOT, INNER_H, TopPanel;
14344
14891
  var init_TopPanel = __esm({
14345
14892
  "src/components/TopPanel.tsx"() {
@@ -14359,36 +14906,36 @@ var init_TopPanel = __esm({
14359
14906
  const leftW = Math.floor(innerW * 0.33);
14360
14907
  const rightW = innerW - leftW - 1;
14361
14908
  const ruleLen = Math.max(8, rightW - 2);
14362
- 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)) });
14363
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: panelW, marginBottom: 1, children: [
14364
- /* @__PURE__ */ jsxs14(Text16, { children: [
14365
- /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "* Welcome to " }),
14366
- /* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.white, children: "deep" }),
14367
- /* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.coralBright, children: "Seek" }),
14368
- /* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.white, children: "Code" }),
14369
- /* @__PURE__ */ jsxs14(Text16, { color: THEME.coralMuted, children: [
14909
+ const VDivider = /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", width: 1, flexShrink: 0, children: Array.from({ length: INNER_H }).map((_, i) => /* @__PURE__ */ jsx17(Text17, { color: THEME.coral, children: "\u2502" }, i)) });
14910
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: panelW, marginBottom: 1, children: [
14911
+ /* @__PURE__ */ jsxs15(Text17, { children: [
14912
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.coralBright, bold: true, children: "* Welcome to " }),
14913
+ /* @__PURE__ */ jsx17(Text17, { bold: true, color: THEME.white, children: "deep" }),
14914
+ /* @__PURE__ */ jsx17(Text17, { bold: true, color: THEME.coralBright, children: "Seek" }),
14915
+ /* @__PURE__ */ jsx17(Text17, { bold: true, color: THEME.white, children: "Code" }),
14916
+ /* @__PURE__ */ jsxs15(Text17, { color: THEME.coralMuted, children: [
14370
14917
  " ",
14371
14918
  VERSION
14372
14919
  ] })
14373
14920
  ] }),
14374
- /* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: cwd }),
14375
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", borderStyle: "round", borderColor: THEME.coral, marginTop: 1, paddingX: 0, paddingY: 0, children: [
14376
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: leftW, height: INNER_H, alignItems: "center", justifyContent: "center", children: [
14377
- /* @__PURE__ */ jsx16(Text16, { color: THEME.white, bold: true, children: "Welcome back!" }),
14378
- ROBOT.map((l, i) => /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, children: l }, i)),
14379
- /* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "Ctrl+C \u9000\u51FA \xB7 Esc \u4E2D\u6B62" }),
14380
- /* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "\u8F93\u5165 / \u67E5\u770B\u547D\u4EE4" })
14921
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.grayDim, children: cwd }),
14922
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "row", borderStyle: "round", borderColor: THEME.coral, marginTop: 1, paddingX: 0, paddingY: 0, children: [
14923
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: leftW, height: INNER_H, alignItems: "center", justifyContent: "center", children: [
14924
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.white, bold: true, children: "Welcome back!" }),
14925
+ ROBOT.map((l, i) => /* @__PURE__ */ jsx17(Text17, { color: THEME.coralBright, children: l }, i)),
14926
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.grayDim, children: "Ctrl+C \u9000\u51FA \xB7 Esc \u4E2D\u6B62" }),
14927
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.grayDim, children: "\u8F93\u5165 / \u67E5\u770B\u547D\u4EE4" })
14381
14928
  ] }),
14382
14929
  VDivider,
14383
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: rightW, height: INNER_H, justifyContent: "space-between", paddingX: 1, children: [
14384
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
14385
- /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "Tips for getting started" }),
14386
- /* @__PURE__ */ jsx16(Text16, { color: THEME.white, children: "\u8F93\u5165\u9700\u6C42\u5F00\u59CB\uFF0C\u8F93\u5165 / \u5524\u51FA\u547D\u4EE4\u3002" })
14930
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: rightW, height: INNER_H, justifyContent: "space-between", paddingX: 1, children: [
14931
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
14932
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.coralBright, bold: true, children: "Tips for getting started" }),
14933
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.white, children: "\u8F93\u5165\u9700\u6C42\u5F00\u59CB\uFF0C\u8F93\u5165 / \u5524\u51FA\u547D\u4EE4\u3002" })
14387
14934
  ] }),
14388
- /* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "\u2500".repeat(ruleLen) }),
14389
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
14390
- /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "What's new" }),
14391
- /* @__PURE__ */ jsx16(Text16, { color: THEME.white, children: "\u5DF2\u5BF9\u63A5\u672C\u5730 Tool Call \u667A\u80FD\u51FD\u6570\u8C03\u7528\u3002" })
14935
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.grayDim, children: "\u2500".repeat(ruleLen) }),
14936
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
14937
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.coralBright, bold: true, children: "What's new" }),
14938
+ /* @__PURE__ */ jsx17(Text17, { color: THEME.white, children: "\u5DF2\u5BF9\u63A5\u672C\u5730 Tool Call \u667A\u80FD\u51FD\u6570\u8C03\u7528\u3002" })
14392
14939
  ] })
14393
14940
  ] })
14394
14941
  ] })
@@ -14539,9 +15086,9 @@ __export(App_exports, {
14539
15086
  App: () => App
14540
15087
  });
14541
15088
  import { useCallback as useCallback2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState4 } from "react";
14542
- import { Box as Box15, Static, Text as Text17, useApp, useInput as useInput2, useStdout } from "ink";
14543
- import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
14544
- var KNOWN_MODELS, CWD2, RowView, isDynamicRow, App;
15089
+ import { Box as Box16, Static, Text as Text18, useApp, useInput as useInput2, useStdout } from "ink";
15090
+ import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
15091
+ var CWD2, RowView, isDynamicRow, App;
14545
15092
  var init_App = __esm({
14546
15093
  "src/App.tsx"() {
14547
15094
  "use strict";
@@ -14566,24 +15113,24 @@ var init_App = __esm({
14566
15113
  init_PlanEditor();
14567
15114
  init_SessionPicker();
14568
15115
  init_ForkPicker();
15116
+ init_ModelPicker();
14569
15117
  init_SlashMenu();
14570
15118
  init_MultilineInput();
14571
15119
  init_StatusStrip();
14572
15120
  init_TopPanel();
14573
15121
  init_inspect();
14574
- KNOWN_MODELS = ["deepseek-v4", "deepseek-v4-flash"];
14575
15122
  CWD2 = process.cwd();
14576
15123
  RowView = ({ row, wrapW, streamTail, showThinking }) => {
14577
- if (row.kind === "todos") return /* @__PURE__ */ jsx17(TodosPanel, { todos: row.todos, wrapW });
14578
- 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 });
14579
- 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 });
15124
+ if (row.kind === "todos") return /* @__PURE__ */ jsx18(TodosPanel, { todos: row.todos, wrapW });
15125
+ if (row.kind === "tool") return /* @__PURE__ */ jsx18(ToolCard, { toolName: row.toolName, args: row.args, result: row.result, ok: row.ok, status: row.status, progress: row.progress, wrapW });
15126
+ if (row.kind === "thinking") return /* @__PURE__ */ jsx18(ThinkingBlock, { streaming: row.streaming ?? false, startedAt: row.startedAt, durationMs: row.durationMs, tokens: row.tokens, text: row.text, expanded: showThinking, wrapW });
14580
15127
  if (row.kind === "user") {
14581
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
14582
- /* @__PURE__ */ jsx17(Text17, { color: THEME.grayDim, children: "\u2500".repeat(Math.max(8, wrapW)) }),
14583
- /* @__PURE__ */ jsx17(MessageBlock, { row, wrapW, streamTail })
15128
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginTop: 1, children: [
15129
+ /* @__PURE__ */ jsx18(Text18, { color: THEME.grayDim, children: "\u2500".repeat(Math.max(8, wrapW)) }),
15130
+ /* @__PURE__ */ jsx18(MessageBlock, { row, wrapW, streamTail })
14584
15131
  ] });
14585
15132
  }
14586
- return /* @__PURE__ */ jsx17(MessageBlock, { row, wrapW, streamTail });
15133
+ return /* @__PURE__ */ jsx18(MessageBlock, { row, wrapW, streamTail });
14587
15134
  };
14588
15135
  isDynamicRow = (r) => r.kind === "assistant" && !!r.streaming || r.kind === "thinking" && !!r.streaming || r.kind === "tool" && r.status === "running" || r.kind === "todos" && !!r.active;
14589
15136
  App = ({ resumeSessionId, initialPlanMode, initialAutoMode, initialIncludeProject, engineReady }) => {
@@ -14659,6 +15206,15 @@ var init_App = __esm({
14659
15206
  await refreshStatusLineRef.current();
14660
15207
  })();
14661
15208
  }, []);
15209
+ useEffect4(() => {
15210
+ void (async () => {
15211
+ const saved = await readModelPref();
15212
+ if (saved) {
15213
+ state.setModelOverride(saved);
15214
+ setModelDisplay(saved);
15215
+ }
15216
+ })();
15217
+ }, []);
14662
15218
  useEffect4(() => {
14663
15219
  void refreshStatusLineRef.current();
14664
15220
  }, [state.busy, state.aborting, modelDisplay]);
@@ -14685,6 +15241,8 @@ var init_App = __esm({
14685
15241
  return S.cmdAuto;
14686
15242
  case "model":
14687
15243
  return S.cmdModel;
15244
+ case "switch":
15245
+ return S.cmdSwitch;
14688
15246
  case "thinking":
14689
15247
  return S.cmdThinking;
14690
15248
  case "lang":
@@ -14727,17 +15285,23 @@ var init_App = __esm({
14727
15285
  const q = input.slice(1).toLowerCase();
14728
15286
  return menuEntries.filter((c) => c.name.toLowerCase().startsWith(q));
14729
15287
  }, [input, menuEntries]);
14730
- const menuActive = state.pendingApproval != null || state.pendingQuestion != null || state.pendingPlan != null || state.pendingSessions != null || state.pendingFork != null;
15288
+ const menuActive = state.pendingApproval != null || state.pendingQuestion != null || state.pendingPlan != null || state.pendingSessions != null || state.pendingFork != null || state.pendingModel != null;
14731
15289
  const slashVisible = !menuActive && input.startsWith("/") && filteredCommands.length > 0;
14732
15290
  const inputActive = !menuActive;
14733
15291
  useEffect4(() => {
14734
15292
  setSelectIdx(0);
14735
15293
  setPlanEditing(false);
14736
- }, [state.pendingApproval, state.pendingQuestion, state.pendingPlan, state.pendingSessions, state.pendingFork, slashVisible, filteredCommands.length]);
15294
+ }, [state.pendingApproval, state.pendingQuestion, state.pendingPlan, state.pendingSessions, state.pendingFork, state.pendingModel, slashVisible, filteredCommands.length]);
14737
15295
  useEffect4(() => {
14738
15296
  setQCursor(0);
14739
15297
  setQChecked(/* @__PURE__ */ new Set());
14740
15298
  }, [state.pendingQuestion]);
15299
+ useEffect4(() => {
15300
+ if (state.pendingModel) {
15301
+ const idx = state.pendingModel.models.indexOf(modelDisplay);
15302
+ setSelectIdx(idx >= 0 ? idx : 0);
15303
+ }
15304
+ }, [state.pendingModel]);
14741
15305
  const runLocalSlash = async (text) => {
14742
15306
  const [cmd, ...rest] = text.trim().split(/\s+/);
14743
15307
  const arg = rest.join(" ");
@@ -14814,13 +15378,15 @@ ${list}
14814
15378
  }
14815
15379
  case "/model":
14816
15380
  if (!arg) {
14817
- state.pushInfo(`\u5F53\u524D\u6A21\u578B\uFF1A${modelDisplay}
14818
- \u53EF\u9009\uFF1A${KNOWN_MODELS.join("\u3001")} \u6216\u4EFB\u610F\u6A21\u578B id\u3002`);
15381
+ state.pushInfo(S.modelUsage(modelDisplay));
14819
15382
  return true;
14820
15383
  }
14821
15384
  state.setModelOverride(arg);
14822
15385
  setModelDisplay(arg);
14823
- state.pushInfo(`\u6A21\u578B\u5DF2\u5207\u6362\uFF1A${arg}`);
15386
+ state.pushInfo(S.modelSwitched(arg));
15387
+ return true;
15388
+ case "/switch":
15389
+ void state.openModelPicker();
14824
15390
  return true;
14825
15391
  case "/thinking": {
14826
15392
  const lvl = arg.toLowerCase();
@@ -14909,7 +15475,7 @@ ${listText}`);
14909
15475
  const v = inputRef.current.trim();
14910
15476
  if (!v) return;
14911
15477
  if (busyRef.current) {
14912
- if (!v.startsWith("/") && state.queueInput(v)) {
15478
+ if (!v.startsWith("/") && !v.startsWith("!") && state.queueInput(v)) {
14913
15479
  setInput("");
14914
15480
  setCursor(0);
14915
15481
  } else {
@@ -14919,6 +15485,10 @@ ${listText}`);
14919
15485
  }
14920
15486
  setInput("");
14921
15487
  setCursor(0);
15488
+ if (v.startsWith("!")) {
15489
+ await state.runBangCommand(v);
15490
+ return;
15491
+ }
14922
15492
  if (v.startsWith("/")) {
14923
15493
  await executeSlash(v);
14924
15494
  return;
@@ -15007,6 +15577,16 @@ ${listText}`);
15007
15577
  } else if (key.escape || key.ctrl && ch === "g") state.resolveFork(null);
15008
15578
  return;
15009
15579
  }
15580
+ if (state.pendingModel) {
15581
+ const list = state.pendingModel.models;
15582
+ if (key.upArrow) setSelectIdx((i) => (i - 1 + list.length) % list.length);
15583
+ else if (key.downArrow) setSelectIdx((i) => (i + 1) % list.length);
15584
+ else if (key.return) {
15585
+ const sel = list[Math.min(selectIdxRef.current, list.length - 1)];
15586
+ state.resolveModel(sel ?? null);
15587
+ } else if (key.escape || key.ctrl && ch === "g") state.resolveModel(null);
15588
+ return;
15589
+ }
15010
15590
  if (key.ctrl && ch === "t") {
15011
15591
  state.toggleShowThinking();
15012
15592
  return;
@@ -15047,19 +15627,19 @@ ${listText}`);
15047
15627
  }
15048
15628
  });
15049
15629
  const sessionShort = state.sessionIdRef.current ? truncateMiddle(state.sessionIdRef.current, 12) : "";
15050
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: cols, children: [
15051
- /* @__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) }),
15052
- /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: cols, children: [
15053
- menuActive ? null : /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, children: [
15054
- dynamicRows.map((row) => /* @__PURE__ */ jsx17(RowView, { row, wrapW, streamTail, showThinking: state.showThinkingText }, row.id)),
15055
- state.busy ? /* @__PURE__ */ jsx17(Box15, { marginTop: 0.5, children: /* @__PURE__ */ jsxs15(Text17, { color: THEME.coralBright, children: [
15630
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", width: cols, children: [
15631
+ /* @__PURE__ */ jsx18(Static, { items: staticItems, children: (item) => item.kind === "__header" ? /* @__PURE__ */ jsx18(TopPanel, { cwd: CWD2, cols }, "header") : /* @__PURE__ */ jsx18(RowView, { row: item, wrapW, streamTail, showThinking: state.showThinkingText }, item.id) }),
15632
+ /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", width: cols, children: [
15633
+ menuActive ? null : /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", paddingX: 1, children: [
15634
+ dynamicRows.map((row) => /* @__PURE__ */ jsx18(RowView, { row, wrapW, streamTail, showThinking: state.showThinkingText }, row.id)),
15635
+ state.busy ? /* @__PURE__ */ jsx18(Box16, { marginTop: 0.5, children: /* @__PURE__ */ jsxs16(Text18, { color: THEME.coralBright, children: [
15056
15636
  "\u25CF ",
15057
15637
  S.generating
15058
15638
  ] }) }) : null
15059
15639
  ] }),
15060
- /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, flexShrink: 0, children: [
15061
- state.pendingApproval ? /* @__PURE__ */ jsx17(ApprovalModal, { toolName: state.pendingApproval.toolName, detail: state.pendingApproval.detail, selectedIndex: selectIdx, wrapW }) : null,
15062
- state.pendingQuestion ? /* @__PURE__ */ jsx17(
15640
+ /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", paddingX: 1, flexShrink: 0, children: [
15641
+ state.pendingApproval ? /* @__PURE__ */ jsx18(ApprovalModal, { toolName: state.pendingApproval.toolName, detail: state.pendingApproval.detail, selectedIndex: selectIdx, wrapW }) : null,
15642
+ state.pendingQuestion ? /* @__PURE__ */ jsx18(
15063
15643
  QuestionModal,
15064
15644
  {
15065
15645
  question: state.pendingQuestion.req.question,
@@ -15070,7 +15650,7 @@ ${listText}`);
15070
15650
  wrapW
15071
15651
  }
15072
15652
  ) : null,
15073
- state.pendingPlan ? planEditing ? /* @__PURE__ */ jsx17(
15653
+ state.pendingPlan ? planEditing ? /* @__PURE__ */ jsx18(
15074
15654
  PlanEditor,
15075
15655
  {
15076
15656
  value: planDraft,
@@ -15081,15 +15661,16 @@ ${listText}`);
15081
15661
  },
15082
15662
  onSubmit: confirmPlanEdit
15083
15663
  }
15084
- ) : /* @__PURE__ */ jsx17(PlanModal, { selectedIndex: selectIdx }) : null,
15085
- state.pendingSessions ? /* @__PURE__ */ jsx17(SessionPicker, { sessions: state.pendingSessions.sessions, selectedIndex: selectIdx, wrapW }) : null,
15086
- state.pendingFork ? /* @__PURE__ */ jsx17(ForkPicker, { anchors: state.pendingFork.anchors, selectedIndex: selectIdx, wrapW }) : null,
15087
- slashVisible ? /* @__PURE__ */ jsx17(SlashMenu, { entries: filteredCommands, selectedIndex: selectIdx, cols }) : null
15664
+ ) : /* @__PURE__ */ jsx18(PlanModal, { selectedIndex: selectIdx }) : null,
15665
+ state.pendingSessions ? /* @__PURE__ */ jsx18(SessionPicker, { sessions: state.pendingSessions.sessions, selectedIndex: selectIdx, wrapW }) : null,
15666
+ state.pendingFork ? /* @__PURE__ */ jsx18(ForkPicker, { anchors: state.pendingFork.anchors, selectedIndex: selectIdx, wrapW }) : null,
15667
+ state.pendingModel ? /* @__PURE__ */ jsx18(ModelPicker, { models: state.pendingModel.models, currentModel: modelDisplay, selectedIndex: selectIdx, wrapW }) : null,
15668
+ slashVisible ? /* @__PURE__ */ jsx18(SlashMenu, { entries: filteredCommands, selectedIndex: selectIdx, cols }) : null
15088
15669
  ] }),
15089
- /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", paddingX: 1, marginTop: 1, flexShrink: 0, children: (() => {
15670
+ /* @__PURE__ */ jsx18(Box16, { flexDirection: "column", paddingX: 1, marginTop: 1, flexShrink: 0, children: (() => {
15090
15671
  const planOn = state.getPlanMode();
15091
15672
  const autoOn = !planOn && state.getAutoMode();
15092
- const inputEl = /* @__PURE__ */ jsx17(
15673
+ const inputEl = /* @__PURE__ */ jsx18(
15093
15674
  MultilineInput,
15094
15675
  {
15095
15676
  value: input,
@@ -15107,17 +15688,17 @@ ${listText}`);
15107
15688
  }
15108
15689
  );
15109
15690
  if (planOn || autoOn) {
15110
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: planOn ? THEME.thinking : THEME.warn, paddingX: 1, children: [
15111
- /* @__PURE__ */ jsx17(Text17, { color: planOn ? THEME.thinking : THEME.warn, children: planOn ? S.inputBadgePlan : S.inputBadgeAuto }),
15691
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: planOn ? THEME.thinking : THEME.warn, paddingX: 1, children: [
15692
+ /* @__PURE__ */ jsx18(Text18, { color: planOn ? THEME.thinking : THEME.warn, children: planOn ? S.inputBadgePlan : S.inputBadgeAuto }),
15112
15693
  inputEl
15113
15694
  ] });
15114
15695
  }
15115
- return /* @__PURE__ */ jsxs15(Fragment3, { children: [
15116
- /* @__PURE__ */ jsx17(Text17, { dimColor: true, color: THEME.gray, children: dimRule(cols) }),
15696
+ return /* @__PURE__ */ jsxs16(Fragment3, { children: [
15697
+ /* @__PURE__ */ jsx18(Text18, { dimColor: true, color: THEME.gray, children: dimRule(cols) }),
15117
15698
  inputEl
15118
15699
  ] });
15119
15700
  })() }),
15120
- /* @__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 }) })
15701
+ /* @__PURE__ */ jsx18(Box16, { paddingX: 1, marginTop: 1, flexShrink: 0, children: /* @__PURE__ */ jsx18(StatusStrip, { model: modelDisplay, busy: state.busy, aborting: state.aborting, planMode: state.getPlanMode(), autoMode: state.getAutoMode(), sessionShort, cols, customLine: statusLineText }) })
15121
15702
  ] })
15122
15703
  ] });
15123
15704
  };
@@ -15177,7 +15758,7 @@ import { render } from "ink";
15177
15758
  import os5 from "os";
15178
15759
  import path42 from "path";
15179
15760
  import { emitKeypressEvents } from "node:readline";
15180
- import { jsx as jsx18 } from "react/jsx-runtime";
15761
+ import { jsx as jsx19 } from "react/jsx-runtime";
15181
15762
  var parseArgs = (argv) => {
15182
15763
  const out = {};
15183
15764
  for (let i = 0; i < argv.length; i++) {
@@ -15327,7 +15908,7 @@ var main = async () => {
15327
15908
  resumeId = await getMostRecentSessionId2() ?? void 0;
15328
15909
  }
15329
15910
  const { waitUntilExit } = render(
15330
- /* @__PURE__ */ jsx18(App2, { resumeSessionId: resumeId, initialPlanMode: args.plan, initialAutoMode: args.auto, initialIncludeProject: includeProject, engineReady }),
15911
+ /* @__PURE__ */ jsx19(App2, { resumeSessionId: resumeId, initialPlanMode: args.plan, initialAutoMode: args.auto, initialIncludeProject: includeProject, engineReady }),
15331
15912
  // exitOnCtrlC:false:Ctrl+C 交由 App useInput 处理(统一退出/中止语义);
15332
15913
  // patchConsole:false:避免 console 劫持与全屏重绘叠加闪屏。
15333
15914
  { exitOnCtrlC: false, patchConsole: false }