jinzd-ai-cli 0.4.75 → 0.4.77

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.
@@ -0,0 +1,167 @@
1
+ // src/symbols/vector-store.ts
2
+ import fs2 from "fs";
3
+ import path2 from "path";
4
+ import os2 from "os";
5
+ import crypto from "crypto";
6
+
7
+ // src/symbols/embedder.ts
8
+ import path from "path";
9
+ import os from "os";
10
+ import fs from "fs";
11
+ var EMBEDDING_MODEL_ID = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
12
+ var EMBEDDING_DIM = 384;
13
+ var pipelinePromise = null;
14
+ function cacheDir() {
15
+ return path.join(os.homedir(), ".aicli", "models");
16
+ }
17
+ async function getEmbedder() {
18
+ if (pipelinePromise) return pipelinePromise;
19
+ pipelinePromise = (async () => {
20
+ const mod = await import("@huggingface/transformers");
21
+ const dir = cacheDir();
22
+ fs.mkdirSync(dir, { recursive: true });
23
+ mod.env.cacheDir = dir;
24
+ mod.env.allowRemoteModels = true;
25
+ mod.env.allowLocalModels = true;
26
+ const pipe = await mod.pipeline("feature-extraction", EMBEDDING_MODEL_ID, {
27
+ // Keep the ONNX session in float32; int8 quantization exists but the
28
+ // quality drop on short code identifiers is noticeable.
29
+ dtype: "fp32"
30
+ });
31
+ return pipe;
32
+ })();
33
+ return pipelinePromise;
34
+ }
35
+ async function embed(texts) {
36
+ if (texts.length === 0) return [];
37
+ const pipe = await getEmbedder();
38
+ const out = await pipe(texts, { pooling: "mean", normalize: true });
39
+ const batch = texts.length;
40
+ const dim = EMBEDDING_DIM;
41
+ const rows = new Array(batch);
42
+ for (let i = 0; i < batch; i++) {
43
+ rows[i] = new Float32Array(out.data.buffer, out.data.byteOffset + i * dim * 4, dim).slice();
44
+ }
45
+ return rows;
46
+ }
47
+ async function embedOne(text) {
48
+ const [vec] = await embed([text]);
49
+ return vec;
50
+ }
51
+
52
+ // src/symbols/vector-store.ts
53
+ var MAGIC = 1094927190;
54
+ var VERSION = 1;
55
+ var HEADER_BYTES = 16;
56
+ function indexDir() {
57
+ return path2.join(os2.homedir(), ".aicli", "index");
58
+ }
59
+ function projectHash(root) {
60
+ return crypto.createHash("sha1").update(path2.resolve(root).toLowerCase()).digest("hex").slice(0, 16);
61
+ }
62
+ function vecPath(root) {
63
+ return path2.join(indexDir(), `${projectHash(root)}.vec`);
64
+ }
65
+ function emptyVectorStore(root) {
66
+ return {
67
+ root: path2.resolve(root),
68
+ count: 0,
69
+ dim: EMBEDDING_DIM,
70
+ vectors: new Float32Array(0),
71
+ symbolIdx: new Uint32Array(0)
72
+ };
73
+ }
74
+ function saveVectorStore(root, indices, vectors) {
75
+ if (indices.length * EMBEDDING_DIM !== vectors.length) {
76
+ throw new Error(
77
+ `saveVectorStore: length mismatch \u2014 ${indices.length} indices vs ${vectors.length / EMBEDDING_DIM} vectors`
78
+ );
79
+ }
80
+ const count = indices.length;
81
+ const dir = indexDir();
82
+ fs2.mkdirSync(dir, { recursive: true });
83
+ const totalBytes = HEADER_BYTES + count * 4 + count * EMBEDDING_DIM * 4;
84
+ const buf = Buffer.alloc(totalBytes);
85
+ buf.writeUInt32LE(MAGIC, 0);
86
+ buf.writeUInt32LE(VERSION, 4);
87
+ buf.writeUInt32LE(count, 8);
88
+ buf.writeUInt32LE(EMBEDDING_DIM, 12);
89
+ Buffer.from(indices.buffer, indices.byteOffset, indices.byteLength).copy(buf, HEADER_BYTES);
90
+ Buffer.from(vectors.buffer, vectors.byteOffset, vectors.byteLength).copy(buf, HEADER_BYTES + count * 4);
91
+ const target = vecPath(root);
92
+ const tmp = `${target}.tmp`;
93
+ fs2.writeFileSync(tmp, buf);
94
+ fs2.renameSync(tmp, target);
95
+ }
96
+ function loadVectorStore(root) {
97
+ const p = vecPath(root);
98
+ if (!fs2.existsSync(p)) return null;
99
+ let buf;
100
+ try {
101
+ buf = fs2.readFileSync(p);
102
+ } catch {
103
+ return null;
104
+ }
105
+ if (buf.length < HEADER_BYTES) return null;
106
+ const magic = buf.readUInt32LE(0);
107
+ const version = buf.readUInt32LE(4);
108
+ const count = buf.readUInt32LE(8);
109
+ const dim = buf.readUInt32LE(12);
110
+ if (magic !== MAGIC || version !== VERSION || dim !== EMBEDDING_DIM) return null;
111
+ const expected = HEADER_BYTES + count * 4 + count * dim * 4;
112
+ if (buf.length !== expected) return null;
113
+ const symbolIdx = new Uint32Array(
114
+ buf.buffer.slice(buf.byteOffset + HEADER_BYTES, buf.byteOffset + HEADER_BYTES + count * 4)
115
+ );
116
+ const vectors = new Float32Array(
117
+ buf.buffer.slice(
118
+ buf.byteOffset + HEADER_BYTES + count * 4,
119
+ buf.byteOffset + HEADER_BYTES + count * 4 + count * dim * 4
120
+ )
121
+ );
122
+ return { root: path2.resolve(root), count, dim, vectors, symbolIdx };
123
+ }
124
+ function clearVectorStore(root) {
125
+ const p = vecPath(root);
126
+ try {
127
+ if (fs2.existsSync(p)) fs2.unlinkSync(p);
128
+ } catch {
129
+ }
130
+ }
131
+ function searchVectorStore(store, queryVec, k) {
132
+ if (store.count === 0) return [];
133
+ if (queryVec.length !== store.dim) {
134
+ throw new Error(`searchVectorStore: dim mismatch (query=${queryVec.length}, store=${store.dim})`);
135
+ }
136
+ const { count, dim, vectors, symbolIdx } = store;
137
+ const heap = [];
138
+ const push = (hit) => {
139
+ if (heap.length < k) {
140
+ heap.push(hit);
141
+ heap.sort((a, b) => a.score - b.score);
142
+ } else if (hit.score > heap[0].score) {
143
+ heap[0] = hit;
144
+ heap.sort((a, b) => a.score - b.score);
145
+ }
146
+ };
147
+ for (let row = 0; row < count; row++) {
148
+ const base = row * dim;
149
+ let score = 0;
150
+ for (let d = 0; d < dim; d++) {
151
+ score += vectors[base + d] * queryVec[d];
152
+ }
153
+ push({ row, symbolIdx: symbolIdx[row], score });
154
+ }
155
+ return heap.sort((a, b) => b.score - a.score);
156
+ }
157
+
158
+ export {
159
+ EMBEDDING_DIM,
160
+ embed,
161
+ embedOne,
162
+ emptyVectorStore,
163
+ saveVectorStore,
164
+ loadVectorStore,
165
+ clearVectorStore,
166
+ searchVectorStore
167
+ };
@@ -385,7 +385,7 @@ ${content}`);
385
385
  }
386
386
  }
387
387
  async function runTaskMode(config, providers, configManager, topic) {
388
- const { TaskOrchestrator } = await import("./task-orchestrator-277NWVSE.js");
388
+ const { TaskOrchestrator } = await import("./task-orchestrator-VC7LCN5J.js");
389
389
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
390
390
  let interrupted = false;
391
391
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -30,10 +30,10 @@ import {
30
30
  saveDevState,
31
31
  sessionHasMeaningfulContent,
32
32
  setupProxy
33
- } from "./chunk-C4MGON2N.js";
33
+ } from "./chunk-5PZMIBEN.js";
34
34
  import {
35
35
  ConfigManager
36
- } from "./chunk-ASNDBI5R.js";
36
+ } from "./chunk-LQ76WLB6.js";
37
37
  import {
38
38
  ToolExecutor,
39
39
  ToolRegistry,
@@ -49,12 +49,16 @@ import {
49
49
  spawnAgentContext,
50
50
  theme,
51
51
  undoStack
52
- } from "./chunk-MPIUYP6Q.js";
52
+ } from "./chunk-LKDX2GOW.js";
53
+ import "./chunk-2ZD3YTVM.js";
53
54
  import {
54
55
  fileCheckpoints
55
56
  } from "./chunk-4BKXL7SM.js";
56
- import "./chunk-3BHGEPIT.js";
57
- import "./chunk-2ZD3YTVM.js";
57
+ import "./chunk-NHNWUBXB.js";
58
+ import "./chunk-HPDDAXFY.js";
59
+ import "./chunk-6VRJGH25.js";
60
+ import "./chunk-PFYAAX2S.js";
61
+ import "./chunk-QATT4NCL.js";
58
62
  import {
59
63
  AGENTIC_BEHAVIOR_GUIDELINE,
60
64
  AUTHOR,
@@ -76,7 +80,7 @@ import {
76
80
  SKILLS_DIR_NAME,
77
81
  VERSION,
78
82
  buildUserIdentityPrompt
79
- } from "./chunk-5P4QTZBI.js";
83
+ } from "./chunk-S4WDPHKS.js";
80
84
 
81
85
  // src/index.ts
82
86
  import { program } from "commander";
@@ -214,7 +218,7 @@ var Renderer = class {
214
218
  console.log(theme.dim(" Gemini (Google) \xB7 Zhipu (GLM) \xB7 OpenRouter \xB7 Ollama (Local, no API key)"));
215
219
  console.log(HR);
216
220
  const mcpToolCount = mcpInfo?.tools ?? 0;
217
- const toolTotal = 24 + pluginCount + mcpToolCount;
221
+ const toolTotal = 28 + pluginCount + mcpToolCount;
218
222
  const extras = [];
219
223
  if (pluginCount > 0) extras.push(`${pluginCount} plugin(s)`);
220
224
  if (mcpToolCount > 0) extras.push(`${mcpToolCount} MCP`);
@@ -244,14 +248,18 @@ var Renderer = class {
244
248
  console.log(tool("git_log", "Show commit history (oneline/full, filter by file/author)"));
245
249
  console.log(tool("git_commit", "Create a git commit (stage files, message, stage_all)"));
246
250
  console.log(tool("notebook_edit", "Edit Jupyter notebook cells (add/edit/delete/move)"));
251
+ console.log(tool("find_symbol", "Locate symbol definitions via persistent tree-sitter index (TS/JS/TSX/Python)"));
252
+ console.log(tool("get_outline", "Enumerate all top-level declarations in one source file"));
253
+ console.log(tool("find_references", "Search indexed files for references to a symbol name"));
254
+ console.log(tool("search_code", 'Semantic (meaning-based) code search via local embeddings \u2014 "grep by meaning", bilingual'));
247
255
  console.log(HR);
248
- console.log(theme.dim(" REPL Commands (40):"));
256
+ console.log(theme.dim(" REPL Commands (42):"));
249
257
  console.log(theme.dim(" /help /about /provider /model /clear /compact /plan /session"));
250
258
  console.log(theme.dim(" /system /context /status /search /undo /export /copy /paste"));
251
259
  console.log(theme.dim(" /cost /init /skill /tools /plugins /mcp /config /checkpoint"));
252
260
  console.log(theme.dim(" /review /security-review /rewind /commands /test /scaffold"));
253
261
  console.log(theme.dim(" /add-dir /memory /profile /doctor /bug /think /diff /fork"));
254
- console.log(theme.dim(" /yolo /exit"));
262
+ console.log(theme.dim(" /branch /index /yolo /exit"));
255
263
  console.log(HR);
256
264
  console.log(theme.dim(" Key Features:"));
257
265
  console.log(feat("Agentic loop (up to 200 tool-call rounds, configurable via config/CLI, final answer streamed)"));
@@ -970,6 +978,8 @@ function createDefaultCommands() {
970
978
  " /bug [--copy] - Generate bug report template (--copy to clipboard)",
971
979
  " /diff [--stats] - Show all file modifications in this session",
972
980
  " /fork [checkpoint] - Fork session from checkpoint or current position",
981
+ " /branch [list|new|switch|delete|rename] - Manage conversation branches (fork tree)",
982
+ " /index [status|rebuild|clear|semantic-rebuild|semantic-clear] - Symbol + semantic index (find_symbol / search_code)",
973
983
  " /yolo [on|off] - Toggle session auto-approve (skip confirmations)",
974
984
  " /exit - Exit"
975
985
  ] : [];
@@ -2356,6 +2366,99 @@ ${hint}` : "")
2356
2366
  ctx.renderer.renderError(`Unknown subcommand: ${sub}. Use list/new/switch/delete/rename.`);
2357
2367
  }
2358
2368
  },
2369
+ // ── /index ────────────────────────────────────────────────────
2370
+ {
2371
+ name: "index",
2372
+ description: "Manage symbol + semantic index (status/rebuild/clear/semantic-rebuild/semantic-clear)",
2373
+ usage: "/index [status | rebuild | clear | semantic-rebuild | semantic-clear]",
2374
+ async execute(args, ctx) {
2375
+ const sub = (args[0] ?? "status").toLowerCase();
2376
+ const root = process.cwd();
2377
+ const { loadIndex, clearIndex } = await import("./store-S24SPPDZ.js");
2378
+ const { indexProject } = await import("./indexer-C7QYYHSZ.js");
2379
+ const { loadVectorStore, clearVectorStore } = await import("./vector-store-YTVHACBV.js");
2380
+ if (sub === "status") {
2381
+ const idx = loadIndex(root);
2382
+ const vec = loadVectorStore(root);
2383
+ if (!idx) {
2384
+ console.log(theme.dim(` No index for ${root}.`));
2385
+ console.log(theme.dim(" Run `/index rebuild` to build one."));
2386
+ return;
2387
+ }
2388
+ console.log(theme.heading("\n Symbol index:\n"));
2389
+ console.log(` Root: ${idx.root}`);
2390
+ console.log(` Generated: ${idx.generated}`);
2391
+ console.log(` Files: ${idx.fileCount}`);
2392
+ console.log(` Symbols: ${idx.symbolCount}`);
2393
+ if (vec) {
2394
+ console.log(` Semantic: ${vec.count} vectors \xD7 ${vec.dim}-dim (run /index semantic-rebuild after major changes)`);
2395
+ } else {
2396
+ console.log(` Semantic: ${theme.dim("not built")} \u2014 run /index semantic-rebuild to enable search_code`);
2397
+ }
2398
+ console.log();
2399
+ return;
2400
+ }
2401
+ if (sub === "rebuild") {
2402
+ console.log(theme.dim(` Indexing ${root}\u2026`));
2403
+ const { stats } = await indexProject(root, {
2404
+ force: true,
2405
+ onProgress: (done, total) => {
2406
+ process.stdout.write(theme.dim(`\r ${done}/${total} files\u2026`));
2407
+ }
2408
+ });
2409
+ process.stdout.write("\r\x1B[K");
2410
+ console.log(theme.success(
2411
+ ` \u2713 Indexed ${stats.filesParsed} files (${stats.symbols} symbols) in ${stats.durationMs}ms`
2412
+ ));
2413
+ if (stats.filesSkipped > 0) {
2414
+ console.log(theme.dim(` (${stats.filesSkipped} skipped: oversized or unreadable)`));
2415
+ }
2416
+ return;
2417
+ }
2418
+ if (sub === "clear") {
2419
+ clearIndex(root);
2420
+ clearVectorStore(root);
2421
+ console.log(theme.success(` \u2713 Cleared symbol + semantic index for ${root}`));
2422
+ return;
2423
+ }
2424
+ if (sub === "semantic-rebuild") {
2425
+ const idx = loadIndex(root);
2426
+ if (!idx) {
2427
+ ctx.renderer.renderError("No symbol index yet. Run `/index rebuild` first, then semantic-rebuild.");
2428
+ return;
2429
+ }
2430
+ console.log(theme.dim(` Building semantic index for ${idx.symbolCount} symbols\u2026`));
2431
+ console.log(theme.dim(" (First run downloads ~117 MB embedding model to ~/.aicli/models/)"));
2432
+ const { rebuildSemanticIndex } = await import("./semantic-RBWU76MD.js");
2433
+ try {
2434
+ const stats = await rebuildSemanticIndex(root, {
2435
+ onProgress: (done, total) => {
2436
+ const pct = total > 0 ? Math.floor(done / total * 100) : 0;
2437
+ process.stdout.write(theme.dim(`\r ${done}/${total} (${pct}%)\u2026`));
2438
+ }
2439
+ });
2440
+ process.stdout.write("\r\x1B[K");
2441
+ const first = stats.modelFirstLoadMs ? ` (model load+first batch ${stats.modelFirstLoadMs}ms)` : "";
2442
+ console.log(theme.success(
2443
+ ` \u2713 Embedded ${stats.symbolsEmbedded} symbols in ${stats.durationMs}ms${first}`
2444
+ ));
2445
+ } catch (err) {
2446
+ process.stdout.write("\r\x1B[K");
2447
+ const msg = err instanceof Error ? err.message : String(err);
2448
+ ctx.renderer.renderError(`Semantic rebuild failed: ${msg}`);
2449
+ }
2450
+ return;
2451
+ }
2452
+ if (sub === "semantic-clear") {
2453
+ clearVectorStore(root);
2454
+ console.log(theme.success(` \u2713 Cleared semantic index (symbol index preserved)`));
2455
+ return;
2456
+ }
2457
+ ctx.renderer.renderError(
2458
+ `Unknown subcommand: ${sub}. Use status/rebuild/clear/semantic-rebuild/semantic-clear.`
2459
+ );
2460
+ }
2461
+ },
2359
2462
  // ── /commands ─────────────────────────────────────────────────
2360
2463
  {
2361
2464
  name: "commands",
@@ -2392,7 +2495,7 @@ ${hint}` : "")
2392
2495
  usage: "/test [command|filter]",
2393
2496
  async execute(args, ctx) {
2394
2497
  try {
2395
- const { executeTests } = await import("./run-tests-V2JJADIU.js");
2498
+ const { executeTests } = await import("./run-tests-GEZ4NPWJ.js");
2396
2499
  const argStr = args.join(" ").trim();
2397
2500
  let testArgs = {};
2398
2501
  if (argStr) {
@@ -4601,6 +4704,27 @@ Session '${this.resumeSessionId}' not found.
4601
4704
  process.stdout.write(theme.dim(` \u{1F4CB} Custom commands: ${customCmdCount} loaded (use /commands to list)
4602
4705
  `));
4603
4706
  }
4707
+ void (async () => {
4708
+ try {
4709
+ const { indexProject } = await import("./indexer-C7QYYHSZ.js");
4710
+ const { loadIndex } = await import("./store-S24SPPDZ.js");
4711
+ const root = process.cwd();
4712
+ const existed = loadIndex(root);
4713
+ const { stats } = await indexProject(root);
4714
+ if (!existed) {
4715
+ process.stdout.write(
4716
+ theme.dim(` \u{1F50E} Symbol index built: ${stats.symbols} symbols across ${stats.filesParsed} files
4717
+ `)
4718
+ );
4719
+ } else if (stats.filesParsed > 0) {
4720
+ process.stdout.write(
4721
+ theme.dim(` \u{1F50E} Symbol index refreshed: ${stats.filesParsed} file(s) updated
4722
+ `)
4723
+ );
4724
+ }
4725
+ } catch {
4726
+ }
4727
+ })();
4604
4728
  const globalMcpServers = this.config.get("mcpServers") ?? {};
4605
4729
  const projectMcpResult = this.loadProjectMcpConfig();
4606
4730
  const projectMcpServers = projectMcpResult?.servers ?? {};
@@ -6264,7 +6388,7 @@ program.command("web").description("Start Web UI server with browser-based chat
6264
6388
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
6265
6389
  process.exit(1);
6266
6390
  }
6267
- const { startWebServer } = await import("./server-2XO72FRP.js");
6391
+ const { startWebServer } = await import("./server-CMSF65WV.js");
6268
6392
  await startWebServer({ port, host: options.host });
6269
6393
  });
6270
6394
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
@@ -6387,7 +6511,7 @@ program.command("sessions").description("List recent conversation sessions").act
6387
6511
  });
6388
6512
  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) => {
6389
6513
  try {
6390
- const batch = await import("./batch-2RTTAHBL.js");
6514
+ const batch = await import("./batch-RRC4RXZF.js");
6391
6515
  switch (action) {
6392
6516
  case "submit":
6393
6517
  if (!arg) {
@@ -6547,7 +6671,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
6547
6671
  }),
6548
6672
  config.get("customProviders")
6549
6673
  );
6550
- const { startHub } = await import("./hub-W3BF22UV.js");
6674
+ const { startHub } = await import("./hub-CZSXSOIH.js");
6551
6675
  await startHub(
6552
6676
  {
6553
6677
  topic: topic ?? "",
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-3BHGEPIT.js";
6
- import "./chunk-5P4QTZBI.js";
5
+ } from "./chunk-QATT4NCL.js";
6
+ import "./chunk-S4WDPHKS.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-E6RP5DBU.js";
4
+ } from "./chunk-IR5EW57V.js";
5
5
  export {
6
6
  executeTests,
7
7
  runTestsTool
@@ -20,13 +20,10 @@ import {
20
20
  persistToolRound,
21
21
  rebuildExtraMessages,
22
22
  setupProxy
23
- } from "./chunk-C4MGON2N.js";
24
- import {
25
- AuthManager
26
- } from "./chunk-BYNY5JPB.js";
23
+ } from "./chunk-5PZMIBEN.js";
27
24
  import {
28
25
  ConfigManager
29
- } from "./chunk-ASNDBI5R.js";
26
+ } from "./chunk-LQ76WLB6.js";
30
27
  import {
31
28
  ToolExecutor,
32
29
  ToolRegistry,
@@ -44,10 +41,14 @@ import {
44
41
  spawnAgentContext,
45
42
  truncateOutput,
46
43
  undoStack
47
- } from "./chunk-MPIUYP6Q.js";
48
- import "./chunk-4BKXL7SM.js";
49
- import "./chunk-3BHGEPIT.js";
44
+ } from "./chunk-LKDX2GOW.js";
50
45
  import "./chunk-2ZD3YTVM.js";
46
+ import "./chunk-4BKXL7SM.js";
47
+ import "./chunk-NHNWUBXB.js";
48
+ import "./chunk-HPDDAXFY.js";
49
+ import "./chunk-6VRJGH25.js";
50
+ import "./chunk-PFYAAX2S.js";
51
+ import "./chunk-QATT4NCL.js";
51
52
  import {
52
53
  AGENTIC_BEHAVIOR_GUIDELINE,
53
54
  AUTHOR,
@@ -66,7 +67,10 @@ import {
66
67
  SKILLS_DIR_NAME,
67
68
  VERSION,
68
69
  buildUserIdentityPrompt
69
- } from "./chunk-5P4QTZBI.js";
70
+ } from "./chunk-S4WDPHKS.js";
71
+ import {
72
+ AuthManager
73
+ } from "./chunk-BYNY5JPB.js";
70
74
 
71
75
  // src/web/server.ts
72
76
  import express from "express";
@@ -1478,6 +1482,8 @@ Tokens: in=${this.sessionTokenUsage.inputTokens} out=${this.sessionTokenUsage.ou
1478
1482
  " /diff [--stats] \u2014 Show file modifications in this session",
1479
1483
  " /checkpoint [save|restore|delete] <name> \u2014 Session checkpoints",
1480
1484
  " /fork [checkpoint] \u2014 Fork session from checkpoint or current",
1485
+ " /branch [list|new|switch|delete|rename] \u2014 Manage conversation branches",
1486
+ " /index [status|rebuild|clear|semantic-rebuild|semantic-clear] \u2014 Symbol + semantic index (find_symbol / search_code)",
1481
1487
  " /review [--staged] \u2014 AI code review from git diff",
1482
1488
  " /security-review \u2014 Security vulnerability scan on git diff",
1483
1489
  " /rewind [list|<n>] \u2014 Rewind conversation & restore files to checkpoint",
@@ -1897,6 +1903,76 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
1897
1903
  this.send({ type: "error", message: `Unknown subcommand: ${sub}. Use list/new/switch/delete/rename.` });
1898
1904
  break;
1899
1905
  }
1906
+ // ── /index ──────────────────────────────────────────────────────
1907
+ case "index": {
1908
+ const sub = (args[0] ?? "status").toLowerCase();
1909
+ const root = process.cwd();
1910
+ const { loadIndex, clearIndex } = await import("./store-S24SPPDZ.js");
1911
+ const { indexProject } = await import("./indexer-C7QYYHSZ.js");
1912
+ const { loadVectorStore, clearVectorStore } = await import("./vector-store-YTVHACBV.js");
1913
+ if (sub === "status") {
1914
+ const idx = loadIndex(root);
1915
+ const vec = loadVectorStore(root);
1916
+ if (!idx) {
1917
+ this.send({ type: "info", message: `No symbol index for ${root}. Run /index rebuild.` });
1918
+ } else {
1919
+ const semantic = vec ? `${vec.count} vectors \xD7 ${vec.dim}-dim` : "not built \u2014 run /index semantic-rebuild to enable search_code";
1920
+ this.send({
1921
+ type: "info",
1922
+ message: [
1923
+ "\u{1F50E} Symbol index:",
1924
+ ` Root: ${idx.root}`,
1925
+ ` Generated: ${idx.generated}`,
1926
+ ` Files: ${idx.fileCount}`,
1927
+ ` Symbols: ${idx.symbolCount}`,
1928
+ ` Semantic: ${semantic}`
1929
+ ].join("\n")
1930
+ });
1931
+ }
1932
+ } else if (sub === "rebuild") {
1933
+ this.send({ type: "info", message: `Indexing ${root}\u2026` });
1934
+ const { stats } = await indexProject(root, { force: true });
1935
+ this.send({
1936
+ type: "info",
1937
+ message: `\u2713 Indexed ${stats.filesParsed} files (${stats.symbols} symbols) in ${stats.durationMs}ms`
1938
+ });
1939
+ } else if (sub === "clear") {
1940
+ clearIndex(root);
1941
+ clearVectorStore(root);
1942
+ this.send({ type: "info", message: `\u2713 Cleared symbol + semantic index for ${root}` });
1943
+ } else if (sub === "semantic-rebuild") {
1944
+ const idx = loadIndex(root);
1945
+ if (!idx) {
1946
+ this.send({ type: "error", message: "No symbol index yet. Run /index rebuild first." });
1947
+ break;
1948
+ }
1949
+ this.send({
1950
+ type: "info",
1951
+ message: `Building semantic index for ${idx.symbolCount} symbols\u2026 (first run downloads ~117 MB model)`
1952
+ });
1953
+ try {
1954
+ const { rebuildSemanticIndex } = await import("./semantic-RBWU76MD.js");
1955
+ const stats = await rebuildSemanticIndex(root);
1956
+ const first = stats.modelFirstLoadMs ? ` (model load+first batch ${stats.modelFirstLoadMs}ms)` : "";
1957
+ this.send({
1958
+ type: "info",
1959
+ message: `\u2713 Embedded ${stats.symbolsEmbedded} symbols in ${stats.durationMs}ms${first}`
1960
+ });
1961
+ } catch (err) {
1962
+ const msg = err instanceof Error ? err.message : String(err);
1963
+ this.send({ type: "error", message: `Semantic rebuild failed: ${msg}` });
1964
+ }
1965
+ } else if (sub === "semantic-clear") {
1966
+ clearVectorStore(root);
1967
+ this.send({ type: "info", message: "\u2713 Cleared semantic index (symbol index preserved)" });
1968
+ } else {
1969
+ this.send({
1970
+ type: "error",
1971
+ message: `Unknown subcommand: ${sub}. Use status/rebuild/clear/semantic-rebuild/semantic-clear.`
1972
+ });
1973
+ }
1974
+ break;
1975
+ }
1900
1976
  // ── /fork ───────────────────────────────────────────────────────
1901
1977
  case "fork": {
1902
1978
  const session = this.sessions.current;
@@ -2062,7 +2138,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2062
2138
  case "test": {
2063
2139
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2064
2140
  try {
2065
- const { executeTests } = await import("./run-tests-V2JJADIU.js");
2141
+ const { executeTests } = await import("./run-tests-GEZ4NPWJ.js");
2066
2142
  const argStr = args.join(" ").trim();
2067
2143
  let testArgs = {};
2068
2144
  if (argStr) {
@@ -4,13 +4,17 @@ import {
4
4
  getDangerLevel,
5
5
  googleSearchContext,
6
6
  truncateOutput
7
- } from "./chunk-MPIUYP6Q.js";
8
- import "./chunk-4BKXL7SM.js";
9
- import "./chunk-3BHGEPIT.js";
7
+ } from "./chunk-LKDX2GOW.js";
10
8
  import "./chunk-2ZD3YTVM.js";
9
+ import "./chunk-4BKXL7SM.js";
10
+ import "./chunk-NHNWUBXB.js";
11
+ import "./chunk-HPDDAXFY.js";
12
+ import "./chunk-6VRJGH25.js";
13
+ import "./chunk-PFYAAX2S.js";
14
+ import "./chunk-QATT4NCL.js";
11
15
  import {
12
16
  SUBAGENT_ALLOWED_TOOLS
13
- } from "./chunk-5P4QTZBI.js";
17
+ } from "./chunk-S4WDPHKS.js";
14
18
 
15
19
  // src/hub/task-orchestrator.ts
16
20
  import { createInterface } from "readline";
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.75",
3
+ "version": "0.4.77",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,7 +38,9 @@
38
38
  },
39
39
  "pkg": {
40
40
  "scripts": "dist-cjs/index.cjs",
41
- "assets": [],
41
+ "assets": [
42
+ "dist/wasm/**/*"
43
+ ],
42
44
  "targets": [
43
45
  "node22-win-x64",
44
46
  "node22-macos-arm64",
@@ -61,6 +63,7 @@
61
63
  "dist/agent-client-*.js",
62
64
  "dist/task-orchestrator-*.js",
63
65
  "dist/web/",
66
+ "dist/wasm/",
64
67
  "README.md"
65
68
  ],
66
69
  "keywords": [
@@ -85,13 +88,18 @@
85
88
  "dependencies": {
86
89
  "@anthropic-ai/sdk": "^0.39.0",
87
90
  "@google/generative-ai": "^0.24.0",
91
+ "@huggingface/transformers": "^4.1.0",
88
92
  "@inquirer/prompts": "^7.0.0",
89
93
  "chalk": "^5.4.1",
90
94
  "commander": "^13.0.0",
91
95
  "express": "^5.2.1",
92
96
  "openai": "^4.77.0",
97
+ "tree-sitter-javascript": "^0.25.0",
98
+ "tree-sitter-python": "^0.25.0",
99
+ "tree-sitter-typescript": "^0.23.2",
93
100
  "undici": "^7.22.0",
94
101
  "uuid": "^11.0.5",
102
+ "web-tree-sitter": "^0.26.8",
95
103
  "ws": "^8.19.0",
96
104
  "zod": "^3.24.1"
97
105
  },