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,431 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ detectLanguage,
4
+ emptyIndex,
5
+ loadIndex,
6
+ removeFile,
7
+ saveIndex,
8
+ upsertFileSymbols
9
+ } from "./chunk-6VRJGH25.js";
10
+
11
+ // src/symbols/indexer.ts
12
+ import fs2 from "fs";
13
+ import path3 from "path";
14
+
15
+ // src/symbols/parser.ts
16
+ import path2 from "path";
17
+
18
+ // src/symbols/loader.ts
19
+ import { Parser, Language } from "web-tree-sitter";
20
+ import { createRequire } from "module";
21
+ import path from "path";
22
+ import fs from "fs";
23
+ import { fileURLToPath } from "url";
24
+ var _metaUrl = import.meta?.url;
25
+ var _cjsFilename = globalThis.__filename;
26
+ var __filename_ = _metaUrl ? fileURLToPath(_metaUrl) : _cjsFilename ?? process.execPath;
27
+ var __dirname_ = path.dirname(__filename_);
28
+ var require_ = _metaUrl ? createRequire(_metaUrl) : createRequire(__filename_);
29
+ var GRAMMAR_FILE = {
30
+ typescript: "tree-sitter-typescript.wasm",
31
+ tsx: "tree-sitter-tsx.wasm",
32
+ javascript: "tree-sitter-javascript.wasm",
33
+ python: "tree-sitter-python.wasm"
34
+ };
35
+ var RUNTIME_WASM = "web-tree-sitter.wasm";
36
+ var parserInitPromise = null;
37
+ var languageCache = /* @__PURE__ */ new Map();
38
+ var parserCache = /* @__PURE__ */ new Map();
39
+ function resolveWasmPath(filename) {
40
+ const candidates = [];
41
+ candidates.push(path.join(__dirname_, "wasm", filename));
42
+ candidates.push(path.join(__dirname_, "..", "wasm", filename));
43
+ candidates.push(path.join(__dirname_, "..", "dist", "wasm", filename));
44
+ if (process.pkg) {
45
+ candidates.push(path.join(path.dirname(process.execPath), "dist", "wasm", filename));
46
+ candidates.push(path.join("/snapshot", "ai-cli", "dist", "wasm", filename));
47
+ candidates.push(path.join("/snapshot", "jinzd-ai-cli", "dist", "wasm", filename));
48
+ }
49
+ const resourcesPath = process.resourcesPath;
50
+ if (resourcesPath) {
51
+ candidates.push(path.join(resourcesPath, "app.asar.unpacked", "dist", "wasm", filename));
52
+ candidates.push(path.join(resourcesPath, "app", "dist", "wasm", filename));
53
+ }
54
+ try {
55
+ if (filename === RUNTIME_WASM) {
56
+ const pkgPath = require_.resolve("web-tree-sitter/package.json");
57
+ candidates.push(path.join(path.dirname(pkgPath), filename));
58
+ } else {
59
+ const grammarPkg = filename.replace(/\.wasm$/, "").replace(/^tree-sitter-tsx$/, "tree-sitter-typescript");
60
+ const pkgPath = require_.resolve(`${grammarPkg}/package.json`);
61
+ candidates.push(path.join(path.dirname(pkgPath), filename));
62
+ }
63
+ } catch {
64
+ }
65
+ candidates.push(path.join(process.cwd(), "dist", "wasm", filename));
66
+ candidates.push(path.join(process.cwd(), "node_modules", "web-tree-sitter", filename));
67
+ for (const p of candidates) {
68
+ try {
69
+ if (fs.existsSync(p)) return p;
70
+ } catch {
71
+ }
72
+ }
73
+ throw new Error(
74
+ `[symbols/loader] Cannot locate ${filename}. Searched:
75
+ ${candidates.join("\n ")}`
76
+ );
77
+ }
78
+ async function initRuntime() {
79
+ if (parserInitPromise) return parserInitPromise;
80
+ parserInitPromise = Parser.init({
81
+ locateFile: (name) => resolveWasmPath(name)
82
+ });
83
+ return parserInitPromise;
84
+ }
85
+ async function loadParser(language) {
86
+ const cached = parserCache.get(language);
87
+ if (cached) return cached;
88
+ await initRuntime();
89
+ let lang = languageCache.get(language);
90
+ if (!lang) {
91
+ const wasmPath = resolveWasmPath(GRAMMAR_FILE[language]);
92
+ lang = await Language.load(wasmPath);
93
+ languageCache.set(language, lang);
94
+ }
95
+ const parser = new Parser();
96
+ parser.setLanguage(lang);
97
+ parserCache.set(language, parser);
98
+ return parser;
99
+ }
100
+
101
+ // src/symbols/parser.ts
102
+ function locationOf(file, node) {
103
+ return {
104
+ file: path2.resolve(file),
105
+ line: node.startPosition.row + 1,
106
+ column: node.startPosition.column,
107
+ endLine: node.endPosition.row + 1,
108
+ endColumn: node.endPosition.column
109
+ };
110
+ }
111
+ function firstLine(text, max = 200) {
112
+ const line = text.split(/\r?\n/)[0] ?? "";
113
+ return line.length > max ? line.slice(0, max) + "\u2026" : line;
114
+ }
115
+ function childByFieldName(node, field) {
116
+ return node.childForFieldName(field) ?? null;
117
+ }
118
+ function nameOf(node) {
119
+ const n = childByFieldName(node, "name") ?? node.children.find((c) => c?.type === "identifier" || c?.type === "property_identifier" || c?.type === "type_identifier");
120
+ return n?.text ?? null;
121
+ }
122
+ function extractTsJs(root, file, language) {
123
+ const out = [];
124
+ const visit = (node, container, exported) => {
125
+ let childrenContainer = container;
126
+ const kindMap = {
127
+ function_declaration: "function",
128
+ generator_function_declaration: "function",
129
+ class_declaration: "class",
130
+ abstract_class_declaration: "class",
131
+ interface_declaration: "interface",
132
+ type_alias_declaration: "type",
133
+ enum_declaration: "enum",
134
+ method_definition: "method",
135
+ method_signature: "method",
136
+ public_field_definition: "property"
137
+ };
138
+ const kind = kindMap[node.type];
139
+ if (kind) {
140
+ const name = nameOf(node);
141
+ if (name) {
142
+ out.push({
143
+ name,
144
+ kind,
145
+ language,
146
+ location: locationOf(file, node),
147
+ signature: firstLine(node.text),
148
+ container,
149
+ exported
150
+ });
151
+ if (kind === "class" || kind === "interface" || kind === "enum") {
152
+ childrenContainer = name;
153
+ }
154
+ }
155
+ } else if (node.type === "lexical_declaration" || node.type === "variable_declaration") {
156
+ for (const decl of node.children) {
157
+ if (decl?.type !== "variable_declarator") continue;
158
+ const nameNode = childByFieldName(decl, "name");
159
+ if (!nameNode || nameNode.type !== "identifier") continue;
160
+ out.push({
161
+ name: nameNode.text,
162
+ kind: "variable",
163
+ language,
164
+ location: locationOf(file, decl),
165
+ signature: firstLine(decl.text),
166
+ container,
167
+ exported
168
+ });
169
+ }
170
+ } else if (node.type === "export_statement") {
171
+ for (const c of node.children) {
172
+ if (c) visit(c, container, true);
173
+ }
174
+ return;
175
+ }
176
+ const descendInto = /* @__PURE__ */ new Set([
177
+ "program",
178
+ "module",
179
+ "class_body",
180
+ "class_declaration",
181
+ "abstract_class_declaration",
182
+ "interface_body",
183
+ "interface_declaration",
184
+ "enum_body",
185
+ "enum_declaration",
186
+ "export_statement",
187
+ "statement_block",
188
+ // for nested class_declaration inside namespace etc.
189
+ "internal_module",
190
+ "namespace_declaration"
191
+ ]);
192
+ if (node === root || descendInto.has(node.type)) {
193
+ for (const c of node.children) {
194
+ if (c) visit(c, childrenContainer, exported);
195
+ }
196
+ }
197
+ };
198
+ visit(root, void 0, false);
199
+ return out;
200
+ }
201
+ function extractPython(root, file) {
202
+ const out = [];
203
+ const visit = (node, container, isModuleLevel) => {
204
+ if (node.type === "decorated_definition") {
205
+ const def = node.children.find(
206
+ (c) => c?.type === "class_definition" || c?.type === "function_definition"
207
+ );
208
+ if (def) visit(def, container, isModuleLevel);
209
+ return;
210
+ }
211
+ if (node.type === "class_definition") {
212
+ const name = nameOf(node);
213
+ if (name) {
214
+ out.push({
215
+ name,
216
+ kind: "class",
217
+ language: "python",
218
+ location: locationOf(file, node),
219
+ signature: firstLine(node.text),
220
+ container,
221
+ exported: isModuleLevel
222
+ });
223
+ const body = childByFieldName(node, "body");
224
+ if (body) {
225
+ for (const c of body.children) {
226
+ if (c) visit(c, name, false);
227
+ }
228
+ }
229
+ }
230
+ return;
231
+ }
232
+ if (node.type === "function_definition") {
233
+ const name = nameOf(node);
234
+ if (name) {
235
+ out.push({
236
+ name,
237
+ kind: container ? "method" : "function",
238
+ language: "python",
239
+ location: locationOf(file, node),
240
+ signature: firstLine(node.text),
241
+ container,
242
+ exported: isModuleLevel && !name.startsWith("_")
243
+ });
244
+ }
245
+ return;
246
+ }
247
+ if (isModuleLevel && node.type === "expression_statement") {
248
+ const assign = node.children.find((c) => c?.type === "assignment");
249
+ if (assign) {
250
+ const left = childByFieldName(assign, "left");
251
+ if (left && left.type === "identifier") {
252
+ out.push({
253
+ name: left.text,
254
+ kind: "variable",
255
+ language: "python",
256
+ location: locationOf(file, assign),
257
+ signature: firstLine(assign.text),
258
+ container,
259
+ exported: !left.text.startsWith("_")
260
+ });
261
+ }
262
+ }
263
+ return;
264
+ }
265
+ if (node === root || node.type === "module") {
266
+ for (const c of node.children) {
267
+ if (c) visit(c, container, true);
268
+ }
269
+ }
270
+ };
271
+ visit(root, void 0, true);
272
+ return out;
273
+ }
274
+ async function parseSource(file, source, language) {
275
+ const lang = language ?? detectLanguage(path2.extname(file).slice(1));
276
+ if (!lang) return [];
277
+ try {
278
+ const parser = await loadParser(lang);
279
+ const tree = parser.parse(source);
280
+ if (!tree) return [];
281
+ const root = tree.rootNode;
282
+ if (lang === "python") return extractPython(root, file);
283
+ return extractTsJs(root, file, lang);
284
+ } catch (err) {
285
+ return [];
286
+ }
287
+ }
288
+
289
+ // src/symbols/indexer.ts
290
+ var SKIP_DIRS = /* @__PURE__ */ new Set([
291
+ "node_modules",
292
+ ".git",
293
+ "dist",
294
+ "dist-cjs",
295
+ "build",
296
+ "out",
297
+ "coverage",
298
+ ".next",
299
+ ".nuxt",
300
+ ".turbo",
301
+ ".cache",
302
+ "__pycache__",
303
+ ".venv",
304
+ "venv",
305
+ ".idea",
306
+ ".vscode",
307
+ "release"
308
+ ]);
309
+ var MAX_FILE_BYTES = 2 * 1024 * 1024;
310
+ function collectFiles(root, maxFiles) {
311
+ const out = [];
312
+ const stack = [root];
313
+ while (stack.length > 0 && out.length < maxFiles) {
314
+ const dir = stack.pop();
315
+ let entries;
316
+ try {
317
+ entries = fs2.readdirSync(dir, { withFileTypes: true });
318
+ } catch {
319
+ continue;
320
+ }
321
+ for (const e of entries) {
322
+ const full = path3.join(dir, e.name);
323
+ if (e.isDirectory()) {
324
+ if (SKIP_DIRS.has(e.name)) continue;
325
+ if (e.name.startsWith(".") && e.name !== ".") {
326
+ continue;
327
+ }
328
+ stack.push(full);
329
+ } else if (e.isFile()) {
330
+ const ext = path3.extname(e.name).slice(1);
331
+ if (detectLanguage(ext)) {
332
+ out.push(full);
333
+ if (out.length >= maxFiles) break;
334
+ }
335
+ }
336
+ }
337
+ }
338
+ return out;
339
+ }
340
+ async function indexProject(root, opts = {}) {
341
+ const start = Date.now();
342
+ const maxFiles = opts.maxFiles ?? 5e3;
343
+ const force = opts.force === true;
344
+ const absRoot = path3.resolve(root);
345
+ let index = force ? emptyIndex(absRoot) : loadIndex(absRoot) ?? emptyIndex(absRoot);
346
+ const files = collectFiles(absRoot, maxFiles);
347
+ const liveSet = new Set(files.map((f) => path3.resolve(f)));
348
+ for (const known of Object.keys(index.files)) {
349
+ if (!liveSet.has(known)) {
350
+ index = removeFile(index, known);
351
+ }
352
+ }
353
+ let parsed = 0;
354
+ let skipped = 0;
355
+ for (let i = 0; i < files.length; i++) {
356
+ const file = path3.resolve(files[i]);
357
+ let stat;
358
+ try {
359
+ stat = fs2.statSync(file);
360
+ } catch {
361
+ skipped++;
362
+ continue;
363
+ }
364
+ if (stat.size > MAX_FILE_BYTES) {
365
+ skipped++;
366
+ continue;
367
+ }
368
+ const prevMtime = index.files[file];
369
+ if (!force && prevMtime !== void 0 && prevMtime === stat.mtimeMs) {
370
+ continue;
371
+ }
372
+ let src;
373
+ try {
374
+ src = fs2.readFileSync(file, "utf-8");
375
+ } catch {
376
+ skipped++;
377
+ continue;
378
+ }
379
+ const symbols = await parseSource(file, src);
380
+ index = upsertFileSymbols(index, file, stat.mtimeMs, symbols);
381
+ parsed++;
382
+ if (opts.onProgress && parsed % 50 === 0) {
383
+ opts.onProgress(i + 1, files.length);
384
+ }
385
+ }
386
+ saveIndex(index);
387
+ return {
388
+ index,
389
+ stats: {
390
+ filesScanned: files.length,
391
+ filesParsed: parsed,
392
+ filesSkipped: skipped,
393
+ symbols: index.symbolCount,
394
+ durationMs: Date.now() - start
395
+ }
396
+ };
397
+ }
398
+ async function updateFile(root, file) {
399
+ const absRoot = path3.resolve(root);
400
+ const absFile = path3.resolve(file);
401
+ let index = loadIndex(absRoot);
402
+ if (!index) return;
403
+ if (!fs2.existsSync(absFile)) {
404
+ index = removeFile(index, absFile);
405
+ saveIndex(index);
406
+ return;
407
+ }
408
+ const ext = path3.extname(absFile).slice(1);
409
+ if (!detectLanguage(ext)) return;
410
+ let stat;
411
+ try {
412
+ stat = fs2.statSync(absFile);
413
+ } catch {
414
+ return;
415
+ }
416
+ if (stat.size > MAX_FILE_BYTES) return;
417
+ let src;
418
+ try {
419
+ src = fs2.readFileSync(absFile, "utf-8");
420
+ } catch {
421
+ return;
422
+ }
423
+ const symbols = await parseSource(absFile, src);
424
+ index = upsertFileSymbols(index, absFile, stat.mtimeMs, symbols);
425
+ saveIndex(index);
426
+ }
427
+
428
+ export {
429
+ indexProject,
430
+ updateFile
431
+ };
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/symbols/vector-store.ts
4
+ import fs2 from "fs";
5
+ import path2 from "path";
6
+ import os2 from "os";
7
+ import crypto from "crypto";
8
+
9
+ // src/symbols/embedder.ts
10
+ import path from "path";
11
+ import os from "os";
12
+ import fs from "fs";
13
+ var EMBEDDING_MODEL_ID = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
14
+ var EMBEDDING_DIM = 384;
15
+ var pipelinePromise = null;
16
+ function cacheDir() {
17
+ return path.join(os.homedir(), ".aicli", "models");
18
+ }
19
+ async function getEmbedder() {
20
+ if (pipelinePromise) return pipelinePromise;
21
+ pipelinePromise = (async () => {
22
+ const mod = await import("@huggingface/transformers");
23
+ const dir = cacheDir();
24
+ fs.mkdirSync(dir, { recursive: true });
25
+ mod.env.cacheDir = dir;
26
+ mod.env.allowRemoteModels = true;
27
+ mod.env.allowLocalModels = true;
28
+ const pipe = await mod.pipeline("feature-extraction", EMBEDDING_MODEL_ID, {
29
+ // Keep the ONNX session in float32; int8 quantization exists but the
30
+ // quality drop on short code identifiers is noticeable.
31
+ dtype: "fp32"
32
+ });
33
+ return pipe;
34
+ })();
35
+ return pipelinePromise;
36
+ }
37
+ async function embed(texts) {
38
+ if (texts.length === 0) return [];
39
+ const pipe = await getEmbedder();
40
+ const out = await pipe(texts, { pooling: "mean", normalize: true });
41
+ const batch = texts.length;
42
+ const dim = EMBEDDING_DIM;
43
+ const rows = new Array(batch);
44
+ for (let i = 0; i < batch; i++) {
45
+ rows[i] = new Float32Array(out.data.buffer, out.data.byteOffset + i * dim * 4, dim).slice();
46
+ }
47
+ return rows;
48
+ }
49
+ async function embedOne(text) {
50
+ const [vec] = await embed([text]);
51
+ return vec;
52
+ }
53
+
54
+ // src/symbols/vector-store.ts
55
+ var MAGIC = 1094927190;
56
+ var VERSION = 1;
57
+ var HEADER_BYTES = 16;
58
+ function indexDir() {
59
+ return path2.join(os2.homedir(), ".aicli", "index");
60
+ }
61
+ function projectHash(root) {
62
+ return crypto.createHash("sha1").update(path2.resolve(root).toLowerCase()).digest("hex").slice(0, 16);
63
+ }
64
+ function vecPath(root) {
65
+ return path2.join(indexDir(), `${projectHash(root)}.vec`);
66
+ }
67
+ function emptyVectorStore(root) {
68
+ return {
69
+ root: path2.resolve(root),
70
+ count: 0,
71
+ dim: EMBEDDING_DIM,
72
+ vectors: new Float32Array(0),
73
+ symbolIdx: new Uint32Array(0)
74
+ };
75
+ }
76
+ function saveVectorStore(root, indices, vectors) {
77
+ if (indices.length * EMBEDDING_DIM !== vectors.length) {
78
+ throw new Error(
79
+ `saveVectorStore: length mismatch \u2014 ${indices.length} indices vs ${vectors.length / EMBEDDING_DIM} vectors`
80
+ );
81
+ }
82
+ const count = indices.length;
83
+ const dir = indexDir();
84
+ fs2.mkdirSync(dir, { recursive: true });
85
+ const totalBytes = HEADER_BYTES + count * 4 + count * EMBEDDING_DIM * 4;
86
+ const buf = Buffer.alloc(totalBytes);
87
+ buf.writeUInt32LE(MAGIC, 0);
88
+ buf.writeUInt32LE(VERSION, 4);
89
+ buf.writeUInt32LE(count, 8);
90
+ buf.writeUInt32LE(EMBEDDING_DIM, 12);
91
+ Buffer.from(indices.buffer, indices.byteOffset, indices.byteLength).copy(buf, HEADER_BYTES);
92
+ Buffer.from(vectors.buffer, vectors.byteOffset, vectors.byteLength).copy(buf, HEADER_BYTES + count * 4);
93
+ const target = vecPath(root);
94
+ const tmp = `${target}.tmp`;
95
+ fs2.writeFileSync(tmp, buf);
96
+ fs2.renameSync(tmp, target);
97
+ }
98
+ function loadVectorStore(root) {
99
+ const p = vecPath(root);
100
+ if (!fs2.existsSync(p)) return null;
101
+ let buf;
102
+ try {
103
+ buf = fs2.readFileSync(p);
104
+ } catch {
105
+ return null;
106
+ }
107
+ if (buf.length < HEADER_BYTES) return null;
108
+ const magic = buf.readUInt32LE(0);
109
+ const version = buf.readUInt32LE(4);
110
+ const count = buf.readUInt32LE(8);
111
+ const dim = buf.readUInt32LE(12);
112
+ if (magic !== MAGIC || version !== VERSION || dim !== EMBEDDING_DIM) return null;
113
+ const expected = HEADER_BYTES + count * 4 + count * dim * 4;
114
+ if (buf.length !== expected) return null;
115
+ const symbolIdx = new Uint32Array(
116
+ buf.buffer.slice(buf.byteOffset + HEADER_BYTES, buf.byteOffset + HEADER_BYTES + count * 4)
117
+ );
118
+ const vectors = new Float32Array(
119
+ buf.buffer.slice(
120
+ buf.byteOffset + HEADER_BYTES + count * 4,
121
+ buf.byteOffset + HEADER_BYTES + count * 4 + count * dim * 4
122
+ )
123
+ );
124
+ return { root: path2.resolve(root), count, dim, vectors, symbolIdx };
125
+ }
126
+ function clearVectorStore(root) {
127
+ const p = vecPath(root);
128
+ try {
129
+ if (fs2.existsSync(p)) fs2.unlinkSync(p);
130
+ } catch {
131
+ }
132
+ }
133
+ function searchVectorStore(store, queryVec, k) {
134
+ if (store.count === 0) return [];
135
+ if (queryVec.length !== store.dim) {
136
+ throw new Error(`searchVectorStore: dim mismatch (query=${queryVec.length}, store=${store.dim})`);
137
+ }
138
+ const { count, dim, vectors, symbolIdx } = store;
139
+ const heap = [];
140
+ const push = (hit) => {
141
+ if (heap.length < k) {
142
+ heap.push(hit);
143
+ heap.sort((a, b) => a.score - b.score);
144
+ } else if (hit.score > heap[0].score) {
145
+ heap[0] = hit;
146
+ heap.sort((a, b) => a.score - b.score);
147
+ }
148
+ };
149
+ for (let row = 0; row < count; row++) {
150
+ const base = row * dim;
151
+ let score = 0;
152
+ for (let d = 0; d < dim; d++) {
153
+ score += vectors[base + d] * queryVec[d];
154
+ }
155
+ push({ row, symbolIdx: symbolIdx[row], score });
156
+ }
157
+ return heap.sort((a, b) => b.score - a.score);
158
+ }
159
+
160
+ export {
161
+ EMBEDDING_DIM,
162
+ embed,
163
+ embedOne,
164
+ emptyVectorStore,
165
+ saveVectorStore,
166
+ loadVectorStore,
167
+ clearVectorStore,
168
+ searchVectorStore
169
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-5P4QTZBI.js";
4
+ } from "./chunk-S4WDPHKS.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync } from "child_process";