jinzd-ai-cli 0.4.320 → 0.4.322

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 (36) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +2 -2
  3. package/dist/{batch-LRYDPB6F.js → batch-IMC6Q63Y.js} +2 -2
  4. package/dist/{chunk-NOAWUEJJ.js → chunk-3TWEKDHH.js} +1 -1
  5. package/dist/{chunk-TKBWA3XJ.js → chunk-FHBV5EUM.js} +4 -4
  6. package/dist/{chunk-WY4IWCQ5.js → chunk-G46THFJN.js} +1 -1
  7. package/dist/{chunk-4S2XD3M2.js → chunk-HVVDGSUN.js} +4 -4
  8. package/dist/{chunk-46OEMKQX.js → chunk-NFPJ6KUU.js} +8 -4
  9. package/dist/{chunk-WW2LFOWE.js → chunk-NX72SBGU.js} +1 -1
  10. package/dist/{chunk-DB4HVUPI.js → chunk-OR46O57D.js} +1 -1
  11. package/dist/{chunk-5VZHSSLW.js → chunk-RO67VWKW.js} +1 -1
  12. package/dist/{chunk-N6YFBRQV.js → chunk-RSWCASRV.js} +1 -1
  13. package/dist/{chunk-QB3MECZJ.js → chunk-SYK2TDKV.js} +24 -17
  14. package/dist/{chunk-P4FJBD2H.js → chunk-W7D4M4KV.js} +1 -1
  15. package/dist/{chunk-SKQUWDRM.js → chunk-X5ZC4TI4.js} +1 -1
  16. package/dist/{chunk-YAMPLTYO.js → chunk-XVB4RARX.js} +74 -1
  17. package/dist/{chunk-46M65JDN.js → chunk-ZSR2UIRD.js} +56 -19
  18. package/dist/{chunk-J7IPNING.js → chunk-ZUONW7FS.js} +1 -1
  19. package/dist/{ci-7TSOMDHV.js → ci-74EPK5JN.js} +5 -5
  20. package/dist/{ci-format-6A2RFYZS.js → ci-format-QADWGCX7.js} +2 -2
  21. package/dist/{constants-EHYM2NS5.js → constants-P5JJ6FO4.js} +1 -1
  22. package/dist/{constants-P33UDQVS.js → constants-SSVJCBAT.js} +1 -1
  23. package/dist/{doctor-cli-2B72UMZO.js → doctor-cli-KJT5HMQB.js} +5 -5
  24. package/dist/electron-server.js +170 -49
  25. package/dist/{hub-JACLTKYY.js → hub-5CPMJQVG.js} +1 -1
  26. package/dist/index.js +29 -20
  27. package/dist/{persistent-memory-5ICLP275.js → persistent-memory-BOUJARIV.js} +2 -2
  28. package/dist/{persistent-memory-ZIM6ICIR.js → persistent-memory-H5MUAC4X.js} +2 -2
  29. package/dist/{pr-UBGLNROK.js → pr-BU2FN7CO.js} +5 -5
  30. package/dist/{run-tests-HCID73KE.js → run-tests-6JKF6JJZ.js} +2 -2
  31. package/dist/{run-tests-SYJG4S3N.js → run-tests-WJJW77HK.js} +2 -2
  32. package/dist/{server-BVTFIPB2.js → server-GFL7MYAP.js} +5 -5
  33. package/dist/{server-3UEEPEUD.js → server-XGY6OUUT.js} +15 -15
  34. package/dist/{task-orchestrator-6NRCGF5V.js → task-orchestrator-EETPUWBK.js} +5 -5
  35. package/dist/{usage-6V64TTRE.js → usage-BVHFDNRW.js} +3 -3
  36. package/package.json +3 -2
@@ -39,7 +39,7 @@ import {
39
39
  TEST_TIMEOUT,
40
40
  VERSION,
41
41
  buildUserIdentityPrompt
42
- } from "./chunk-J7IPNING.js";
42
+ } from "./chunk-ZUONW7FS.js";
43
43
  export {
44
44
  AGENTIC_BEHAVIOR_GUIDELINE,
45
45
  APP_NAME,
@@ -2,16 +2,16 @@
2
2
  import {
3
3
  formatDoctorReport,
4
4
  runDoctorCli
5
- } from "./chunk-4S2XD3M2.js";
6
- import "./chunk-5VZHSSLW.js";
5
+ } from "./chunk-HVVDGSUN.js";
6
+ import "./chunk-RO67VWKW.js";
7
7
  import "./chunk-RS7SKYTS.js";
8
- import "./chunk-YAMPLTYO.js";
9
- import "./chunk-DB4HVUPI.js";
8
+ import "./chunk-XVB4RARX.js";
9
+ import "./chunk-OR46O57D.js";
10
10
  import "./chunk-E2W2MI6H.js";
11
11
  import "./chunk-TU3L3PW7.js";
12
12
  import "./chunk-HOSJZMQS.js";
13
13
  import "./chunk-BMLQPSHP.js";
14
- import "./chunk-J7IPNING.js";
14
+ import "./chunk-ZUONW7FS.js";
15
15
  export {
16
16
  formatDoctorReport,
17
17
  runDoctorCli
@@ -55,7 +55,7 @@ import {
55
55
  touchMemoryReferences,
56
56
  updateMemoryApproval,
57
57
  updateMemoryEntry
58
- } from "./chunk-WW2LFOWE.js";
58
+ } from "./chunk-NX72SBGU.js";
59
59
  import {
60
60
  DEFAULT_PATTERNS,
61
61
  redactJson,
@@ -81,7 +81,7 @@ import {
81
81
  recoverGbkMojibake,
82
82
  runTestsTool,
83
83
  shellInvocation
84
- } from "./chunk-N6YFBRQV.js";
84
+ } from "./chunk-RSWCASRV.js";
85
85
  import {
86
86
  getCurrentSessionKey,
87
87
  getExecutionConfigDir,
@@ -123,7 +123,7 @@ import {
123
123
  SUBAGENT_MAX_ROUNDS_LIMIT,
124
124
  VERSION,
125
125
  buildUserIdentityPrompt
126
- } from "./chunk-SKQUWDRM.js";
126
+ } from "./chunk-X5ZC4TI4.js";
127
127
 
128
128
  // src/web/access.ts
129
129
  import { randomBytes, timingSafeEqual } from "crypto";
@@ -205,7 +205,7 @@ function imageValidationError(images) {
205
205
  }
206
206
 
207
207
  // src/web/server.ts
208
- import { join as join25, dirname as dirname11, resolve as resolve12, relative as relative6, sep as sep5, extname as extname3, resolve as resolvePath } from "path";
208
+ import { join as join25, dirname as dirname12, resolve as resolve12, relative as relative6, sep as sep5, extname as extname3, resolve as resolvePath } from "path";
209
209
  import { existsSync as existsSync31, readFileSync as readFileSync22, readdirSync as readdirSync15, statSync as statSync16, realpathSync as realpathSync3, createReadStream } from "fs";
210
210
  import { networkInterfaces as networkInterfaces2 } from "os";
211
211
 
@@ -981,17 +981,21 @@ var PRICING_TABLE = {
981
981
  "glm-4.6": { input: 0.6, output: 2.2 },
982
982
  "glm-4.6v": { input: 0.6, output: 2.2 },
983
983
  "glm-5": { input: 0.85, output: 2.85 },
984
- // GLM-5.3(2026-08-14 发布)官方公告口径「与 GLM-5.2 同价」,直连 API $1.40 / $4.40。
984
+ // GLM-5.3:官方定价页(open.bigmodel.cn/pricing,2026-10-08 浏览器读取)——输入 8 元、
985
+ // 输出 28 元、缓存命中 2 元(每百万 token),按 ¥6.9/$1 换算。此前记的 $1.40/$4.40 是
986
+ // Z.ai 国际站的美元价,而本 provider 打的是国内站、按人民币计费,高报约 20%;更大的
987
+ // 偏差在**缓存**:没有 cacheRead 时缓存命中按输入全价算,2026-10-07 审计会话 1474 万
988
+ // 缓存 token 被记成 $21.34,按官方缓存价约 $4.90(2026-10-07 审计 X-03)。
985
989
  // 注意它**始终思考**,思考 token 按输出价计费 —— 实际成本高度取决于 reasoning_effort。
986
- "glm-5.3": { input: 1.4, output: 4.4 },
990
+ "glm-5.3": { input: 8 / CNY_PER_USD, output: 28 / CNY_PER_USD, cacheRead: 2 / CNY_PER_USD },
987
991
  // GLM-5.3-Flash:官方定价页(open.bigmodel.cn/pricing)一手数字——输入 0.8 元、
988
992
  // 输出 2.8 元、缓存命中 0.23 元(每百万 token),按记账汇率 ¥6.9/$1 换算。
989
993
  // **刻意记恢复价而非当前的 5 折限时价**(0.4/1.4/0.115 元):官方只说「限时两周」、
990
994
  // 没公布截止日期,静态表表达不了这个时间维度;高估比低估安全——预算告警早触发
991
995
  // 好过晚触发。折扣期内 `/cost` 会比实际偏高约一倍,这是刻意的取舍。
992
996
  "glm-5.3-flash": { input: 0.116, output: 0.406, cacheRead: 0.033 },
993
- // GLM-5.2(2026-06)官方直连 API 定价 $1.40 / $4.40。
994
- "glm-5.2": { input: 1.4, output: 4.4 },
997
+ // GLM-5.2:与 GLM-5.3 同价(同一定价页:8 / 28 / 缓存命中 2 元),口径修正同上。
998
+ "glm-5.2": { input: 8 / CNY_PER_USD, output: 28 / CNY_PER_USD, cacheRead: 2 / CNY_PER_USD },
995
999
  // GLM-5V-Turbo(2026-04 视觉编程旗舰)官方直连 API 定价 $1.20 / $4.00。
996
1000
  "glm-5v-turbo": { input: 1.2, output: 4 },
997
1001
  "glm-5.1": { input: 0.95, output: 3.15 },
@@ -2710,12 +2714,12 @@ function findPhantomClaims(content, extraMessages) {
2710
2714
  const claimed = extractClaimedFilePaths(content);
2711
2715
  if (claimed.length === 0) return [];
2712
2716
  const normalize = (p) => p.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
2713
- const basename10 = (p) => {
2717
+ const basename11 = (p) => {
2714
2718
  const parts = normalize(p).split("/");
2715
2719
  return parts[parts.length - 1] ?? "";
2716
2720
  };
2717
2721
  const written = extractWrittenFilePaths(extraMessages).map(normalize);
2718
- const writtenBases = new Set(written.map(basename10));
2722
+ const writtenBases = new Set(written.map(basename11));
2719
2723
  const writtenFull = new Set(written);
2720
2724
  const bashText = extractBashCommands(extraMessages).map((c) => c.replace(/\\/g, "/").toLowerCase()).join("\n");
2721
2725
  return claimed.filter((raw) => {
@@ -2724,8 +2728,8 @@ function findPhantomClaims(content, extraMessages) {
2724
2728
  for (const w of writtenFull) {
2725
2729
  if (w.endsWith("/" + norm2) || norm2.endsWith("/" + w)) return false;
2726
2730
  }
2727
- if (writtenBases.has(basename10(norm2))) return false;
2728
- const base = basename10(norm2);
2731
+ if (writtenBases.has(basename11(norm2))) return false;
2732
+ const base = basename11(norm2);
2729
2733
  if (base && bashText.includes(base)) return false;
2730
2734
  return true;
2731
2735
  });
@@ -4773,6 +4777,7 @@ function ollamaNativeBaseUrl(openAiBaseUrl) {
4773
4777
  return openAiBaseUrl.replace(/\/+$/, "").replace(/\/v1$/, "");
4774
4778
  }
4775
4779
  var NATIVE_API_TIMEOUT_MS = 3e3;
4780
+ var SMALL_CONTEXT_WARN = 16384;
4776
4781
  var OllamaProvider = class extends OpenAICompatibleProvider {
4777
4782
  // 用 127.0.0.1 而非 localhost:Node.js 18+ 在 Windows 上优先解析 localhost 为 IPv6 (::1),
4778
4783
  // 但 Ollama 默认只监听 IPv4,导致连接失败。
@@ -4851,12 +4856,13 @@ var OllamaProvider = class extends OpenAICompatibleProvider {
4851
4856
  if (show?.capabilities?.includes("thinking")) thinkingModels.add(id);
4852
4857
  if (running.size === 0 && !show) return;
4853
4858
  const digest = digests.get(id);
4854
- const { contextWindow } = resolveOllamaContextWindow({
4859
+ const { contextWindow, source: source2 } = resolveOllamaContextWindow({
4855
4860
  runningContext: digest && running.get(digest) || running.get(id),
4856
4861
  show,
4857
4862
  fallback: this.estimateContextWindow(id)
4858
4863
  });
4859
4864
  result.set(id, contextWindow);
4865
+ this.contextSources.set(id, source2);
4860
4866
  }));
4861
4867
  return { contextWindows: result, thinkingModels };
4862
4868
  }
@@ -4952,6 +4958,77 @@ var OllamaProvider = class extends OpenAICompatibleProvider {
4952
4958
  const target = norm2(model);
4953
4959
  return this.dynamicModels.some((m) => m.supportsThinking === true && norm2(m.id) === target);
4954
4960
  }
4961
+ // ── 加载后补读真实窗口(2026-10-07 审计 C-01)────────────────────────────
4962
+ //
4963
+ // 上下文窗口只在启动时读一次。模型当时若还没加载,`/api/ps` 里没有它,只能取训练上限
4964
+ // (Qwen3.8 是 262K);而服务端实际开的窗口可能只有它的几十分之一。第一次请求把模型
4965
+ // 加载进来之后若不再读,上下文压力监控、自动压缩与工具预算就整场按那个大数在算——
4966
+ // aicli 以为还有余量,Ollama 早已在悄悄截掉最早的消息(v0.4.311 那次说的正是这个后果)。
4967
+ // 所以每个模型在首次请求之后补读一次 `/api/ps`;读到的窗口若小得连工具定义都放不下,
4968
+ // 提示一次怎么调大。都是后台做,不拖慢这次请求。
4969
+ /** 每个模型的窗口是从哪一级读到的(只有 'running' 是服务端实际值) */
4970
+ contextSources = /* @__PURE__ */ new Map();
4971
+ refreshedAfterLoad = /* @__PURE__ */ new Set();
4972
+ warnedSmallContext = /* @__PURE__ */ new Set();
4973
+ async chat(request) {
4974
+ try {
4975
+ return await super.chat(request);
4976
+ } finally {
4977
+ this.scheduleContextRefresh(request.model);
4978
+ }
4979
+ }
4980
+ async *chatStream(request) {
4981
+ try {
4982
+ yield* super.chatStream(request);
4983
+ } finally {
4984
+ this.scheduleContextRefresh(request.model);
4985
+ }
4986
+ }
4987
+ async chatWithTools(request, tools) {
4988
+ try {
4989
+ return await super.chatWithTools(request, tools);
4990
+ } finally {
4991
+ this.scheduleContextRefresh(request.model);
4992
+ }
4993
+ }
4994
+ async *chatWithToolsStream(request, tools) {
4995
+ try {
4996
+ yield* super.chatWithToolsStream(request, tools);
4997
+ } finally {
4998
+ this.scheduleContextRefresh(request.model);
4999
+ }
5000
+ }
5001
+ scheduleContextRefresh(model) {
5002
+ const key = model.replace(/:latest$/, "");
5003
+ if (this.refreshedAfterLoad.has(key)) return;
5004
+ this.refreshedAfterLoad.add(key);
5005
+ void this.refreshLoadedContext(model).catch(() => {
5006
+ });
5007
+ }
5008
+ /** 补读已加载模型的实际窗口,更新同一份权重(digest 相同)的所有别名。测试可直接 await。 */
5009
+ async refreshLoadedContext(model) {
5010
+ const norm2 = (id2) => id2.replace(/:latest$/, "");
5011
+ const [running, digests] = await Promise.all([this.fetchRunningContexts(), this.fetchDigests()]);
5012
+ const self = this.dynamicModels.find((m) => norm2(m.id) === norm2(model));
5013
+ const id = self?.id ?? model;
5014
+ const digest = digests.get(id);
5015
+ const actual = digest && running.get(digest) || running.get(id);
5016
+ if (!actual) return;
5017
+ for (const m of this.dynamicModels) {
5018
+ if (m.id === id || digest && digests.get(m.id) === digest) {
5019
+ m.contextWindow = actual;
5020
+ this.contextSources.set(m.id, "running");
5021
+ }
5022
+ }
5023
+ if (actual < SMALL_CONTEXT_WARN && !this.warnedSmallContext.has(norm2(id))) {
5024
+ this.warnedSmallContext.add(norm2(id));
5025
+ process.stderr.write(
5026
+ `
5027
+ [ollama] ${id} is loaded with a ${actual.toLocaleString()}-token context window. aicli's tool definitions alone take about 8K tokens, so earlier messages will be silently cut off. Raise it: set OLLAMA_CONTEXT_LENGTH=32768 (or more) for the Ollama server, or add "PARAMETER num_ctx 32768" to the model's Modelfile.
5028
+ `
5029
+ );
5030
+ }
5031
+ }
4955
5032
  /** 实时刷新模型列表 */
4956
5033
  async listModels() {
4957
5034
  await this.tryConnect();
@@ -13487,21 +13564,37 @@ function estimateTokens(text) {
13487
13564
  return Math.ceil(tokens) + 4;
13488
13565
  }
13489
13566
  function estimateToolDefinitionTokens(def) {
13490
- let charCount = def.name.length + def.description.length;
13491
- for (const [key, param] of Object.entries(def.parameters)) {
13492
- charCount += key.length + param.type.length + param.description.length;
13493
- if (param.enum) {
13494
- charCount += param.enum.join(" ").length;
13495
- }
13496
- }
13497
- const structuralOverhead = 40 + Object.keys(def.parameters).length * 30;
13498
- return Math.ceil((charCount + structuralOverhead) * 0.25) + 10;
13567
+ const json = JSON.stringify({ name: def.name, description: def.description, parameters: def.parameters });
13568
+ const cjk = json.match(CJK_REGEX)?.length ?? 0;
13569
+ return Math.ceil((json.length - cjk + 40) / 3.7 + cjk * 1.5);
13499
13570
  }
13500
13571
 
13501
13572
  // src/tools/registry.ts
13502
13573
  import { pathToFileURL } from "url";
13503
13574
  import { existsSync as existsSync19, mkdirSync as mkdirSync9, readdirSync as readdirSync9 } from "fs";
13504
13575
  import { join as join13 } from "path";
13576
+ var TRIMMABLE_BUILTIN_ORDER = [
13577
+ "google_search",
13578
+ "recall_memory",
13579
+ "search_code",
13580
+ "notebook_edit",
13581
+ "spawn_agent",
13582
+ "run_interactive",
13583
+ "save_memory",
13584
+ "find_references",
13585
+ "get_outline",
13586
+ "find_symbol",
13587
+ "task_stop",
13588
+ "task_list",
13589
+ "task_create",
13590
+ "git_log",
13591
+ "git_diff",
13592
+ "git_commit",
13593
+ "git_status",
13594
+ "web_fetch",
13595
+ "web_search",
13596
+ "run_tests"
13597
+ ];
13505
13598
  var ToolRegistry = class {
13506
13599
  tools = /* @__PURE__ */ new Map();
13507
13600
  pluginToolNames = /* @__PURE__ */ new Set();
@@ -13569,7 +13662,7 @@ var ToolRegistry = class {
13569
13662
  totalTokens += estimateToolDefinitionTokens(def);
13570
13663
  }
13571
13664
  if (totalTokens <= tokenBudget) {
13572
- return { definitions: allDefs, trimmedCount: 0, systemNote: null };
13665
+ return { definitions: allDefs, trimmedCount: 0, trimmedBuiltins: [], systemNote: null };
13573
13666
  }
13574
13667
  const builtinDefs = [];
13575
13668
  const mcpDefs = [];
@@ -13581,10 +13674,19 @@ var ToolRegistry = class {
13581
13674
  }
13582
13675
  }
13583
13676
  let budget = tokenBudget;
13584
- for (const def of builtinDefs) {
13585
- budget -= estimateToolDefinitionTokens(def);
13586
- }
13587
- const kept = [...builtinDefs];
13677
+ const trimmedBuiltins = [];
13678
+ let builtinCost = builtinDefs.reduce((n, d) => n + estimateToolDefinitionTokens(d), 0);
13679
+ const keptBuiltins = new Set(builtinDefs.map((d) => d.name));
13680
+ for (const name of TRIMMABLE_BUILTIN_ORDER) {
13681
+ if (builtinCost <= budget) break;
13682
+ const def = builtinDefs.find((d) => d.name === name);
13683
+ if (!def || this.pluginToolNames.has(name)) continue;
13684
+ keptBuiltins.delete(name);
13685
+ trimmedBuiltins.push(name);
13686
+ builtinCost -= estimateToolDefinitionTokens(def);
13687
+ }
13688
+ budget -= builtinCost;
13689
+ const kept = builtinDefs.filter((d) => keptBuiltins.has(d.name));
13588
13690
  const used = usedToolNames ?? /* @__PURE__ */ new Set();
13589
13691
  const remaining = [];
13590
13692
  for (const def of mcpDefs) {
@@ -13606,6 +13708,12 @@ var ToolRegistry = class {
13606
13708
  trimmed++;
13607
13709
  }
13608
13710
  }
13711
+ const notes = [];
13712
+ if (trimmedBuiltins.length > 0) {
13713
+ notes.push(
13714
+ `[Tool Budget] To fit this model's context window, these tools are not available in this session: ${trimmedBuiltins.join(", ")}. Use bash for the equivalent (git commands, grep for symbols, curl for web pages) instead of calling them.`
13715
+ );
13716
+ }
13609
13717
  let systemNote = null;
13610
13718
  if (trimmed > 0) {
13611
13719
  const trimmedServers = /* @__PURE__ */ new Set();
@@ -13618,7 +13726,13 @@ var ToolRegistry = class {
13618
13726
  }
13619
13727
  systemNote = `[MCP Tool Budget] ${trimmed} MCP tool(s) from server(s) [${[...trimmedServers].join(", ")}] were excluded to fit the context window. If you need a specific MCP tool that isn't listed, tell the user to ask for it explicitly.`;
13620
13728
  }
13621
- return { definitions: kept, trimmedCount: trimmed, systemNote };
13729
+ if (systemNote) notes.push(systemNote);
13730
+ return {
13731
+ definitions: kept,
13732
+ trimmedCount: trimmed,
13733
+ trimmedBuiltins,
13734
+ systemNote: notes.length > 0 ? notes.join("\n\n") : null
13735
+ };
13622
13736
  }
13623
13737
  listAll() {
13624
13738
  return [...this.tools.values()];
@@ -14239,7 +14353,7 @@ var McpManager = class {
14239
14353
 
14240
14354
  // src/skills/manager.ts
14241
14355
  import { existsSync as existsSync20, readdirSync as readdirSync10, mkdirSync as mkdirSync10, statSync as statSync9 } from "fs";
14242
- import { join as join14 } from "path";
14356
+ import { basename as basename8, dirname as dirname8, join as join14 } from "path";
14243
14357
 
14244
14358
  // src/skills/types.ts
14245
14359
  import { readFileSync as readFileSync13 } from "fs";
@@ -14379,7 +14493,14 @@ var SkillManager = class {
14379
14493
  }
14380
14494
  /** 获取激活技能的 prompt 内容(null 表示无激活技能) */
14381
14495
  getActivePromptContent() {
14382
- return this.activeSkill?.content ?? null;
14496
+ const skill = this.activeSkill;
14497
+ if (!skill) return null;
14498
+ if (basename8(skill.filePath) === "SKILL.md") {
14499
+ return `Skill directory (SKILL_DIR, \u6280\u80FD\u76EE\u5F55): ${dirname8(skill.filePath)}
14500
+
14501
+ ${skill.content}`;
14502
+ }
14503
+ return skill.content;
14383
14504
  }
14384
14505
  /** 获取激活技能的工具白名单 Set(null 表示无限制) */
14385
14506
  getActiveToolFilter() {
@@ -15371,7 +15492,7 @@ function loadContextFiles(options) {
15371
15492
 
15372
15493
  // src/tools/deferred-save.ts
15373
15494
  import { statSync as statSync10 } from "fs";
15374
- import { basename as basename8 } from "path";
15495
+ import { basename as basename9 } from "path";
15375
15496
  function snapshotFile(path3) {
15376
15497
  try {
15377
15498
  const st = statSync10(path3);
@@ -15392,7 +15513,7 @@ var SAVE_CLAIM_PATTERNS = [
15392
15513
  /\b(?:saved|written|created|generated)\s+(?:to|at|as|into)\b/i
15393
15514
  ];
15394
15515
  function narratesSavedTarget(content, path3) {
15395
- const base = basename8(path3);
15516
+ const base = basename9(path3);
15396
15517
  if (!base || !content.includes(base)) return null;
15397
15518
  for (const re of SAVE_CLAIM_PATTERNS) {
15398
15519
  if (re.test(content)) return re.source;
@@ -15414,7 +15535,7 @@ function decideDeferredSave(params) {
15414
15535
  return {
15415
15536
  kind: "skip",
15416
15537
  reason: "narrates-target",
15417
- message: `\u21AA \u8DF3\u8FC7 deferred \u843D\u76D8\uFF1A\u6700\u7EC8\u56DE\u590D\u662F\u5173\u4E8E ${basename8(path3)} \u7684\u6C47\u62A5\u800C\u975E\u6587\u6863\u6B63\u6587\uFF08matched: ${narrated}\uFF09\u3002`
15538
+ message: `\u21AA \u8DF3\u8FC7 deferred \u843D\u76D8\uFF1A\u6700\u7EC8\u56DE\u590D\u662F\u5173\u4E8E ${basename9(path3)} \u7684\u6C47\u62A5\u800C\u975E\u6587\u6863\u6B63\u6587\uFF08matched: ${narrated}\uFF09\u3002`
15418
15539
  };
15419
15540
  }
15420
15541
  if (!isCleanDocumentBody(body)) {
@@ -15429,7 +15550,7 @@ function decideDeferredSave(params) {
15429
15550
 
15430
15551
  // src/web/session-handler.ts
15431
15552
  import { mkdirSync as mkdirSync15, createWriteStream as createWriteStream2 } from "fs";
15432
- import { dirname as dirname10 } from "path";
15553
+ import { dirname as dirname11 } from "path";
15433
15554
 
15434
15555
  // src/repl/commands/project-init.ts
15435
15556
  import { existsSync as existsSync24, readFileSync as readFileSync17, readdirSync as readdirSync11, statSync as statSync11 } from "fs";
@@ -16808,7 +16929,7 @@ function costSourceNote(source2) {
16808
16929
 
16809
16930
  // src/web/commands/_shared.ts
16810
16931
  import { existsSync as existsSync27, readFileSync as readFileSync19, writeFileSync as writeFileSync3, mkdirSync as mkdirSync13, readdirSync as readdirSync13, statSync as statSync14, createWriteStream } from "fs";
16811
- import { join as join21, resolve as resolve9, dirname as dirname8 } from "path";
16932
+ import { join as join21, resolve as resolve9, dirname as dirname9 } from "path";
16812
16933
 
16813
16934
  // src/cli/review-prompts.ts
16814
16935
  function buildReviewPrompt(diff, gitContextStr, detailed) {
@@ -17595,7 +17716,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
17595
17716
  Cost: ${formatCost(cost)}` : "";
17596
17717
  let memoryLine = "";
17597
17718
  try {
17598
- const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-ZIM6ICIR.js");
17719
+ const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-H5MUAC4X.js");
17599
17720
  const pending = countPendingMemories2(ctx.config.getConfigDir());
17600
17721
  if (pending > 0) memoryLine = `
17601
17722
  Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
@@ -18583,7 +18704,7 @@ async function handleTest(args, ctx) {
18583
18704
  const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
18584
18705
  testArgs = isCommand ? { command: argStr } : { filter: argStr };
18585
18706
  }
18586
- const runTests = ctx.runTests ?? (await import("./run-tests-HCID73KE.js")).executeTests;
18707
+ const runTests = ctx.runTests ?? (await import("./run-tests-6JKF6JJZ.js")).executeTests;
18587
18708
  const report = await runTests(testArgs);
18588
18709
  ctx.send({ type: "info", message: report });
18589
18710
  } catch (err) {
@@ -18974,7 +19095,7 @@ async function handleMemory(args, ctx) {
18974
19095
  }
18975
19096
  if (intent.kind === "status") {
18976
19097
  const { getChatIndexStatus: getChatIndexStatus2 } = await import("./chat-index-RLVLQRRC.js");
18977
- const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-ZIM6ICIR.js");
19098
+ const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-H5MUAC4X.js");
18978
19099
  const memories = listMemoryEntries2(configDir, { includeExpired: true, includeRejected: true });
18979
19100
  const injected = formatMemoryForPrompt2(configDir, process.cwd(), ctx.config.get("memory")?.maxChars);
18980
19101
  const view = buildMemoryStatusView({
@@ -18997,7 +19118,7 @@ async function handleMemory(args, ctx) {
18997
19118
  return;
18998
19119
  }
18999
19120
  if (intent.kind === "recall") {
19000
- const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-ZIM6ICIR.js");
19121
+ const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-H5MUAC4X.js");
19001
19122
  const { searchChatMemory: searchChatMemory2 } = await import("./chat-index-RLVLQRRC.js");
19002
19123
  const persistentHits = searchPersistentMemories2(configDir, intent.query, process.cwd(), 3);
19003
19124
  if (persistentHits.length > 0) {
@@ -19118,7 +19239,7 @@ async function handleMemory(args, ctx) {
19118
19239
  ctx.handleMemoryManage(intent.action, args[1], intent.action === "expire" ? args[2] : void 0);
19119
19240
  } else if (intent.kind === "export") {
19120
19241
  if (args[1] === "md") {
19121
- const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-ZIM6ICIR.js");
19242
+ const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-H5MUAC4X.js");
19122
19243
  ctx.send({
19123
19244
  type: "export_data",
19124
19245
  format: "md",
@@ -20123,7 +20244,7 @@ No tools match "${filter}".
20123
20244
  const { join: join26 } = await import("path");
20124
20245
  const { existsSync: existsSync32 } = await import("fs");
20125
20246
  const { getGitRoot: getGitRoot2 } = await import("./git-context-VNCA2GU7.js");
20126
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-EHYM2NS5.js");
20247
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-P5JJ6FO4.js");
20127
20248
  const { approveProject, hashMcpFile } = await import("./project-trust-6CJB5ZMX.js");
20128
20249
  const cwd = process.cwd();
20129
20250
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -21042,7 +21163,7 @@ function createReviewCommands() {
21042
21163
  usage: "/test [command|filter]",
21043
21164
  async execute(args, ctx) {
21044
21165
  try {
21045
- const { executeTests } = await import("./run-tests-HCID73KE.js");
21166
+ const { executeTests } = await import("./run-tests-6JKF6JJZ.js");
21046
21167
  const argStr = args.join(" ").trim();
21047
21168
  let testArgs = {};
21048
21169
  if (argStr) {
@@ -21784,7 +21905,7 @@ ${view.chatHeading}
21784
21905
 
21785
21906
  // src/repl/commands/session-commands.ts
21786
21907
  import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync14 } from "fs";
21787
- import { resolve as resolve11, dirname as dirname9 } from "path";
21908
+ import { resolve as resolve11, dirname as dirname10 } from "path";
21788
21909
  import chalk7 from "chalk";
21789
21910
  function createSessionCommands() {
21790
21911
  return [
@@ -22074,7 +22195,7 @@ function createSessionCommands() {
22074
22195
  const exported = buildSessionExport(session, format, outFile);
22075
22196
  const absPath = resolve11(process.cwd(), exported.filename);
22076
22197
  try {
22077
- mkdirSync14(dirname9(absPath), { recursive: true });
22198
+ mkdirSync14(dirname10(absPath), { recursive: true });
22078
22199
  writeFileSync5(absPath, exported.content, "utf-8");
22079
22200
  ctx.renderer.printSuccess(`Exported ${exported.messageCount} messages \u2192 ${absPath}`);
22080
22201
  } catch (err) {
@@ -22241,7 +22362,7 @@ function createSessionCommands() {
22241
22362
  }
22242
22363
 
22243
22364
  // src/repl/commands/misc-commands.ts
22244
- import { basename as basename9 } from "path";
22365
+ import { basename as basename10 } from "path";
22245
22366
  import { platform as platform8 } from "os";
22246
22367
 
22247
22368
  // src/repl/clipboard.ts
@@ -22587,7 +22708,7 @@ ${hint}` : "")
22587
22708
  return;
22588
22709
  }
22589
22710
  const description = args.join(" ").trim() || "Please describe this image";
22590
- ctx.renderer.printSuccess(`\u{1F4CB} Image loaded: ${basename9(imgPath)}`);
22711
+ ctx.renderer.printSuccess(`\u{1F4CB} Image loaded: ${basename10(imgPath)}`);
22591
22712
  await ctx.sendAsChat(`@${imgPath} ${description}`);
22592
22713
  }
22593
22714
  },
@@ -23794,7 +23915,7 @@ Try: /compact to reduce context, /clear to reset, or switch to a larger-context
23794
23915
  });
23795
23916
  if (decision.kind === "save") {
23796
23917
  try {
23797
- mkdirSync15(dirname10(target), { recursive: true });
23918
+ mkdirSync15(dirname11(target), { recursive: true });
23798
23919
  atomicWriteFileSync(target, decision.body);
23799
23920
  undoStack.push(target, `save_last_response (deferred): ${target}`);
23800
23921
  const lines = decision.body.split("\n").length;
@@ -23972,7 +24093,7 @@ ${summaryContent}`,
23972
24093
  let isError = false;
23973
24094
  let summary;
23974
24095
  try {
23975
- mkdirSync15(dirname10(saveToFile), { recursive: true });
24096
+ mkdirSync15(dirname11(saveToFile), { recursive: true });
23976
24097
  fileStream = createWriteStream2(saveToFile);
23977
24098
  const teeSystemPrompt = stripToolCallReminder(systemPrompt ?? "") + CONTENT_ONLY_STREAM_REMINDER;
23978
24099
  const teeExtraMessages = extraMessages.length > 0 ? [...extraMessages, { role: "user", content: TEE_FINAL_USER_NUDGE }] : [{ role: "user", content: TEE_FINAL_USER_NUDGE }];
@@ -25007,7 +25128,7 @@ function getModuleDir() {
25007
25128
  if (typeof import.meta?.url === "string") {
25008
25129
  const url = new URL(import.meta.url);
25009
25130
  const filePath = url.pathname.replace(/^\/([A-Z]:)/i, "$1");
25010
- return dirname11(filePath);
25131
+ return dirname12(filePath);
25011
25132
  }
25012
25133
  } catch {
25013
25134
  }
@@ -158,7 +158,7 @@ ${content}`);
158
158
  }
159
159
  }
160
160
  async function runTaskMode(config, providers, configManager, topic) {
161
- const { TaskOrchestrator } = await import("./task-orchestrator-6NRCGF5V.js");
161
+ const { TaskOrchestrator } = await import("./task-orchestrator-EETPUWBK.js");
162
162
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
163
163
  let interrupted = false;
164
164
  const onSigint = () => {