jinzd-ai-cli 0.4.28 → 0.4.29

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.
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.28";
9
+ var VERSION = "0.4.29";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -7,7 +7,7 @@ import {
7
7
  ProviderNotFoundError,
8
8
  RateLimitError,
9
9
  schemaToJsonSchema
10
- } from "./chunk-EWJQOJSB.js";
10
+ } from "./chunk-SXL6H7XR.js";
11
11
  import {
12
12
  APP_NAME,
13
13
  CONFIG_DIR_NAME,
@@ -20,7 +20,7 @@ import {
20
20
  MCP_TOOL_PREFIX,
21
21
  PLUGINS_DIR_NAME,
22
22
  VERSION
23
- } from "./chunk-7SW4XRDJ.js";
23
+ } from "./chunk-TE6QE7FJ.js";
24
24
 
25
25
  // src/config/config-manager.ts
26
26
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -1587,6 +1587,95 @@ Describing file content in text without calling the tool = the file does not exi
1587
1587
  If multiple files need to be generated, you MUST call write_file separately for each file \u2014 do not skip any.
1588
1588
  Do NOT output fake "completion summaries" unless you have actually completed all file writes via tool_calls.`;
1589
1589
  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.";
1590
+ function extractClaimedFilePaths(content) {
1591
+ const paths = /* @__PURE__ */ new Set();
1592
+ const add = (p) => {
1593
+ const trimmed = p.trim().replace(/[,,。、;;::]+$/, "");
1594
+ if (trimmed && /\.\w{1,6}$/.test(trimmed)) paths.add(trimmed);
1595
+ };
1596
+ const backtickRe = /`([^`\n]+?\.\w{1,6})`/g;
1597
+ let m;
1598
+ while ((m = backtickRe.exec(content)) !== null) add(m[1]);
1599
+ const zhRe = /(?:已保存(?:到)?|已写入(?:到)?|已创建|已生成|文件路径[::]|保存为|写入到)\s*[`'"“”]?([^\s`'"“”,,。\n]+?\.\w{1,6})/g;
1600
+ while ((m = zhRe.exec(content)) !== null) add(m[1]);
1601
+ const enRe = /(?:saved|written|created)\s+(?:to|as|at)\s+[`'"]?([^\s`'"\n,]+?\.\w{1,6})/gi;
1602
+ while ((m = enRe.exec(content)) !== null) add(m[1]);
1603
+ const checkRe = /✅[^\n`]*?[`'"]?([^\s`'"\n,,。]+?\.\w{1,6})/g;
1604
+ while ((m = checkRe.exec(content)) !== null) add(m[1]);
1605
+ return Array.from(paths);
1606
+ }
1607
+ function extractWrittenFilePaths(extraMessages) {
1608
+ const paths = /* @__PURE__ */ new Set();
1609
+ const msgs = extraMessages;
1610
+ const addFromArgs = (raw) => {
1611
+ if (typeof raw === "string") {
1612
+ try {
1613
+ const parsed = JSON.parse(raw);
1614
+ if (typeof parsed.path === "string") paths.add(parsed.path);
1615
+ } catch {
1616
+ }
1617
+ } else if (raw && typeof raw === "object") {
1618
+ const p = raw.path;
1619
+ if (typeof p === "string") paths.add(p);
1620
+ }
1621
+ };
1622
+ for (const msg of msgs) {
1623
+ if (msg.role === "assistant" && Array.isArray(msg.tool_calls)) {
1624
+ for (const tc of msg.tool_calls) {
1625
+ const fn = tc.function;
1626
+ const name = fn?.name ?? "";
1627
+ if (name === "write_file" || name === "edit_file") {
1628
+ addFromArgs(fn?.arguments);
1629
+ }
1630
+ }
1631
+ }
1632
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
1633
+ for (const block of msg.content) {
1634
+ if (block.type !== "tool_use") continue;
1635
+ const name = block.name ?? "";
1636
+ if (name === "write_file" || name === "edit_file") {
1637
+ addFromArgs(block.input);
1638
+ }
1639
+ }
1640
+ }
1641
+ if (msg.role === "model" && Array.isArray(msg.parts)) {
1642
+ for (const part of msg.parts) {
1643
+ const fc = part.functionCall;
1644
+ if (!fc) continue;
1645
+ const name = fc.name ?? "";
1646
+ if (name === "write_file" || name === "edit_file") {
1647
+ addFromArgs(fc.args);
1648
+ }
1649
+ }
1650
+ }
1651
+ }
1652
+ return Array.from(paths);
1653
+ }
1654
+ function findPhantomClaims(content, extraMessages) {
1655
+ const claimed = extractClaimedFilePaths(content);
1656
+ if (claimed.length === 0) return [];
1657
+ const normalize = (p) => p.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
1658
+ const basename2 = (p) => {
1659
+ const parts = normalize(p).split("/");
1660
+ return parts[parts.length - 1] ?? "";
1661
+ };
1662
+ const written = extractWrittenFilePaths(extraMessages).map(normalize);
1663
+ const writtenBases = new Set(written.map(basename2));
1664
+ const writtenFull = new Set(written);
1665
+ return claimed.filter((raw) => {
1666
+ const norm = normalize(raw);
1667
+ if (writtenFull.has(norm)) return false;
1668
+ for (const w of writtenFull) {
1669
+ if (w.endsWith("/" + norm) || norm.endsWith("/" + w)) return false;
1670
+ }
1671
+ if (writtenBases.has(basename2(norm))) return false;
1672
+ return true;
1673
+ });
1674
+ }
1675
+ function buildPhantomCorrectionMessage(phantoms) {
1676
+ const list = phantoms.map((p) => ` - ${p}`).join("\n");
1677
+ 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.';
1678
+ }
1590
1679
 
1591
1680
  // src/providers/kimi.ts
1592
1681
  var KIMI_XML_REMINDER = `
@@ -3335,6 +3424,8 @@ export {
3335
3424
  hadPreviousWriteToolCalls,
3336
3425
  TOOL_CALL_REMINDER,
3337
3426
  HALLUCINATION_CORRECTION_MESSAGE,
3427
+ findPhantomClaims,
3428
+ buildPhantomCorrectionMessage,
3338
3429
  ProviderRegistry,
3339
3430
  getContentText,
3340
3431
  SessionManager,
@@ -9,7 +9,7 @@ import {
9
9
  SUBAGENT_DEFAULT_MAX_ROUNDS,
10
10
  SUBAGENT_MAX_ROUNDS_LIMIT,
11
11
  runTestsTool
12
- } from "./chunk-7SW4XRDJ.js";
12
+ } from "./chunk-TE6QE7FJ.js";
13
13
 
14
14
  // src/tools/builtin/bash.ts
15
15
  import { execSync } from "child_process";
@@ -8,7 +8,7 @@ import { platform } from "os";
8
8
  import chalk from "chalk";
9
9
 
10
10
  // src/core/constants.ts
11
- var VERSION = "0.4.28";
11
+ var VERSION = "0.4.29";
12
12
  var APP_NAME = "ai-cli";
13
13
  var CONFIG_DIR_NAME = ".aicli";
14
14
  var CONFIG_FILE_NAME = "config.json";
@@ -387,7 +387,7 @@ ${content}`);
387
387
  }
388
388
  }
389
389
  async function runTaskMode(config, providers, configManager, topic) {
390
- const { TaskOrchestrator } = await import("./task-orchestrator-TDBWMIH4.js");
390
+ const { TaskOrchestrator } = await import("./task-orchestrator-LLCLCGR2.js");
391
391
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
392
392
  let interrupted = false;
393
393
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -8,8 +8,10 @@ import {
8
8
  SessionManager,
9
9
  SkillManager,
10
10
  TOOL_CALL_REMINDER,
11
+ buildPhantomCorrectionMessage,
11
12
  clearDevState,
12
13
  detectsHallucinatedFileOp,
14
+ findPhantomClaims,
13
15
  formatGitContextForPrompt,
14
16
  getContentText,
15
17
  getGitContext,
@@ -20,7 +22,7 @@ import {
20
22
  saveDevState,
21
23
  sessionHasMeaningfulContent,
22
24
  setupProxy
23
- } from "./chunk-SAJICC6G.js";
25
+ } from "./chunk-JHVH276O.js";
24
26
  import {
25
27
  ToolExecutor,
26
28
  ToolRegistry,
@@ -33,7 +35,7 @@ import {
33
35
  spawnAgentContext,
34
36
  theme,
35
37
  undoStack
36
- } from "./chunk-EWJQOJSB.js";
38
+ } from "./chunk-SXL6H7XR.js";
37
39
  import {
38
40
  fileCheckpoints
39
41
  } from "./chunk-4BKXL7SM.js";
@@ -57,7 +59,7 @@ import {
57
59
  SKILLS_DIR_NAME,
58
60
  VERSION,
59
61
  buildUserIdentityPrompt
60
- } from "./chunk-7SW4XRDJ.js";
62
+ } from "./chunk-TE6QE7FJ.js";
61
63
 
62
64
  // src/index.ts
63
65
  import { program } from "commander";
@@ -2083,7 +2085,7 @@ ${hint}` : "")
2083
2085
  usage: "/test [command|filter]",
2084
2086
  async execute(args, ctx) {
2085
2087
  try {
2086
- const { executeTests } = await import("./run-tests-QRH2Z2OH.js");
2088
+ const { executeTests } = await import("./run-tests-FNWRWJUI.js");
2087
2089
  const argStr = args.join(" ").trim();
2088
2090
  let testArgs = {};
2089
2091
  if (argStr) {
@@ -4807,19 +4809,22 @@ You have a maximum of ${MAX_TOOL_ROUNDS} tool call rounds for this task. Plan ef
4807
4809
  if ("content" in result) {
4808
4810
  const hasWriteTools = toolDefs.some((t) => t.name === "write_file" || t.name === "edit_file");
4809
4811
  const alreadyWrote = hadPreviousWriteToolCalls(extraMessages);
4810
- if (!this.planMode && // Plan Mode 下跳过虚假声明检测
4811
- hasWriteTools && !alreadyWrote && result.content && detectsHallucinatedFileOp(result.content) && round < MAX_TOOL_ROUNDS - 1) {
4812
+ const phantomPaths = !this.planMode && hasWriteTools && result.content ? findPhantomClaims(result.content, extraMessages) : [];
4813
+ const coarseHallucination = !this.planMode && hasWriteTools && !alreadyWrote && !!result.content && detectsHallucinatedFileOp(result.content);
4814
+ if ((phantomPaths.length > 0 || coarseHallucination) && round < MAX_TOOL_ROUNDS - 1) {
4812
4815
  const providerName = this.currentProvider;
4816
+ const detail = phantomPaths.length > 0 ? ` phantom files: ${phantomPaths.join(", ")}` : "";
4813
4817
  process.stderr.write(
4814
- `[${providerName}] \u26A0 Hallucinated completion detected (AI claimed file was written but no tool was called), forcing retry...
4818
+ `[${providerName}] \u26A0 Hallucinated completion detected (AI claimed file was written but no tool was called), forcing retry...${detail}
4815
4819
  `
4816
4820
  );
4817
4821
  if (alreadyRendered) {
4818
4822
  process.stdout.write("\n");
4819
4823
  }
4824
+ const correctionMsg = phantomPaths.length > 0 ? buildPhantomCorrectionMessage(phantomPaths) : HALLUCINATION_CORRECTION_MESSAGE;
4820
4825
  extraMessages.push(
4821
4826
  { role: "assistant", content: result.content },
4822
- { role: "user", content: HALLUCINATION_CORRECTION_MESSAGE }
4827
+ { role: "user", content: correctionMsg }
4823
4828
  );
4824
4829
  spinner.start(`Retrying... (round ${round + 2}/${MAX_TOOL_ROUNDS})`);
4825
4830
  continue;
@@ -5378,7 +5383,7 @@ program.command("web").description("Start Web UI server with browser-based chat
5378
5383
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
5379
5384
  process.exit(1);
5380
5385
  }
5381
- const { startWebServer } = await import("./server-46ANSDN7.js");
5386
+ const { startWebServer } = await import("./server-DSICPNYM.js");
5382
5387
  await startWebServer({ port, host: options.host });
5383
5388
  });
5384
5389
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
@@ -5611,7 +5616,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
5611
5616
  }),
5612
5617
  config.get("customProviders")
5613
5618
  );
5614
- const { startHub } = await import("./hub-QJBT4RDT.js");
5619
+ const { startHub } = await import("./hub-RMUO6RN2.js");
5615
5620
  await startHub(
5616
5621
  {
5617
5622
  topic: topic ?? "",
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-7SW4XRDJ.js";
5
+ } from "./chunk-TE6QE7FJ.js";
6
6
  export {
7
7
  executeTests,
8
8
  runTestsTool
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-L7OCMF5F.js";
4
+ } from "./chunk-FETMBU6E.js";
5
5
  export {
6
6
  executeTests,
7
7
  runTestsTool
@@ -15,7 +15,7 @@ import {
15
15
  hadPreviousWriteToolCalls,
16
16
  loadDevState,
17
17
  setupProxy
18
- } from "./chunk-SAJICC6G.js";
18
+ } from "./chunk-JHVH276O.js";
19
19
  import {
20
20
  AuthManager
21
21
  } from "./chunk-BYNY5JPB.js";
@@ -33,7 +33,7 @@ import {
33
33
  spawnAgentContext,
34
34
  truncateOutput,
35
35
  undoStack
36
- } from "./chunk-EWJQOJSB.js";
36
+ } from "./chunk-SXL6H7XR.js";
37
37
  import "./chunk-4BKXL7SM.js";
38
38
  import {
39
39
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -52,7 +52,7 @@ import {
52
52
  SKILLS_DIR_NAME,
53
53
  VERSION,
54
54
  buildUserIdentityPrompt
55
- } from "./chunk-7SW4XRDJ.js";
55
+ } from "./chunk-TE6QE7FJ.js";
56
56
 
57
57
  // src/web/server.ts
58
58
  import express from "express";
@@ -1606,7 +1606,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
1606
1606
  case "test": {
1607
1607
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
1608
1608
  try {
1609
- const { executeTests } = await import("./run-tests-QRH2Z2OH.js");
1609
+ const { executeTests } = await import("./run-tests-FNWRWJUI.js");
1610
1610
  const argStr = args.join(" ").trim();
1611
1611
  let testArgs = {};
1612
1612
  if (argStr) {
@@ -4,11 +4,11 @@ import {
4
4
  getDangerLevel,
5
5
  googleSearchContext,
6
6
  truncateOutput
7
- } from "./chunk-EWJQOJSB.js";
7
+ } from "./chunk-SXL6H7XR.js";
8
8
  import "./chunk-4BKXL7SM.js";
9
9
  import {
10
10
  SUBAGENT_ALLOWED_TOOLS
11
- } from "./chunk-7SW4XRDJ.js";
11
+ } from "./chunk-TE6QE7FJ.js";
12
12
 
13
13
  // src/hub/task-orchestrator.ts
14
14
  import { createInterface } from "readline";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.28",
3
+ "version": "0.4.29",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",