dsh-code-index 0.3.1 → 0.5.0
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 +7 -2
- package/README.zh.md +7 -2
- package/dist/client.js +279 -0
- package/dist/client.js.map +1 -0
- package/dist/index.js +602 -19
- package/dist/index.js.map +1 -1
- package/package.json +21 -4
package/dist/index.js
CHANGED
|
@@ -15,7 +15,9 @@ var GRAMMAR_NAMES = {
|
|
|
15
15
|
python: "tree-sitter-python",
|
|
16
16
|
go: "tree-sitter-go",
|
|
17
17
|
rust: "tree-sitter-rust",
|
|
18
|
-
java: "tree-sitter-java"
|
|
18
|
+
java: "tree-sitter-java",
|
|
19
|
+
cpp: "tree-sitter-cpp",
|
|
20
|
+
c: "tree-sitter-c"
|
|
19
21
|
};
|
|
20
22
|
var EXT_TO_LANG = {
|
|
21
23
|
".ts": "typescript",
|
|
@@ -30,7 +32,19 @@ var EXT_TO_LANG = {
|
|
|
30
32
|
".pyi": "python",
|
|
31
33
|
".go": "go",
|
|
32
34
|
".rs": "rust",
|
|
33
|
-
".java": "java"
|
|
35
|
+
".java": "java",
|
|
36
|
+
".cpp": "cpp",
|
|
37
|
+
".cc": "cpp",
|
|
38
|
+
".cxx": "cpp",
|
|
39
|
+
".c++": "cpp",
|
|
40
|
+
".hpp": "cpp",
|
|
41
|
+
".hxx": "cpp",
|
|
42
|
+
".hh": "cpp",
|
|
43
|
+
".h": "cpp",
|
|
44
|
+
".ipp": "cpp",
|
|
45
|
+
".tpp": "cpp",
|
|
46
|
+
".inl": "cpp",
|
|
47
|
+
".c": "c"
|
|
34
48
|
};
|
|
35
49
|
function languageForFile(filePath) {
|
|
36
50
|
const ext = path.extname(filePath).toLowerCase();
|
|
@@ -79,6 +93,31 @@ var QUERIES = {
|
|
|
79
93
|
(enum_declaration) @enum
|
|
80
94
|
(method_declaration) @method
|
|
81
95
|
(constructor_declaration) @method
|
|
96
|
+
`,
|
|
97
|
+
// C++ grammar (superset of C — also serves .h headers). function names
|
|
98
|
+
// live inside the declarator chain, so patterns stay broad and names,
|
|
99
|
+
// kinds and signatures are resolved in code (cppNameOf / kindFor /
|
|
100
|
+
// signatureFor). Top-level `declaration` covers prototypes, constructors
|
|
101
|
+
// and globals; field_declaration covers class-body members.
|
|
102
|
+
cpp: `
|
|
103
|
+
(function_definition) @function
|
|
104
|
+
(class_specifier body: (_)) @class
|
|
105
|
+
(struct_specifier body: (_)) @class
|
|
106
|
+
(enum_specifier body: (_)) @enum
|
|
107
|
+
(type_definition) @type
|
|
108
|
+
(alias_declaration) @type
|
|
109
|
+
(namespace_definition) @module
|
|
110
|
+
(field_declaration) @field
|
|
111
|
+
(declaration) @variable
|
|
112
|
+
`,
|
|
113
|
+
// Plain C: same core nodes minus C++-only namespace/alias forms.
|
|
114
|
+
c: `
|
|
115
|
+
(function_definition) @function
|
|
116
|
+
(struct_specifier body: (_)) @class
|
|
117
|
+
(enum_specifier body: (_)) @enum
|
|
118
|
+
(type_definition) @type
|
|
119
|
+
(field_declaration) @field
|
|
120
|
+
(declaration) @variable
|
|
82
121
|
`
|
|
83
122
|
};
|
|
84
123
|
var CAPTURE_KINDS = {
|
|
@@ -89,7 +128,8 @@ var CAPTURE_KINDS = {
|
|
|
89
128
|
type: { kind: "type" },
|
|
90
129
|
enum: { kind: "enum" },
|
|
91
130
|
variable: { kind: "variable" },
|
|
92
|
-
field: { kind: "field" }
|
|
131
|
+
field: { kind: "field" },
|
|
132
|
+
module: { kind: "module" }
|
|
93
133
|
};
|
|
94
134
|
var IMPORT_QUERIES = {
|
|
95
135
|
typescript: `
|
|
@@ -112,8 +152,76 @@ var IMPORT_QUERIES = {
|
|
|
112
152
|
`,
|
|
113
153
|
java: `
|
|
114
154
|
(import_declaration) @import
|
|
155
|
+
`,
|
|
156
|
+
// C/C++: #include "local.hpp" — quoted form resolves in-repo; <system>
|
|
157
|
+
// captures too but yields null and is dropped by the extractor.
|
|
158
|
+
cpp: `
|
|
159
|
+
(preproc_include) @import
|
|
160
|
+
`,
|
|
161
|
+
c: `
|
|
162
|
+
(preproc_include) @import
|
|
163
|
+
`
|
|
164
|
+
};
|
|
165
|
+
var CALL_QUERIES = {
|
|
166
|
+
typescript: `
|
|
167
|
+
(call_expression function: (identifier) @call)
|
|
168
|
+
(call_expression function: (member_expression property: (property_identifier) @call))
|
|
169
|
+
(new_expression constructor: (identifier) @call)
|
|
170
|
+
`,
|
|
171
|
+
javascript: `
|
|
172
|
+
(call_expression function: (identifier) @call)
|
|
173
|
+
(call_expression function: (member_expression property: (property_identifier) @call))
|
|
174
|
+
(new_expression constructor: (identifier) @call)
|
|
175
|
+
`,
|
|
176
|
+
python: `
|
|
177
|
+
(call function: (identifier) @call)
|
|
178
|
+
(call function: (attribute attribute: (identifier) @call))
|
|
179
|
+
`,
|
|
180
|
+
go: `
|
|
181
|
+
(call_expression function: (identifier) @call)
|
|
182
|
+
(call_expression function: (selector_expression field: (field_identifier) @call))
|
|
183
|
+
`,
|
|
184
|
+
rust: `
|
|
185
|
+
(call_expression function: (identifier) @call)
|
|
186
|
+
(call_expression function: (field_expression field: (field_identifier) @call))
|
|
187
|
+
(call_expression function: (scoped_identifier name: (identifier) @call))
|
|
188
|
+
`,
|
|
189
|
+
java: `
|
|
190
|
+
(method_invocation name: (identifier) @call)
|
|
191
|
+
(object_creation_expression type: (type_identifier) @call)
|
|
192
|
+
`,
|
|
193
|
+
cpp: `
|
|
194
|
+
(call_expression function: (identifier) @call)
|
|
195
|
+
(call_expression function: (field_expression field: (field_identifier) @call))
|
|
196
|
+
(call_expression function: (qualified_identifier name: (identifier) @call))
|
|
197
|
+
`,
|
|
198
|
+
c: `
|
|
199
|
+
(call_expression function: (identifier) @call)
|
|
200
|
+
(call_expression function: (field_expression field: (field_identifier) @call))
|
|
115
201
|
`
|
|
116
202
|
};
|
|
203
|
+
var CALLABLE_NODES = {
|
|
204
|
+
typescript: /* @__PURE__ */ new Set([
|
|
205
|
+
"function_declaration",
|
|
206
|
+
"generator_function_declaration",
|
|
207
|
+
"method_definition",
|
|
208
|
+
"function_expression",
|
|
209
|
+
"arrow_function"
|
|
210
|
+
]),
|
|
211
|
+
javascript: /* @__PURE__ */ new Set([
|
|
212
|
+
"function_declaration",
|
|
213
|
+
"generator_function_declaration",
|
|
214
|
+
"method_definition",
|
|
215
|
+
"function_expression",
|
|
216
|
+
"arrow_function"
|
|
217
|
+
]),
|
|
218
|
+
python: /* @__PURE__ */ new Set(["function_definition"]),
|
|
219
|
+
go: /* @__PURE__ */ new Set(["function_declaration", "method_declaration", "func_literal"]),
|
|
220
|
+
rust: /* @__PURE__ */ new Set(["function_item", "function_signature_item"]),
|
|
221
|
+
java: /* @__PURE__ */ new Set(["method_declaration", "constructor_declaration"]),
|
|
222
|
+
cpp: /* @__PURE__ */ new Set(["function_definition", "lambda_expression"]),
|
|
223
|
+
c: /* @__PURE__ */ new Set(["function_definition"])
|
|
224
|
+
};
|
|
117
225
|
var parserPromise = null;
|
|
118
226
|
async function getParser() {
|
|
119
227
|
if (!parserPromise) {
|
|
@@ -136,6 +244,7 @@ function getLanguage(id) {
|
|
|
136
244
|
const lang = await Language.load(bytes);
|
|
137
245
|
new Query(lang, QUERIES[id]).delete();
|
|
138
246
|
new Query(lang, IMPORT_QUERIES[id]).delete();
|
|
247
|
+
new Query(lang, CALL_QUERIES[id]).delete();
|
|
139
248
|
return lang;
|
|
140
249
|
});
|
|
141
250
|
languageCache.set(id, entry);
|
|
@@ -157,8 +266,8 @@ async function extractAll(code, id) {
|
|
|
157
266
|
const def = CAPTURE_KINDS[cap.name];
|
|
158
267
|
if (!def) continue;
|
|
159
268
|
const node = cap.node;
|
|
160
|
-
if (def.kind === "variable" && !isModuleLevelVariable(node)) continue;
|
|
161
|
-
const name2 = nameOf(node);
|
|
269
|
+
if (def.kind === "variable" && !isModuleLevelVariable(id, node)) continue;
|
|
270
|
+
const name2 = nameOf(id, node);
|
|
162
271
|
if (!name2) continue;
|
|
163
272
|
symbols.push({
|
|
164
273
|
name: name2,
|
|
@@ -168,7 +277,7 @@ async function extractAll(code, id) {
|
|
|
168
277
|
line: node.startPosition.row + 1,
|
|
169
278
|
endLine: node.endPosition.row + 1,
|
|
170
279
|
exported: isExported(id, node),
|
|
171
|
-
signature: signatureFor(node)
|
|
280
|
+
signature: signatureFor(id, node)
|
|
172
281
|
});
|
|
173
282
|
}
|
|
174
283
|
} finally {
|
|
@@ -184,8 +293,33 @@ async function extractAll(code, id) {
|
|
|
184
293
|
} finally {
|
|
185
294
|
importQuery.delete();
|
|
186
295
|
}
|
|
296
|
+
const calls = [];
|
|
297
|
+
const callQuery = new Query(lang, CALL_QUERIES[id]);
|
|
298
|
+
try {
|
|
299
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
300
|
+
for (const cap of callQuery.captures(tree.rootNode)) {
|
|
301
|
+
const name2 = cap.node.text.trim();
|
|
302
|
+
if (!name2) continue;
|
|
303
|
+
const line = cap.node.startPosition.row + 1;
|
|
304
|
+
const from = enclosingCallable(id, cap.node);
|
|
305
|
+
const key = `${from}|${name2}|${line}`;
|
|
306
|
+
if (seen2.has(key)) continue;
|
|
307
|
+
seen2.add(key);
|
|
308
|
+
calls.push({ name: name2, line, from });
|
|
309
|
+
}
|
|
310
|
+
} finally {
|
|
311
|
+
callQuery.delete();
|
|
312
|
+
}
|
|
313
|
+
calls.sort((a, b) => a.line - b.line || a.name.localeCompare(b.name));
|
|
187
314
|
symbols.sort((a, b) => a.line - b.line);
|
|
188
|
-
|
|
315
|
+
const seen = /* @__PURE__ */ new Set();
|
|
316
|
+
const deduped = symbols.filter((s) => {
|
|
317
|
+
const key = `${s.kind}|${s.name}|${s.line}`;
|
|
318
|
+
if (seen.has(key)) return false;
|
|
319
|
+
seen.add(key);
|
|
320
|
+
return true;
|
|
321
|
+
});
|
|
322
|
+
return { symbols: deduped, imports, calls };
|
|
189
323
|
} finally {
|
|
190
324
|
tree.delete();
|
|
191
325
|
}
|
|
@@ -193,11 +327,53 @@ async function extractAll(code, id) {
|
|
|
193
327
|
async function extractSymbols(code, id) {
|
|
194
328
|
return (await extractAll(code, id)).symbols;
|
|
195
329
|
}
|
|
196
|
-
function nameOf(node) {
|
|
330
|
+
function nameOf(id, node) {
|
|
331
|
+
if (id === "cpp" || id === "c") return cppNameOf(node);
|
|
197
332
|
const field = node.childForFieldName?.("name");
|
|
198
333
|
if (field) return field.text.trim();
|
|
199
334
|
return "";
|
|
200
335
|
}
|
|
336
|
+
function cppNameOf(node) {
|
|
337
|
+
const nameField = node.childForFieldName?.("name");
|
|
338
|
+
if (nameField) return nameField.text.trim();
|
|
339
|
+
if (node.type === "type_definition") {
|
|
340
|
+
return node.childForFieldName?.("declarator")?.text.trim() ?? "";
|
|
341
|
+
}
|
|
342
|
+
let declarator = node.childForFieldName?.("declarator");
|
|
343
|
+
if (declarator?.type === "init_declarator") {
|
|
344
|
+
declarator = declarator.childForFieldName?.("declarator");
|
|
345
|
+
}
|
|
346
|
+
if (declarator) {
|
|
347
|
+
let current = declarator;
|
|
348
|
+
while (current) {
|
|
349
|
+
if (current.type === "function_declarator" || current.type === "pointer_declarator" || current.type === "array_declarator" || current.type === "reference_declarator" || current.type === "parenthesized_declarator" || current.type === "init_declarator") {
|
|
350
|
+
current = current.childForFieldName?.("declarator") ?? current.namedChildren[0] ?? null;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (current.type === "qualified_identifier") {
|
|
354
|
+
return current.childForFieldName?.("name")?.text.trim() ?? current.text.trim();
|
|
355
|
+
}
|
|
356
|
+
if (current.type === "identifier" || current.type === "field_identifier" || current.type === "type_identifier") {
|
|
357
|
+
return current.text.trim();
|
|
358
|
+
}
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return "";
|
|
363
|
+
}
|
|
364
|
+
function enclosingCallable(id, node) {
|
|
365
|
+
const callable = CALLABLE_NODES[id];
|
|
366
|
+
for (let parent = node.parent; parent; parent = parent.parent) {
|
|
367
|
+
if (!callable.has(parent.type)) continue;
|
|
368
|
+
const named = nameOf(id, parent);
|
|
369
|
+
if (named) return named;
|
|
370
|
+
const declaration = parent.parent;
|
|
371
|
+
const field = declaration?.type === "variable_declarator" ? "name" : null;
|
|
372
|
+
if (field) return declaration?.childForFieldName?.(field)?.text.trim() ?? "";
|
|
373
|
+
return "";
|
|
374
|
+
}
|
|
375
|
+
return "";
|
|
376
|
+
}
|
|
201
377
|
function specifierOf(id, node) {
|
|
202
378
|
switch (node.type) {
|
|
203
379
|
case "import_statement":
|
|
@@ -216,6 +392,8 @@ function specifierOf(id, node) {
|
|
|
216
392
|
return rustUsePath(node.childForFieldName("argument")?.text);
|
|
217
393
|
case "import_declaration":
|
|
218
394
|
return dottedToPath(node.namedChildren[0]?.text);
|
|
395
|
+
case "preproc_include":
|
|
396
|
+
return stripQuotes(node.childForFieldName("path")?.text);
|
|
219
397
|
default:
|
|
220
398
|
return null;
|
|
221
399
|
}
|
|
@@ -247,21 +425,43 @@ function pythonRelative(raw) {
|
|
|
247
425
|
const prefix = dots === 1 ? "./" : "../".repeat(dots - 1);
|
|
248
426
|
return prefix + rest;
|
|
249
427
|
}
|
|
250
|
-
function signatureFor(node) {
|
|
251
|
-
const
|
|
428
|
+
function signatureFor(id, node) {
|
|
429
|
+
const sig = rawSignature(id, node);
|
|
430
|
+
return sig.length > 80 ? `${sig.slice(0, 77)}...` : sig;
|
|
431
|
+
}
|
|
432
|
+
function rawSignature(id, node) {
|
|
433
|
+
const name2 = nameOf(id, node);
|
|
252
434
|
const params = node.childForFieldName?.("parameters") ?? node.namedChildren.find(
|
|
253
435
|
(c) => c?.type === "formal_parameters" || c?.type === "method_parameters" || c?.type === "parameters" || c?.type === "parameter_list"
|
|
254
436
|
);
|
|
255
437
|
if (params) {
|
|
256
438
|
return `${name2}${collapseSpace(params.text)}`;
|
|
257
439
|
}
|
|
440
|
+
if (id === "cpp" || id === "c") {
|
|
441
|
+
let current = node.childForFieldName?.("declarator");
|
|
442
|
+
while (current) {
|
|
443
|
+
if (current.type === "function_declarator") {
|
|
444
|
+
const list = current.childForFieldName?.("parameters");
|
|
445
|
+
return list ? `${name2}${collapseSpace(list.text)}` : name2;
|
|
446
|
+
}
|
|
447
|
+
current = current.childForFieldName?.("declarator") ?? current.namedChildren[0] ?? null;
|
|
448
|
+
if (current && !current.type.includes("declarator") && current.type !== "identifier" && current.type !== "qualified_identifier" && current.type !== "field_identifier") break;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
258
451
|
const first = node.namedChildren[0];
|
|
259
452
|
return first ? collapseSpace(first.text) : name2;
|
|
260
453
|
}
|
|
261
454
|
function collapseSpace(text) {
|
|
262
455
|
return text.replace(/\s+/g, " ").replace(/\( /g, "(").replace(/ \)/g, ")").replace(/ ,/g, ",").replace(/,\)/g, ")").trim();
|
|
263
456
|
}
|
|
264
|
-
function isModuleLevelVariable(node) {
|
|
457
|
+
function isModuleLevelVariable(id, node) {
|
|
458
|
+
if (id === "cpp" || id === "c") {
|
|
459
|
+
for (let parent = node.parent; parent; parent = parent.parent) {
|
|
460
|
+
if (parent.type === "function_definition" || parent.type === "compound_statement") return false;
|
|
461
|
+
if (parent.type === "translation_unit" || parent.type === "declaration_list" || parent.type === "field_declaration_list") return true;
|
|
462
|
+
}
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
265
465
|
const declaration = node.parent;
|
|
266
466
|
const container = declaration?.parent;
|
|
267
467
|
return container?.type === "program" || container?.type === "export_statement";
|
|
@@ -271,7 +471,7 @@ function isExported(id, node) {
|
|
|
271
471
|
return node.parent?.type === "module";
|
|
272
472
|
}
|
|
273
473
|
if (id === "go") {
|
|
274
|
-
const name2 = nameOf(node);
|
|
474
|
+
const name2 = nameOf(id, node);
|
|
275
475
|
return !!name2 && /^[A-Z]/.test(name2);
|
|
276
476
|
}
|
|
277
477
|
if (id === "rust") {
|
|
@@ -283,6 +483,9 @@ function isExported(id, node) {
|
|
|
283
483
|
if (node.parent?.type === "interface_body") return true;
|
|
284
484
|
return node.namedChildren.some((c) => c?.type === "modifiers" && /\bpublic\b/.test(c?.text ?? ""));
|
|
285
485
|
}
|
|
486
|
+
if (id === "cpp" || id === "c") {
|
|
487
|
+
return cppIsExported(node);
|
|
488
|
+
}
|
|
286
489
|
for (let parent = node.parent; parent; parent = parent.parent) {
|
|
287
490
|
if (parent.type === "export_statement") return true;
|
|
288
491
|
if (parent.type === "statement_block" || parent.type === "class_body") return false;
|
|
@@ -290,6 +493,31 @@ function isExported(id, node) {
|
|
|
290
493
|
}
|
|
291
494
|
return false;
|
|
292
495
|
}
|
|
496
|
+
function cppIsExported(node) {
|
|
497
|
+
const isStatic = node.namedChildren.some(
|
|
498
|
+
(c) => c?.type === "storage_class_specifier" && c.text === "static"
|
|
499
|
+
);
|
|
500
|
+
for (let parent = node.parent; parent; parent = parent.parent) {
|
|
501
|
+
if (parent.type === "field_declaration_list") {
|
|
502
|
+
const body = parent;
|
|
503
|
+
const structKind = body.parent?.type === "struct_specifier" ? "struct" : "class";
|
|
504
|
+
let current = structKind === "struct" ? "public" : "private";
|
|
505
|
+
for (let up = node; up && up.id !== body.id; up = up.parent) {
|
|
506
|
+
const next = up.parent;
|
|
507
|
+
if (next?.type === "field_declaration_list") {
|
|
508
|
+
const siblingIndex = next.namedChildren.findIndex((c) => c?.id === up.id);
|
|
509
|
+
const accessBefore = next.namedChildren.slice(0, siblingIndex).filter((c) => c?.type === "access_specifier");
|
|
510
|
+
if (accessBefore.length > 0) {
|
|
511
|
+
current = accessBefore.at(-1).text.replace(":", "").trim();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return current === "public" && !isStatic;
|
|
516
|
+
}
|
|
517
|
+
if (parent.type === "translation_unit") return !isStatic;
|
|
518
|
+
}
|
|
519
|
+
return !isStatic;
|
|
520
|
+
}
|
|
293
521
|
function kindFor(id, node, kind) {
|
|
294
522
|
if (id === "python" && kind === "function") {
|
|
295
523
|
const inClassBody = node.parent?.type === "block" && node.parent?.parent?.type === "class_definition";
|
|
@@ -305,6 +533,19 @@ function kindFor(id, node, kind) {
|
|
|
305
533
|
const inImpl = node.parent?.type === "declaration_list" && node.parent?.parent?.type === "impl_item";
|
|
306
534
|
if (inImpl) return "method";
|
|
307
535
|
}
|
|
536
|
+
if ((id === "cpp" || id === "c") && (kind === "variable" || kind === "field")) {
|
|
537
|
+
let current = node.childForFieldName?.("declarator");
|
|
538
|
+
while (current) {
|
|
539
|
+
if (current.type === "function_declarator") {
|
|
540
|
+
return node.parent?.type === "field_declaration_list" ? "method" : "function";
|
|
541
|
+
}
|
|
542
|
+
current = current.childForFieldName?.("declarator") ?? current.namedChildren[0] ?? null;
|
|
543
|
+
}
|
|
544
|
+
return node.type === "field_declaration" ? "field" : "variable";
|
|
545
|
+
}
|
|
546
|
+
if ((id === "cpp" || id === "c") && node.type === "function_definition") {
|
|
547
|
+
if (node.parent?.type === "field_declaration_list") return "method";
|
|
548
|
+
}
|
|
308
549
|
return kind;
|
|
309
550
|
}
|
|
310
551
|
async function parseFileToSymbols(filePath, repoRoot, code) {
|
|
@@ -348,7 +589,19 @@ var SUPPORTED_EXTS = /* @__PURE__ */ new Set([
|
|
|
348
589
|
".pyi",
|
|
349
590
|
".go",
|
|
350
591
|
".rs",
|
|
351
|
-
".java"
|
|
592
|
+
".java",
|
|
593
|
+
".cpp",
|
|
594
|
+
".cc",
|
|
595
|
+
".cxx",
|
|
596
|
+
".c++",
|
|
597
|
+
".hpp",
|
|
598
|
+
".hxx",
|
|
599
|
+
".hh",
|
|
600
|
+
".h",
|
|
601
|
+
".ipp",
|
|
602
|
+
".tpp",
|
|
603
|
+
".inl",
|
|
604
|
+
".c"
|
|
352
605
|
]);
|
|
353
606
|
async function scanRepo(root, options = {}) {
|
|
354
607
|
const excluded = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDED_DIRS, ...options.excludeDirs ?? []]);
|
|
@@ -456,13 +709,14 @@ async function buildIndex(root, options = {}, previous = null) {
|
|
|
456
709
|
} catch {
|
|
457
710
|
return null;
|
|
458
711
|
}
|
|
459
|
-
const { symbols, imports } = await extractAll(code, lang);
|
|
712
|
+
const { symbols, imports, calls } = await extractAll(code, lang);
|
|
460
713
|
return {
|
|
461
714
|
path: f.rel,
|
|
462
715
|
lang,
|
|
463
716
|
mtimeMs: f.mtimeMs,
|
|
464
717
|
symbols: symbols.map((s) => ({ ...s, file: f.rel })),
|
|
465
|
-
imports
|
|
718
|
+
imports,
|
|
719
|
+
calls
|
|
466
720
|
};
|
|
467
721
|
})
|
|
468
722
|
);
|
|
@@ -508,12 +762,22 @@ function indexesEqual(left, right) {
|
|
|
508
762
|
return false;
|
|
509
763
|
}
|
|
510
764
|
if (file.symbols.length !== other.symbols.length) return false;
|
|
765
|
+
if (!callsEqual(file.calls, other.calls)) return false;
|
|
511
766
|
return file.symbols.every((symbol, symbolIndex) => {
|
|
512
767
|
const candidate = other.symbols[symbolIndex];
|
|
513
768
|
return candidate !== void 0 && symbol.name === candidate.name && symbol.kind === candidate.kind && symbol.file === candidate.file && symbol.line === candidate.line && symbol.endLine === candidate.endLine && symbol.exported === candidate.exported && symbol.signature === candidate.signature;
|
|
514
769
|
});
|
|
515
770
|
});
|
|
516
771
|
}
|
|
772
|
+
function callsEqual(left, right) {
|
|
773
|
+
const a = left ?? [];
|
|
774
|
+
const b = right ?? [];
|
|
775
|
+
if (a.length !== b.length) return false;
|
|
776
|
+
return a.every((call, index) => {
|
|
777
|
+
const other = b[index];
|
|
778
|
+
return other !== void 0 && call.name === other.name && call.line === other.line && call.from === other.from;
|
|
779
|
+
});
|
|
780
|
+
}
|
|
517
781
|
async function findRepoRoot(startDir, maxLevels = 12) {
|
|
518
782
|
let dir = path4.resolve(startDir);
|
|
519
783
|
for (let level = 0; level < maxLevels; level++) {
|
|
@@ -534,6 +798,56 @@ function symbolCount(index) {
|
|
|
534
798
|
return index.files.reduce((n, f) => n + f.symbols.length, 0);
|
|
535
799
|
}
|
|
536
800
|
|
|
801
|
+
// src/refgraph.ts
|
|
802
|
+
function buildSymbolTable(index) {
|
|
803
|
+
const table = /* @__PURE__ */ new Map();
|
|
804
|
+
for (const file of index.files) {
|
|
805
|
+
for (const symbol of file.symbols) {
|
|
806
|
+
const list = table.get(symbol.name);
|
|
807
|
+
if (list) list.push(symbol);
|
|
808
|
+
else table.set(symbol.name, [symbol]);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
for (const list of table.values()) {
|
|
812
|
+
list.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
|
|
813
|
+
}
|
|
814
|
+
return table;
|
|
815
|
+
}
|
|
816
|
+
function callerCounts(index) {
|
|
817
|
+
const counts = /* @__PURE__ */ new Map();
|
|
818
|
+
for (const file of index.files) {
|
|
819
|
+
for (const call of file.calls ?? []) {
|
|
820
|
+
counts.set(call.name, (counts.get(call.name) ?? 0) + 1);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return counts;
|
|
824
|
+
}
|
|
825
|
+
function symbolRefs(index, symbol, limit = 200) {
|
|
826
|
+
const table = buildSymbolTable(index);
|
|
827
|
+
const defs = table.get(symbol) ?? [];
|
|
828
|
+
const callers = [];
|
|
829
|
+
const calleeFirstLine = /* @__PURE__ */ new Map();
|
|
830
|
+
for (const file of index.files) {
|
|
831
|
+
for (const call of file.calls ?? []) {
|
|
832
|
+
if (call.name === symbol) {
|
|
833
|
+
callers.push({ file: file.path, line: call.line, from: call.from });
|
|
834
|
+
}
|
|
835
|
+
if (call.from === symbol && !calleeFirstLine.has(call.name)) {
|
|
836
|
+
calleeFirstLine.set(call.name, call.line);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
callers.sort(
|
|
841
|
+
(a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.from.localeCompare(b.from)
|
|
842
|
+
);
|
|
843
|
+
const callees = [...calleeFirstLine.entries()].map(([name2, line]) => ({ name: name2, line, targets: table.get(name2) ?? [] })).sort((a, b) => a.line - b.line || a.name.localeCompare(b.name));
|
|
844
|
+
return {
|
|
845
|
+
defs,
|
|
846
|
+
callers: callers.slice(0, limit),
|
|
847
|
+
callees: callees.slice(0, limit)
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
|
|
537
851
|
// src/search.ts
|
|
538
852
|
function matchScore(name2, query) {
|
|
539
853
|
const q = query.toLowerCase();
|
|
@@ -566,8 +880,9 @@ function searchSymbols(index, filter, limit = 50) {
|
|
|
566
880
|
hits.push({ ...sym, score });
|
|
567
881
|
}
|
|
568
882
|
}
|
|
883
|
+
const refs = callerCounts(index);
|
|
569
884
|
hits.sort((a, b) => {
|
|
570
|
-
const ab = Number(b.exported) - Number(a.exported) || b.score - a.score || a.name.localeCompare(b.name) || a.file.localeCompare(b.file);
|
|
885
|
+
const ab = Number(b.exported) - Number(a.exported) || b.score - a.score || (refs.get(b.name) ?? 0) - (refs.get(a.name) ?? 0) || a.name.localeCompare(b.name) || a.file.localeCompare(b.file);
|
|
571
886
|
return ab;
|
|
572
887
|
});
|
|
573
888
|
return hits.slice(0, limit);
|
|
@@ -697,6 +1012,7 @@ function resolveImport(spec, fromPath, fileSet) {
|
|
|
697
1012
|
return null;
|
|
698
1013
|
}
|
|
699
1014
|
function candidateFor(base, fileSet) {
|
|
1015
|
+
if (fileSet.has(base)) return base;
|
|
700
1016
|
for (const ext of SUPPORTED_EXTS) {
|
|
701
1017
|
if (fileSet.has(`${base}${ext}`)) return `${base}${ext}`;
|
|
702
1018
|
}
|
|
@@ -726,6 +1042,76 @@ function renderRepoMap(entries, options = {}) {
|
|
|
726
1042
|
return totalSymbols > 0 ? text : "";
|
|
727
1043
|
}
|
|
728
1044
|
|
|
1045
|
+
// src/health.ts
|
|
1046
|
+
function buildModuleGraph(index) {
|
|
1047
|
+
const nodes = index.files.map((file) => file.path).sort((a, b) => a.localeCompare(b));
|
|
1048
|
+
const fileSet = new Set(nodes);
|
|
1049
|
+
const edges = /* @__PURE__ */ new Map();
|
|
1050
|
+
for (const file of index.files) {
|
|
1051
|
+
const targets = /* @__PURE__ */ new Set();
|
|
1052
|
+
for (const spec of file.imports ?? []) {
|
|
1053
|
+
const target = resolveImport(spec, file.path, fileSet);
|
|
1054
|
+
if (target && target !== file.path) targets.add(target);
|
|
1055
|
+
}
|
|
1056
|
+
edges.set(file.path, targets);
|
|
1057
|
+
}
|
|
1058
|
+
return { nodes, edges };
|
|
1059
|
+
}
|
|
1060
|
+
function findCycles(index) {
|
|
1061
|
+
const { nodes, edges } = buildModuleGraph(index);
|
|
1062
|
+
const discovery = /* @__PURE__ */ new Map();
|
|
1063
|
+
const low = /* @__PURE__ */ new Map();
|
|
1064
|
+
const onStack = /* @__PURE__ */ new Set();
|
|
1065
|
+
const stack = [];
|
|
1066
|
+
const components = [];
|
|
1067
|
+
let counter = 0;
|
|
1068
|
+
const visit = (node) => {
|
|
1069
|
+
discovery.set(node, counter);
|
|
1070
|
+
low.set(node, counter);
|
|
1071
|
+
counter++;
|
|
1072
|
+
stack.push(node);
|
|
1073
|
+
onStack.add(node);
|
|
1074
|
+
for (const next of edges.get(node) ?? []) {
|
|
1075
|
+
if (!discovery.has(next)) {
|
|
1076
|
+
visit(next);
|
|
1077
|
+
low.set(node, Math.min(low.get(node), low.get(next)));
|
|
1078
|
+
} else if (onStack.has(next)) {
|
|
1079
|
+
low.set(node, Math.min(low.get(node), discovery.get(next)));
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (low.get(node) === discovery.get(node)) {
|
|
1083
|
+
const component = [];
|
|
1084
|
+
for (; ; ) {
|
|
1085
|
+
const member = stack.pop();
|
|
1086
|
+
onStack.delete(member);
|
|
1087
|
+
component.push(member);
|
|
1088
|
+
if (member === node) break;
|
|
1089
|
+
}
|
|
1090
|
+
if (component.length > 1) components.push(component.sort());
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
for (const node of nodes) {
|
|
1094
|
+
if (!discovery.has(node)) visit(node);
|
|
1095
|
+
}
|
|
1096
|
+
components.sort((a, b) => a[0].localeCompare(b[0]));
|
|
1097
|
+
return components;
|
|
1098
|
+
}
|
|
1099
|
+
var ENTRY_RE = /(^|\/)(index|main|cli|app|server|mod|lib|__init__)\.[A-Za-z0-9]+$|(^|\/)(bin|cmd|scripts)\/|\.config\.[A-Za-z0-9]+$/;
|
|
1100
|
+
var TEST_RE = /(^|\/)(tests?|__tests__)(\/|$)|\.(?:spec|test)\.[cm]?[jt]sx?$|(^|\/)(?:test_[^/]+\.py|[^/]+_test\.(?:py|go))$/;
|
|
1101
|
+
function findOrphanModules(index) {
|
|
1102
|
+
const { nodes, edges } = buildModuleGraph(index);
|
|
1103
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
1104
|
+
for (const targets of edges.values()) {
|
|
1105
|
+
for (const target of targets) incoming.set(target, (incoming.get(target) ?? 0) + 1);
|
|
1106
|
+
}
|
|
1107
|
+
const withSymbols = new Set(
|
|
1108
|
+
index.files.filter((file) => file.symbols.length > 0).map((file) => file.path)
|
|
1109
|
+
);
|
|
1110
|
+
return nodes.filter(
|
|
1111
|
+
(path7) => withSymbols.has(path7) && (incoming.get(path7) ?? 0) === 0 && (edges.get(path7)?.size ?? 0) === 0 && !ENTRY_RE.test(path7) && !TEST_RE.test(path7)
|
|
1112
|
+
);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
729
1115
|
// src/tools.ts
|
|
730
1116
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
731
1117
|
import path6 from "path";
|
|
@@ -736,7 +1122,8 @@ var DEFAULTS = {
|
|
|
736
1122
|
mapTopFiles: 24,
|
|
737
1123
|
mapMaxChars: 3200,
|
|
738
1124
|
mapTtlMs: 6e4,
|
|
739
|
-
autoInject: true
|
|
1125
|
+
autoInject: true,
|
|
1126
|
+
codeHealth: false
|
|
740
1127
|
};
|
|
741
1128
|
var state = { current: { ...DEFAULTS } };
|
|
742
1129
|
function applyConfig(partial) {
|
|
@@ -825,6 +1212,38 @@ async function resolveRoot(arg, exec) {
|
|
|
825
1212
|
if (!root) throw new Error(`no git repository found from ${path6.resolve(base)}`);
|
|
826
1213
|
return root;
|
|
827
1214
|
}
|
|
1215
|
+
function hitsToSearchMeta(hits) {
|
|
1216
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
1217
|
+
for (const raw of hits) {
|
|
1218
|
+
const hit = raw;
|
|
1219
|
+
if (!hit.file || typeof hit.line !== "number") continue;
|
|
1220
|
+
const label = `${hit.kind ?? ""} ${hit.signature || hit.name || ""}`.trim();
|
|
1221
|
+
const list = byFile.get(hit.file) ?? [];
|
|
1222
|
+
list.push({ lineNumber: hit.line, line: label });
|
|
1223
|
+
byFile.set(hit.file, list);
|
|
1224
|
+
}
|
|
1225
|
+
return {
|
|
1226
|
+
shape: "matches",
|
|
1227
|
+
files: [...byFile.entries()].map(([path7, matches]) => ({ path: path7, matches })),
|
|
1228
|
+
truncated: false,
|
|
1229
|
+
total: hits.length
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
function searchCardFromMeta(meta) {
|
|
1233
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return void 0;
|
|
1234
|
+
const record = meta;
|
|
1235
|
+
if (record.shape !== "matches" || !Array.isArray(record.files)) return void 0;
|
|
1236
|
+
const files = record.files.filter(
|
|
1237
|
+
(entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry)
|
|
1238
|
+
);
|
|
1239
|
+
return {
|
|
1240
|
+
card: "search",
|
|
1241
|
+
shape: "matches",
|
|
1242
|
+
files,
|
|
1243
|
+
truncated: record.truncated === true,
|
|
1244
|
+
total: typeof record.total === "number" ? record.total : 0
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
828
1247
|
var tools = [
|
|
829
1248
|
defineTool({
|
|
830
1249
|
name: "code_index",
|
|
@@ -897,8 +1316,16 @@ var tools = [
|
|
|
897
1316
|
render: (_args, value) => value.map((v) => ({
|
|
898
1317
|
type: "text",
|
|
899
1318
|
text: renderHit(v)
|
|
900
|
-
}))
|
|
1319
|
+
})),
|
|
1320
|
+
presentationMeta: (_args, value) => hitsToSearchMeta(value)
|
|
901
1321
|
},
|
|
1322
|
+
presentCall: (args) => ({
|
|
1323
|
+
card: "generic",
|
|
1324
|
+
title: args.kind ? `List ${args.kind} symbols` : "List symbols",
|
|
1325
|
+
kind: "search",
|
|
1326
|
+
rawInput: { query: args.query, file: args.file, kind: args.kind }
|
|
1327
|
+
}),
|
|
1328
|
+
presentResult: (_args, result) => searchCardFromMeta(result.meta),
|
|
902
1329
|
async execute(args, exec) {
|
|
903
1330
|
const root = await resolveRoot(args.repoRoot, exec);
|
|
904
1331
|
const index = await getIndex(root);
|
|
@@ -933,8 +1360,16 @@ var tools = [
|
|
|
933
1360
|
render: (_args, value) => value.map((v) => ({
|
|
934
1361
|
type: "text",
|
|
935
1362
|
text: renderHit(v)
|
|
936
|
-
}))
|
|
1363
|
+
})),
|
|
1364
|
+
presentationMeta: (_args, value) => hitsToSearchMeta(value)
|
|
937
1365
|
},
|
|
1366
|
+
presentCall: (args) => ({
|
|
1367
|
+
card: "generic",
|
|
1368
|
+
title: `Search "${args.query}"`,
|
|
1369
|
+
kind: "search",
|
|
1370
|
+
rawInput: { query: args.query }
|
|
1371
|
+
}),
|
|
1372
|
+
presentResult: (_args, result) => searchCardFromMeta(result.meta),
|
|
938
1373
|
async execute(args, exec) {
|
|
939
1374
|
const root = await resolveRoot(args.repoRoot, exec);
|
|
940
1375
|
const index = await getIndex(root);
|
|
@@ -970,9 +1405,141 @@ var tools = [
|
|
|
970
1405
|
return `code_index: ${error.message ?? String(error)}`;
|
|
971
1406
|
}
|
|
972
1407
|
}
|
|
1408
|
+
}),
|
|
1409
|
+
defineTool({
|
|
1410
|
+
name: "code_refs",
|
|
1411
|
+
description: "Trace a symbol through the call graph: who calls it (callers) and what it calls (callees), resolved to in-repo definitions with file:line. Complements code_search \u2014 search finds a definition, code_refs shows how it is used. Resolution is name-based, so like-named symbols are reported as candidate definitions.",
|
|
1412
|
+
parameters: {
|
|
1413
|
+
symbol: {
|
|
1414
|
+
type: "string",
|
|
1415
|
+
required: true,
|
|
1416
|
+
description: "Symbol name to trace (case-sensitive)."
|
|
1417
|
+
},
|
|
1418
|
+
direction: {
|
|
1419
|
+
type: "string",
|
|
1420
|
+
enum: ["callers", "callees", "both"],
|
|
1421
|
+
description: 'Which side of the call graph to return (default "both").'
|
|
1422
|
+
},
|
|
1423
|
+
limit: {
|
|
1424
|
+
type: "number",
|
|
1425
|
+
description: "Max rows per side (default 50)."
|
|
1426
|
+
},
|
|
1427
|
+
repoRoot: {
|
|
1428
|
+
type: "string",
|
|
1429
|
+
description: "Optional absolute repo path; defaults to the session workspace root."
|
|
1430
|
+
}
|
|
1431
|
+
},
|
|
1432
|
+
output: {
|
|
1433
|
+
schema: { type: "string" },
|
|
1434
|
+
render: (_args, value) => [{ type: "text", text: value }]
|
|
1435
|
+
},
|
|
1436
|
+
presentCall: (args) => ({
|
|
1437
|
+
card: "generic",
|
|
1438
|
+
title: `Refs ${args.symbol}`,
|
|
1439
|
+
kind: "search",
|
|
1440
|
+
rawInput: { symbol: args.symbol, direction: args.direction }
|
|
1441
|
+
}),
|
|
1442
|
+
async execute(args, exec) {
|
|
1443
|
+
try {
|
|
1444
|
+
const root = await resolveRoot(args.repoRoot, exec);
|
|
1445
|
+
const index = await getIndex(root);
|
|
1446
|
+
const refs = symbolRefs(index, args.symbol, args.limit ?? 50);
|
|
1447
|
+
const direction = args.direction ?? "both";
|
|
1448
|
+
const lines = [];
|
|
1449
|
+
if (refs.defs.length > 0) {
|
|
1450
|
+
lines.push("definitions:");
|
|
1451
|
+
for (const def of refs.defs) {
|
|
1452
|
+
lines.push(` ${def.kind} ${def.signature || def.name} \u2014 ${def.file}:${def.line}`);
|
|
1453
|
+
}
|
|
1454
|
+
} else {
|
|
1455
|
+
lines.push(`no definition of "${args.symbol}" in this repo`);
|
|
1456
|
+
}
|
|
1457
|
+
if (direction === "callers" || direction === "both") {
|
|
1458
|
+
lines.push("", `callers (${refs.callers.length}):`);
|
|
1459
|
+
if (refs.callers.length === 0) lines.push(" (none)");
|
|
1460
|
+
for (const caller of refs.callers) {
|
|
1461
|
+
lines.push(` ${caller.file}:${caller.line}${caller.from ? ` in ${caller.from}` : ""}`);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
if (direction === "callees" || direction === "both") {
|
|
1465
|
+
lines.push("", `callees (${refs.callees.length}):`);
|
|
1466
|
+
if (refs.callees.length === 0) lines.push(" (none)");
|
|
1467
|
+
for (const callee of refs.callees) {
|
|
1468
|
+
const target = callee.targets[0];
|
|
1469
|
+
lines.push(
|
|
1470
|
+
` ${callee.name} :${callee.line}${target ? ` \u2192 ${target.file}:${target.line}` : " (external)"}`
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
return lines.join("\n");
|
|
1475
|
+
} catch (error) {
|
|
1476
|
+
return `code_refs: ${error.message ?? String(error)}`;
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}),
|
|
1480
|
+
defineTool({
|
|
1481
|
+
name: "code_health",
|
|
1482
|
+
description: "Report structural health from the import graph: circular dependencies (import cycles) and orphan modules (symbol-bearing files that nothing imports and that import nothing, excluding entry points and tests).",
|
|
1483
|
+
parameters: {
|
|
1484
|
+
limit: {
|
|
1485
|
+
type: "number",
|
|
1486
|
+
description: "Max cycles and orphan rows to list (default 50)."
|
|
1487
|
+
},
|
|
1488
|
+
repoRoot: {
|
|
1489
|
+
type: "string",
|
|
1490
|
+
description: "Optional absolute repo path; defaults to the session workspace root."
|
|
1491
|
+
}
|
|
1492
|
+
},
|
|
1493
|
+
output: {
|
|
1494
|
+
schema: { type: "string" },
|
|
1495
|
+
render: (_args, value) => [{ type: "text", text: value }]
|
|
1496
|
+
},
|
|
1497
|
+
presentCall: () => ({ card: "generic", title: "Code health", kind: "read" }),
|
|
1498
|
+
async execute(args, exec) {
|
|
1499
|
+
try {
|
|
1500
|
+
const root = await resolveRoot(args.repoRoot, exec);
|
|
1501
|
+
const index = await getIndex(root);
|
|
1502
|
+
const limit = args.limit ?? 50;
|
|
1503
|
+
const cycles = findCycles(index);
|
|
1504
|
+
const orphans = findOrphanModules(index);
|
|
1505
|
+
const lines = [`repo health \u2014 ${index.files.length} files`];
|
|
1506
|
+
lines.push("", `circular dependencies (${cycles.length}):`);
|
|
1507
|
+
if (cycles.length === 0) lines.push(" (none)");
|
|
1508
|
+
for (const cycle of cycles.slice(0, limit)) lines.push(` ${cycle.join(" \u2192 ")}`);
|
|
1509
|
+
lines.push("", `orphan modules (${orphans.length}):`);
|
|
1510
|
+
if (orphans.length === 0) lines.push(" (none)");
|
|
1511
|
+
for (const orphan of orphans.slice(0, limit)) lines.push(` ${orphan}`);
|
|
1512
|
+
return lines.join("\n");
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
return `code_health: ${error.message ?? String(error)}`;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
973
1517
|
})
|
|
974
1518
|
];
|
|
975
1519
|
|
|
1520
|
+
// src/settings.ts
|
|
1521
|
+
import Schema from "@deepseek-ai/schemastery";
|
|
1522
|
+
var SETTINGS_NAMESPACE = "code-index";
|
|
1523
|
+
var settingsSchema = Schema.object({
|
|
1524
|
+
excludeDirs: Schema.array(Schema.string()).default([]),
|
|
1525
|
+
mapTopFiles: Schema.number().default(24),
|
|
1526
|
+
mapMaxChars: Schema.number().default(3200),
|
|
1527
|
+
mapTtlMs: Schema.number().default(6e4),
|
|
1528
|
+
autoInject: Schema.boolean().default(true),
|
|
1529
|
+
codeHealth: Schema.boolean().default(false)
|
|
1530
|
+
});
|
|
1531
|
+
function registerSettings(getService, pluginConfig, onResolved) {
|
|
1532
|
+
const service = getService("settings");
|
|
1533
|
+
if (!service) return;
|
|
1534
|
+
const scope = service.register(SETTINGS_NAMESPACE, settingsSchema, {
|
|
1535
|
+
base: pluginConfig ?? {}
|
|
1536
|
+
});
|
|
1537
|
+
onResolved(scope.get());
|
|
1538
|
+
scope.watch((next) => {
|
|
1539
|
+
onResolved(next);
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
|
|
976
1543
|
// src/index.ts
|
|
977
1544
|
var name = "dsh-code-index";
|
|
978
1545
|
var inject = ["tools", "systemPrompt"];
|
|
@@ -982,7 +1549,17 @@ function apply(ctx, pluginConfig) {
|
|
|
982
1549
|
ctx.effect(() => {
|
|
983
1550
|
const disposers = [];
|
|
984
1551
|
console.log("[dsh-code-index] plugin loaded");
|
|
1552
|
+
if (ctx.inject) {
|
|
1553
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
1554
|
+
registerSettings(
|
|
1555
|
+
(name2) => settingsCtx.get(name2),
|
|
1556
|
+
pluginConfig,
|
|
1557
|
+
(resolved) => applyConfig(resolved)
|
|
1558
|
+
);
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
985
1561
|
for (const tool of tools) {
|
|
1562
|
+
if (tool.name === "code_health" && !getConfig().codeHealth) continue;
|
|
986
1563
|
disposers.push(ctx.tools.register(tool));
|
|
987
1564
|
console.log(`[dsh-code-index] registered tool: ${tool.name}`);
|
|
988
1565
|
}
|
|
@@ -1048,9 +1625,14 @@ export {
|
|
|
1048
1625
|
apply,
|
|
1049
1626
|
buildIndex,
|
|
1050
1627
|
buildIndexWithCache,
|
|
1628
|
+
buildModuleGraph,
|
|
1629
|
+
buildSymbolTable,
|
|
1630
|
+
callerCounts,
|
|
1051
1631
|
defaultCachePath,
|
|
1052
1632
|
extractAll,
|
|
1053
1633
|
extractSymbols,
|
|
1634
|
+
findCycles,
|
|
1635
|
+
findOrphanModules,
|
|
1054
1636
|
findRepoRoot,
|
|
1055
1637
|
inject,
|
|
1056
1638
|
languageForFile,
|
|
@@ -1065,6 +1647,7 @@ export {
|
|
|
1065
1647
|
scoreFile,
|
|
1066
1648
|
searchSymbols,
|
|
1067
1649
|
symbolCount,
|
|
1650
|
+
symbolRefs,
|
|
1068
1651
|
tools
|
|
1069
1652
|
};
|
|
1070
1653
|
//# sourceMappingURL=index.js.map
|