deepseeker-code 1.0.49 → 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 +839 -271
  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
 
@@ -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"]
@@ -5602,23 +5731,23 @@ ${treeResult}`;
5602
5731
  type: "function",
5603
5732
  function: {
5604
5733
  name: "edit_file",
5605
- 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",
5606
5735
  parameters: {
5607
5736
  type: "object",
5608
5737
  properties: {
5609
- path: { type: "string", description: "\u51C6\u5907\u4FEE\u6539\u7684\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84" },
5610
- 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" },
5611
- new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF09" },
5612
- 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" },
5613
5742
  edits: {
5614
5743
  type: "array",
5615
- 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",
5616
5745
  items: {
5617
5746
  type: "object",
5618
5747
  properties: {
5619
- old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757" },
5620
- new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757" },
5621
- 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" }
5622
5751
  },
5623
5752
  required: ["old_str", "new_str"]
5624
5753
  }
@@ -5784,7 +5913,7 @@ ${summaries.join("\n")}`;
5784
5913
  type: "function",
5785
5914
  function: {
5786
5915
  name: "write_file",
5787
- 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",
5788
5917
  parameters: {
5789
5918
  type: "object",
5790
5919
  properties: {
@@ -5970,14 +6099,14 @@ var init_search = __esm({
5970
6099
  type: "function",
5971
6100
  function: {
5972
6101
  name: "search_grep",
5973
- 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",
5974
6103
  parameters: {
5975
6104
  type: "object",
5976
6105
  properties: {
5977
- 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" },
5978
- 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" },
5979
- 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" },
5980
- 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" }
5981
6110
  },
5982
6111
  required: ["query"]
5983
6112
  },
@@ -6121,7 +6250,7 @@ ${content}`;
6121
6250
 
6122
6251
  // ../core/src/tool/registry/command.ts
6123
6252
  import { spawn as spawn4 } from "child_process";
6124
- 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;
6125
6254
  var init_command = __esm({
6126
6255
  "../core/src/tool/registry/command.ts"() {
6127
6256
  "use strict";
@@ -6132,6 +6261,8 @@ var init_command = __esm({
6132
6261
  EXIT_SENTINEL = (code) => `
6133
6262
  \u27E6DSC_EXIT:${code}\u27E7`;
6134
6263
  EXIT_SENTINEL_RE = /⟦DSC_EXIT:(-?\d+)⟧/g;
6264
+ AUTO_BG_NOTICE = "\u27E6DSC_BG\u27E7";
6265
+ AUTO_BG_SENTINEL_RE = /⟦DSC_BG⟧\s*$/;
6135
6266
  RUN_COMMAND_MAX_CHARS = 2e4;
6136
6267
  commandTools = [
6137
6268
  {
@@ -6156,8 +6287,13 @@ var init_command = __esm({
6156
6287
  // 💡 我们将在 execute 内部真正落地这个长度限制
6157
6288
  verifyResult: (rawOutput) => {
6158
6289
  const matches2 = [...rawOutput.matchAll(EXIT_SENTINEL_RE)];
6159
- 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;
6160
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
+ }
6161
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" : "";
6162
6298
  return { status: "failed" /* FAILED */, summary: `\u547D\u4EE4\u9000\u51FA\u7801\u975E\u96F6\uFF1A${code}${hint}` };
6163
6299
  },
@@ -6346,6 +6482,7 @@ ${tail}`,
6346
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
6347
6483
  task_id: ${taskId}
6348
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}
6349
6486
  `;
6350
6487
  } else if (overLimit) {
6351
6488
  yield EXIT_SENTINEL(-1);
@@ -7267,9 +7404,9 @@ var init_http = __esm({
7267
7404
  function: {
7268
7405
  name: "http_request",
7269
7406
  description: [
7270
- "\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",
7271
- "\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",
7272
- "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"
7273
7410
  ].join(" "),
7274
7411
  parameters: {
7275
7412
  type: "object",
@@ -7365,7 +7502,7 @@ var init_http = __esm({
7365
7502
  // ../core/src/tool/registry/typescript.ts
7366
7503
  import fs16 from "fs/promises";
7367
7504
  import path20 from "path";
7368
- 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;
7369
7506
  var init_typescript = __esm({
7370
7507
  "../core/src/tool/registry/typescript.ts"() {
7371
7508
  "use strict";
@@ -7379,6 +7516,7 @@ var init_typescript = __esm({
7379
7516
  if (rel && !rel.startsWith("..") && !path20.isAbsolute(rel)) return rel.replace(/\\/g, "/");
7380
7517
  return abs.replace(/\\/g, "/").split("/").slice(-3).join("/");
7381
7518
  };
7519
+ isLibFile = (abs) => /(?:^|\/)node_modules\//.test(abs.replace(/\\/g, "/")) || /\.d\.ts$/i.test(abs);
7382
7520
  precheck = async (displayPath, absPath) => {
7383
7521
  const readBlock = await assertReadable(absPath, displayPath);
7384
7522
  if (readBlock) return readBlock;
@@ -7392,6 +7530,8 @@ var init_typescript = __esm({
7392
7530
  };
7393
7531
  MAX_DIAG_ENTRIES = 300;
7394
7532
  MAX_DIAG_FILES = 20;
7533
+ MAX_REF_ENTRIES = 200;
7534
+ REF_SNIPPET_MAX = 160;
7395
7535
  diagnoseOneFile = async (TS, displayPath, checkJs) => {
7396
7536
  try {
7397
7537
  const absPath = realpathNative(resolveReadablePath(displayPath));
@@ -7446,7 +7586,7 @@ ${body}${tail}` };
7446
7586
  type: "function",
7447
7587
  function: {
7448
7588
  name: "get_diagnostics",
7449
- 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\uFF0C\u5176\u4F59\u6269\u5C55\u540D\uFF08.java/.py/.go \u7B49\uFF09\u76F4\u63A5\u62D2\u7EDD\u3001\u52FF\u4F20\u5165\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",
7450
7590
  parameters: {
7451
7591
  type: "object",
7452
7592
  properties: {
@@ -7501,7 +7641,7 @@ ${sections.join("\n\n")}`;
7501
7641
  type: "function",
7502
7642
  function: {
7503
7643
  name: "goto_definition",
7504
- 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\uFF0C\u5176\u4F59\u6269\u5C55\u540D\uFF08.java/.py/.go \u7B49\uFF09\u76F4\u63A5\u62D2\u7EDD\u3001\u52FF\u4F20\u5165\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",
7505
7645
  parameters: {
7506
7646
  type: "object",
7507
7647
  properties: {
@@ -7541,7 +7681,7 @@ ${sections.join("\n\n")}`;
7541
7681
  const lc = posToLineCol(TS, defSf, def.textSpan.start);
7542
7682
  loc = `${toDisplayPath(wsRoot, def.fileName)}:${lc.line}:${lc.column}`;
7543
7683
  }
7544
- const isLib = /(?:^|\/)node_modules\//.test(def.fileName.replace(/\\/g, "/")) || /\.d\.ts$/i.test(def.fileName);
7684
+ const isLib = isLibFile(def.fileName);
7545
7685
  const name = def.name || "(anonymous)";
7546
7686
  const kind = def.kind ? ` [${def.kind}]` : "";
7547
7687
  return `${name}${kind} \u2192 ${loc}${isLib ? " (declaration/library)" : ""}`;
@@ -7553,6 +7693,97 @@ ${out.join("\n")}`;
7553
7693
  }
7554
7694
  }
7555
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
+ }
7556
7787
  }
7557
7788
  ];
7558
7789
  }
@@ -8528,10 +8759,9 @@ var init_ask = __esm({
8528
8759
  function: {
8529
8760
  name: "ask_question",
8530
8761
  description: [
8531
- "\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",
8532
- "\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",
8533
- "\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",
8534
- "\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"
8535
8765
  ].join("\n"),
8536
8766
  parameters: {
8537
8767
  type: "object",
@@ -8974,30 +9204,30 @@ ${body.trim()}
8974
9204
  type: "function",
8975
9205
  function: {
8976
9206
  name: "memory_save",
8977
- 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",
8978
9208
  parameters: {
8979
9209
  type: "object",
8980
9210
  properties: {
8981
9211
  name: {
8982
9212
  type: "string",
8983
- 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"
8984
9214
  },
8985
9215
  description: {
8986
9216
  type: "string",
8987
- 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"
8988
9218
  },
8989
9219
  body: {
8990
9220
  type: "string",
8991
- 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"
8992
9222
  },
8993
9223
  type: {
8994
9224
  type: "string",
8995
9225
  enum: ["user", "feedback", "project", "reference"],
8996
- 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"
8997
9227
  },
8998
9228
  project: {
8999
9229
  type: "boolean",
9000
- 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"
9001
9231
  }
9002
9232
  },
9003
9233
  required: ["name", "description", "body"]
@@ -9150,7 +9380,7 @@ var init_recall = __esm({
9150
9380
  type: "function",
9151
9381
  function: {
9152
9382
  name: "recall",
9153
- 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",
9154
9384
  parameters: {
9155
9385
  type: "object",
9156
9386
  properties: {
@@ -9630,7 +9860,8 @@ async function runBackgroundTool(gen, lockKey, toolName, signal) {
9630
9860
  if (lockKey && !acquireLock(lockKey)) {
9631
9861
  try {
9632
9862
  await gen.return(void 0);
9633
- } 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);
9634
9865
  }
9635
9866
  return `\u{1F512} [\u4E92\u65A5\u9501\u963B\u585E]\uFF1A\u9501 [${lockKey}] \u5DF2\u88AB\u5360\u7528\uFF0C[${toolName}] \u672A\u542F\u52A8\u3002`;
9636
9867
  }
@@ -9681,7 +9912,7 @@ var init_backgroundTool = __esm({
9681
9912
 
9682
9913
  // ../core/src/tool/autoPermission.ts
9683
9914
  import path30 from "path";
9684
- 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;
9685
9916
  var init_autoPermission = __esm({
9686
9917
  "../core/src/tool/autoPermission.ts"() {
9687
9918
  "use strict";
@@ -9788,12 +10019,25 @@ var init_autoPermission = __esm({
9788
10019
  // —— 版本号 ——
9789
10020
  /^(node|npm|pnpm|npx|git|tsc|python|python3)\s+(-v|-V|--version)\b/,
9790
10021
  // —— 验证类(跑项目代码但不改源码)——
9791
- /^npm test\b/,
9792
- /^npm run (test|lint|typecheck|type-check)\b/,
9793
- /^pnpm (test|lint|typecheck)\b/,
9794
- /^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 门)。
9795
10026
  /^tsc --noEmit\b/
9796
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
+ };
9797
10041
  hasWriteModifier = (cmd) => {
9798
10042
  if (!cmd) return false;
9799
10043
  if (/^sed\b/.test(cmd) && /(^|\s)-i\b/.test(cmd)) return true;
@@ -9950,7 +10194,7 @@ var init_toolExecution = __esm({
9950
10194
  preHooksAdvanced = true;
9951
10195
  let veto;
9952
10196
  try {
9953
- veto = await runPreHooks(calledName, calledArgs, toolCtx);
10197
+ veto = await runPreHooks(resolveMcpPermissionName(calledName, calledArgs), calledArgs, toolCtx);
9954
10198
  } catch (e) {
9955
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` };
9956
10200
  }
@@ -9982,7 +10226,20 @@ var init_toolExecution = __esm({
9982
10226
  } catch {
9983
10227
  perm = null;
9984
10228
  }
9985
- 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 : "")) {
9986
10243
  needApproval = false;
9987
10244
  }
9988
10245
  if ((calledName === "run_command" || calledName === "run_in_background") && matchCommandDeny(typeof calledArgs?.command === "string" ? calledArgs.command : "")) {
@@ -9995,7 +10252,7 @@ var init_toolExecution = __esm({
9995
10252
  denied = true;
9996
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`;
9997
10254
  }
9998
- if (needApproval && !denied) {
10255
+ if (needApproval && !denied && !scriptRunnerBlocked) {
9999
10256
  const auto = await runAutoCheck(resolveMcpPermissionName(calledName, calledArgs), calledArgs, toolCtx, permissionMode === "auto");
10000
10257
  if (auto === "allow") {
10001
10258
  needApproval = false;
@@ -10030,7 +10287,7 @@ var init_toolExecution = __esm({
10030
10287
  if (!denied && !preHooksAdvanced) {
10031
10288
  let veto;
10032
10289
  try {
10033
- veto = await runPreHooks(calledName, calledArgs, toolCtx);
10290
+ veto = await runPreHooks(resolveMcpPermissionName(calledName, calledArgs), calledArgs, toolCtx);
10034
10291
  } catch (e) {
10035
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` };
10036
10293
  }
@@ -10072,7 +10329,7 @@ ${result}`;
10072
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 } });
10073
10330
  }
10074
10331
  try {
10075
- const post = await runPostHooks(calledName, calledArgs, result, toolCtx);
10332
+ const post = await runPostHooks(resolveMcpPermissionName(calledName, calledArgs), calledArgs, result, toolCtx);
10076
10333
  postHookOverride = post?.resultOverride;
10077
10334
  } catch (e) {
10078
10335
  console.warn(`\u26A0\uFE0F post-hook [${calledName}] \u5F02\u5E38\uFF08\u5DF2\u5FFD\u7565\uFF09:`, e?.message ?? e);
@@ -10232,7 +10489,8 @@ var init_toolScheduling = __esm({
10232
10489
  });
10233
10490
 
10234
10491
  // ../core/src/agent/streamInference.ts
10235
- var streamInference;
10492
+ import { createHash as createHash2 } from "node:crypto";
10493
+ var sha1short, RETRY_BACKOFF_CAP_MS, extractRetryAfterMs, withNudgeTail, streamInference;
10236
10494
  var init_streamInference = __esm({
10237
10495
  "../core/src/agent/streamInference.ts"() {
10238
10496
  "use strict";
@@ -10241,6 +10499,32 @@ var init_streamInference = __esm({
10241
10499
  init_transcript();
10242
10500
  init_contextCore();
10243
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
+ };
10244
10528
  streamInference = async function* (ctx) {
10245
10529
  const {
10246
10530
  message,
@@ -10258,16 +10542,24 @@ var init_streamInference = __esm({
10258
10542
  events,
10259
10543
  keepRecentUnits,
10260
10544
  compactRatio,
10261
- modelWindow
10545
+ modelWindow,
10546
+ toolsTokens = 0
10262
10547
  } = ctx;
10263
- let inferenceMessages = nudgeMsg ? [...message, nudgeMsg] : message;
10548
+ let inferenceMessages = withNudgeTail(message, nudgeMsg);
10264
10549
  let assistantMessage = { role: "assistant", content: null };
10265
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
+ };
10266
10557
  events({
10267
10558
  sessionId,
10268
10559
  eventType: "llm.request",
10269
- metadata: { depth, decisionSource: userDecisionSource, ok: true, durationMs: performance.now() - startTime, round },
10270
- 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 },
10271
10563
  payload: { input: msgText(message[message.length - 1].content) }
10272
10564
  // ★ 多模态:trace 只记文本视图
10273
10565
  });
@@ -10277,7 +10569,7 @@ var init_streamInference = __esm({
10277
10569
  const toolCallsBuf = /* @__PURE__ */ new Map();
10278
10570
  let lastUsage;
10279
10571
  const MAX_STREAM_RETRIES = 2;
10280
- const MAX_API_RETRIES = 2;
10572
+ const MAX_API_RETRIES = 3;
10281
10573
  let apiRetries = 0;
10282
10574
  let compactedThisRound = false;
10283
10575
  for (let streamAttempt = 0; ; streamAttempt++) {
@@ -10337,10 +10629,15 @@ var init_streamInference = __esm({
10337
10629
  }
10338
10630
  if (activeProvider.isTransientError(streamErr) && apiRetries < MAX_API_RETRIES && !signal?.aborted) {
10339
10631
  apiRetries++;
10340
- 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
+ );
10341
10637
  if (!noOutputYet) yield { type: "text.reset" };
10342
10638
  const statusHint = streamErr?.status ? `${streamErr.status} ` : "";
10343
- 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}...`);
10344
10641
  await new Promise((resolve, reject) => {
10345
10642
  const t = setTimeout(resolve, backoffMs);
10346
10643
  signal?.addEventListener("abort", () => {
@@ -10364,9 +10661,10 @@ var init_streamInference = __esm({
10364
10661
  modelWindow,
10365
10662
  events,
10366
10663
  depth,
10367
- signal
10664
+ signal,
10665
+ toolsTokens
10368
10666
  });
10369
- inferenceMessages = nudgeMsg ? [...message, nudgeMsg] : message;
10667
+ inferenceMessages = withNudgeTail(message, nudgeMsg);
10370
10668
  compactedThisRound = true;
10371
10669
  contentBuf = "";
10372
10670
  reasoningBuf = "";
@@ -10447,12 +10745,12 @@ var init_agentNudges = __esm({
10447
10745
  GREP_REPEAT_THRESHOLD = 2;
10448
10746
  REPEAT_NUDGE_MAX = 3;
10449
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";
10450
- 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`;
10451
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";
10452
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`;
10453
- COMPLEX_VERBS = /实现|新增|添加|重构|改造|迁移|重写|拆分|升级|开发|编写|构建|集成|支持|完善/;
10454
- COMPLEX_OBJECTS = /功能|模块|系统|架构|流程|机制|组件|服务|页面|接口|能力|特性|面板/;
10455
- 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;
10456
10754
  QUERY_LEAD = /^(请)?\s*(解释|说明|查(一下|询)?|搜索|搜一下|怎么看|如何(用|使用|配置|启动)|怎么用|为什么|是什么|帮我看看|分析一下|检查|review|对比|评价)/i;
10457
10755
  looksComplex = (text) => {
10458
10756
  const t = (text || "").trim();
@@ -10480,7 +10778,7 @@ var init_agentNudges = __esm({
10480
10778
  return s;
10481
10779
  };
10482
10780
  normQuery = (q) => String(q ?? "").trim().toLowerCase().replace(/\s+/g, " ");
10483
- 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`;
10484
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`;
10485
10783
  createNudgeScheduler = (opts = {}) => {
10486
10784
  const firstPrompt = opts.firstPrompt ?? "";
@@ -10548,7 +10846,7 @@ ${TOOL_DIGEST_TEXT}` };
10548
10846
  ${PHANTOM_TEXT}` };
10549
10847
  return true;
10550
10848
  }
10551
- 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)) {
10552
10850
  earlyFinalNudges++;
10553
10851
  earlyFinalPending = { role: "system", content: `${EARLY_FINAL_FENCE}
10554
10852
  ${EARLY_FINAL_TEXT(round)}` };
@@ -10608,10 +10906,11 @@ ${REPEAT_GREP_TEXT(q, n)}` };
10608
10906
  // ../core/src/agent/runAgent.ts
10609
10907
  async function* runAgent(message, options) {
10610
10908
  const sessionId = options.sessionId;
10909
+ const runId = createUUID();
10611
10910
  const rawEvents = options.events;
10612
10911
  const events = async (base) => {
10613
10912
  try {
10614
- await rawEvents(base);
10913
+ await rawEvents({ ...base, metadata: { ...base.metadata, runId } });
10615
10914
  } catch (e) {
10616
10915
  console.warn("\u26A0\uFE0F \u57CB\u70B9\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u63A8\u7406\uFF09:", e instanceof Error ? e.message : e);
10617
10916
  }
@@ -10623,7 +10922,7 @@ async function* runAgent(message, options) {
10623
10922
  const keepRecentUnits = options.keepRecentUnits;
10624
10923
  const compactRatio = options.compactRatio;
10625
10924
  const parentSystemPrompt = options.parentSystemPrompt;
10626
- const { rawTools, cleanedToolSchemas } = await prepareToolsAndInjections(message, options, events);
10925
+ const { rawTools, cleanedToolSchemas, toolsTokens } = await prepareToolsAndInjections(message, options, events);
10627
10926
  let round = 0;
10628
10927
  let lastContent = "";
10629
10928
  let stopReason = "normal";
@@ -10642,7 +10941,6 @@ async function* runAgent(message, options) {
10642
10941
  let lastRealPromptTokens = persistedCalib.lastRealPromptTokens;
10643
10942
  let lastCachedTokens = persistedCalib.lastCachedTokens;
10644
10943
  const breaker = createRepeatBreaker({ sessionId, depth, llmDecisionSource, startTime, events });
10645
- const runId = createUUID();
10646
10944
  let usageSum;
10647
10945
  const addUsage = (u) => {
10648
10946
  if (!u) return;
@@ -10703,7 +11001,8 @@ async function* runAgent(message, options) {
10703
11001
  signal,
10704
11002
  correctionRatio: calibRatio,
10705
11003
  lastRealPromptTokens,
10706
- lastCachedTokens
11004
+ lastCachedTokens,
11005
+ toolsTokens
10707
11006
  }
10708
11007
  );
10709
11008
  } catch (e) {
@@ -10735,7 +11034,8 @@ async function* runAgent(message, options) {
10735
11034
  events,
10736
11035
  keepRecentUnits,
10737
11036
  compactRatio,
10738
- modelWindow
11037
+ modelWindow,
11038
+ toolsTokens
10739
11039
  });
10740
11040
  if (infResult.kind === "aborted") {
10741
11041
  yield { type: "final", text: infResult.partialText || lastContent || "\uFF08\u5DF2\u4E2D\u6B62\uFF09" };
@@ -10747,7 +11047,7 @@ async function* runAgent(message, options) {
10747
11047
  return;
10748
11048
  }
10749
11049
  if (infResult.usage?.prompt_tokens) {
10750
- const estAtInfer = estimateTokens(message);
11050
+ const estAtInfer = estimateTokens(message) + toolsTokens;
10751
11051
  if (estAtInfer > 1e3) {
10752
11052
  const observed = infResult.usage.prompt_tokens / estAtInfer;
10753
11053
  calibRatio = calibRatio * 0.6 + observed * 0.4;
@@ -10837,11 +11137,13 @@ async function* runAgent(message, options) {
10837
11137
  try {
10838
11138
  const reason = signal?.aborted ? "aborted" : stopReason;
10839
11139
  await dispatch("Stop", { sessionId, cwd, lastText: lastContent || "", reason });
10840
- } 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);
10841
11142
  }
10842
11143
  try {
10843
11144
  await updateCalibration(sessionId, { calibRatio, lastRealPromptTokens, lastCachedTokens });
10844
- } 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);
10845
11147
  }
10846
11148
  }
10847
11149
  }
@@ -10984,9 +11286,9 @@ var init_content = __esm({
10984
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]");
10985
11287
  });
10986
11288
  };
10987
- 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]";
10988
- enforceVisionGate = (msgs) => isVisionEnabled() ? msgs : msgs.map((m) => collapseToText(m, NO_VISION_IMAGE_NOTE));
10989
- 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) => {
10990
11292
  const lines = await readTranscriptLines(sessionId);
10991
11293
  const store = await getRollingState(sessionId);
10992
11294
  const eventAware = appConfig.transcriptEvents || lines.some(isEventLine);
@@ -11005,12 +11307,12 @@ var init_content = __esm({
11005
11307
  const messageAll = all.slice(archivedMessageCount);
11006
11308
  if (messageAll.length === 0) {
11007
11309
  result.push(currentUserMsg);
11008
- return enforceVisionGate(result);
11310
+ return enforceVisionGate(result, modelId);
11009
11311
  }
11010
11312
  const repair = repairOrphanToolCalls(messageAll, recovery.interruption.kind === "crashed");
11011
11313
  result.push(...decayOldToolResults(repair.msgs));
11012
11314
  result.push(currentUserMsg);
11013
- return enforceVisionGate(result);
11315
+ return enforceVisionGate(result, modelId);
11014
11316
  };
11015
11317
  }
11016
11318
  });
@@ -11171,7 +11473,7 @@ var init_subagent = __esm({
11171
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)}..."`);
11172
11474
  activeSubagents.add(subSessionId);
11173
11475
  try {
11174
- const subMessages = await buildContextMessages(subSessionId, { role: "user", content: task }, subSystem);
11476
+ const subMessages = await buildContextMessages(subSessionId, { role: "user", content: task }, subSystem, manifest?.model);
11175
11477
  await appendMessage({ sessionId: subSessionId, role: "user", content: task });
11176
11478
  let subResult = "";
11177
11479
  let hasFinalResult = false;
@@ -11348,7 +11650,7 @@ var init_loader4 = __esm({
11348
11650
  console.warn(`\u26A0\uFE0F [hooks] ${where} \u975E\u5DE5\u5177\u4E8B\u4EF6\u4E0D\u652F\u6301 matcher\uFF0C\u5DF2\u5FFD\u7565`);
11349
11651
  }
11350
11652
  const matcher = TOOL_EVENTS.has(event) && typeof raw.matcher === "string" ? raw.matcher : void 0;
11351
- 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;
11352
11654
  let denyOnNonZero = typeof raw.denyOnNonZero === "boolean" ? raw.denyOnNonZero : void 0;
11353
11655
  if (denyOnNonZero === true && !INTERCEPTABLE_EVENTS.has(event)) {
11354
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`);
@@ -11376,7 +11678,7 @@ var init_loader4 = __esm({
11376
11678
  text: type === "prompt" && typeof raw.text === "string" ? raw.text : void 0,
11377
11679
  task: type === "agent" && typeof raw.task === "string" ? raw.task : void 0,
11378
11680
  matcher,
11379
- timeoutMs,
11681
+ timeoutMs: timeoutMs2,
11380
11682
  denyOnNonZero,
11381
11683
  onError,
11382
11684
  requireApproval: raw.requireApproval === true ? true : void 0
@@ -11419,7 +11721,7 @@ var init_loader4 = __esm({
11419
11721
  };
11420
11722
  compileRule2 = (event, raw) => {
11421
11723
  const denyOnNonZero = raw.denyOnNonZero ?? event === "PreToolUse";
11422
- const timeoutMs = raw.timeoutMs ?? DEFAULT_TIMEOUT_BY_EVENT[event];
11724
+ const timeoutMs2 = raw.timeoutMs ?? DEFAULT_TIMEOUT_BY_EVENT[event];
11423
11725
  const base = { event, matcher: raw.matcher, source: "config", onError: raw.onError };
11424
11726
  if (raw.type === "prompt") {
11425
11727
  const text = raw.text;
@@ -11464,7 +11766,7 @@ var init_loader4 = __esm({
11464
11766
  headers: raw.headers,
11465
11767
  body: ctx,
11466
11768
  // 整个 hook 上下文 JSON 化发出(含 sessionId/toolName/args/prompt 等)
11467
- timeoutMs
11769
+ timeoutMs: timeoutMs2
11468
11770
  });
11469
11771
  if (!res.ok) {
11470
11772
  return denyOnNonZero ? { deny: true, reason: `hook http \u8BF7\u6C42\u5931\u8D25\uFF1A${res.error}` } : { deny: false };
@@ -11498,11 +11800,11 @@ var init_loader4 = __esm({
11498
11800
  command,
11499
11801
  cwd: ctx?.cwd,
11500
11802
  env: ctx?.env,
11501
- timeoutMs,
11803
+ timeoutMs: timeoutMs2,
11502
11804
  stdinPayload: ctx
11503
11805
  });
11504
11806
  if (res.timedOut) {
11505
- 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 };
11506
11808
  }
11507
11809
  if (denyOnNonZero && res.exitCode !== 0) {
11508
11810
  const detail = res.stderr ? `\uFF1A${res.stderr.slice(0, 200)}` : "";
@@ -11524,9 +11826,7 @@ var init_loader4 = __esm({
11524
11826
  if (!list || list.length === 0) continue;
11525
11827
  for (const raw of list) compiled.push(compileRule2(event, raw));
11526
11828
  }
11527
- if (compiled.length > 0) {
11528
- registerHooks(compiled);
11529
- }
11829
+ replaceDeclarativeHooks(compiled);
11530
11830
  return compiled.length;
11531
11831
  };
11532
11832
  initHooks = async (includeProject) => {
@@ -12103,14 +12403,6 @@ var init_runner = __esm({
12103
12403
  }
12104
12404
  });
12105
12405
 
12106
- // ../core/src/llm/createModel.ts
12107
- var init_createModel = __esm({
12108
- "../core/src/llm/createModel.ts"() {
12109
- "use strict";
12110
- init_client();
12111
- }
12112
- });
12113
-
12114
12406
  // ../core/src/observability/store.ts
12115
12407
  import path39 from "path";
12116
12408
  import fs37 from "fs/promises";
@@ -12427,11 +12719,12 @@ var init_systemPrompt = __esm({
12427
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
12428
12720
 
12429
12721
  \u3010\u56DE\u7B54\u51C6\u5219 / \u5B8C\u6210\u5224\u5B9A\u3011
12430
- - \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
12431
- - **"\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
12432
- - \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
12433
- - **\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
12434
- - **\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
12435
12728
 
12436
12729
  \u3010\u5DE5\u5177\u4F7F\u7528\u51C6\u5219\u3011
12437
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
@@ -12532,18 +12825,29 @@ ${lines.join("\n")}
12532
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
12533
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`;
12534
12827
  }
12535
- let replyText = "";
12536
- let userContent = inbound.content;
12537
- if (Array.isArray(inbound.attachments) && inbound.attachments.length > 0) {
12538
- 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 + `
12539
12839
 
12540
- \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`;
12541
- }
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);
12542
12844
  try {
12543
12845
  const fullMessages = await buildContextMessages(
12544
12846
  sessionId,
12545
12847
  { role: "user", content: userContent },
12546
- sysPrompt
12848
+ sysPrompt,
12849
+ opts?.model
12850
+ // ★ vision 自动判定与实际请求模型(opts.model ?? MODEL_NAME)同源
12547
12851
  );
12548
12852
  await emitTrace({
12549
12853
  sessionId,
@@ -12555,7 +12859,7 @@ ${lines.join("\n")}
12555
12859
  });
12556
12860
  void sweepStaleAtomicTmp().catch(() => {
12557
12861
  });
12558
- await appendMessage({ sessionId, role: "user", content: userContent });
12862
+ await appendMessage({ sessionId, role: "user", content: archiveContent });
12559
12863
  let streamedAnyText = false;
12560
12864
  const onUIEvent = opts?.onUIEvent ?? ((evt) => sseWrite?.(evt));
12561
12865
  const requestApproval2 = opts?.requestApproval ?? createWebRequestApproval((evt) => sseWrite?.(evt), abortSignal);
@@ -12744,6 +13048,75 @@ var init_fork = __esm({
12744
13048
  }
12745
13049
  });
12746
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
+
12747
13120
  // src/cliHost.ts
12748
13121
  var createCliRequestApproval, createCliRequestQuestion;
12749
13122
  var init_cliHost = __esm({
@@ -12938,9 +13311,12 @@ var init_useChatState = __esm({
12938
13311
  init_fork();
12939
13312
  init_inbox();
12940
13313
  init_contextCore();
13314
+ init_bashDirect();
13315
+ init_guard();
12941
13316
  init_createModel();
12942
13317
  init_tool();
12943
13318
  init_cliHost();
13319
+ init_prefs();
12944
13320
  init_strings();
12945
13321
  init_util();
12946
13322
  init_replay2();
@@ -12962,6 +13338,7 @@ var init_useChatState = __esm({
12962
13338
  const [pendingPlan, setPendingPlan] = useState(null);
12963
13339
  const [pendingSessions, setPendingSessions] = useState(null);
12964
13340
  const [pendingFork, setPendingFork] = useState(null);
13341
+ const [pendingModel, setPendingModel] = useState(null);
12965
13342
  const nextId = useRef(1);
12966
13343
  const assistantStreamingId = useRef(null);
12967
13344
  const thinkingStreamingId = useRef(null);
@@ -13333,6 +13710,22 @@ ${finalPlan}`, false, res.autoExecute);
13333
13710
  if (turnGenRef.current === myGen) setBusy(false);
13334
13711
  }
13335
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]);
13336
13729
  const abortCurrent = useCallback(() => {
13337
13730
  const ac = currentAcRef.current;
13338
13731
  if (!ac) return;
@@ -13416,7 +13809,21 @@ ${finalPlan}`, false, res.autoExecute);
13416
13809
  }, [pushInfo, loadSession]);
13417
13810
  const setModelOverride = useCallback((m) => {
13418
13811
  modelRef.current = m;
13812
+ void writePrefs({ model: m });
13813
+ }, []);
13814
+ const resolveModel = useCallback((model2) => {
13815
+ setPendingModel((prev) => {
13816
+ prev?.resolve(model2);
13817
+ return null;
13818
+ });
13419
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]);
13420
13827
  const setPlanMode = useCallback((on) => {
13421
13828
  planModeRef.current = on;
13422
13829
  }, []);
@@ -13444,6 +13851,7 @@ ${finalPlan}`, false, res.autoExecute);
13444
13851
  pendingPlan,
13445
13852
  pendingSessions,
13446
13853
  pendingFork,
13854
+ pendingModel,
13447
13855
  sessionIdRef,
13448
13856
  // 动作
13449
13857
  submit,
@@ -13452,6 +13860,7 @@ ${finalPlan}`, false, res.autoExecute);
13452
13860
  pushUser,
13453
13861
  pushInfo,
13454
13862
  pushEvent,
13863
+ runBangCommand,
13455
13864
  askApproval,
13456
13865
  resolveApproval,
13457
13866
  resolveQuestion,
@@ -13472,7 +13881,9 @@ ${finalPlan}`, false, res.autoExecute);
13472
13881
  resolveSession,
13473
13882
  loadSession,
13474
13883
  openForkPicker,
13475
- resolveFork
13884
+ resolveFork,
13885
+ openModelPicker,
13886
+ resolveModel
13476
13887
  };
13477
13888
  };
13478
13889
  }
@@ -13561,7 +13972,7 @@ var init_StreamingCursor = __esm({
13561
13972
  // src/components/MessageBlock.tsx
13562
13973
  import { Box, Text as Text3 } from "ink";
13563
13974
  import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
13564
- var UsageFooter, listPrefix, AssistantLine, MessageBlock;
13975
+ var UsageFooter, listPrefix, AssistantLine, isFenceMark, isMdRow, isMdSep, mdCells, parseBlocks, fitCell, tableWidths, buildVLines, AssistantVLine, MessageBlock;
13565
13976
  var init_MessageBlock = __esm({
13566
13977
  "src/components/MessageBlock.tsx"() {
13567
13978
  "use strict";
@@ -13600,6 +14011,94 @@ var init_MessageBlock = __esm({
13600
14011
  }
13601
14012
  return /* @__PURE__ */ jsx3(RichText, { text: line });
13602
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
+ };
13603
14102
  MessageBlock = ({ row, wrapW, streamTail }) => {
13604
14103
  if (row.kind === "meta") {
13605
14104
  if (/^第 \d+ 轮$/.test(row.text)) {
@@ -13616,15 +14115,15 @@ var init_MessageBlock = __esm({
13616
14115
  ] }) });
13617
14116
  }
13618
14117
  if (row.kind === "info") {
13619
- const lines2 = wrapText(row.text, Math.max(8, wrapW));
13620
- 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: [
13621
14120
  j === 0 ? "\u203A " : " ",
13622
14121
  line
13623
14122
  ] }, j)) });
13624
14123
  }
13625
14124
  if (row.kind === "user") {
13626
- const lines2 = wrapText(row.text, Math.max(8, wrapW - 2));
13627
- 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: [
13628
14127
  /* @__PURE__ */ jsx3(Text3, { color: THEME.coralBright, bold: true, children: "> " }),
13629
14128
  /* @__PURE__ */ jsx3(Text3, { color: THEME.white, children: line })
13630
14129
  ] }) : /* @__PURE__ */ jsxs(Text3, { color: THEME.white, children: [
@@ -13633,19 +14132,19 @@ var init_MessageBlock = __esm({
13633
14132
  ] }) }, j)) });
13634
14133
  }
13635
14134
  if (row.kind === "system") {
13636
- const lines2 = wrapText(row.text, Math.max(8, wrapW - 2));
13637
- 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: [
13638
14137
  j === 0 ? "! " : " ",
13639
14138
  line
13640
14139
  ] }, j)) });
13641
14140
  }
13642
14141
  const contentW = Math.max(8, wrapW - 2);
13643
- const allLines = wrapText(row.text, contentW);
13644
- let lines = allLines;
14142
+ const allLines = buildVLines(row.text, contentW);
14143
+ let vlines = allLines;
13645
14144
  let folded = 0;
13646
14145
  if (row.streaming && streamTail && allLines.length > streamTail) {
13647
14146
  folded = allLines.length - streamTail;
13648
- lines = allLines.slice(folded);
14147
+ vlines = allLines.slice(folded);
13649
14148
  }
13650
14149
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: [
13651
14150
  folded > 0 ? /* @__PURE__ */ jsxs(Text3, { color: THEME.grayDim, children: [
@@ -13653,11 +14152,11 @@ var init_MessageBlock = __esm({
13653
14152
  folded,
13654
14153
  " \u884C\u2026"
13655
14154
  ] }) : null,
13656
- lines.map((line, j) => {
13657
- const isLast = j === lines.length - 1;
14155
+ vlines.map((v, j) => {
14156
+ const isLast = j === vlines.length - 1;
13658
14157
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
13659
14158
  /* @__PURE__ */ jsx3(Text3, { bold: true, color: THEME.coralBright, children: j === 0 ? "\u25CF " : " " }),
13660
- /* @__PURE__ */ jsx3(AssistantLine, { line }),
14159
+ /* @__PURE__ */ jsx3(AssistantVLine, { v }),
13661
14160
  isLast && row.streaming ? /* @__PURE__ */ jsx3(StreamingCursor, {}) : null
13662
14161
  ] }, j);
13663
14162
  }),
@@ -14281,9 +14780,44 @@ var init_ForkPicker = __esm({
14281
14780
  }
14282
14781
  });
14283
14782
 
14284
- // src/components/SlashMenu.tsx
14783
+ // src/components/ModelPicker.tsx
14285
14784
  import { Box as Box12, Text as Text14 } from "ink";
14286
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";
14287
14821
  var MAX_ROWS, SlashMenu;
14288
14822
  var init_SlashMenu = __esm({
14289
14823
  "src/components/SlashMenu.tsx"() {
@@ -14295,22 +14829,22 @@ var init_SlashMenu = __esm({
14295
14829
  const visible = entries.slice(start, start + MAX_ROWS);
14296
14830
  const cmdW = Math.min(22, Math.max(8, ...visible.map((e) => e.name.length)) + 1);
14297
14831
  const descMax = Math.max(12, cols - cmdW - 6);
14298
- 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: [
14299
14833
  visible.map((e, i) => {
14300
14834
  const active = i + start === selectedIndex;
14301
14835
  const desc = e.description.length > descMax ? `${e.description.slice(0, descMax - 1)}\u2026` : e.description;
14302
14836
  const gap = Math.max(1, cmdW - e.name.length);
14303
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
14304
- /* @__PURE__ */ jsx14(Text14, { color: active ? THEME.coralBright : void 0, bold: true, children: active ? "\u276F " : " " }),
14305
- /* @__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: [
14306
14840
  "/",
14307
14841
  e.name
14308
14842
  ] }),
14309
- /* @__PURE__ */ jsx14(Text14, { color: THEME.grayDim, children: " ".repeat(gap) }),
14310
- /* @__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 })
14311
14845
  ] }, e.name);
14312
14846
  }),
14313
- entries.length > MAX_ROWS ? /* @__PURE__ */ jsxs12(Text14, { color: THEME.coralMuted, children: [
14847
+ entries.length > MAX_ROWS ? /* @__PURE__ */ jsxs13(Text15, { color: THEME.coralMuted, children: [
14314
14848
  "\u2191\u2193 \u6EDA\u52A8 \xB7 ",
14315
14849
  selectedIndex + 1,
14316
14850
  "/",
@@ -14323,8 +14857,8 @@ var init_SlashMenu = __esm({
14323
14857
  });
14324
14858
 
14325
14859
  // src/components/StatusStrip.tsx
14326
- import { Box as Box13, Text as Text15 } from "ink";
14327
- 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";
14328
14862
  var StatusStrip;
14329
14863
  var init_StatusStrip = __esm({
14330
14864
  "src/components/StatusStrip.tsx"() {
@@ -14341,18 +14875,18 @@ var init_StatusStrip = __esm({
14341
14875
  `state: ${stateText}`,
14342
14876
  sessionShort ? `session: ${sessionShort}` : ""
14343
14877
  ].filter(Boolean);
14344
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexShrink: 0, children: [
14345
- /* @__PURE__ */ jsx15(Text15, { color: THEME.coralMuted, children: customLine && customLine.trim() ? customLine : bits.join(" \xB7 ") }),
14346
- /* @__PURE__ */ jsx15(Text15, { color: stateColor, children: "" }),
14347
- /* @__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 })
14348
14882
  ] });
14349
14883
  };
14350
14884
  }
14351
14885
  });
14352
14886
 
14353
14887
  // src/components/TopPanel.tsx
14354
- import { Box as Box14, Text as Text16 } from "ink";
14355
- 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";
14356
14890
  var ROBOT, INNER_H, TopPanel;
14357
14891
  var init_TopPanel = __esm({
14358
14892
  "src/components/TopPanel.tsx"() {
@@ -14372,36 +14906,36 @@ var init_TopPanel = __esm({
14372
14906
  const leftW = Math.floor(innerW * 0.33);
14373
14907
  const rightW = innerW - leftW - 1;
14374
14908
  const ruleLen = Math.max(8, rightW - 2);
14375
- 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)) });
14376
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: panelW, marginBottom: 1, children: [
14377
- /* @__PURE__ */ jsxs14(Text16, { children: [
14378
- /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "* Welcome to " }),
14379
- /* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.white, children: "deep" }),
14380
- /* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.coralBright, children: "Seek" }),
14381
- /* @__PURE__ */ jsx16(Text16, { bold: true, color: THEME.white, children: "Code" }),
14382
- /* @__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: [
14383
14917
  " ",
14384
14918
  VERSION
14385
14919
  ] })
14386
14920
  ] }),
14387
- /* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: cwd }),
14388
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", borderStyle: "round", borderColor: THEME.coral, marginTop: 1, paddingX: 0, paddingY: 0, children: [
14389
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: leftW, height: INNER_H, alignItems: "center", justifyContent: "center", children: [
14390
- /* @__PURE__ */ jsx16(Text16, { color: THEME.white, bold: true, children: "Welcome back!" }),
14391
- ROBOT.map((l, i) => /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, children: l }, i)),
14392
- /* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "Ctrl+C \u9000\u51FA \xB7 Esc \u4E2D\u6B62" }),
14393
- /* @__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" })
14394
14928
  ] }),
14395
14929
  VDivider,
14396
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: rightW, height: INNER_H, justifyContent: "space-between", paddingX: 1, children: [
14397
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
14398
- /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "Tips for getting started" }),
14399
- /* @__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" })
14400
14934
  ] }),
14401
- /* @__PURE__ */ jsx16(Text16, { color: THEME.grayDim, children: "\u2500".repeat(ruleLen) }),
14402
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
14403
- /* @__PURE__ */ jsx16(Text16, { color: THEME.coralBright, bold: true, children: "What's new" }),
14404
- /* @__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" })
14405
14939
  ] })
14406
14940
  ] })
14407
14941
  ] })
@@ -14552,9 +15086,9 @@ __export(App_exports, {
14552
15086
  App: () => App
14553
15087
  });
14554
15088
  import { useCallback as useCallback2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState4 } from "react";
14555
- import { Box as Box15, Static, Text as Text17, useApp, useInput as useInput2, useStdout } from "ink";
14556
- import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
14557
- 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;
14558
15092
  var init_App = __esm({
14559
15093
  "src/App.tsx"() {
14560
15094
  "use strict";
@@ -14579,24 +15113,24 @@ var init_App = __esm({
14579
15113
  init_PlanEditor();
14580
15114
  init_SessionPicker();
14581
15115
  init_ForkPicker();
15116
+ init_ModelPicker();
14582
15117
  init_SlashMenu();
14583
15118
  init_MultilineInput();
14584
15119
  init_StatusStrip();
14585
15120
  init_TopPanel();
14586
15121
  init_inspect();
14587
- KNOWN_MODELS = ["deepseek-v4", "deepseek-v4-flash"];
14588
15122
  CWD2 = process.cwd();
14589
15123
  RowView = ({ row, wrapW, streamTail, showThinking }) => {
14590
- if (row.kind === "todos") return /* @__PURE__ */ jsx17(TodosPanel, { todos: row.todos, wrapW });
14591
- 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 });
14592
- 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 });
14593
15127
  if (row.kind === "user") {
14594
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
14595
- /* @__PURE__ */ jsx17(Text17, { color: THEME.grayDim, children: "\u2500".repeat(Math.max(8, wrapW)) }),
14596
- /* @__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 })
14597
15131
  ] });
14598
15132
  }
14599
- return /* @__PURE__ */ jsx17(MessageBlock, { row, wrapW, streamTail });
15133
+ return /* @__PURE__ */ jsx18(MessageBlock, { row, wrapW, streamTail });
14600
15134
  };
14601
15135
  isDynamicRow = (r) => r.kind === "assistant" && !!r.streaming || r.kind === "thinking" && !!r.streaming || r.kind === "tool" && r.status === "running" || r.kind === "todos" && !!r.active;
14602
15136
  App = ({ resumeSessionId, initialPlanMode, initialAutoMode, initialIncludeProject, engineReady }) => {
@@ -14672,6 +15206,15 @@ var init_App = __esm({
14672
15206
  await refreshStatusLineRef.current();
14673
15207
  })();
14674
15208
  }, []);
15209
+ useEffect4(() => {
15210
+ void (async () => {
15211
+ const saved = await readModelPref();
15212
+ if (saved) {
15213
+ state.setModelOverride(saved);
15214
+ setModelDisplay(saved);
15215
+ }
15216
+ })();
15217
+ }, []);
14675
15218
  useEffect4(() => {
14676
15219
  void refreshStatusLineRef.current();
14677
15220
  }, [state.busy, state.aborting, modelDisplay]);
@@ -14698,6 +15241,8 @@ var init_App = __esm({
14698
15241
  return S.cmdAuto;
14699
15242
  case "model":
14700
15243
  return S.cmdModel;
15244
+ case "switch":
15245
+ return S.cmdSwitch;
14701
15246
  case "thinking":
14702
15247
  return S.cmdThinking;
14703
15248
  case "lang":
@@ -14740,17 +15285,23 @@ var init_App = __esm({
14740
15285
  const q = input.slice(1).toLowerCase();
14741
15286
  return menuEntries.filter((c) => c.name.toLowerCase().startsWith(q));
14742
15287
  }, [input, menuEntries]);
14743
- 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;
14744
15289
  const slashVisible = !menuActive && input.startsWith("/") && filteredCommands.length > 0;
14745
15290
  const inputActive = !menuActive;
14746
15291
  useEffect4(() => {
14747
15292
  setSelectIdx(0);
14748
15293
  setPlanEditing(false);
14749
- }, [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]);
14750
15295
  useEffect4(() => {
14751
15296
  setQCursor(0);
14752
15297
  setQChecked(/* @__PURE__ */ new Set());
14753
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]);
14754
15305
  const runLocalSlash = async (text) => {
14755
15306
  const [cmd, ...rest] = text.trim().split(/\s+/);
14756
15307
  const arg = rest.join(" ");
@@ -14827,13 +15378,15 @@ ${list}
14827
15378
  }
14828
15379
  case "/model":
14829
15380
  if (!arg) {
14830
- state.pushInfo(`\u5F53\u524D\u6A21\u578B\uFF1A${modelDisplay}
14831
- \u53EF\u9009\uFF1A${KNOWN_MODELS.join("\u3001")} \u6216\u4EFB\u610F\u6A21\u578B id\u3002`);
15381
+ state.pushInfo(S.modelUsage(modelDisplay));
14832
15382
  return true;
14833
15383
  }
14834
15384
  state.setModelOverride(arg);
14835
15385
  setModelDisplay(arg);
14836
- 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();
14837
15390
  return true;
14838
15391
  case "/thinking": {
14839
15392
  const lvl = arg.toLowerCase();
@@ -14922,7 +15475,7 @@ ${listText}`);
14922
15475
  const v = inputRef.current.trim();
14923
15476
  if (!v) return;
14924
15477
  if (busyRef.current) {
14925
- if (!v.startsWith("/") && state.queueInput(v)) {
15478
+ if (!v.startsWith("/") && !v.startsWith("!") && state.queueInput(v)) {
14926
15479
  setInput("");
14927
15480
  setCursor(0);
14928
15481
  } else {
@@ -14932,6 +15485,10 @@ ${listText}`);
14932
15485
  }
14933
15486
  setInput("");
14934
15487
  setCursor(0);
15488
+ if (v.startsWith("!")) {
15489
+ await state.runBangCommand(v);
15490
+ return;
15491
+ }
14935
15492
  if (v.startsWith("/")) {
14936
15493
  await executeSlash(v);
14937
15494
  return;
@@ -15020,6 +15577,16 @@ ${listText}`);
15020
15577
  } else if (key.escape || key.ctrl && ch === "g") state.resolveFork(null);
15021
15578
  return;
15022
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
+ }
15023
15590
  if (key.ctrl && ch === "t") {
15024
15591
  state.toggleShowThinking();
15025
15592
  return;
@@ -15060,19 +15627,19 @@ ${listText}`);
15060
15627
  }
15061
15628
  });
15062
15629
  const sessionShort = state.sessionIdRef.current ? truncateMiddle(state.sessionIdRef.current, 12) : "";
15063
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: cols, children: [
15064
- /* @__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) }),
15065
- /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", width: cols, children: [
15066
- menuActive ? null : /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, children: [
15067
- dynamicRows.map((row) => /* @__PURE__ */ jsx17(RowView, { row, wrapW, streamTail, showThinking: state.showThinkingText }, row.id)),
15068
- 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: [
15069
15636
  "\u25CF ",
15070
15637
  S.generating
15071
15638
  ] }) }) : null
15072
15639
  ] }),
15073
- /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, flexShrink: 0, children: [
15074
- state.pendingApproval ? /* @__PURE__ */ jsx17(ApprovalModal, { toolName: state.pendingApproval.toolName, detail: state.pendingApproval.detail, selectedIndex: selectIdx, wrapW }) : null,
15075
- 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(
15076
15643
  QuestionModal,
15077
15644
  {
15078
15645
  question: state.pendingQuestion.req.question,
@@ -15083,7 +15650,7 @@ ${listText}`);
15083
15650
  wrapW
15084
15651
  }
15085
15652
  ) : null,
15086
- state.pendingPlan ? planEditing ? /* @__PURE__ */ jsx17(
15653
+ state.pendingPlan ? planEditing ? /* @__PURE__ */ jsx18(
15087
15654
  PlanEditor,
15088
15655
  {
15089
15656
  value: planDraft,
@@ -15094,15 +15661,16 @@ ${listText}`);
15094
15661
  },
15095
15662
  onSubmit: confirmPlanEdit
15096
15663
  }
15097
- ) : /* @__PURE__ */ jsx17(PlanModal, { selectedIndex: selectIdx }) : null,
15098
- state.pendingSessions ? /* @__PURE__ */ jsx17(SessionPicker, { sessions: state.pendingSessions.sessions, selectedIndex: selectIdx, wrapW }) : null,
15099
- state.pendingFork ? /* @__PURE__ */ jsx17(ForkPicker, { anchors: state.pendingFork.anchors, selectedIndex: selectIdx, wrapW }) : null,
15100
- 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
15101
15669
  ] }),
15102
- /* @__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: (() => {
15103
15671
  const planOn = state.getPlanMode();
15104
15672
  const autoOn = !planOn && state.getAutoMode();
15105
- const inputEl = /* @__PURE__ */ jsx17(
15673
+ const inputEl = /* @__PURE__ */ jsx18(
15106
15674
  MultilineInput,
15107
15675
  {
15108
15676
  value: input,
@@ -15120,17 +15688,17 @@ ${listText}`);
15120
15688
  }
15121
15689
  );
15122
15690
  if (planOn || autoOn) {
15123
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: planOn ? THEME.thinking : THEME.warn, paddingX: 1, children: [
15124
- /* @__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 }),
15125
15693
  inputEl
15126
15694
  ] });
15127
15695
  }
15128
- return /* @__PURE__ */ jsxs15(Fragment3, { children: [
15129
- /* @__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) }),
15130
15698
  inputEl
15131
15699
  ] });
15132
15700
  })() }),
15133
- /* @__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 }) })
15134
15702
  ] })
15135
15703
  ] });
15136
15704
  };
@@ -15190,7 +15758,7 @@ import { render } from "ink";
15190
15758
  import os5 from "os";
15191
15759
  import path42 from "path";
15192
15760
  import { emitKeypressEvents } from "node:readline";
15193
- import { jsx as jsx18 } from "react/jsx-runtime";
15761
+ import { jsx as jsx19 } from "react/jsx-runtime";
15194
15762
  var parseArgs = (argv) => {
15195
15763
  const out = {};
15196
15764
  for (let i = 0; i < argv.length; i++) {
@@ -15340,7 +15908,7 @@ var main = async () => {
15340
15908
  resumeId = await getMostRecentSessionId2() ?? void 0;
15341
15909
  }
15342
15910
  const { waitUntilExit } = render(
15343
- /* @__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 }),
15344
15912
  // exitOnCtrlC:false:Ctrl+C 交由 App useInput 处理(统一退出/中止语义);
15345
15913
  // patchConsole:false:避免 console 劫持与全屏重绘叠加闪屏。
15346
15914
  { exitOnCtrlC: false, patchConsole: false }