jinzd-ai-cli 0.4.304 → 0.4.305

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 (64) hide show
  1. package/dist/{batch-RY2F7BX5.js → batch-OX27K4GG.js} +2 -2
  2. package/dist/{chunk-7L7T46PI.js → chunk-3ZABGT3S.js} +1 -1
  3. package/dist/{chunk-RWM2GFRC.js → chunk-45UVJXFQ.js} +6 -2
  4. package/dist/{chunk-6AGTDWO3.js → chunk-4DH5LZR5.js} +1 -1
  5. package/dist/{chunk-23SJVOQD.js → chunk-72AR23R2.js} +26 -5
  6. package/dist/{chunk-OECPGCHP.js → chunk-AXKERUXH.js} +3 -3
  7. package/dist/{chunk-VOIOUJXI.js → chunk-C2Z77RTU.js} +13 -5
  8. package/dist/{chunk-F3EJ4MIP.js → chunk-GOIDKTBE.js} +12 -11
  9. package/dist/{chunk-BSBGPDCX.js → chunk-I6RATYRF.js} +1 -1
  10. package/dist/{chunk-2PLYXL4P.js → chunk-IPUTC5EX.js} +12 -10
  11. package/dist/{chunk-7XU4BATV.js → chunk-KBDKKHXB.js} +15 -6
  12. package/dist/{chunk-4DEMGCK4.js → chunk-LF67HWWR.js} +37 -13
  13. package/dist/{chunk-RHCRE6XE.js → chunk-NBYSFFCO.js} +1 -1
  14. package/dist/{chunk-XIMM47EG.js → chunk-NFLE34QG.js} +1 -1
  15. package/dist/{chunk-BXP6YZ2P.js → chunk-NRSYBKWA.js} +5 -4
  16. package/dist/{chunk-IEQAE3QG.js → chunk-OAXLMF3U.js} +5 -4
  17. package/dist/{chunk-2GRGLTAK.js → chunk-PA4C452B.js} +1 -1
  18. package/dist/{chunk-I2WJ44D3.js → chunk-Q4DAKI7I.js} +1 -1
  19. package/dist/{chunk-TBTVV3KK.js → chunk-SZ4226XY.js} +1 -1
  20. package/dist/{chunk-3FI4TE5S.js → chunk-UFK5CTBU.js} +3 -3
  21. package/dist/{chunk-PPIISCFN.js → chunk-UFW4S3RU.js} +37 -13
  22. package/dist/{chunk-CKH4KQ4E.js → chunk-WQ3OMEC4.js} +6 -2
  23. package/dist/{chunk-UUSRWSSX.js → chunk-XJOK5353.js} +15 -6
  24. package/dist/{chunk-DNGUSTL6.js → chunk-YPOWDFOV.js} +1 -1
  25. package/dist/{ci-QYTLBM6Z.js → ci-IIMLOXFH.js} +4 -4
  26. package/dist/{ci-format-E5X27NC2.js → ci-format-FMBJC3EY.js} +2 -2
  27. package/dist/{constants-JDPKWZJP.js → constants-55QQ3RYE.js} +1 -1
  28. package/dist/{constants-F5WA5VPO.js → constants-7NVAPQVR.js} +1 -1
  29. package/dist/{doctor-cli-7NSEVW63.js → doctor-cli-ZHZ2XOF3.js} +4 -4
  30. package/dist/electron-server.js +232 -106
  31. package/dist/{hub-43PWTGGO.js → hub-MF53NIM2.js} +4 -4
  32. package/dist/{hub-server-RF6LURXY.js → hub-server-CBKCP5VD.js} +1 -1
  33. package/dist/index.js +24 -23
  34. package/dist/{indexer-RBEKMFT4.js → indexer-FPKY7LCT.js} +2 -2
  35. package/dist/{indexer-TNDWGFRI.js → indexer-P3FPRTPJ.js} +2 -2
  36. package/dist/{persistent-memory-A7RPDLR7.js → persistent-memory-LCOKUDTM.js} +2 -2
  37. package/dist/{persistent-memory-SHG3CJCP.js → persistent-memory-NACQW2VB.js} +2 -2
  38. package/dist/{pr-LW755EL7.js → pr-NHWE5FW7.js} +4 -4
  39. package/dist/{run-tests-MJ3SCW27.js → run-tests-EUPJLDXS.js} +2 -2
  40. package/dist/{run-tests-HV37CM5U.js → run-tests-ZG5X25BJ.js} +2 -2
  41. package/dist/{semantic-HLAE2O4F.js → semantic-7GM5M4MU.js} +3 -3
  42. package/dist/{semantic-VPNKXKKK.js → semantic-QOBAXEQ4.js} +3 -3
  43. package/dist/{server-EZ5ULLDP.js → server-PG7QCH53.js} +193 -82
  44. package/dist/{server-WI3Q4EDH.js → server-PNYRE3AL.js} +9 -9
  45. package/dist/{store-MWNHVGJT.js → store-CMSSWZF7.js} +3 -1
  46. package/dist/{store-VO37H6LS.js → store-SIKHCUYJ.js} +3 -1
  47. package/dist/{task-orchestrator-PWW5I2KE.js → task-orchestrator-WAJTCE6D.js} +9 -9
  48. package/dist/{usage-MAIV6XUZ.js → usage-DOES3DOS.js} +2 -2
  49. package/dist/{vector-store-JBAE6PS4.js → vector-store-JAXWDZYW.js} +1 -1
  50. package/dist/{vector-store-BBDXB5IQ.js → vector-store-PWIOQFTP.js} +1 -1
  51. package/dist/web/client/app.js +135 -60
  52. package/dist/web/client/app.js.br +0 -0
  53. package/dist/web/client/app.js.gz +0 -0
  54. package/dist/web/client/chat-input.js +38 -0
  55. package/dist/web/client/chat-input.js.br +0 -0
  56. package/dist/web/client/chat-input.js.gz +0 -0
  57. package/dist/web/client/index.html +1 -1
  58. package/dist/web/client/index.html.br +0 -0
  59. package/dist/web/client/index.html.gz +0 -0
  60. package/dist/web/client/stream-render.js +33 -0
  61. package/dist/web/client/style.css +2 -1
  62. package/dist/web/client/style.css.br +0 -0
  63. package/dist/web/client/style.css.gz +0 -0
  64. package/package.json +1 -1
@@ -4,12 +4,12 @@ import {
4
4
  } from "./chunk-RS7SKYTS.js";
5
5
  import {
6
6
  ConfigManager
7
- } from "./chunk-XIMM47EG.js";
7
+ } from "./chunk-NFLE34QG.js";
8
8
  import "./chunk-TU3L3PW7.js";
9
9
  import {
10
10
  atomicWriteFileSync
11
11
  } from "./chunk-IW3Q7AE5.js";
12
- import "./chunk-RHCRE6XE.js";
12
+ import "./chunk-NBYSFFCO.js";
13
13
 
14
14
  // src/cli/batch.ts
15
15
  import Anthropic from "@anthropic-ai/sdk";
@@ -13,7 +13,7 @@ import {
13
13
  MEMORY_FILE_NAME,
14
14
  MEMORY_MAX_CHARS,
15
15
  MEMORY_STORE_FILE_NAME
16
- } from "./chunk-RHCRE6XE.js";
16
+ } from "./chunk-NBYSFFCO.js";
17
17
 
18
18
  // src/memory/persistent-memory.ts
19
19
  import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync } from "fs";
@@ -79,6 +79,9 @@ function saveIndex(index) {
79
79
  const target = indexPath(index.root);
80
80
  atomicWriteFileSync(target, JSON.stringify(index));
81
81
  }
82
+ function symbolFingerprint(index) {
83
+ return crypto.createHash("sha256").update(JSON.stringify(index.symbols)).digest("hex");
84
+ }
82
85
  function clearIndex(root) {
83
86
  const p = indexPath(root);
84
87
  try {
@@ -100,11 +103,11 @@ function emptyIndex(root) {
100
103
  function upsertFileSymbols(index, file, mtime, symbols) {
101
104
  const absFile = path.resolve(file);
102
105
  const had = absFile in index.files;
103
- index.symbols = index.symbols.filter((s) => s.location.file !== absFile);
106
+ if (had) index.symbols = index.symbols.filter((s) => s.location.file !== absFile);
104
107
  index.symbols.push(...symbols);
105
108
  index.files[absFile] = mtime;
106
109
  index.symbolCount = index.symbols.length;
107
- if (!had) index.fileCount = Object.keys(index.files).length;
110
+ if (!had) index.fileCount++;
108
111
  index.generated = (/* @__PURE__ */ new Date()).toISOString();
109
112
  return index;
110
113
  }
@@ -123,6 +126,7 @@ export {
123
126
  detectLanguage,
124
127
  loadIndex,
125
128
  saveIndex,
129
+ symbolFingerprint,
126
130
  clearIndex,
127
131
  emptyIndex,
128
132
  upsertFileSymbols,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-RHCRE6XE.js";
4
+ } from "./chunk-NBYSFFCO.js";
5
5
 
6
6
  // src/cli/ci-format.ts
7
7
  var DEFAULT_CI_THRESHOLDS = {
@@ -2,13 +2,15 @@
2
2
  import {
3
3
  HubAgent,
4
4
  isConverged
5
- } from "./chunk-VOIOUJXI.js";
5
+ } from "./chunk-C2Z77RTU.js";
6
6
 
7
7
  // src/hub/discuss.ts
8
8
  var DiscussionOrchestrator = class {
9
9
  agents = [];
10
10
  state;
11
11
  aborted = false;
12
+ controller = new AbortController();
13
+ cancelReview;
12
14
  humanSteer;
13
15
  voteConverge;
14
16
  /** Callback for rendering events */
@@ -48,6 +50,8 @@ var DiscussionOrchestrator = class {
48
50
  /** Signal the orchestrator to stop after current turn */
49
51
  abort() {
50
52
  this.aborted = true;
53
+ this.controller.abort();
54
+ this.cancelReview?.();
51
55
  }
52
56
  /**
53
57
  * Run the full discussion on a given topic.
@@ -58,6 +62,7 @@ var DiscussionOrchestrator = class {
58
62
  this.state.round = 0;
59
63
  this.state.finished = false;
60
64
  this.aborted = false;
65
+ this.controller = new AbortController();
61
66
  try {
62
67
  for (let round = 1; round <= this.state.maxRounds; round++) {
63
68
  if (this.aborted) {
@@ -78,7 +83,7 @@ var DiscussionOrchestrator = class {
78
83
  round,
79
84
  this.state.maxRounds,
80
85
  (token) => this.emit({ type: "agent_token", roleId: agent.role.id, token }),
81
- { voteConverge: this.voteConverge }
86
+ { voteConverge: this.voteConverge, signal: this.controller.signal }
82
87
  );
83
88
  this.state.messages.push(message);
84
89
  if (message.converged) convergedCount++;
@@ -90,6 +95,7 @@ var DiscussionOrchestrator = class {
90
95
  this.emit({ type: "agent_spoke", roleId: agent.role.id, message });
91
96
  }
92
97
  } catch (err) {
98
+ if (this.aborted) break;
93
99
  const errMsg = err instanceof Error ? err.message : String(err);
94
100
  this.emit({ type: "error", roleId: agent.role.id, message: errMsg });
95
101
  this.state.messages.push({
@@ -101,6 +107,10 @@ var DiscussionOrchestrator = class {
101
107
  }
102
108
  }
103
109
  this.emit({ type: "round_end", round });
110
+ if (this.aborted) {
111
+ this.emit({ type: "discussion_end", reason: "user_interrupt" });
112
+ break;
113
+ }
104
114
  if (allPassed && round > 1) {
105
115
  this.emit({ type: "discussion_end", reason: "consensus" });
106
116
  break;
@@ -117,7 +127,18 @@ var DiscussionOrchestrator = class {
117
127
  break;
118
128
  }
119
129
  if (this.humanSteer && this.onRoundReview && !this.aborted) {
120
- const steer = await this.onRoundReview({ round, maxRounds: this.state.maxRounds, state: this.state });
130
+ const stopped = new Promise((resolve) => {
131
+ this.cancelReview = () => resolve({ action: "stop" });
132
+ });
133
+ let steer;
134
+ try {
135
+ steer = await Promise.race([
136
+ this.onRoundReview({ round, maxRounds: this.state.maxRounds, state: this.state }),
137
+ stopped
138
+ ]);
139
+ } finally {
140
+ this.cancelReview = void 0;
141
+ }
121
142
  if (steer.action === "stop") {
122
143
  this.emit({ type: "discussion_end", reason: "human_stop" });
123
144
  break;
@@ -138,7 +159,7 @@ var DiscussionOrchestrator = class {
138
159
  const errMsg = err instanceof Error ? err.message : String(err);
139
160
  this.emit({ type: "error", message: errMsg });
140
161
  }
141
- await this.generateSummary();
162
+ if (!this.aborted) await this.generateSummary();
142
163
  this.state.finished = true;
143
164
  return this.state;
144
165
  }
@@ -156,7 +177,7 @@ var DiscussionOrchestrator = class {
156
177
  return;
157
178
  }
158
179
  try {
159
- this.state.summary = await summarizer.summarize(this.state.topic, this.state.messages);
180
+ this.state.summary = await summarizer.summarize(this.state.topic, this.state.messages, this.controller.signal);
160
181
  this.emit({ type: "summary", content: this.state.summary });
161
182
  } catch (err) {
162
183
  const errMsg = err instanceof Error ? err.message : String(err);
@@ -8,13 +8,13 @@ import {
8
8
  listHooks,
9
9
  listInstalledPlugins,
10
10
  resetStats
11
- } from "./chunk-I2WJ44D3.js";
11
+ } from "./chunk-Q4DAKI7I.js";
12
12
  import {
13
13
  ProviderRegistry
14
14
  } from "./chunk-VXEF2SWG.js";
15
15
  import {
16
16
  ConfigManager
17
- } from "./chunk-XIMM47EG.js";
17
+ } from "./chunk-NFLE34QG.js";
18
18
  import {
19
19
  getGitRoot
20
20
  } from "./chunk-HOSJZMQS.js";
@@ -26,7 +26,7 @@ import {
26
26
  MCP_PROJECT_CONFIG_NAME,
27
27
  MEMORY_FILE_NAME,
28
28
  VERSION
29
- } from "./chunk-RHCRE6XE.js";
29
+ } from "./chunk-NBYSFFCO.js";
30
30
 
31
31
  // src/diagnostics/doctor-report.ts
32
32
  import { existsSync as existsSync3, statSync as statSync2 } from "fs";
@@ -70,6 +70,7 @@ var HubAgent = class {
70
70
  model: this.modelId,
71
71
  systemPrompt,
72
72
  stream: false,
73
+ signal: opts?.signal,
73
74
  temperature: 0.7,
74
75
  maxTokens: 4096,
75
76
  ...this.thinking ?? {}
@@ -104,15 +105,21 @@ var HubAgent = class {
104
105
  model: this.modelId,
105
106
  systemPrompt,
106
107
  stream: true,
108
+ signal: opts?.signal,
107
109
  temperature: 0.7,
108
110
  maxTokens: 4096,
109
111
  ...this.thinking ?? {}
110
112
  });
111
- for await (const chunk of stream) {
112
- if (chunk.delta) {
113
- raw += chunk.delta;
114
- onToken?.(chunk.delta);
113
+ try {
114
+ for await (const chunk of stream) {
115
+ if (chunk.delta) {
116
+ raw += chunk.delta;
117
+ onToken?.(chunk.delta);
118
+ }
119
+ if (opts?.signal?.aborted) break;
115
120
  }
121
+ } catch (error) {
122
+ if (!opts?.signal?.aborted) throw error;
116
123
  }
117
124
  const { content, passed, converged } = parseTurn(raw);
118
125
  return {
@@ -127,7 +134,7 @@ var HubAgent = class {
127
134
  /**
128
135
  * Generate a summary of the entire discussion from this agent's perspective.
129
136
  */
130
- async summarize(topic, history) {
137
+ async summarize(topic, history, signal) {
131
138
  const provider = this.providers.get(this.providerId);
132
139
  if (!provider) {
133
140
  throw new Error(`Provider "${this.providerId}" not available`);
@@ -144,6 +151,7 @@ var HubAgent = class {
144
151
  model: this.modelId,
145
152
  stream: false,
146
153
  temperature: 0.3,
154
+ signal,
147
155
  maxTokens: 4096,
148
156
  ...this.thinking ?? {}
149
157
  });
@@ -16,7 +16,7 @@ import {
16
16
  setPreferredAgentName,
17
17
  truncateForPersist,
18
18
  undoStack
19
- } from "./chunk-2PLYXL4P.js";
19
+ } from "./chunk-IPUTC5EX.js";
20
20
  import {
21
21
  buildReviewPrompt,
22
22
  buildSecurityReviewPrompt
@@ -51,7 +51,7 @@ import {
51
51
  touchMemoryReferences,
52
52
  updateMemoryApproval,
53
53
  updateMemoryEntry
54
- } from "./chunk-7L7T46PI.js";
54
+ } from "./chunk-3ZABGT3S.js";
55
55
  import {
56
56
  theme
57
57
  } from "./chunk-5C76XDDF.js";
@@ -65,7 +65,7 @@ import {
65
65
  import {
66
66
  buildDoctorReport,
67
67
  formatDoctorReport
68
- } from "./chunk-OECPGCHP.js";
68
+ } from "./chunk-AXKERUXH.js";
69
69
  import {
70
70
  describePlugin,
71
71
  getActivePluginAssets,
@@ -80,7 +80,7 @@ import {
80
80
  trustHook,
81
81
  trustPlugin,
82
82
  untrustHook
83
- } from "./chunk-I2WJ44D3.js";
83
+ } from "./chunk-Q4DAKI7I.js";
84
84
  import {
85
85
  isCleanDocumentBody,
86
86
  stripOuterCodeFence
@@ -109,7 +109,7 @@ import {
109
109
  MCP_TOOL_PREFIX,
110
110
  REPO_URL,
111
111
  VERSION
112
- } from "./chunk-RHCRE6XE.js";
112
+ } from "./chunk-NBYSFFCO.js";
113
113
 
114
114
  // src/skills/manager.ts
115
115
  import { existsSync, readdirSync, mkdirSync, statSync } from "fs";
@@ -2426,7 +2426,7 @@ No tools match "${filter}".
2426
2426
  const { join: join6 } = await import("path");
2427
2427
  const { existsSync: existsSync6 } = await import("fs");
2428
2428
  const { getGitRoot } = await import("./git-context-EXOEHQSF.js");
2429
- const { MCP_PROJECT_CONFIG_NAME } = await import("./constants-F5WA5VPO.js");
2429
+ const { MCP_PROJECT_CONFIG_NAME } = await import("./constants-7NVAPQVR.js");
2430
2430
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
2431
2431
  const cwd = process.cwd();
2432
2432
  const projectRoot = getGitRoot(cwd) ?? cwd;
@@ -3534,7 +3534,7 @@ function createReviewCommands() {
3534
3534
  usage: "/test [command|filter]",
3535
3535
  async execute(args, ctx) {
3536
3536
  try {
3537
- const { executeTests } = await import("./run-tests-HV37CM5U.js");
3537
+ const { executeTests } = await import("./run-tests-ZG5X25BJ.js");
3538
3538
  const argStr = args.join(" ").trim();
3539
3539
  let testArgs = {};
3540
3540
  if (argStr) {
@@ -3900,9 +3900,9 @@ function createMemoryCommands() {
3900
3900
  async execute(args, ctx) {
3901
3901
  const sub = (args[0] ?? "status").toLowerCase();
3902
3902
  const root = process.cwd();
3903
- const { loadIndex, clearIndex } = await import("./store-MWNHVGJT.js");
3904
- const { indexProject } = await import("./indexer-TNDWGFRI.js");
3905
- const { loadVectorStore, clearVectorStore } = await import("./vector-store-BBDXB5IQ.js");
3903
+ const { loadIndex, clearIndex } = await import("./store-CMSSWZF7.js");
3904
+ const { indexProject } = await import("./indexer-P3FPRTPJ.js");
3905
+ const { loadVectorStore, clearVectorStore } = await import("./vector-store-PWIOQFTP.js");
3906
3906
  if (sub === "status") {
3907
3907
  const idx = loadIndex(root);
3908
3908
  const vec = loadVectorStore(root);
@@ -3933,6 +3933,7 @@ function createMemoryCommands() {
3933
3933
  }
3934
3934
  });
3935
3935
  process.stdout.write("\r\x1B[K");
3936
+ if (stats.incomplete) console.log(theme.dim(" Partial index: scan limit or unreadable files reached; unscanned entries retained."));
3936
3937
  console.log(theme.success(
3937
3938
  ` \u2713 Indexed ${stats.filesParsed} files (${stats.symbols} symbols) in ${stats.durationMs}ms`
3938
3939
  ));
@@ -3961,7 +3962,7 @@ function createMemoryCommands() {
3961
3962
  }
3962
3963
  console.log(theme.dim(` Building semantic index for ${idx.symbolCount} symbols\u2026`));
3963
3964
  console.log(theme.dim(" (First run downloads ~117 MB embedding model to ~/.aicli/models/)"));
3964
- const { rebuildSemanticIndex } = await import("./semantic-HLAE2O4F.js");
3965
+ const { rebuildSemanticIndex } = await import("./semantic-7GM5M4MU.js");
3965
3966
  try {
3966
3967
  const stats = await rebuildSemanticIndex(root, {
3967
3968
  onProgress: (done, total) => {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-RHCRE6XE.js";
4
+ } from "./chunk-NBYSFFCO.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -11,17 +11,17 @@ import {
11
11
  searchPersistentMemories,
12
12
  touchMemoryReferences,
13
13
  updateMemoryEntry
14
- } from "./chunk-7L7T46PI.js";
14
+ } from "./chunk-3ZABGT3S.js";
15
15
  import {
16
16
  indexProject
17
- } from "./chunk-4DEMGCK4.js";
17
+ } from "./chunk-LF67HWWR.js";
18
18
  import {
19
19
  hasSemanticIndex,
20
20
  semanticSearch
21
- } from "./chunk-UUSRWSSX.js";
21
+ } from "./chunk-XJOK5353.js";
22
22
  import {
23
23
  loadIndex
24
- } from "./chunk-CKH4KQ4E.js";
24
+ } from "./chunk-WQ3OMEC4.js";
25
25
  import {
26
26
  theme
27
27
  } from "./chunk-5C76XDDF.js";
@@ -30,7 +30,7 @@ import {
30
30
  runHook,
31
31
  runLifecycleHooks,
32
32
  runTool
33
- } from "./chunk-I2WJ44D3.js";
33
+ } from "./chunk-Q4DAKI7I.js";
34
34
  import {
35
35
  buildTruncatedArgumentsError,
36
36
  getDangerLevel,
@@ -50,7 +50,7 @@ import {
50
50
  } from "./chunk-4BKXL7SM.js";
51
51
  import {
52
52
  runTestsTool
53
- } from "./chunk-BSBGPDCX.js";
53
+ } from "./chunk-I6RATYRF.js";
54
54
  import {
55
55
  CONFIG_DIR_NAME,
56
56
  DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
@@ -58,7 +58,7 @@ import {
58
58
  SUBAGENT_ALLOWED_TOOLS,
59
59
  SUBAGENT_DEFAULT_MAX_ROUNDS,
60
60
  SUBAGENT_MAX_ROUNDS_LIMIT
61
- } from "./chunk-RHCRE6XE.js";
61
+ } from "./chunk-NBYSFFCO.js";
62
62
 
63
63
  // src/tools/shell-pool.ts
64
64
  import { spawn as spawn2 } from "child_process";
@@ -2131,9 +2131,9 @@ function setMaxOutputCap(cap) {
2131
2131
  activeMaxChars = getMaxOutputChars(lastContextWindow);
2132
2132
  }
2133
2133
  }
2134
- function getMaxOutputChars(contextWindow) {
2134
+ function getMaxOutputChars(contextWindow, cap = activeCap) {
2135
2135
  if (!contextWindow || contextWindow <= 0) return DEFAULT_MAX_TOOL_OUTPUT_CHARS;
2136
- return Math.max(DEFAULT_MAX_TOOL_OUTPUT_CHARS, Math.min(Math.floor(contextWindow / 4), activeCap));
2136
+ return Math.max(DEFAULT_MAX_TOOL_OUTPUT_CHARS, Math.min(Math.floor(contextWindow / 4), cap > 0 ? cap : DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP));
2137
2137
  }
2138
2138
  var activeMaxChars = DEFAULT_MAX_TOOL_OUTPUT_CHARS;
2139
2139
  var lastContextWindow = 0;
@@ -3138,7 +3138,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
3138
3138
  const mode = appendMode ? "appended" : "written";
3139
3139
  void (async () => {
3140
3140
  try {
3141
- const { updateFile } = await import("./indexer-TNDWGFRI.js");
3141
+ const { updateFile } = await import("./indexer-P3FPRTPJ.js");
3142
3142
  await updateFile(process.cwd(), filePath);
3143
3143
  } catch {
3144
3144
  }
@@ -7195,7 +7195,9 @@ export {
7195
7195
  checkPermissionWithProfile,
7196
7196
  formatPermissionProfileWarning,
7197
7197
  checkNetworkPolicy,
7198
+ DEFAULT_MAX_TOOL_OUTPUT_CHARS,
7198
7199
  setMaxOutputCap,
7200
+ getMaxOutputChars,
7199
7201
  setContextWindow,
7200
7202
  truncateForPersist,
7201
7203
  truncateOutput,
@@ -2,15 +2,16 @@ import {
2
2
  loadVectorStore,
3
3
  saveVectorStore,
4
4
  searchVectorStore
5
- } from "./chunk-IEQAE3QG.js";
5
+ } from "./chunk-OAXLMF3U.js";
6
6
  import {
7
7
  EMBEDDING_DIM,
8
8
  embed,
9
9
  embedOne
10
10
  } from "./chunk-JV5N65KN.js";
11
11
  import {
12
- loadIndex
13
- } from "./chunk-RWM2GFRC.js";
12
+ loadIndex,
13
+ symbolFingerprint
14
+ } from "./chunk-45UVJXFQ.js";
14
15
 
15
16
  // src/symbols/semantic.ts
16
17
  function pathTokens(absFile, root) {
@@ -66,7 +67,7 @@ async function rebuildSemanticIndex(root, opts = {}) {
66
67
  const batchSize = opts.batchSize ?? 32;
67
68
  const total = Math.min(index.symbols.length, maxSymbols);
68
69
  if (total === 0) {
69
- saveVectorStore(root, new Uint32Array(0), new Float32Array(0));
70
+ saveVectorStore(root, new Uint32Array(0), new Float32Array(0), symbolFingerprint(index));
70
71
  return { symbolsEmbedded: 0, durationMs: Date.now() - start };
71
72
  }
72
73
  const symbolIdx = new Uint32Array(total);
@@ -87,7 +88,7 @@ async function rebuildSemanticIndex(root, opts = {}) {
87
88
  }
88
89
  if (opts.onProgress) opts.onProgress(end, total);
89
90
  }
90
- saveVectorStore(root, symbolIdx, vectors);
91
+ saveVectorStore(root, symbolIdx, vectors, symbolFingerprint(index));
91
92
  return {
92
93
  symbolsEmbedded: total,
93
94
  durationMs: Date.now() - start,
@@ -99,7 +100,14 @@ async function semanticSearch(root, query, k = 10) {
99
100
  if (!index) return [];
100
101
  const store = loadVectorStore(root);
101
102
  if (!store || store.count === 0) return [];
103
+ if (store.sourceFingerprint !== symbolFingerprint(index)) {
104
+ throw new Error("Semantic index is stale. Run /index semantic-rebuild before searching again.");
105
+ }
102
106
  const queryVec = await embedOne(query);
107
+ const current = loadIndex(root);
108
+ if (!current || symbolFingerprint(current) !== store.sourceFingerprint) {
109
+ throw new Error("Symbol index changed during search. Run /index semantic-rebuild and retry.");
110
+ }
103
111
  const hits = searchVectorStore(store, queryVec, k);
104
112
  return hits.map((h) => ({
105
113
  ...h,
@@ -108,7 +116,8 @@ async function semanticSearch(root, query, k = 10) {
108
116
  }
109
117
  function hasSemanticIndex(root) {
110
118
  const s = loadVectorStore(root);
111
- return s !== null && s.count > 0;
119
+ const index = loadIndex(root);
120
+ return s !== null && s.count > 0 && index !== null && s.sourceFingerprint === symbolFingerprint(index);
112
121
  }
113
122
 
114
123
  export {
@@ -6,7 +6,7 @@ import {
6
6
  removeFile,
7
7
  saveIndex,
8
8
  upsertFileSymbols
9
- } from "./chunk-CKH4KQ4E.js";
9
+ } from "./chunk-WQ3OMEC4.js";
10
10
 
11
11
  // src/symbols/indexer.ts
12
12
  import fs2 from "fs";
@@ -582,15 +582,18 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
582
582
  "cmake-build-release"
583
583
  ]);
584
584
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
585
- function collectFiles(root, maxFiles) {
585
+ async function collectFiles(root, maxFiles, signal) {
586
586
  const out = [];
587
+ let incomplete = false;
587
588
  const stack = [root];
588
589
  while (stack.length > 0 && out.length < maxFiles) {
590
+ signal?.throwIfAborted();
589
591
  const dir = stack.pop();
590
592
  let entries;
591
593
  try {
592
- entries = fs2.readdirSync(dir, { withFileTypes: true });
594
+ entries = await fs2.promises.readdir(dir, { withFileTypes: true });
593
595
  } catch {
596
+ incomplete = true;
594
597
  continue;
595
598
  }
596
599
  for (const e of entries) {
@@ -605,33 +608,47 @@ function collectFiles(root, maxFiles) {
605
608
  const ext = path3.extname(e.name).slice(1);
606
609
  if (detectLanguage(ext)) {
607
610
  out.push(full);
608
- if (out.length >= maxFiles) break;
611
+ if (out.length >= maxFiles) {
612
+ incomplete = true;
613
+ break;
614
+ }
609
615
  }
610
616
  }
611
617
  }
612
618
  }
613
- return out;
619
+ return { files: out, incomplete };
614
620
  }
615
621
  async function indexProject(root, opts = {}) {
616
622
  const start = Date.now();
617
623
  const maxFiles = opts.maxFiles ?? 5e3;
624
+ if (!Number.isSafeInteger(maxFiles) || maxFiles < 1) throw new Error("maxFiles must be a positive integer");
618
625
  const force = opts.force === true;
619
626
  const absRoot = path3.resolve(root);
620
- let index = force ? emptyIndex(absRoot) : loadIndex(absRoot) ?? emptyIndex(absRoot);
621
- const files = collectFiles(absRoot, maxFiles);
627
+ const index = loadIndex(absRoot) ?? emptyIndex(absRoot);
628
+ const { files, incomplete } = await collectFiles(absRoot, maxFiles, opts.signal);
622
629
  const liveSet = new Set(files.map((f) => path3.resolve(f)));
630
+ const byFile = /* @__PURE__ */ new Map();
631
+ for (const symbol of index.symbols) {
632
+ const file = symbol.location.file;
633
+ const entries = byFile.get(file) ?? [];
634
+ entries.push(symbol);
635
+ byFile.set(file, entries);
636
+ }
623
637
  for (const known of Object.keys(index.files)) {
624
- if (!liveSet.has(known)) {
625
- index = removeFile(index, known);
638
+ if (!incomplete && !liveSet.has(known)) {
639
+ byFile.delete(known);
640
+ delete index.files[known];
626
641
  }
627
642
  }
628
643
  let parsed = 0;
629
644
  let skipped = 0;
630
645
  for (let i = 0; i < files.length; i++) {
646
+ opts.signal?.throwIfAborted();
647
+ if (i % 50 === 0) await new Promise((resolve) => setImmediate(resolve));
631
648
  const file = path3.resolve(files[i]);
632
649
  let stat;
633
650
  try {
634
- stat = fs2.statSync(file);
651
+ stat = await fs2.promises.stat(file);
635
652
  } catch {
636
653
  skipped++;
637
654
  continue;
@@ -646,18 +663,24 @@ async function indexProject(root, opts = {}) {
646
663
  }
647
664
  let src;
648
665
  try {
649
- src = fs2.readFileSync(file, "utf-8");
666
+ src = await fs2.promises.readFile(file, "utf-8");
650
667
  } catch {
651
668
  skipped++;
652
669
  continue;
653
670
  }
654
671
  const symbols = await parseSource(file, src);
655
- index = upsertFileSymbols(index, file, stat.mtimeMs, symbols);
672
+ byFile.set(file, symbols);
673
+ index.files[file] = stat.mtimeMs;
656
674
  parsed++;
657
675
  if (opts.onProgress && parsed % 50 === 0) {
658
676
  opts.onProgress(i + 1, files.length);
659
677
  }
660
678
  }
679
+ opts.signal?.throwIfAborted();
680
+ index.symbols = [...byFile.values()].flat();
681
+ index.fileCount = Object.keys(index.files).length;
682
+ index.symbolCount = index.symbols.length;
683
+ index.generated = (/* @__PURE__ */ new Date()).toISOString();
661
684
  saveIndex(index);
662
685
  return {
663
686
  index,
@@ -666,7 +689,8 @@ async function indexProject(root, opts = {}) {
666
689
  filesParsed: parsed,
667
690
  filesSkipped: skipped,
668
691
  symbols: index.symbolCount,
669
- durationMs: Date.now() - start
692
+ durationMs: Date.now() - start,
693
+ incomplete: incomplete || skipped > 0
670
694
  }
671
695
  };
672
696
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.304";
4
+ var VERSION = "0.4.305";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -11,7 +11,7 @@ import {
11
11
  CONFIG_FILE_NAME,
12
12
  HISTORY_DIR_NAME,
13
13
  PLUGINS_DIR_NAME
14
- } from "./chunk-RHCRE6XE.js";
14
+ } from "./chunk-NBYSFFCO.js";
15
15
 
16
16
  // src/config/config-manager.ts
17
17
  import { readFileSync, existsSync, mkdirSync } from "fs";
@@ -12,8 +12,8 @@ import path from "path";
12
12
  import os from "os";
13
13
  import crypto from "crypto";
14
14
  var MAGIC = 1094927190;
15
- var VERSION = 1;
16
- var HEADER_BYTES = 16;
15
+ var VERSION = 2;
16
+ var HEADER_BYTES = 48;
17
17
  function indexDir() {
18
18
  return path.join(os.homedir(), ".aicli", "index");
19
19
  }
@@ -32,7 +32,7 @@ function emptyVectorStore(root) {
32
32
  symbolIdx: new Uint32Array(0)
33
33
  };
34
34
  }
35
- function saveVectorStore(root, indices, vectors) {
35
+ function saveVectorStore(root, indices, vectors, sourceFingerprint) {
36
36
  if (indices.length * EMBEDDING_DIM !== vectors.length) {
37
37
  throw new Error(
38
38
  `saveVectorStore: length mismatch \u2014 ${indices.length} indices vs ${vectors.length / EMBEDDING_DIM} vectors`
@@ -47,6 +47,7 @@ function saveVectorStore(root, indices, vectors) {
47
47
  buf.writeUInt32LE(VERSION, 4);
48
48
  buf.writeUInt32LE(count, 8);
49
49
  buf.writeUInt32LE(EMBEDDING_DIM, 12);
50
+ if (sourceFingerprint) Buffer.from(sourceFingerprint, "hex").copy(buf, 16, 0, 32);
50
51
  Buffer.from(indices.buffer, indices.byteOffset, indices.byteLength).copy(buf, HEADER_BYTES);
51
52
  Buffer.from(vectors.buffer, vectors.byteOffset, vectors.byteLength).copy(buf, HEADER_BYTES + count * 4);
52
53
  const target = vecPath(root);
@@ -78,7 +79,7 @@ function loadVectorStore(root) {
78
79
  buf.byteOffset + HEADER_BYTES + count * 4 + count * dim * 4
79
80
  )
80
81
  );
81
- return { root: path.resolve(root), count, dim, vectors, symbolIdx };
82
+ return { root: path.resolve(root), count, dim, vectors, symbolIdx, sourceFingerprint: buf.subarray(16, 48).toString("hex") };
82
83
  }
83
84
  function clearVectorStore(root) {
84
85
  const p = vecPath(root);