jinzd-ai-cli 0.4.260 → 0.4.262

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 (39) hide show
  1. package/README.md +10 -8
  2. package/README.zh-CN.md +11 -9
  3. package/dist/{batch-LBMJWMMO.js → batch-2B7UUX27.js} +2 -2
  4. package/dist/{chunk-U2HN3EW6.js → chunk-25HFWCM3.js} +19 -7
  5. package/dist/{chunk-2BGNEVS5.js → chunk-2XPJRRBB.js} +4 -4
  6. package/dist/{chunk-AAWV4BP4.js → chunk-A6JLBNAI.js} +2 -2
  7. package/dist/{chunk-XTA3LSPQ.js → chunk-BS44XEZ4.js} +1 -1
  8. package/dist/{chunk-NEYNE6UE.js → chunk-D6DHS5GL.js} +11 -9
  9. package/dist/{chunk-63M2ELJS.js → chunk-FWBSGBB7.js} +4 -4
  10. package/dist/{chunk-HBR33J6J.js → chunk-HPDI4F5F.js} +1 -1
  11. package/dist/{chunk-Y7UZSFGS.js → chunk-JEJHNVA2.js} +1 -1
  12. package/dist/{chunk-CLJKNKUN.js → chunk-JFXKQPKY.js} +1 -1
  13. package/dist/{chunk-3TE7ZWO5.js → chunk-KMS3LBO3.js} +1 -1
  14. package/dist/{chunk-KRENSXPC.js → chunk-KWYJFLXY.js} +1 -1
  15. package/dist/{chunk-K6WMQBUP.js → chunk-MTIS7H6V.js} +1 -1
  16. package/dist/{chunk-VJP2GLW5.js → chunk-WAAFA32V.js} +1 -1
  17. package/dist/{chunk-FCPYMBTA.js → chunk-XZNRZGG2.js} +57 -25
  18. package/dist/{chunk-26C6YZ3A.js → chunk-ZQZEBPAQ.js} +1 -1
  19. package/dist/{ci-PSA7F4EI.js → ci-G6OZDH4H.js} +6 -6
  20. package/dist/{ci-format-WAHEZZMY.js → ci-format-BRS7G5X5.js} +2 -2
  21. package/dist/{constants-C55LGUR7.js → constants-24AD5JQV.js} +1 -1
  22. package/dist/{doctor-cli-YANDJBHC.js → doctor-cli-WWZRFGQJ.js} +6 -6
  23. package/dist/electron-server.js +87 -42
  24. package/dist/{hub-CBOC3TT3.js → hub-2DYZQVEN.js} +1 -1
  25. package/dist/index.js +90 -41
  26. package/dist/{persistent-memory-DUFOZTDV.js → persistent-memory-DFSZZSYP.js} +2 -2
  27. package/dist/{persistent-memory-KEYVKD54.js → persistent-memory-LJT37XVO.js} +2 -2
  28. package/dist/{pr-T6KCK5DT.js → pr-OOIQPCBX.js} +6 -6
  29. package/dist/{run-tests-K43DLTA3.js → run-tests-ICTVJSJN.js} +2 -2
  30. package/dist/{run-tests-S2RLPMCR.js → run-tests-W4TG4OQV.js} +2 -2
  31. package/dist/{server-GTRCCOXN.js → server-GTVYIHBG.js} +6 -6
  32. package/dist/{server-SV3TV5BJ.js → server-IXUVVPTV.js} +14 -14
  33. package/dist/{task-orchestrator-DW5AWW7J.js → task-orchestrator-6MHSDOFR.js} +6 -6
  34. package/dist/{usage-BP442V2Q.js → usage-23I3ZJZO.js} +2 -2
  35. package/dist/web/client/actions.js +12 -7
  36. package/dist/web/client/app.js +4 -36
  37. package/dist/web/client/sidebar-tabs.js +48 -0
  38. package/dist/web/client/sw.js +1 -1
  39. package/package.json +1 -1
@@ -34,14 +34,14 @@ import {
34
34
  touchMemoryReferences,
35
35
  updateMemoryApproval,
36
36
  updateMemoryEntry
37
- } from "./chunk-CLJKNKUN.js";
37
+ } from "./chunk-JFXKQPKY.js";
38
38
  import {
39
39
  redactJson,
40
40
  scanString
41
41
  } from "./chunk-YVTASHS5.js";
42
42
  import {
43
43
  runTestsTool
44
- } from "./chunk-XTA3LSPQ.js";
44
+ } from "./chunk-BS44XEZ4.js";
45
45
  import {
46
46
  AGENTIC_BEHAVIOR_GUIDELINE,
47
47
  APP_NAME,
@@ -73,7 +73,7 @@ import {
73
73
  SUBAGENT_MAX_ROUNDS_LIMIT,
74
74
  VERSION,
75
75
  buildUserIdentityPrompt
76
- } from "./chunk-26C6YZ3A.js";
76
+ } from "./chunk-ZQZEBPAQ.js";
77
77
  import {
78
78
  hasSemanticIndex,
79
79
  semanticSearch
@@ -1813,6 +1813,52 @@ CRITICAL \u2014 Batch file generation rules:
1813
1813
  4. Only produce a text summary AFTER all write_file calls have been made and returned success.
1814
1814
  5. The system compares every "file saved" claim against actual tool calls. Phantom claims trigger an automatic retry \u2014 do not waste rounds.`;
1815
1815
  var HALLUCINATION_CORRECTION_MESSAGE = "You did NOT actually call the write_file tool \u2014 the file was NOT created! Please immediately use the write_file tool via the function calling API to perform the actual file write. Do NOT describe file content in text \u2014 you MUST invoke write_file through the tool_calls mechanism.";
1816
+ var ACTION_WORD_RE = /(?:已[生保写创]|saved|written|created|完成.*(?:写入|保存|创建|生成)|输出|file\s+(?:saved|written|created))/i;
1817
+ var CLAUSE_BOUNDARY_RE = /[。.!?!?;;,,]/;
1818
+ var LIST_LINE_RE = /^\s*(?:[-*+]|\d+[.)]|\|)/;
1819
+ function hasWriteIntentNear(content, pathStart, pathEnd) {
1820
+ const lineStart = content.lastIndexOf("\n", pathStart - 1) + 1;
1821
+ const lineEndRaw = content.indexOf("\n", pathEnd);
1822
+ const lineEnd = lineEndRaw === -1 ? content.length : lineEndRaw;
1823
+ const currentLine = content.slice(lineStart, lineEnd);
1824
+ const prevLineStart = lineStart === 0 ? 0 : content.lastIndexOf("\n", lineStart - 2) + 1;
1825
+ const prevLine = lineStart === 0 ? "" : content.slice(prevLineStart, lineStart - 1);
1826
+ const introColon = /[::]\s*$/.test(prevLine);
1827
+ if (LIST_LINE_RE.test(currentLine) || introColon) {
1828
+ let pos = pathStart;
1829
+ let linesBack = 0;
1830
+ while (linesBack < 9 && pos > 0) {
1831
+ pos--;
1832
+ if (content[pos] === "\n") linesBack++;
1833
+ }
1834
+ const windowStart = pos === 0 ? 0 : pos + 1;
1835
+ return ACTION_WORD_RE.test(content.slice(windowStart, lineEnd));
1836
+ }
1837
+ const boundaryBefore = (from) => {
1838
+ for (let i = from - 1; i >= lineStart; i--) {
1839
+ if (CLAUSE_BOUNDARY_RE.test(content[i] ?? "")) return i + 1;
1840
+ }
1841
+ return lineStart;
1842
+ };
1843
+ let clauseEnd = lineEnd;
1844
+ for (let i = pathEnd; i < lineEnd; i++) {
1845
+ if (CLAUSE_BOUNDARY_RE.test(content[i] ?? "")) {
1846
+ clauseEnd = i + 1;
1847
+ break;
1848
+ }
1849
+ }
1850
+ const isBareClause = (text2) => text2.replace(/`[^`\n]*`/g, "").replace(content.slice(pathStart, pathEnd), "").replace(/[\s'"“”‘’()()、,,。;;::+\-和与及]/g, "").length <= 2;
1851
+ let start = boundaryBefore(pathStart);
1852
+ let text = content.slice(start, clauseEnd);
1853
+ if (ACTION_WORD_RE.test(text)) return true;
1854
+ for (let step = 0; step < 6 && start > lineStart && isBareClause(text); step++) {
1855
+ const prevEnd = start - 1;
1856
+ start = boundaryBefore(prevEnd);
1857
+ text = content.slice(start, prevEnd);
1858
+ if (ACTION_WORD_RE.test(text)) return true;
1859
+ }
1860
+ return false;
1861
+ }
1816
1862
  function extractClaimedFilePaths(content) {
1817
1863
  const paths = /* @__PURE__ */ new Set();
1818
1864
  const add = (p) => {
@@ -1820,36 +1866,19 @@ function extractClaimedFilePaths(content) {
1820
1866
  if (trimmed && /\.\w{1,6}$/.test(trimmed)) paths.add(trimmed);
1821
1867
  };
1822
1868
  let m;
1823
- const actionLineRe = /(?:已[生保写创]|saved|written|created|完成.*(?:写入|保存|创建|生成)|输出|file\s+(?:saved|written|created))/i;
1824
1869
  const backtickRe = /`([^`\n]+?\.\w{1,6})`/g;
1825
1870
  while ((m = backtickRe.exec(content)) !== null) {
1826
- let pos = m.index;
1827
- let linesBack = 0;
1828
- while (linesBack < 9 && pos > 0) {
1829
- pos--;
1830
- if (content[pos] === "\n") linesBack++;
1831
- }
1832
- const windowStart = pos === 0 ? 0 : pos + 1;
1833
- const lineEndIdx = content.indexOf("\n", m.index + m[0].length);
1834
- const window = content.slice(windowStart, lineEndIdx === -1 ? void 0 : lineEndIdx);
1835
- if (actionLineRe.test(window)) add(m[1]);
1871
+ const pathStart = m.index + m[0].indexOf(m[1]);
1872
+ if (hasWriteIntentNear(content, pathStart, pathStart + m[1].length)) add(m[1]);
1836
1873
  }
1837
- const zhRe = /(?:已保存(?:到)?|已写入(?:到)?|已创建|已生成|文件路径[::]|保存为|写入到)\s*[`'”””]?([^\s`'”””,,。\n]+?\.\w{1,6})/g;
1874
+ const zhRe = /(?:已保存(?:到)?|已写入(?:到)?|已创建|已生成|文件路径[::]|保存为|写入到)\s*[`'”””]?([^\s`'”””,,。\n]+\.\w{1,6})/g;
1838
1875
  while ((m = zhRe.exec(content)) !== null) add(m[1]);
1839
- const enRe = /(?:saved|written|created)\s+(?:to|as|at)\s+[`'”]?([^\s`'”\n,]+?\.\w{1,6})/gi;
1876
+ const enRe = /(?:saved|written|created)\s+(?:to|as|at)\s+[`'”]?([^\s`'”\n,]+\.\w{1,6})/gi;
1840
1877
  while ((m = enRe.exec(content)) !== null) add(m[1]);
1841
1878
  const checkRe = /✅[^\n`]*?[`'”]?([^\s`'”\n,,。]+?\.\w{1,6})/g;
1842
1879
  while ((m = checkRe.exec(content)) !== null) {
1843
- let pos = m.index;
1844
- let linesBack = 0;
1845
- while (linesBack < 9 && pos > 0) {
1846
- pos--;
1847
- if (content[pos] === "\n") linesBack++;
1848
- }
1849
- const windowStart = pos === 0 ? 0 : pos + 1;
1850
- const lineEndIdx = content.indexOf("\n", m.index + m[0].length);
1851
- const window = content.slice(windowStart, lineEndIdx === -1 ? void 0 : lineEndIdx);
1852
- if (actionLineRe.test(window)) add(m[1]);
1880
+ const pathStart = m.index + m[0].lastIndexOf(m[1]);
1881
+ if (hasWriteIntentNear(content, pathStart, pathStart + m[1].length)) add(m[1]);
1853
1882
  }
1854
1883
  return Array.from(paths);
1855
1884
  }
@@ -1962,7 +1991,7 @@ function findPhantomClaims(content, extraMessages) {
1962
1991
  }
1963
1992
  function buildPhantomCorrectionMessage(phantoms) {
1964
1993
  const list = phantoms.map((p) => ` - ${p}`).join("\n");
1965
- return "You claimed to have written the following file(s), but no matching write_file tool call was actually made in this turn:\n" + list + '\n\nEach of these files does NOT exist on disk. You MUST now invoke write_file (via the function calling API) for every missing file listed above. Do NOT output another "completion summary" until the tool calls have actually been made.';
1994
+ return 'Your reply mentions the following file(s) alongside a "written / saved / created" claim, but no matching write_file or edit_file tool call was made in this turn:\n' + list + "\n\nIf you did intend to create or modify them, invoke write_file / edit_file NOW \u2014 they do not exist on disk yet, and you must not report the task as done until the tool calls return.\n\nIf you were only REFERENCING them (files you merely read, cited as examples, or named as prior art), then this was a false alarm: do NOT create them, do NOT overwrite anything. Simply restate your answer and say explicitly which of the listed paths you only read or cited. Creating a file that the user never asked for is worse than the false alarm.";
1966
1995
  }
1967
1996
  var DSML_PIPE_CLASS = "[|\\uFF5C\\u2502\\u2503\\u01C0]";
1968
1997
  var PSEUDO_TOOL_CALL_PATTERNS = [
@@ -2597,6 +2626,8 @@ async function runAgentLoop(host) {
2597
2626
  const freeRounds = new FreeRoundTracker();
2598
2627
  const roundToolHistory = [];
2599
2628
  const hasWriteTools = host.toolDefs.some((t) => t.name === "write_file" || t.name === "edit_file");
2629
+ let hallucinationRetries = 0;
2630
+ const MAX_HALLUCINATION_RETRIES = 2;
2600
2631
  for (let round = 0; round < maxToolRounds; round++) {
2601
2632
  if (host.signal?.aborted) return { reason: "aborted", usage };
2602
2633
  host.onRoundStart?.(round, maxToolRounds);
@@ -2634,7 +2665,8 @@ async function runAgentLoop(host) {
2634
2665
  const phantomPaths = (coarseHallucination || alreadyWrote) && !host.planMode && hasWriteTools && content ? findPhantomClaims(content, extraMessages) : [];
2635
2666
  const bashRanThisTurn = extractBashCommands(extraMessages).length > 0;
2636
2667
  const coarseShouldFire = coarseHallucination && !bashRanThisTurn;
2637
- if ((phantomPaths.length > 0 || coarseShouldFire) && round < maxToolRounds - 1) {
2668
+ if ((phantomPaths.length > 0 || coarseShouldFire) && round < maxToolRounds - 1 && hallucinationRetries < MAX_HALLUCINATION_RETRIES) {
2669
+ hallucinationRetries++;
2638
2670
  host.onHallucinationRetry?.({ phantomPaths, round, alreadyRendered });
2639
2671
  const correctionMsg = phantomPaths.length > 0 ? buildPhantomCorrectionMessage(phantomPaths) : HALLUCINATION_CORRECTION_MESSAGE;
2640
2672
  const reasoningField = outcome.reasoningContent ? { reasoning_content: outcome.reasoningContent } : host.providerId === "deepseek" ? { reasoning_content: "" } : {};
@@ -3959,6 +3991,18 @@ var BUILT_IN_PROVIDERS = [
3959
3991
  OpenRouterProvider,
3960
3992
  OllamaProvider
3961
3993
  ];
3994
+ function listBuiltInProviderMetadata() {
3995
+ return BUILT_IN_PROVIDERS.map((ProviderClass) => {
3996
+ const { info } = new ProviderClass();
3997
+ return {
3998
+ id: info.id,
3999
+ displayName: info.displayName,
4000
+ defaultModel: info.defaultModel,
4001
+ apiKeyEnvVar: info.apiKeyEnvVar,
4002
+ requiresApiKey: info.requiresApiKey
4003
+ };
4004
+ });
4005
+ }
3962
4006
  var ProviderRegistry = class {
3963
4007
  providers = /* @__PURE__ */ new Map();
3964
4008
  customConfigs = [];
@@ -4053,13 +4097,12 @@ var ProviderRegistry = class {
4053
4097
  return [...this.providers.values()];
4054
4098
  }
4055
4099
  listAll() {
4056
- const builtIn = BUILT_IN_PROVIDERS.map((P) => {
4057
- const p = new P();
4100
+ const builtIn = listBuiltInProviderMetadata().map((info) => {
4058
4101
  return {
4059
- id: p.info.id,
4060
- displayName: p.info.displayName,
4061
- configured: this.providers.has(p.info.id),
4062
- defaultModel: p.info.defaultModel,
4102
+ id: info.id,
4103
+ displayName: info.displayName,
4104
+ configured: this.providers.has(info.id),
4105
+ defaultModel: info.defaultModel,
4063
4106
  isCustom: false
4064
4107
  };
4065
4108
  });
@@ -5081,9 +5124,9 @@ function buildWrappedCommand(command, id, isWindows) {
5081
5124
  if (!isWindows) {
5082
5125
  return `echo "${markerStart}"; ${command}; echo "${markerEnd}:$?"`;
5083
5126
  }
5084
- const inner = `${WIN_UTF8_PREAMBLE} Write-Output "${markerStart}"; ${command}; $__ok = $?; $__ec = $LASTEXITCODE; $__code = if ($__ok) { 0 } elseif ($null -ne $__ec -and $__ec -ne 0) { $__ec } else { 1 }; Write-Output "${markerEnd}:$__code"`;
5085
- const b64 = Buffer.from(inner, "utf-8").toString("base64");
5086
- return `Invoke-Expression ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${b64}')))`;
5127
+ const b64 = Buffer.from(command, "utf-8").toString("base64");
5128
+ const decoded = `[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${b64}'))`;
5129
+ return `${WIN_UTF8_PREAMBLE} Write-Output "${markerStart}"; $global:LASTEXITCODE = 0; Invoke-Expression (${decoded}); $__ok = $?; $__ec = $LASTEXITCODE; $__code = if ($null -ne $__ec -and $__ec -ne 0) { $__ec } elseif ($__ok) { 0 } else { 1 }; Write-Output "${markerEnd}:$__code"`;
5087
5130
  }
5088
5131
  async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
5089
5132
  let entry = pool.get(sessionKey);
@@ -8446,7 +8489,9 @@ Note: Path can be absolute or relative to cwd.`,
8446
8489
  }
8447
8490
  const lines = [];
8448
8491
  if (anyFailed && stopOnError) {
8449
- lines.push(`ERROR: Batch edit aborted \u2014 ${appliedCount}/${edits.length} applied, then edit #${appliedCount} failed. No changes written (stop_on_error=true).`);
8492
+ const failedIdx = reports.find((r) => !r.ok)?.index;
8493
+ const failedLabel = failedIdx != null ? `#${failedIdx + 1}` : "an edit";
8494
+ lines.push(`ERROR: Batch edit aborted \u2014 ${appliedCount}/${edits.length} applied, then edit ${failedLabel} failed. No changes written (stop_on_error=true).`);
8450
8495
  } else if (anyFailed) {
8451
8496
  lines.push(`Partial success: ${appliedCount}/${edits.length} edits applied to ${filePath} (stop_on_error=false).`);
8452
8497
  } else {
@@ -15335,7 +15380,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
15335
15380
  Cost: ${formatCost(cost)}` : "";
15336
15381
  let memoryLine = "";
15337
15382
  try {
15338
- const { countPendingMemories } = await import("./persistent-memory-DUFOZTDV.js");
15383
+ const { countPendingMemories } = await import("./persistent-memory-DFSZZSYP.js");
15339
15384
  const pending = countPendingMemories(ctx.config.getConfigDir());
15340
15385
  if (pending > 0) memoryLine = `
15341
15386
  Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
@@ -16144,14 +16189,14 @@ async function handleSecurityReview(args, ctx) {
16144
16189
  async function handleTest(args, ctx) {
16145
16190
  ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
16146
16191
  try {
16147
- const { executeTests } = await import("./run-tests-S2RLPMCR.js");
16148
16192
  const argStr = args.join(" ").trim();
16149
16193
  let testArgs = {};
16150
16194
  if (argStr) {
16151
16195
  const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
16152
16196
  testArgs = isCommand ? { command: argStr } : { filter: argStr };
16153
16197
  }
16154
- const report = await executeTests(testArgs);
16198
+ const runTests = ctx.runTests ?? (await import("./run-tests-W4TG4OQV.js")).executeTests;
16199
+ const report = await runTests(testArgs);
16155
16200
  ctx.send({ type: "info", message: report });
16156
16201
  } catch (err) {
16157
16202
  ctx.send({ type: "error", message: `Test failed: ${err.message}` });
@@ -16408,7 +16453,7 @@ async function handleMemory(args, ctx) {
16408
16453
  ctx.handleMemoryManage(sub, args[1], sub === "expire" ? args[2] : void 0);
16409
16454
  } else if (sub === "export") {
16410
16455
  if (args[1] === "md") {
16411
- const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-DUFOZTDV.js");
16456
+ const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-DFSZZSYP.js");
16412
16457
  ctx.send({
16413
16458
  type: "export_data",
16414
16459
  format: "md",
@@ -154,7 +154,7 @@ ${content}`);
154
154
  }
155
155
  }
156
156
  async function runTaskMode(config, providers, configManager, topic) {
157
- const { TaskOrchestrator } = await import("./task-orchestrator-DW5AWW7J.js");
157
+ const { TaskOrchestrator } = await import("./task-orchestrator-6MHSDOFR.js");
158
158
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
159
159
  let interrupted = false;
160
160
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  scanProject,
18
18
  sessionHasMeaningfulContent,
19
19
  setupProxy
20
- } from "./chunk-AAWV4BP4.js";
20
+ } from "./chunk-A6JLBNAI.js";
21
21
  import {
22
22
  computeCost,
23
23
  formatCost,
@@ -50,7 +50,7 @@ import {
50
50
  spawnAgentContext,
51
51
  theme,
52
52
  undoStack
53
- } from "./chunk-NEYNE6UE.js";
53
+ } from "./chunk-D6DHS5GL.js";
54
54
  import {
55
55
  addMemoryEntry,
56
56
  backupMemoryStore,
@@ -76,7 +76,7 @@ import {
76
76
  touchMemoryReferences,
77
77
  updateMemoryApproval,
78
78
  updateMemoryEntry
79
- } from "./chunk-3TE7ZWO5.js";
79
+ } from "./chunk-KMS3LBO3.js";
80
80
  import "./chunk-GLSR2NR3.js";
81
81
  import "./chunk-UUSRWSSX.js";
82
82
  import "./chunk-CKH4KQ4E.js";
@@ -90,13 +90,14 @@ import {
90
90
  formatDoctorReport,
91
91
  loadContextFiles,
92
92
  writeCrashLog
93
- } from "./chunk-63M2ELJS.js";
93
+ } from "./chunk-FWBSGBB7.js";
94
94
  import {
95
- ProviderRegistry
96
- } from "./chunk-U2HN3EW6.js";
95
+ ProviderRegistry,
96
+ listBuiltInProviderMetadata
97
+ } from "./chunk-25HFWCM3.js";
97
98
  import {
98
99
  ConfigManager
99
- } from "./chunk-K6WMQBUP.js";
100
+ } from "./chunk-MTIS7H6V.js";
100
101
  import {
101
102
  describePlugin,
102
103
  getActivePluginAssets,
@@ -113,7 +114,7 @@ import {
113
114
  trustHook,
114
115
  trustPlugin,
115
116
  untrustHook
116
- } from "./chunk-Y7UZSFGS.js";
117
+ } from "./chunk-JEJHNVA2.js";
117
118
  import {
118
119
  CONTENT_ONLY_STREAM_REMINDER,
119
120
  TEE_FINAL_USER_NUDGE,
@@ -133,7 +134,7 @@ import {
133
134
  stripOuterCodeFence,
134
135
  stripToolCallReminder,
135
136
  teeStreamErrorSummary
136
- } from "./chunk-FCPYMBTA.js";
137
+ } from "./chunk-XZNRZGG2.js";
137
138
  import {
138
139
  AuthError,
139
140
  ProviderError,
@@ -147,7 +148,7 @@ import {
147
148
  import {
148
149
  fileCheckpoints
149
150
  } from "./chunk-4BKXL7SM.js";
150
- import "./chunk-HBR33J6J.js";
151
+ import "./chunk-HPDI4F5F.js";
151
152
  import {
152
153
  AGENTIC_BEHAVIOR_GUIDELINE,
153
154
  AUTHOR,
@@ -166,7 +167,7 @@ import {
166
167
  SKILLS_DIR_NAME,
167
168
  VERSION,
168
169
  buildUserIdentityPrompt
169
- } from "./chunk-KRENSXPC.js";
170
+ } from "./chunk-KWYJFLXY.js";
170
171
  import {
171
172
  buildChatIndex,
172
173
  clearChatIndex,
@@ -1398,7 +1399,7 @@ No tools match "${filter}".
1398
1399
  const { join: join6 } = await import("path");
1399
1400
  const { existsSync: existsSync6 } = await import("fs");
1400
1401
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1401
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-C55LGUR7.js");
1402
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-24AD5JQV.js");
1402
1403
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1403
1404
  const cwd = process.cwd();
1404
1405
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -1602,6 +1603,15 @@ No tools match "${filter}".
1602
1603
  // src/repl/commands/security-commands.ts
1603
1604
  import { platform as platform2 } from "os";
1604
1605
  import chalk2 from "chalk";
1606
+ function stripSurroundingQuotes(value) {
1607
+ const pairs = [['"', '"'], ["'", "'"], ["\u201C", "\u201D"], ["\u2018", "\u2019"], ["\u300C", "\u300D"]];
1608
+ for (const [open, close] of pairs) {
1609
+ if (value.length >= 2 && value.startsWith(open) && value.endsWith(close)) {
1610
+ return value.slice(open.length, value.length - close.length).trim();
1611
+ }
1612
+ }
1613
+ return value;
1614
+ }
1605
1615
  function createSecurityCommands() {
1606
1616
  return [
1607
1617
  {
@@ -1702,9 +1712,9 @@ function createSecurityCommands() {
1702
1712
  }
1703
1713
  const updated = { ...profile };
1704
1714
  if (field === "interests") {
1705
- updated.interests = value.split(",").map((s) => s.trim()).filter(Boolean);
1715
+ updated.interests = value.split(",").map((s) => stripSurroundingQuotes(s.trim())).filter(Boolean);
1706
1716
  } else {
1707
- updated[field] = value;
1717
+ updated[field] = stripSurroundingQuotes(value);
1708
1718
  }
1709
1719
  ctx.config.set("userProfile", updated);
1710
1720
  ctx.config.save();
@@ -2377,7 +2387,7 @@ function createReviewCommands() {
2377
2387
  usage: "/test [command|filter]",
2378
2388
  async execute(args, ctx) {
2379
2389
  try {
2380
- const { executeTests } = await import("./run-tests-K43DLTA3.js");
2390
+ const { executeTests } = await import("./run-tests-ICTVJSJN.js");
2381
2391
  const argStr = args.join(" ").trim();
2382
2392
  let testArgs = {};
2383
2393
  if (argStr) {
@@ -5206,6 +5216,23 @@ var IMAGE_MIME = {
5206
5216
  ".webp": "image/webp"
5207
5217
  };
5208
5218
  var MAX_IMAGE_BYTES = 10 * 1024 * 1024;
5219
+ var MAX_PATH_SPACE_TOKENS = 8;
5220
+ function expandUnquotedPath(input2, pathStart, rawPath, cwd) {
5221
+ const plain = { raw: rawPath, consumed: rawPath.length };
5222
+ if (existsSync4(resolve2(cwd, rawPath))) return plain;
5223
+ let acc = rawPath;
5224
+ let consumed = rawPath.length;
5225
+ let rest = input2.slice(pathStart + rawPath.length);
5226
+ for (let i = 0; i < MAX_PATH_SPACE_TOKENS; i++) {
5227
+ const next = /^([ \t]+)(\S+)/.exec(rest);
5228
+ if (!next) break;
5229
+ acc += next[1] + next[2];
5230
+ consumed += next[0].length;
5231
+ rest = rest.slice(next[0].length);
5232
+ if (existsSync4(resolve2(cwd, acc))) return { raw: acc, consumed };
5233
+ }
5234
+ return plain;
5235
+ }
5209
5236
  function parseAtReferences(input2, cwd) {
5210
5237
  const atPattern = /@(?:"([^"]+)"|'([^']+)'|(\S+))/g;
5211
5238
  const refs = [];
@@ -5213,7 +5240,17 @@ function parseAtReferences(input2, cwd) {
5213
5240
  let textBody = input2;
5214
5241
  let match;
5215
5242
  while ((match = atPattern.exec(input2)) !== null) {
5216
- const rawPath = match[1] ?? match[2] ?? match[3] ?? "";
5243
+ let rawPath = match[1] ?? match[2] ?? match[3] ?? "";
5244
+ let matchedText = match[0];
5245
+ if (match[3] !== void 0) {
5246
+ const pathStart = match.index + 1;
5247
+ const expanded = expandUnquotedPath(input2, pathStart, rawPath, cwd);
5248
+ if (expanded.consumed > rawPath.length) {
5249
+ rawPath = expanded.raw;
5250
+ matchedText = "@" + expanded.raw;
5251
+ atPattern.lastIndex = pathStart + expanded.consumed;
5252
+ }
5253
+ }
5217
5254
  const absPath = resolve2(cwd, rawPath);
5218
5255
  const ext = extname3(rawPath).toLowerCase();
5219
5256
  const mime = IMAGE_MIME[ext];
@@ -5233,7 +5270,7 @@ function parseAtReferences(input2, cwd) {
5233
5270
  image_url: { url: `data:${mime};base64,${data}` }
5234
5271
  });
5235
5272
  refs.push({ path: rawPath, type: "image" });
5236
- textBody = textBody.replace(match[0], "").trim();
5273
+ textBody = textBody.replace(matchedText, "").trim();
5237
5274
  } else {
5238
5275
  const content = readFileSync4(absPath, "utf-8");
5239
5276
  const inlined = `
@@ -5242,7 +5279,7 @@ function parseAtReferences(input2, cwd) {
5242
5279
  \`\`\`
5243
5280
  ${content}
5244
5281
  \`\`\``;
5245
- textBody = textBody.replace(match[0], inlined);
5282
+ textBody = textBody.replace(matchedText, inlined);
5246
5283
  refs.push({ path: rawPath, type: "text" });
5247
5284
  }
5248
5285
  }
@@ -5254,6 +5291,16 @@ ${content}
5254
5291
  return { parts, hasImage: imageParts.length > 0, refs };
5255
5292
  }
5256
5293
 
5294
+ // src/repl/startup-notice.ts
5295
+ function writeStartupNotice(line, promptShown, redraw) {
5296
+ if (promptShown) {
5297
+ process.stdout.write("\n" + line);
5298
+ redraw();
5299
+ } else {
5300
+ process.stdout.write(line);
5301
+ }
5302
+ }
5303
+
5257
5304
  // src/core/model-router.ts
5258
5305
  var TAG_REGEX = /(?:^|\s)#([a-zA-Z][\w-]{0,31})\b/g;
5259
5306
  function extractTags(message) {
@@ -5597,6 +5644,8 @@ var Repl = class {
5597
5644
  config;
5598
5645
  events;
5599
5646
  rl;
5647
+ /** 第一次 prompt 是否已画出(决定启动期后台横幅要不要重画 prompt)。 */
5648
+ firstPromptShown = false;
5600
5649
  currentProvider;
5601
5650
  currentModel;
5602
5651
  running = false;
@@ -6063,7 +6112,11 @@ ${ctxLine}` : "")
6063
6112
  const promptStr = theme.success(`[${this.currentProvider}]`) + skillTag + planTag + thinkTag + chalk5.white(" > ");
6064
6113
  this.rl.setPrompt(promptStr);
6065
6114
  }
6115
+ notice(line) {
6116
+ writeStartupNotice(line, this.firstPromptShown, () => this.showPrompt());
6117
+ }
6066
6118
  showPrompt() {
6119
+ this.firstPromptShown = true;
6067
6120
  this.refreshPrompt();
6068
6121
  const rlInternal2 = this.rl;
6069
6122
  rlInternal2.prevRows = 0;
@@ -6217,12 +6270,12 @@ Session '${this.resumeSessionId}' not found.
6217
6270
  const existed = loadIndex(root);
6218
6271
  const { stats } = await indexProject(root);
6219
6272
  if (!existed) {
6220
- process.stdout.write(
6273
+ this.notice(
6221
6274
  theme.dim(` \u{1F50E} Symbol index built: ${stats.symbols} symbols across ${stats.filesParsed} files
6222
6275
  `)
6223
6276
  );
6224
6277
  } else if (stats.filesParsed > 0) {
6225
- process.stdout.write(
6278
+ this.notice(
6226
6279
  theme.dim(` \u{1F50E} Symbol index refreshed: ${stats.filesParsed} file(s) updated
6227
6280
  `)
6228
6281
  );
@@ -6243,7 +6296,7 @@ Session '${this.resumeSessionId}' not found.
6243
6296
  try {
6244
6297
  const sessionCount = this.sessions.listSessions().length;
6245
6298
  if (sessionCount >= 5) {
6246
- process.stdout.write(theme.dim(
6299
+ this.notice(theme.dim(
6247
6300
  ` \u{1F4A1} ${sessionCount} past sessions have no memory index \u2014 run /memory rebuild to enable cross-session recall (first run downloads ~117 MB)
6248
6301
  `
6249
6302
  ));
@@ -6260,7 +6313,7 @@ Session '${this.resumeSessionId}' not found.
6260
6313
  sessions: after.sessions
6261
6314
  };
6262
6315
  if (stats.sessionsIndexed > 0 || stats.chunksRemoved > 0) {
6263
- process.stdout.write(
6316
+ this.notice(
6264
6317
  theme.dim(
6265
6318
  ` \u{1F9E0} Chat memory refreshed: ${stats.chunksAdded} new \xB7 ${stats.chunksRemoved} removed \xB7 ${stats.chunksTotal} total
6266
6319
  `
@@ -6309,7 +6362,7 @@ Session '${this.resumeSessionId}' not found.
6309
6362
  this.mcpManager = new McpManager();
6310
6363
  const mcpProjectCount = Object.keys(projectMcpServers).length;
6311
6364
  let bannerEmitted = false;
6312
- const emitBanner = (afterDeadline) => {
6365
+ const emitBanner = () => {
6313
6366
  if (bannerEmitted) return;
6314
6367
  bannerEmitted = true;
6315
6368
  const statuses = this.mcpManager.getStatus();
@@ -6323,12 +6376,7 @@ Session '${this.resumeSessionId}' not found.
6323
6376
  const names = failed.map((f) => f.serverId).join(", ");
6324
6377
  line += ` \u26A0 failed: ${names}`;
6325
6378
  }
6326
- if (afterDeadline) {
6327
- process.stdout.write("\n" + theme.dim(line) + "\n");
6328
- this.showPrompt();
6329
- } else {
6330
- process.stdout.write(theme.dim(line) + "\n");
6331
- }
6379
+ this.notice(theme.dim(line) + "\n");
6332
6380
  };
6333
6381
  mcpReadyPromise = this.mcpManager.connectAll(mergedMcpServers, { quiet: true }).then(() => {
6334
6382
  const mcpTools = this.mcpManager.getAllTools();
@@ -6349,9 +6397,9 @@ Session '${this.resumeSessionId}' not found.
6349
6397
  deadlinePromise
6350
6398
  ]);
6351
6399
  if (winner === "ready") {
6352
- emitBanner(false);
6400
+ emitBanner();
6353
6401
  } else {
6354
- void mcpReadyPromise.then(() => emitBanner(true));
6402
+ void mcpReadyPromise.then(() => emitBanner());
6355
6403
  }
6356
6404
  }
6357
6405
  this.setupClipboardPaste();
@@ -8018,8 +8066,9 @@ process.on("unhandledRejection", (reason) => {
8018
8066
  `);
8019
8067
  process.exit(1);
8020
8068
  });
8069
+ var builtInProviderIds = listBuiltInProviderMetadata().map(({ id }) => id).join("/");
8021
8070
  program.name("aicli").description("Cross-platform REPL-style AI CLI with multi-provider support").version(VERSION);
8022
- program.option("--provider <name>", "AI provider to use (claude/gemini/deepseek/zhipu/kimi or any custom provider)").option("-m, --model <name>", "Model to use").option("-p, --prompt <text>", "Headless mode: send a single prompt and exit (reads stdin as context if piped)").option("--system <prompt>", "System prompt override (headless mode)").option("--json", "Output result as JSON object (headless mode only)").option("--output-format <format>", "Output format: text (default) | streaming-json (NDJSON per-chunk, headless only)").option("--no-stream", "Disable streaming output").option("--allowed-tools <tools>", "Comma-separated whitelist of tools (e.g. bash,read_file)").option("--blocked-tools <tools>", "Comma-separated blacklist of tools (e.g. bash,write_file)").option("--resume <id>", "Resume a previous session by ID (prefix match supported)").option("--max-tool-rounds <n>", "Max agentic tool-call rounds per conversation (default: 200)").action(async (options) => {
8071
+ program.option("--provider <name>", `AI provider to use (${builtInProviderIds}, or any custom provider)`).option("-m, --model <name>", "Model to use").option("-p, --prompt <text>", "Headless mode: send a single prompt and exit (reads stdin as context if piped)").option("--system <prompt>", "System prompt override (headless mode)").option("--json", "Output result as JSON object (headless mode only)").option("--output-format <format>", "Output format: text (default) | streaming-json (NDJSON per-chunk, headless only)").option("--no-stream", "Disable streaming output").option("--allowed-tools <tools>", "Comma-separated whitelist of tools (e.g. bash,read_file)").option("--blocked-tools <tools>", "Comma-separated blacklist of tools (e.g. bash,write_file)").option("--resume <id>", "Resume a previous session by ID (prefix match supported)").option("--max-tool-rounds <n>", "Max agentic tool-call rounds per conversation (default: 200)").action(async (options) => {
8023
8072
  if (options.prompt !== void 0) {
8024
8073
  await runHeadless(options);
8025
8074
  } else {
@@ -8066,7 +8115,7 @@ program.command("web").description("Start Web UI server with browser-based chat
8066
8115
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
8067
8116
  process.exit(1);
8068
8117
  }
8069
- const { startWebServer } = await import("./server-SV3TV5BJ.js");
8118
+ const { startWebServer } = await import("./server-IXUVVPTV.js");
8070
8119
  await startWebServer({ port, host: options.host });
8071
8120
  });
8072
8121
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
@@ -8233,11 +8282,11 @@ program.command("sessions").description("List recent conversation sessions").opt
8233
8282
  console.log(footer + "\n");
8234
8283
  });
8235
8284
  program.command("usage").description("Show token + cost usage grouped by provider/model (cross-session)").option("--days <n>", "Only the last N days (inclusive of today)").option("--month <ym>", "Only a specific month, format YYYY-MM (e.g. 2026-06)").option("--json", "Output as JSON (for scripting)").action(async (options) => {
8236
- const { runUsageCli } = await import("./usage-BP442V2Q.js");
8285
+ const { runUsageCli } = await import("./usage-23I3ZJZO.js");
8237
8286
  await runUsageCli(options);
8238
8287
  });
8239
8288
  program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
8240
- const { runDoctorCli } = await import("./doctor-cli-YANDJBHC.js");
8289
+ const { runDoctorCli } = await import("./doctor-cli-WWZRFGQJ.js");
8241
8290
  const argv = process.argv.slice(2);
8242
8291
  await runDoctorCli({
8243
8292
  json: !!options.json || argv.includes("--json"),
@@ -8246,7 +8295,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
8246
8295
  });
8247
8296
  program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
8248
8297
  try {
8249
- const batch = await import("./batch-LBMJWMMO.js");
8298
+ const batch = await import("./batch-2B7UUX27.js");
8250
8299
  switch (action) {
8251
8300
  case "submit":
8252
8301
  if (!arg) {
@@ -8289,7 +8338,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
8289
8338
  }
8290
8339
  });
8291
8340
  program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
8292
- const { startMcpServer } = await import("./server-GTRCCOXN.js");
8341
+ const { startMcpServer } = await import("./server-GTVYIHBG.js");
8293
8342
  await startMcpServer({
8294
8343
  allowDestructive: !!options.allowDestructive,
8295
8344
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -8302,7 +8351,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
8302
8351
  console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
8303
8352
  process.exit(1);
8304
8353
  }
8305
- const { runPrCli } = await import("./pr-T6KCK5DT.js");
8354
+ const { runPrCli } = await import("./pr-OOIQPCBX.js");
8306
8355
  const result = await runPrCli({
8307
8356
  action,
8308
8357
  target,
@@ -8322,8 +8371,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
8322
8371
  process.exit(result.exitCode);
8323
8372
  });
8324
8373
  program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number or URL; diff fetched via gh pr diff <value>", (v) => /^#?\d+$/.test(v) ? parseInt(v.replace(/^#/, ""), 10) : v).option("--base <ref>", "Base ref for git diff <ref>...HEAD (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").option("--json", "Output a structured JSON report").option("--markdown", "Output Markdown report (default)").option("--sarif", "Output SARIF 2.1.0 for code scanning artifacts").option("--fail-on-security-high", "Fail when the security review contains HIGH/CRITICAL findings (default)").option("--no-fail-on-security-high", "Do not fail on security HIGH/CRITICAL findings").option("--fail-on-test-failure", "Fail when the report mentions test failures (default)").option("--no-fail-on-test-failure", "Do not fail on test failure findings").option("--fail-on-lint-failure", "Fail when the report mentions lint/typecheck failures (default)").option("--no-fail-on-lint-failure", "Do not fail on lint/typecheck failure findings").action(async (options) => {
8325
- const { runCi } = await import("./ci-PSA7F4EI.js");
8326
- const { formatCiResult } = await import("./ci-format-WAHEZZMY.js");
8374
+ const { runCi } = await import("./ci-G6OZDH4H.js");
8375
+ const { formatCiResult } = await import("./ci-format-BRS7G5X5.js");
8327
8376
  const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
8328
8377
  if (formats > 1) {
8329
8378
  console.error("Choose only one output format: --json, --markdown, or --sarif.");
@@ -8481,7 +8530,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
8481
8530
  config.get("customProviders"),
8482
8531
  config.getConfigDir()
8483
8532
  );
8484
- const { startHub } = await import("./hub-CBOC3TT3.js");
8533
+ const { startHub } = await import("./hub-2DYZQVEN.js");
8485
8534
  await startHub(
8486
8535
  {
8487
8536
  topic: topic ?? "",
@@ -27,9 +27,9 @@ import {
27
27
  touchMemoryReferences,
28
28
  updateMemoryApproval,
29
29
  updateMemoryEntry
30
- } from "./chunk-CLJKNKUN.js";
30
+ } from "./chunk-JFXKQPKY.js";
31
31
  import "./chunk-YVTASHS5.js";
32
- import "./chunk-26C6YZ3A.js";
32
+ import "./chunk-ZQZEBPAQ.js";
33
33
  import "./chunk-6BUTA5VW.js";
34
34
  export {
35
35
  addMemoryEntry,
@@ -28,9 +28,9 @@ import {
28
28
  touchMemoryReferences,
29
29
  updateMemoryApproval,
30
30
  updateMemoryEntry
31
- } from "./chunk-3TE7ZWO5.js";
31
+ } from "./chunk-KMS3LBO3.js";
32
32
  import "./chunk-HOSJZMQS.js";
33
- import "./chunk-KRENSXPC.js";
33
+ import "./chunk-KWYJFLXY.js";
34
34
  import "./chunk-B5TYJO7V.js";
35
35
  import "./chunk-IW3Q7AE5.js";
36
36
  export {