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.
- package/README.md +8 -1
- package/dist/{chunk-C4MGON2N.js → chunk-5PZMIBEN.js} +2 -2
- package/dist/chunk-6VRJGH25.js +115 -0
- package/dist/chunk-BJAT4GNC.js +113 -0
- package/dist/chunk-HPDDAXFY.js +84 -0
- package/dist/{chunk-E6RP5DBU.js → chunk-IR5EW57V.js} +15 -3
- package/dist/{chunk-MPIUYP6Q.js → chunk-LKDX2GOW.js} +305 -9
- package/dist/{chunk-ASNDBI5R.js → chunk-LQ76WLB6.js} +1 -1
- package/dist/chunk-NHNWUBXB.js +431 -0
- package/dist/chunk-PFYAAX2S.js +169 -0
- package/dist/{chunk-3BHGEPIT.js → chunk-QATT4NCL.js} +1 -1
- package/dist/chunk-RFQVUMDB.js +430 -0
- package/dist/{chunk-5P4QTZBI.js → chunk-S4WDPHKS.js} +15 -3
- package/dist/chunk-UTCC3UMT.js +83 -0
- package/dist/chunk-XMA222FQ.js +167 -0
- package/dist/{hub-W3BF22UV.js → hub-CZSXSOIH.js} +1 -1
- package/dist/index.js +137 -13
- package/dist/{run-tests-V2JJADIU.js → run-tests-GEZ4NPWJ.js} +2 -2
- package/dist/{run-tests-LEYTZHPU.js → run-tests-RHAXFEOL.js} +1 -1
- package/dist/{server-2XO72FRP.js → server-CMSF65WV.js} +86 -10
- package/dist/{task-orchestrator-277NWVSE.js → task-orchestrator-VC7LCN5J.js} +8 -4
- package/dist/wasm/tree-sitter-javascript.wasm +0 -0
- package/dist/wasm/tree-sitter-python.wasm +0 -0
- package/dist/wasm/tree-sitter-tsx.wasm +0 -0
- package/dist/wasm/tree-sitter-typescript.wasm +0 -0
- package/dist/wasm/web-tree-sitter.wasm +0 -0
- package/package.json +10 -2
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectLanguage,
|
|
3
|
+
emptyIndex,
|
|
4
|
+
loadIndex,
|
|
5
|
+
removeFile,
|
|
6
|
+
saveIndex,
|
|
7
|
+
upsertFileSymbols
|
|
8
|
+
} from "./chunk-BJAT4GNC.js";
|
|
9
|
+
|
|
10
|
+
// src/symbols/indexer.ts
|
|
11
|
+
import fs2 from "fs";
|
|
12
|
+
import path3 from "path";
|
|
13
|
+
|
|
14
|
+
// src/symbols/parser.ts
|
|
15
|
+
import path2 from "path";
|
|
16
|
+
|
|
17
|
+
// src/symbols/loader.ts
|
|
18
|
+
import { Parser, Language } from "web-tree-sitter";
|
|
19
|
+
import { createRequire } from "module";
|
|
20
|
+
import path from "path";
|
|
21
|
+
import fs from "fs";
|
|
22
|
+
import { fileURLToPath } from "url";
|
|
23
|
+
var _metaUrl = import.meta?.url;
|
|
24
|
+
var _cjsFilename = globalThis.__filename;
|
|
25
|
+
var __filename_ = _metaUrl ? fileURLToPath(_metaUrl) : _cjsFilename ?? process.execPath;
|
|
26
|
+
var __dirname_ = path.dirname(__filename_);
|
|
27
|
+
var require_ = _metaUrl ? createRequire(_metaUrl) : createRequire(__filename_);
|
|
28
|
+
var GRAMMAR_FILE = {
|
|
29
|
+
typescript: "tree-sitter-typescript.wasm",
|
|
30
|
+
tsx: "tree-sitter-tsx.wasm",
|
|
31
|
+
javascript: "tree-sitter-javascript.wasm",
|
|
32
|
+
python: "tree-sitter-python.wasm"
|
|
33
|
+
};
|
|
34
|
+
var RUNTIME_WASM = "web-tree-sitter.wasm";
|
|
35
|
+
var parserInitPromise = null;
|
|
36
|
+
var languageCache = /* @__PURE__ */ new Map();
|
|
37
|
+
var parserCache = /* @__PURE__ */ new Map();
|
|
38
|
+
function resolveWasmPath(filename) {
|
|
39
|
+
const candidates = [];
|
|
40
|
+
candidates.push(path.join(__dirname_, "wasm", filename));
|
|
41
|
+
candidates.push(path.join(__dirname_, "..", "wasm", filename));
|
|
42
|
+
candidates.push(path.join(__dirname_, "..", "dist", "wasm", filename));
|
|
43
|
+
if (process.pkg) {
|
|
44
|
+
candidates.push(path.join(path.dirname(process.execPath), "dist", "wasm", filename));
|
|
45
|
+
candidates.push(path.join("/snapshot", "ai-cli", "dist", "wasm", filename));
|
|
46
|
+
candidates.push(path.join("/snapshot", "jinzd-ai-cli", "dist", "wasm", filename));
|
|
47
|
+
}
|
|
48
|
+
const resourcesPath = process.resourcesPath;
|
|
49
|
+
if (resourcesPath) {
|
|
50
|
+
candidates.push(path.join(resourcesPath, "app.asar.unpacked", "dist", "wasm", filename));
|
|
51
|
+
candidates.push(path.join(resourcesPath, "app", "dist", "wasm", filename));
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
if (filename === RUNTIME_WASM) {
|
|
55
|
+
const pkgPath = require_.resolve("web-tree-sitter/package.json");
|
|
56
|
+
candidates.push(path.join(path.dirname(pkgPath), filename));
|
|
57
|
+
} else {
|
|
58
|
+
const grammarPkg = filename.replace(/\.wasm$/, "").replace(/^tree-sitter-tsx$/, "tree-sitter-typescript");
|
|
59
|
+
const pkgPath = require_.resolve(`${grammarPkg}/package.json`);
|
|
60
|
+
candidates.push(path.join(path.dirname(pkgPath), filename));
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
}
|
|
64
|
+
candidates.push(path.join(process.cwd(), "dist", "wasm", filename));
|
|
65
|
+
candidates.push(path.join(process.cwd(), "node_modules", "web-tree-sitter", filename));
|
|
66
|
+
for (const p of candidates) {
|
|
67
|
+
try {
|
|
68
|
+
if (fs.existsSync(p)) return p;
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
throw new Error(
|
|
73
|
+
`[symbols/loader] Cannot locate ${filename}. Searched:
|
|
74
|
+
${candidates.join("\n ")}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
async function initRuntime() {
|
|
78
|
+
if (parserInitPromise) return parserInitPromise;
|
|
79
|
+
parserInitPromise = Parser.init({
|
|
80
|
+
locateFile: (name) => resolveWasmPath(name)
|
|
81
|
+
});
|
|
82
|
+
return parserInitPromise;
|
|
83
|
+
}
|
|
84
|
+
async function loadParser(language) {
|
|
85
|
+
const cached = parserCache.get(language);
|
|
86
|
+
if (cached) return cached;
|
|
87
|
+
await initRuntime();
|
|
88
|
+
let lang = languageCache.get(language);
|
|
89
|
+
if (!lang) {
|
|
90
|
+
const wasmPath = resolveWasmPath(GRAMMAR_FILE[language]);
|
|
91
|
+
lang = await Language.load(wasmPath);
|
|
92
|
+
languageCache.set(language, lang);
|
|
93
|
+
}
|
|
94
|
+
const parser = new Parser();
|
|
95
|
+
parser.setLanguage(lang);
|
|
96
|
+
parserCache.set(language, parser);
|
|
97
|
+
return parser;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/symbols/parser.ts
|
|
101
|
+
function locationOf(file, node) {
|
|
102
|
+
return {
|
|
103
|
+
file: path2.resolve(file),
|
|
104
|
+
line: node.startPosition.row + 1,
|
|
105
|
+
column: node.startPosition.column,
|
|
106
|
+
endLine: node.endPosition.row + 1,
|
|
107
|
+
endColumn: node.endPosition.column
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function firstLine(text, max = 200) {
|
|
111
|
+
const line = text.split(/\r?\n/)[0] ?? "";
|
|
112
|
+
return line.length > max ? line.slice(0, max) + "\u2026" : line;
|
|
113
|
+
}
|
|
114
|
+
function childByFieldName(node, field) {
|
|
115
|
+
return node.childForFieldName(field) ?? null;
|
|
116
|
+
}
|
|
117
|
+
function nameOf(node) {
|
|
118
|
+
const n = childByFieldName(node, "name") ?? node.children.find((c) => c?.type === "identifier" || c?.type === "property_identifier" || c?.type === "type_identifier");
|
|
119
|
+
return n?.text ?? null;
|
|
120
|
+
}
|
|
121
|
+
function extractTsJs(root, file, language) {
|
|
122
|
+
const out = [];
|
|
123
|
+
const visit = (node, container, exported) => {
|
|
124
|
+
let childrenContainer = container;
|
|
125
|
+
const kindMap = {
|
|
126
|
+
function_declaration: "function",
|
|
127
|
+
generator_function_declaration: "function",
|
|
128
|
+
class_declaration: "class",
|
|
129
|
+
abstract_class_declaration: "class",
|
|
130
|
+
interface_declaration: "interface",
|
|
131
|
+
type_alias_declaration: "type",
|
|
132
|
+
enum_declaration: "enum",
|
|
133
|
+
method_definition: "method",
|
|
134
|
+
method_signature: "method",
|
|
135
|
+
public_field_definition: "property"
|
|
136
|
+
};
|
|
137
|
+
const kind = kindMap[node.type];
|
|
138
|
+
if (kind) {
|
|
139
|
+
const name = nameOf(node);
|
|
140
|
+
if (name) {
|
|
141
|
+
out.push({
|
|
142
|
+
name,
|
|
143
|
+
kind,
|
|
144
|
+
language,
|
|
145
|
+
location: locationOf(file, node),
|
|
146
|
+
signature: firstLine(node.text),
|
|
147
|
+
container,
|
|
148
|
+
exported
|
|
149
|
+
});
|
|
150
|
+
if (kind === "class" || kind === "interface" || kind === "enum") {
|
|
151
|
+
childrenContainer = name;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} else if (node.type === "lexical_declaration" || node.type === "variable_declaration") {
|
|
155
|
+
for (const decl of node.children) {
|
|
156
|
+
if (decl?.type !== "variable_declarator") continue;
|
|
157
|
+
const nameNode = childByFieldName(decl, "name");
|
|
158
|
+
if (!nameNode || nameNode.type !== "identifier") continue;
|
|
159
|
+
out.push({
|
|
160
|
+
name: nameNode.text,
|
|
161
|
+
kind: "variable",
|
|
162
|
+
language,
|
|
163
|
+
location: locationOf(file, decl),
|
|
164
|
+
signature: firstLine(decl.text),
|
|
165
|
+
container,
|
|
166
|
+
exported
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
} else if (node.type === "export_statement") {
|
|
170
|
+
for (const c of node.children) {
|
|
171
|
+
if (c) visit(c, container, true);
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const descendInto = /* @__PURE__ */ new Set([
|
|
176
|
+
"program",
|
|
177
|
+
"module",
|
|
178
|
+
"class_body",
|
|
179
|
+
"class_declaration",
|
|
180
|
+
"abstract_class_declaration",
|
|
181
|
+
"interface_body",
|
|
182
|
+
"interface_declaration",
|
|
183
|
+
"enum_body",
|
|
184
|
+
"enum_declaration",
|
|
185
|
+
"export_statement",
|
|
186
|
+
"statement_block",
|
|
187
|
+
// for nested class_declaration inside namespace etc.
|
|
188
|
+
"internal_module",
|
|
189
|
+
"namespace_declaration"
|
|
190
|
+
]);
|
|
191
|
+
if (node === root || descendInto.has(node.type)) {
|
|
192
|
+
for (const c of node.children) {
|
|
193
|
+
if (c) visit(c, childrenContainer, exported);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
visit(root, void 0, false);
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
function extractPython(root, file) {
|
|
201
|
+
const out = [];
|
|
202
|
+
const visit = (node, container, isModuleLevel) => {
|
|
203
|
+
if (node.type === "decorated_definition") {
|
|
204
|
+
const def = node.children.find(
|
|
205
|
+
(c) => c?.type === "class_definition" || c?.type === "function_definition"
|
|
206
|
+
);
|
|
207
|
+
if (def) visit(def, container, isModuleLevel);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (node.type === "class_definition") {
|
|
211
|
+
const name = nameOf(node);
|
|
212
|
+
if (name) {
|
|
213
|
+
out.push({
|
|
214
|
+
name,
|
|
215
|
+
kind: "class",
|
|
216
|
+
language: "python",
|
|
217
|
+
location: locationOf(file, node),
|
|
218
|
+
signature: firstLine(node.text),
|
|
219
|
+
container,
|
|
220
|
+
exported: isModuleLevel
|
|
221
|
+
});
|
|
222
|
+
const body = childByFieldName(node, "body");
|
|
223
|
+
if (body) {
|
|
224
|
+
for (const c of body.children) {
|
|
225
|
+
if (c) visit(c, name, false);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (node.type === "function_definition") {
|
|
232
|
+
const name = nameOf(node);
|
|
233
|
+
if (name) {
|
|
234
|
+
out.push({
|
|
235
|
+
name,
|
|
236
|
+
kind: container ? "method" : "function",
|
|
237
|
+
language: "python",
|
|
238
|
+
location: locationOf(file, node),
|
|
239
|
+
signature: firstLine(node.text),
|
|
240
|
+
container,
|
|
241
|
+
exported: isModuleLevel && !name.startsWith("_")
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (isModuleLevel && node.type === "expression_statement") {
|
|
247
|
+
const assign = node.children.find((c) => c?.type === "assignment");
|
|
248
|
+
if (assign) {
|
|
249
|
+
const left = childByFieldName(assign, "left");
|
|
250
|
+
if (left && left.type === "identifier") {
|
|
251
|
+
out.push({
|
|
252
|
+
name: left.text,
|
|
253
|
+
kind: "variable",
|
|
254
|
+
language: "python",
|
|
255
|
+
location: locationOf(file, assign),
|
|
256
|
+
signature: firstLine(assign.text),
|
|
257
|
+
container,
|
|
258
|
+
exported: !left.text.startsWith("_")
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (node === root || node.type === "module") {
|
|
265
|
+
for (const c of node.children) {
|
|
266
|
+
if (c) visit(c, container, true);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
visit(root, void 0, true);
|
|
271
|
+
return out;
|
|
272
|
+
}
|
|
273
|
+
async function parseSource(file, source, language) {
|
|
274
|
+
const lang = language ?? detectLanguage(path2.extname(file).slice(1));
|
|
275
|
+
if (!lang) return [];
|
|
276
|
+
try {
|
|
277
|
+
const parser = await loadParser(lang);
|
|
278
|
+
const tree = parser.parse(source);
|
|
279
|
+
if (!tree) return [];
|
|
280
|
+
const root = tree.rootNode;
|
|
281
|
+
if (lang === "python") return extractPython(root, file);
|
|
282
|
+
return extractTsJs(root, file, lang);
|
|
283
|
+
} catch (err) {
|
|
284
|
+
return [];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/symbols/indexer.ts
|
|
289
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
290
|
+
"node_modules",
|
|
291
|
+
".git",
|
|
292
|
+
"dist",
|
|
293
|
+
"dist-cjs",
|
|
294
|
+
"build",
|
|
295
|
+
"out",
|
|
296
|
+
"coverage",
|
|
297
|
+
".next",
|
|
298
|
+
".nuxt",
|
|
299
|
+
".turbo",
|
|
300
|
+
".cache",
|
|
301
|
+
"__pycache__",
|
|
302
|
+
".venv",
|
|
303
|
+
"venv",
|
|
304
|
+
".idea",
|
|
305
|
+
".vscode",
|
|
306
|
+
"release"
|
|
307
|
+
]);
|
|
308
|
+
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
309
|
+
function collectFiles(root, maxFiles) {
|
|
310
|
+
const out = [];
|
|
311
|
+
const stack = [root];
|
|
312
|
+
while (stack.length > 0 && out.length < maxFiles) {
|
|
313
|
+
const dir = stack.pop();
|
|
314
|
+
let entries;
|
|
315
|
+
try {
|
|
316
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
317
|
+
} catch {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
for (const e of entries) {
|
|
321
|
+
const full = path3.join(dir, e.name);
|
|
322
|
+
if (e.isDirectory()) {
|
|
323
|
+
if (SKIP_DIRS.has(e.name)) continue;
|
|
324
|
+
if (e.name.startsWith(".") && e.name !== ".") {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
stack.push(full);
|
|
328
|
+
} else if (e.isFile()) {
|
|
329
|
+
const ext = path3.extname(e.name).slice(1);
|
|
330
|
+
if (detectLanguage(ext)) {
|
|
331
|
+
out.push(full);
|
|
332
|
+
if (out.length >= maxFiles) break;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
339
|
+
async function indexProject(root, opts = {}) {
|
|
340
|
+
const start = Date.now();
|
|
341
|
+
const maxFiles = opts.maxFiles ?? 5e3;
|
|
342
|
+
const force = opts.force === true;
|
|
343
|
+
const absRoot = path3.resolve(root);
|
|
344
|
+
let index = force ? emptyIndex(absRoot) : loadIndex(absRoot) ?? emptyIndex(absRoot);
|
|
345
|
+
const files = collectFiles(absRoot, maxFiles);
|
|
346
|
+
const liveSet = new Set(files.map((f) => path3.resolve(f)));
|
|
347
|
+
for (const known of Object.keys(index.files)) {
|
|
348
|
+
if (!liveSet.has(known)) {
|
|
349
|
+
index = removeFile(index, known);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
let parsed = 0;
|
|
353
|
+
let skipped = 0;
|
|
354
|
+
for (let i = 0; i < files.length; i++) {
|
|
355
|
+
const file = path3.resolve(files[i]);
|
|
356
|
+
let stat;
|
|
357
|
+
try {
|
|
358
|
+
stat = fs2.statSync(file);
|
|
359
|
+
} catch {
|
|
360
|
+
skipped++;
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (stat.size > MAX_FILE_BYTES) {
|
|
364
|
+
skipped++;
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
const prevMtime = index.files[file];
|
|
368
|
+
if (!force && prevMtime !== void 0 && prevMtime === stat.mtimeMs) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
let src;
|
|
372
|
+
try {
|
|
373
|
+
src = fs2.readFileSync(file, "utf-8");
|
|
374
|
+
} catch {
|
|
375
|
+
skipped++;
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
const symbols = await parseSource(file, src);
|
|
379
|
+
index = upsertFileSymbols(index, file, stat.mtimeMs, symbols);
|
|
380
|
+
parsed++;
|
|
381
|
+
if (opts.onProgress && parsed % 50 === 0) {
|
|
382
|
+
opts.onProgress(i + 1, files.length);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
saveIndex(index);
|
|
386
|
+
return {
|
|
387
|
+
index,
|
|
388
|
+
stats: {
|
|
389
|
+
filesScanned: files.length,
|
|
390
|
+
filesParsed: parsed,
|
|
391
|
+
filesSkipped: skipped,
|
|
392
|
+
symbols: index.symbolCount,
|
|
393
|
+
durationMs: Date.now() - start
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
async function updateFile(root, file) {
|
|
398
|
+
const absRoot = path3.resolve(root);
|
|
399
|
+
const absFile = path3.resolve(file);
|
|
400
|
+
let index = loadIndex(absRoot);
|
|
401
|
+
if (!index) return;
|
|
402
|
+
if (!fs2.existsSync(absFile)) {
|
|
403
|
+
index = removeFile(index, absFile);
|
|
404
|
+
saveIndex(index);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const ext = path3.extname(absFile).slice(1);
|
|
408
|
+
if (!detectLanguage(ext)) return;
|
|
409
|
+
let stat;
|
|
410
|
+
try {
|
|
411
|
+
stat = fs2.statSync(absFile);
|
|
412
|
+
} catch {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (stat.size > MAX_FILE_BYTES) return;
|
|
416
|
+
let src;
|
|
417
|
+
try {
|
|
418
|
+
src = fs2.readFileSync(absFile, "utf-8");
|
|
419
|
+
} catch {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const symbols = await parseSource(absFile, src);
|
|
423
|
+
index = upsertFileSymbols(index, absFile, stat.mtimeMs, symbols);
|
|
424
|
+
saveIndex(index);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export {
|
|
428
|
+
indexProject,
|
|
429
|
+
updateFile
|
|
430
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/core/constants.ts
|
|
4
|
-
var VERSION = "0.4.
|
|
4
|
+
var VERSION = "0.4.77";
|
|
5
5
|
var APP_NAME = "ai-cli";
|
|
6
6
|
var CONFIG_DIR_NAME = ".aicli";
|
|
7
7
|
var CONFIG_FILE_NAME = "config.json";
|
|
@@ -30,8 +30,16 @@ var PLAN_MODE_READONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
|
30
30
|
"google_search",
|
|
31
31
|
"ask_user",
|
|
32
32
|
// 允许:可向用户澄清需求
|
|
33
|
-
"write_todos"
|
|
33
|
+
"write_todos",
|
|
34
34
|
// 允许:可输出任务列表作为实施计划
|
|
35
|
+
"find_symbol",
|
|
36
|
+
// C1 symbol index (read-only)
|
|
37
|
+
"get_outline",
|
|
38
|
+
// C1 symbol index (read-only)
|
|
39
|
+
"find_references",
|
|
40
|
+
// C1 symbol index (read-only)
|
|
41
|
+
"search_code"
|
|
42
|
+
// C2 semantic search (read-only)
|
|
35
43
|
]);
|
|
36
44
|
var PLAN_MODE_SYSTEM_ADDON = `# \u{1F50D} Plan Mode \u2014 Read-Only Planning Mode
|
|
37
45
|
|
|
@@ -71,7 +79,11 @@ var SUBAGENT_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
71
79
|
"web_fetch",
|
|
72
80
|
"google_search",
|
|
73
81
|
"write_todos",
|
|
74
|
-
"run_tests"
|
|
82
|
+
"run_tests",
|
|
83
|
+
"find_symbol",
|
|
84
|
+
"get_outline",
|
|
85
|
+
"find_references",
|
|
86
|
+
"search_code"
|
|
75
87
|
]);
|
|
76
88
|
var CONTEXT_PRESSURE_THRESHOLD = 0.8;
|
|
77
89
|
var TEST_TIMEOUT = 3e5;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadIndex
|
|
3
|
+
} from "./chunk-BJAT4GNC.js";
|
|
4
|
+
import {
|
|
5
|
+
EMBEDDING_DIM,
|
|
6
|
+
embed,
|
|
7
|
+
embedOne,
|
|
8
|
+
loadVectorStore,
|
|
9
|
+
saveVectorStore,
|
|
10
|
+
searchVectorStore
|
|
11
|
+
} from "./chunk-XMA222FQ.js";
|
|
12
|
+
|
|
13
|
+
// src/symbols/semantic.ts
|
|
14
|
+
function buildEmbeddingText(s) {
|
|
15
|
+
const parts = [s.kind, s.name];
|
|
16
|
+
if (s.container) parts.push(`in ${s.container}`);
|
|
17
|
+
if (s.signature) parts.push(s.signature);
|
|
18
|
+
if (s.doc) parts.push(s.doc);
|
|
19
|
+
return parts.join(" ").slice(0, 512);
|
|
20
|
+
}
|
|
21
|
+
async function rebuildSemanticIndex(root, opts = {}) {
|
|
22
|
+
const start = Date.now();
|
|
23
|
+
const index = loadIndex(root);
|
|
24
|
+
if (!index) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`No symbol index for ${root}. Run /index rebuild first so find_symbol has data to embed.`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const maxSymbols = opts.maxSymbols ?? 2e4;
|
|
30
|
+
const batchSize = opts.batchSize ?? 32;
|
|
31
|
+
const total = Math.min(index.symbols.length, maxSymbols);
|
|
32
|
+
if (total === 0) {
|
|
33
|
+
saveVectorStore(root, new Uint32Array(0), new Float32Array(0));
|
|
34
|
+
return { symbolsEmbedded: 0, durationMs: Date.now() - start };
|
|
35
|
+
}
|
|
36
|
+
const symbolIdx = new Uint32Array(total);
|
|
37
|
+
const vectors = new Float32Array(total * EMBEDDING_DIM);
|
|
38
|
+
let modelFirstLoadMs;
|
|
39
|
+
for (let i = 0; i < total; i += batchSize) {
|
|
40
|
+
const end = Math.min(i + batchSize, total);
|
|
41
|
+
const batch = [];
|
|
42
|
+
for (let j = i; j < end; j++) {
|
|
43
|
+
symbolIdx[j] = j;
|
|
44
|
+
batch.push(buildEmbeddingText(index.symbols[j]));
|
|
45
|
+
}
|
|
46
|
+
const batchStart = Date.now();
|
|
47
|
+
const rows = await embed(batch);
|
|
48
|
+
if (i === 0) modelFirstLoadMs = Date.now() - batchStart;
|
|
49
|
+
for (let r = 0; r < rows.length; r++) {
|
|
50
|
+
vectors.set(rows[r], (i + r) * EMBEDDING_DIM);
|
|
51
|
+
}
|
|
52
|
+
if (opts.onProgress) opts.onProgress(end, total);
|
|
53
|
+
}
|
|
54
|
+
saveVectorStore(root, symbolIdx, vectors);
|
|
55
|
+
return {
|
|
56
|
+
symbolsEmbedded: total,
|
|
57
|
+
durationMs: Date.now() - start,
|
|
58
|
+
modelFirstLoadMs
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function semanticSearch(root, query, k = 10) {
|
|
62
|
+
const index = loadIndex(root);
|
|
63
|
+
if (!index) return [];
|
|
64
|
+
const store = loadVectorStore(root);
|
|
65
|
+
if (!store || store.count === 0) return [];
|
|
66
|
+
const queryVec = await embedOne(query);
|
|
67
|
+
const hits = searchVectorStore(store, queryVec, k);
|
|
68
|
+
return hits.map((h) => ({
|
|
69
|
+
...h,
|
|
70
|
+
symbol: index.symbols[h.symbolIdx]
|
|
71
|
+
})).filter((h) => h.symbol !== void 0);
|
|
72
|
+
}
|
|
73
|
+
function hasSemanticIndex(root) {
|
|
74
|
+
const s = loadVectorStore(root);
|
|
75
|
+
return s !== null && s.count > 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
buildEmbeddingText,
|
|
80
|
+
rebuildSemanticIndex,
|
|
81
|
+
semanticSearch,
|
|
82
|
+
hasSemanticIndex
|
|
83
|
+
};
|