trace-mcp 1.5.4 → 1.6.1

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/dist/cli.js CHANGED
@@ -4563,7 +4563,8 @@ var TraceMcpConfigSchema = z.object({
4563
4563
  watch: z.object({
4564
4564
  enabled: z.boolean().default(true),
4565
4565
  debounceMs: z.number().int().min(500).max(3e4).default(2e3)
4566
- }).default({})
4566
+ }).default({}),
4567
+ children: z.array(z.string()).optional()
4567
4568
  });
4568
4569
  function loadGlobalConfigRaw() {
4569
4570
  if (!fs2.existsSync(GLOBAL_CONFIG_PATH)) return {};
@@ -4636,6 +4637,13 @@ function saveProjectConfig(projectRoot, config) {
4636
4637
  existing.projects = projects;
4637
4638
  fs2.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(existing, null, 2) + "\n");
4638
4639
  }
4640
+ function removeProjectConfig(projectRoot) {
4641
+ const existing = loadGlobalConfigRaw();
4642
+ const projects = existing.projects ?? {};
4643
+ delete projects[projectRoot];
4644
+ existing.projects = projects;
4645
+ fs2.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(existing, null, 2) + "\n");
4646
+ }
4639
4647
 
4640
4648
  // src/server/server.ts
4641
4649
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -5014,6 +5022,26 @@ function detectWorkspaces(rootPath) {
5014
5022
  if (composerResult.length > 0) return composerResult;
5015
5023
  return [];
5016
5024
  }
5025
+ function buildMultiRootWorkspaces(parentDir, childRoots) {
5026
+ const workspaces = [];
5027
+ for (const childRoot of childRoots) {
5028
+ if (!fs4.existsSync(childRoot)) {
5029
+ logger.warn({ childRoot }, "Skipping missing multi-root child directory");
5030
+ continue;
5031
+ }
5032
+ const relPath = path3.relative(parentDir, childRoot).replace(/\\/g, "/");
5033
+ const childName = path3.basename(childRoot);
5034
+ workspaces.push({ name: childName, path: relPath });
5035
+ const subWorkspaces = detectWorkspaces(childRoot);
5036
+ for (const sub of subWorkspaces) {
5037
+ workspaces.push({
5038
+ name: `${childName}/${sub.name}`,
5039
+ path: `${relPath}/${sub.path}`
5040
+ });
5041
+ }
5042
+ }
5043
+ return workspaces;
5044
+ }
5017
5045
  function detectPnpmWorkspaces(rootPath) {
5018
5046
  const yamlPath = path3.join(rootPath, "pnpm-workspace.yaml");
5019
5047
  if (!fs4.existsSync(yamlPath)) return [];
@@ -6288,12 +6316,15 @@ var FilePersister = class {
6288
6316
  }
6289
6317
  if (ext.symbols.length > 0) {
6290
6318
  const insertedIds = store.insertSymbols(fileId, ext.symbols);
6291
- const trigramBatch = ext.symbols.map((sym, i) => ({
6292
- id: insertedIds[i],
6293
- name: sym.name,
6294
- fqn: sym.fqn ?? null
6295
- }));
6296
- indexTrigramsBatch(store.db, trigramBatch);
6319
+ const trigramBySymbolId = /* @__PURE__ */ new Map();
6320
+ for (let i = 0; i < ext.symbols.length; i++) {
6321
+ trigramBySymbolId.set(ext.symbols[i].symbolId, {
6322
+ id: insertedIds[i],
6323
+ name: ext.symbols[i].name,
6324
+ fqn: ext.symbols[i].fqn ?? null
6325
+ });
6326
+ }
6327
+ indexTrigramsBatch(store.db, [...trigramBySymbolId.values()]);
6297
6328
  }
6298
6329
  if (ext.otherEdges.length > 0) this.storeRawEdges(ext.otherEdges);
6299
6330
  if (ext.importEdges.length > 0) {
@@ -6309,11 +6340,15 @@ var FilePersister = class {
6309
6340
  for (const fwResult of ext.frameworkExtracts) {
6310
6341
  if (fwResult.symbols.length > 0) {
6311
6342
  const fwIds = store.insertSymbols(fileId, fwResult.symbols);
6312
- indexTrigramsBatch(store.db, fwResult.symbols.map((sym, i) => ({
6313
- id: fwIds[i],
6314
- name: sym.name,
6315
- fqn: sym.fqn ?? null
6316
- })));
6343
+ const fwTrigramBySymbolId = /* @__PURE__ */ new Map();
6344
+ for (let i = 0; i < fwResult.symbols.length; i++) {
6345
+ fwTrigramBySymbolId.set(fwResult.symbols[i].symbolId, {
6346
+ id: fwIds[i],
6347
+ name: fwResult.symbols[i].name,
6348
+ fqn: fwResult.symbols[i].fqn ?? null
6349
+ });
6350
+ }
6351
+ indexTrigramsBatch(store.db, [...fwTrigramBySymbolId.values()]);
6317
6352
  }
6318
6353
  if (fwResult.edges?.length) {
6319
6354
  this.storeRawEdges(fwResult.edges);
@@ -7411,9 +7446,14 @@ var IndexingPipeline = class _IndexingPipeline {
7411
7446
  const result = this._lock.then(async () => {
7412
7447
  this._isIncremental = false;
7413
7448
  const start = Date.now();
7414
- this.workspaces = detectWorkspaces(this.rootPath);
7415
- if (this.workspaces.length > 0) {
7416
- logger.info({ workspaces: this.workspaces.map((w) => w.name) }, "Detected workspaces");
7449
+ if (this.config.children?.length) {
7450
+ this.workspaces = buildMultiRootWorkspaces(this.rootPath, this.config.children);
7451
+ logger.info({ workspaces: this.workspaces.map((w) => w.name) }, "Multi-root workspaces");
7452
+ } else {
7453
+ this.workspaces = detectWorkspaces(this.rootPath);
7454
+ if (this.workspaces.length > 0) {
7455
+ logger.info({ workspaces: this.workspaces.map((w) => w.name) }, "Detected workspaces");
7456
+ }
7417
7457
  }
7418
7458
  const filePaths = await this.collectFiles();
7419
7459
  return this.runPipeline(filePaths, force ?? false, start);
@@ -9727,6 +9767,14 @@ function buildInstructions(detectedFrameworks, verbosity) {
9727
9767
  "Before creating new functions/classes:",
9728
9768
  '- `check_duplication` { name: "functionName", kind: "function" } \u2014 checks if similar symbols already exist. Use BEFORE writing new code to avoid reinventing existing logic.',
9729
9769
  "",
9770
+ "Bulk mechanical changes (adding async/await, updating patterns, fixing imports across many files):",
9771
+ "- `apply_codemod` { pattern, replacement, file_pattern } \u2014 regex find-and-replace across files. Dry-run by default (shows preview). Two-step workflow:",
9772
+ " 1. Call with dry_run: true (default) \u2192 review preview with context lines",
9773
+ " 2. Call with dry_run: false \u2192 apply changes. Requires confirm_large: true if >20 files affected.",
9774
+ "- Use `filter_content` to narrow scope to files containing a specific substring.",
9775
+ "- Use `multiline: true` for patterns spanning multiple lines.",
9776
+ "- NEVER use dozens of Edit calls for the same regex replacement \u2014 use apply_codemod instead.",
9777
+ "",
9730
9778
  "WHEN TO USE native tools (Read/Grep/Glob):",
9731
9779
  "- Non-code files (.md, .json, .yaml, .toml, config) \u2192 Read/Grep",
9732
9780
  "- Reading a file before editing (Edit needs full content) \u2192 Read",
@@ -18903,6 +18951,7 @@ import { z as z7 } from "zod";
18903
18951
  // src/tools/refactoring/refactor.ts
18904
18952
  import fs24 from "fs";
18905
18953
  import path35 from "path";
18954
+ import fg4 from "fast-glob";
18906
18955
  function readLines2(filePath) {
18907
18956
  return fs24.readFileSync(filePath, "utf-8").split("\n");
18908
18957
  }
@@ -19236,6 +19285,193 @@ ${functionDef}`
19236
19285
  }
19237
19286
  return result;
19238
19287
  }
19288
+ var CODEMOD_MAX_PREVIEW = 20;
19289
+ var CODEMOD_LARGE_THRESHOLD = 20;
19290
+ var CODEMOD_CONTEXT_LINES = 2;
19291
+ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
19292
+ ".png",
19293
+ ".jpg",
19294
+ ".jpeg",
19295
+ ".gif",
19296
+ ".bmp",
19297
+ ".ico",
19298
+ ".svg",
19299
+ ".webp",
19300
+ ".woff",
19301
+ ".woff2",
19302
+ ".ttf",
19303
+ ".eot",
19304
+ ".otf",
19305
+ ".zip",
19306
+ ".tar",
19307
+ ".gz",
19308
+ ".bz2",
19309
+ ".7z",
19310
+ ".rar",
19311
+ ".pdf",
19312
+ ".doc",
19313
+ ".docx",
19314
+ ".xls",
19315
+ ".xlsx",
19316
+ ".mp3",
19317
+ ".mp4",
19318
+ ".avi",
19319
+ ".mov",
19320
+ ".wav",
19321
+ ".exe",
19322
+ ".dll",
19323
+ ".so",
19324
+ ".dylib",
19325
+ ".o",
19326
+ ".a",
19327
+ ".wasm",
19328
+ ".pyc",
19329
+ ".class"
19330
+ ]);
19331
+ var SKIP_DIRS = ["node_modules", ".git", "dist", "build", "vendor", "__pycache__", ".next", ".nuxt"];
19332
+ function applyCodemod(projectRoot, pattern, replacement, filePattern, options) {
19333
+ const result = {
19334
+ success: false,
19335
+ tool: "apply_codemod",
19336
+ dry_run: options.dryRun,
19337
+ matches: [],
19338
+ files_modified: [],
19339
+ total_replacements: 0,
19340
+ total_files: 0,
19341
+ warnings: []
19342
+ };
19343
+ let regex;
19344
+ try {
19345
+ const flags = options.multiline ? "gms" : "gm";
19346
+ regex = new RegExp(pattern, flags);
19347
+ } catch (e) {
19348
+ result.error = `Invalid regex pattern: ${e.message}`;
19349
+ return result;
19350
+ }
19351
+ let files;
19352
+ try {
19353
+ files = fg4.sync(filePattern, {
19354
+ cwd: projectRoot,
19355
+ ignore: SKIP_DIRS.map((d) => `**/${d}/**`),
19356
+ onlyFiles: true,
19357
+ absolute: false
19358
+ });
19359
+ } catch (e) {
19360
+ result.error = `Invalid file pattern: ${e.message}`;
19361
+ return result;
19362
+ }
19363
+ files = files.filter((f) => !BINARY_EXTENSIONS.has(path35.extname(f).toLowerCase()));
19364
+ if (files.length === 0) {
19365
+ result.error = `No files matched pattern: ${filePattern}`;
19366
+ return result;
19367
+ }
19368
+ const allMatches = [];
19369
+ const filesWithMatches = /* @__PURE__ */ new Set();
19370
+ for (const relPath of files) {
19371
+ const absPath = path35.resolve(projectRoot, relPath);
19372
+ if (!fs24.existsSync(absPath)) continue;
19373
+ let content;
19374
+ try {
19375
+ content = fs24.readFileSync(absPath, "utf-8");
19376
+ } catch {
19377
+ result.warnings.push(`Could not read: ${relPath}`);
19378
+ continue;
19379
+ }
19380
+ if (options.filterContent && !content.includes(options.filterContent)) {
19381
+ continue;
19382
+ }
19383
+ const lines = content.split("\n");
19384
+ if (options.multiline) {
19385
+ regex.lastIndex = 0;
19386
+ if (!regex.test(content)) continue;
19387
+ filesWithMatches.add(relPath);
19388
+ regex.lastIndex = 0;
19389
+ let matchCount = 0;
19390
+ const matchPositions = [];
19391
+ let m;
19392
+ while ((m = regex.exec(content)) !== null) {
19393
+ matchPositions.push({ index: m.index, match: m[0] });
19394
+ matchCount++;
19395
+ if (m[0].length === 0) {
19396
+ regex.lastIndex++;
19397
+ }
19398
+ }
19399
+ for (const pos of matchPositions.slice(0, CODEMOD_MAX_PREVIEW - allMatches.length)) {
19400
+ const lineNum = content.slice(0, pos.index).split("\n").length;
19401
+ const original = pos.match;
19402
+ regex.lastIndex = 0;
19403
+ const replaced = original.replace(regex, replacement);
19404
+ allMatches.push({
19405
+ file: relPath,
19406
+ line: lineNum,
19407
+ original: original.length > 200 ? original.slice(0, 200) + "\u2026" : original,
19408
+ replaced: replaced.length > 200 ? replaced.slice(0, 200) + "\u2026" : replaced,
19409
+ context_before: lines.slice(Math.max(0, lineNum - 1 - CODEMOD_CONTEXT_LINES), lineNum - 1),
19410
+ context_after: lines.slice(lineNum, lineNum + CODEMOD_CONTEXT_LINES)
19411
+ });
19412
+ }
19413
+ result.total_replacements += matchCount;
19414
+ } else {
19415
+ let fileMatchCount = 0;
19416
+ for (let i = 0; i < lines.length; i++) {
19417
+ regex.lastIndex = 0;
19418
+ if (!regex.test(lines[i])) continue;
19419
+ filesWithMatches.add(relPath);
19420
+ fileMatchCount++;
19421
+ regex.lastIndex = 0;
19422
+ const newLine = lines[i].replace(regex, replacement);
19423
+ if (allMatches.length < CODEMOD_MAX_PREVIEW) {
19424
+ allMatches.push({
19425
+ file: relPath,
19426
+ line: i + 1,
19427
+ original: lines[i],
19428
+ replaced: newLine,
19429
+ context_before: lines.slice(Math.max(0, i - CODEMOD_CONTEXT_LINES), i),
19430
+ context_after: lines.slice(i + 1, i + 1 + CODEMOD_CONTEXT_LINES)
19431
+ });
19432
+ }
19433
+ }
19434
+ result.total_replacements += fileMatchCount;
19435
+ }
19436
+ }
19437
+ result.total_files = filesWithMatches.size;
19438
+ if (allMatches.length === 0) {
19439
+ result.error = `No matches found for pattern in ${files.length} files`;
19440
+ return result;
19441
+ }
19442
+ if (filesWithMatches.size > CODEMOD_LARGE_THRESHOLD && !options.confirmLarge) {
19443
+ result.matches = allMatches;
19444
+ result.warnings.push(
19445
+ `Affects ${filesWithMatches.size} files (>${CODEMOD_LARGE_THRESHOLD}). Re-run with confirm_large: true to proceed, or narrow file_pattern.`
19446
+ );
19447
+ result.dry_run = true;
19448
+ result.success = true;
19449
+ return result;
19450
+ }
19451
+ if (options.dryRun) {
19452
+ result.matches = allMatches;
19453
+ result.success = true;
19454
+ return result;
19455
+ }
19456
+ for (const relPath of filesWithMatches) {
19457
+ const absPath = path35.resolve(projectRoot, relPath);
19458
+ try {
19459
+ const content = fs24.readFileSync(absPath, "utf-8");
19460
+ const flags = options.multiline ? "gms" : "gm";
19461
+ const freshRegex = new RegExp(pattern, flags);
19462
+ const newContent = content.replace(freshRegex, replacement);
19463
+ if (newContent !== content) {
19464
+ fs24.writeFileSync(absPath, newContent, "utf-8");
19465
+ result.files_modified.push(relPath);
19466
+ }
19467
+ } catch (e) {
19468
+ result.warnings.push(`Failed to write ${relPath}: ${e.message}`);
19469
+ }
19470
+ }
19471
+ result.matches = allMatches;
19472
+ result.success = true;
19473
+ return result;
19474
+ }
19239
19475
  function detectLanguage2(ext) {
19240
19476
  switch (ext) {
19241
19477
  case ".ts":
@@ -19472,6 +19708,31 @@ function registerRefactoringTools(server, ctx) {
19472
19708
  return { content: [{ type: "text", text: j3(result) }] };
19473
19709
  }
19474
19710
  );
19711
+ server.tool(
19712
+ "apply_codemod",
19713
+ "Bulk regex find-and-replace across files. Dry-run by default \u2014 first call shows preview, second call with dry_run=false applies. Use for mechanical changes like adding async/await, renaming patterns, updating imports across many files.",
19714
+ {
19715
+ pattern: z7.string().min(1).max(1e3).describe("Regex pattern to match (JavaScript regex syntax)"),
19716
+ replacement: z7.string().max(1e3).describe("Replacement string ($1, $2 for capture groups)"),
19717
+ file_pattern: z7.string().min(1).max(512).describe('Glob pattern for files to scan (e.g. "tests/**/*.test.ts", "src/**/*.py")'),
19718
+ dry_run: z7.boolean().default(true).describe("Preview changes without writing (default: true). Set to false to apply."),
19719
+ confirm_large: z7.boolean().optional().describe("Required when >20 files affected. Acknowledges large-scale change."),
19720
+ filter_content: z7.string().max(500).optional().describe("Only process files containing this substring (narrows scope)"),
19721
+ multiline: z7.boolean().optional().describe("Enable multiline mode (dot matches newlines, patterns span lines)")
19722
+ },
19723
+ async ({ pattern, replacement, file_pattern, dry_run, confirm_large, filter_content, multiline }) => {
19724
+ const result = applyCodemod(projectRoot, pattern, replacement, file_pattern, {
19725
+ dryRun: dry_run,
19726
+ confirmLarge: confirm_large,
19727
+ filterContent: filter_content,
19728
+ multiline
19729
+ });
19730
+ if (!result.success) {
19731
+ return { content: [{ type: "text", text: j3(result) }], isError: true };
19732
+ }
19733
+ return { content: [{ type: "text", text: j3(result) }] };
19734
+ }
19735
+ );
19475
19736
  }
19476
19737
 
19477
19738
  // src/tools/register/advanced.ts
@@ -28652,6 +28913,8 @@ var KNOWN_PACKAGES = {
28652
28913
  "@clack/prompts": { category: "infra", priority: "medium", plugin: "clack" },
28653
28914
  "@clack/core": { category: "infra", priority: "medium", plugin: "clack" },
28654
28915
  "tree-sitter": { category: "infra", priority: "medium", plugin: "tree-sitter" },
28916
+ "web-tree-sitter": { category: "infra", priority: "medium", plugin: "tree-sitter" },
28917
+ "tree-sitter-wasms": { category: "infra", priority: "low", plugin: "tree-sitter" },
28655
28918
  "n8n-workflow": { category: "infra", priority: "high", plugin: "n8n" },
28656
28919
  // --- JavaScript / npm: Build tools (with plugin) ---
28657
28920
  "tsup": { category: "infra", priority: "low", plugin: "build-tools" },
@@ -29621,7 +29884,7 @@ function registerSessionTools(server, ctx) {
29621
29884
  }
29622
29885
 
29623
29886
  // src/server/server.ts
29624
- var PKG_VERSION = true ? "1.5.4" : "0.0.0-dev";
29887
+ var PKG_VERSION = true ? "1.6.1" : "0.0.0-dev";
29625
29888
  function j2(value) {
29626
29889
  return JSON.stringify(value, (_key, val) => val === null || val === void 0 ? void 0 : val);
29627
29890
  }
@@ -29894,9 +30157,76 @@ function createServer2(store, registry, config, rootPath) {
29894
30157
  }
29895
30158
 
29896
30159
  // src/indexer/plugins/language/php/index.ts
29897
- import { createRequire } from "module";
29898
30160
  import { ok as ok9, err as err12 } from "neverthrow";
29899
30161
 
30162
+ // src/parser/tree-sitter.ts
30163
+ import Parser from "web-tree-sitter";
30164
+ import { createRequire } from "module";
30165
+ var initPromise = null;
30166
+ var languageCache = /* @__PURE__ */ new Map();
30167
+ var parserCache = /* @__PURE__ */ new Map();
30168
+ var LANG_WASM_MAP = {
30169
+ bash: "tree-sitter-bash.wasm",
30170
+ c: "tree-sitter-c.wasm",
30171
+ cpp: "tree-sitter-cpp.wasm",
30172
+ csharp: "tree-sitter-c_sharp.wasm",
30173
+ css: "tree-sitter-css.wasm",
30174
+ dart: "tree-sitter-dart.wasm",
30175
+ elisp: "tree-sitter-elisp.wasm",
30176
+ elixir: "tree-sitter-elixir.wasm",
30177
+ elm: "tree-sitter-elm.wasm",
30178
+ embedded_template: "tree-sitter-embedded_template.wasm",
30179
+ go: "tree-sitter-go.wasm",
30180
+ html: "tree-sitter-html.wasm",
30181
+ java: "tree-sitter-java.wasm",
30182
+ javascript: "tree-sitter-javascript.wasm",
30183
+ json: "tree-sitter-json.wasm",
30184
+ kotlin: "tree-sitter-kotlin.wasm",
30185
+ lua: "tree-sitter-lua.wasm",
30186
+ objc: "tree-sitter-objc.wasm",
30187
+ ocaml: "tree-sitter-ocaml.wasm",
30188
+ php: "tree-sitter-php.wasm",
30189
+ python: "tree-sitter-python.wasm",
30190
+ ql: "tree-sitter-ql.wasm",
30191
+ rescript: "tree-sitter-rescript.wasm",
30192
+ ruby: "tree-sitter-ruby.wasm",
30193
+ rust: "tree-sitter-rust.wasm",
30194
+ scala: "tree-sitter-scala.wasm",
30195
+ solidity: "tree-sitter-solidity.wasm",
30196
+ swift: "tree-sitter-swift.wasm",
30197
+ systemrdl: "tree-sitter-systemrdl.wasm",
30198
+ tlaplus: "tree-sitter-tlaplus.wasm",
30199
+ toml: "tree-sitter-toml.wasm",
30200
+ tsx: "tree-sitter-tsx.wasm",
30201
+ typescript: "tree-sitter-typescript.wasm",
30202
+ vue: "tree-sitter-vue.wasm",
30203
+ yaml: "tree-sitter-yaml.wasm",
30204
+ zig: "tree-sitter-zig.wasm"
30205
+ };
30206
+ var _require = createRequire(import.meta.url);
30207
+ function ensureInit() {
30208
+ if (!initPromise) {
30209
+ initPromise = Parser.init();
30210
+ }
30211
+ return initPromise;
30212
+ }
30213
+ async function getParser(language) {
30214
+ await ensureInit();
30215
+ if (parserCache.has(language)) return parserCache.get(language);
30216
+ const wasmFile = LANG_WASM_MAP[language];
30217
+ if (!wasmFile) throw new Error(`Unsupported tree-sitter language: ${language}`);
30218
+ let lang = languageCache.get(language);
30219
+ if (!lang) {
30220
+ const wasmPath = _require.resolve(`tree-sitter-wasms/out/${wasmFile}`);
30221
+ lang = await Parser.Language.load(wasmPath);
30222
+ languageCache.set(language, lang);
30223
+ }
30224
+ const parser = new Parser();
30225
+ parser.setLanguage(lang);
30226
+ parserCache.set(language, parser);
30227
+ return parser;
30228
+ }
30229
+
29900
30230
  // src/indexer/plugins/language/php/helpers.ts
29901
30231
  function extractNamespace(rootNode) {
29902
30232
  for (const child of rootNode.namedChildren) {
@@ -30152,17 +30482,6 @@ function detectMinPhpVersion(nodeTypes) {
30152
30482
  }
30153
30483
 
30154
30484
  // src/indexer/plugins/language/php/index.ts
30155
- var require2 = createRequire(import.meta.url);
30156
- var Parser = require2("tree-sitter");
30157
- var PhpGrammar = require2("tree-sitter-php");
30158
- var parserInstance = null;
30159
- function getParser() {
30160
- if (!parserInstance) {
30161
- parserInstance = new Parser();
30162
- parserInstance.setLanguage(PhpGrammar.php);
30163
- }
30164
- return parserInstance;
30165
- }
30166
30485
  var PhpLanguagePlugin = class {
30167
30486
  manifest = {
30168
30487
  name: "php-language",
@@ -30189,9 +30508,9 @@ var PhpLanguagePlugin = class {
30189
30508
  "8.3",
30190
30509
  "8.4"
30191
30510
  ];
30192
- extractSymbols(filePath, content) {
30511
+ async extractSymbols(filePath, content) {
30193
30512
  try {
30194
- const parser = getParser();
30513
+ const parser = await getParser("php");
30195
30514
  const sourceCode = content.toString("utf-8");
30196
30515
  const tree = parser.parse(sourceCode);
30197
30516
  const root = tree.rootNode;
@@ -30416,7 +30735,6 @@ var PhpLanguagePlugin = class {
30416
30735
  };
30417
30736
 
30418
30737
  // src/indexer/plugins/language/typescript/index.ts
30419
- import { createRequire as createRequire2 } from "module";
30420
30738
  import { ok as ok10, err as err13 } from "neverthrow";
30421
30739
 
30422
30740
  // src/indexer/plugins/language/typescript/helpers.ts
@@ -30738,25 +31056,6 @@ function detectMinEsVersion(nodeTypes) {
30738
31056
  }
30739
31057
 
30740
31058
  // src/indexer/plugins/language/typescript/index.ts
30741
- var require3 = createRequire2(import.meta.url);
30742
- var Parser2 = require3("tree-sitter");
30743
- var TsGrammar = require3("tree-sitter-typescript");
30744
- var tsParser = null;
30745
- var tsxParser = null;
30746
- function getParser2(tsx) {
30747
- if (tsx) {
30748
- if (!tsxParser) {
30749
- tsxParser = new Parser2();
30750
- tsxParser.setLanguage(TsGrammar.tsx);
30751
- }
30752
- return tsxParser;
30753
- }
30754
- if (!tsParser) {
30755
- tsParser = new Parser2();
30756
- tsParser.setLanguage(TsGrammar.typescript);
30757
- }
30758
- return tsParser;
30759
- }
30760
31059
  var TSX_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx"]);
30761
31060
  var JS_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs"]);
30762
31061
  var TypeScriptLanguagePlugin = class {
@@ -30767,11 +31066,11 @@ var TypeScriptLanguagePlugin = class {
30767
31066
  };
30768
31067
  supportedExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
30769
31068
  supportedVersions = ["12", "14", "16", "17", "18", "19", "20", "21", "22", "23", "24"];
30770
- extractSymbols(filePath, content) {
31069
+ async extractSymbols(filePath, content) {
30771
31070
  try {
30772
31071
  const ext = filePath.substring(filePath.lastIndexOf("."));
30773
31072
  const useTsx = TSX_EXTENSIONS.has(ext);
30774
- const parser = getParser2(useTsx);
31073
+ const parser = await getParser(useTsx ? "tsx" : "typescript");
30775
31074
  const sourceCode = content.toString("utf-8");
30776
31075
  const tree = parser.parse(sourceCode);
30777
31076
  const root = tree.rootNode;
@@ -31022,7 +31321,6 @@ var TypeScriptLanguagePlugin = class {
31022
31321
  };
31023
31322
 
31024
31323
  // src/indexer/plugins/language/vue/index.ts
31025
- import { createRequire as createRequire3 } from "module";
31026
31324
  import { parse as parseSFC } from "@vue/compiler-sfc";
31027
31325
  import { ok as ok11, err as err14 } from "neverthrow";
31028
31326
 
@@ -31321,17 +31619,6 @@ function componentNameFromPath(filePath) {
31321
31619
  }
31322
31620
 
31323
31621
  // src/indexer/plugins/language/vue/index.ts
31324
- var require4 = createRequire3(import.meta.url);
31325
- var Parser3 = require4("tree-sitter");
31326
- var TsGrammar2 = require4("tree-sitter-typescript");
31327
- var tsParser2 = null;
31328
- function getParser3() {
31329
- if (!tsParser2) {
31330
- tsParser2 = new Parser3();
31331
- tsParser2.setLanguage(TsGrammar2.typescript);
31332
- }
31333
- return tsParser2;
31334
- }
31335
31622
  var VueLanguagePlugin = class {
31336
31623
  manifest = {
31337
31624
  name: "vue-language",
@@ -31339,7 +31626,7 @@ var VueLanguagePlugin = class {
31339
31626
  priority: 10
31340
31627
  };
31341
31628
  supportedExtensions = [".vue"];
31342
- extractSymbols(filePath, content) {
31629
+ async extractSymbols(filePath, content) {
31343
31630
  try {
31344
31631
  const sourceCode = content.toString("utf-8");
31345
31632
  const { descriptor, errors } = parseSFC(sourceCode, {
@@ -31378,14 +31665,14 @@ var VueLanguagePlugin = class {
31378
31665
  emits = extractEmits(setupContent);
31379
31666
  exposed = extractExposed(setupContent);
31380
31667
  composables = extractComposables(setupContent);
31381
- const setupEdges = this.parseScriptEdges(setupContent);
31668
+ const setupEdges = await this.parseScriptEdges(setupContent);
31382
31669
  edges.push(...setupEdges);
31383
31670
  }
31384
31671
  if (descriptor.script) {
31385
31672
  const scriptContent = descriptor.script.content;
31386
- const scriptSymbols = this.parseScriptSymbols(scriptContent, filePath);
31673
+ const scriptSymbols = await this.parseScriptSymbols(scriptContent, filePath);
31387
31674
  symbols.push(...scriptSymbols);
31388
- const scriptEdges = this.parseScriptEdges(scriptContent);
31675
+ const scriptEdges = await this.parseScriptEdges(scriptContent);
31389
31676
  edges.push(...scriptEdges);
31390
31677
  }
31391
31678
  let templateComponents = [];
@@ -31426,9 +31713,9 @@ var VueLanguagePlugin = class {
31426
31713
  /**
31427
31714
  * Parse a script block with tree-sitter to extract import edges.
31428
31715
  */
31429
- parseScriptEdges(scriptContent) {
31716
+ async parseScriptEdges(scriptContent) {
31430
31717
  try {
31431
- const parser = getParser3();
31718
+ const parser = await getParser("typescript");
31432
31719
  const tree = parser.parse(scriptContent);
31433
31720
  return extractImportEdges(tree.rootNode);
31434
31721
  } catch {
@@ -31439,9 +31726,9 @@ var VueLanguagePlugin = class {
31439
31726
  * Parse a <script> block with tree-sitter to extract top-level symbols.
31440
31727
  * Used for Options API / non-setup scripts.
31441
31728
  */
31442
- parseScriptSymbols(scriptContent, filePath) {
31729
+ async parseScriptSymbols(scriptContent, filePath) {
31443
31730
  try {
31444
- const parser = getParser3();
31731
+ const parser = await getParser("typescript");
31445
31732
  const tree = parser.parse(scriptContent);
31446
31733
  const root = tree.rootNode;
31447
31734
  const symbols = [];
@@ -31502,7 +31789,6 @@ var VueLanguagePlugin = class {
31502
31789
  };
31503
31790
 
31504
31791
  // src/indexer/plugins/language/python/index.ts
31505
- import { createRequire as createRequire4 } from "module";
31506
31792
  import { ok as ok12, err as err15 } from "neverthrow";
31507
31793
 
31508
31794
  // src/indexer/plugins/language/python/helpers.ts
@@ -31831,17 +32117,6 @@ function detectMinPythonVersion(nodeTypes) {
31831
32117
  }
31832
32118
 
31833
32119
  // src/indexer/plugins/language/python/index.ts
31834
- var require5 = createRequire4(import.meta.url);
31835
- var Parser4 = require5("tree-sitter");
31836
- var PythonGrammar = require5("tree-sitter-python");
31837
- var parserInstance2 = null;
31838
- function getParser4() {
31839
- if (!parserInstance2) {
31840
- parserInstance2 = new Parser4();
31841
- parserInstance2.setLanguage(PythonGrammar);
31842
- }
31843
- return parserInstance2;
31844
- }
31845
32120
  var PythonLanguagePlugin = class {
31846
32121
  manifest = {
31847
32122
  name: "python-language",
@@ -31867,9 +32142,9 @@ var PythonLanguagePlugin = class {
31867
32142
  "3.13",
31868
32143
  "3.14"
31869
32144
  ];
31870
- extractSymbols(filePath, content) {
32145
+ async extractSymbols(filePath, content) {
31871
32146
  try {
31872
- const parser = getParser4();
32147
+ const parser = await getParser("python");
31873
32148
  const sourceCode = content.toString("utf-8");
31874
32149
  const tree = parser.parse(sourceCode);
31875
32150
  const root = tree.rootNode;
@@ -32140,7 +32415,6 @@ var PythonLanguagePlugin = class {
32140
32415
  };
32141
32416
 
32142
32417
  // src/indexer/plugins/language/java/index.ts
32143
- import { createRequire as createRequire5 } from "module";
32144
32418
  import { ok as ok13, err as err16 } from "neverthrow";
32145
32419
 
32146
32420
  // src/indexer/plugins/language/java/version-features.ts
@@ -32441,17 +32715,6 @@ function findChildByType(node, type) {
32441
32715
  }
32442
32716
 
32443
32717
  // src/indexer/plugins/language/java/index.ts
32444
- var require6 = createRequire5(import.meta.url);
32445
- var Parser5 = require6("tree-sitter");
32446
- var JavaGrammar = require6("tree-sitter-java");
32447
- var parserInstance3 = null;
32448
- function getParser5() {
32449
- if (!parserInstance3) {
32450
- parserInstance3 = new Parser5();
32451
- parserInstance3.setLanguage(JavaGrammar);
32452
- }
32453
- return parserInstance3;
32454
- }
32455
32718
  var JavaLanguagePlugin = class {
32456
32719
  manifest = {
32457
32720
  name: "java-language",
@@ -32460,9 +32723,9 @@ var JavaLanguagePlugin = class {
32460
32723
  };
32461
32724
  supportedExtensions = [".java"];
32462
32725
  supportedVersions = ["8", "9", "10", "11", "14", "15", "16", "17", "21", "22", "23"];
32463
- extractSymbols(filePath, content) {
32726
+ async extractSymbols(filePath, content) {
32464
32727
  try {
32465
- const parser = getParser5();
32728
+ const parser = await getParser("java");
32466
32729
  const sourceCode = content.toString("utf-8");
32467
32730
  const tree = parser.parse(sourceCode);
32468
32731
  const root = tree.rootNode;
@@ -32806,7 +33069,6 @@ var KotlinLanguagePlugin = class {
32806
33069
  };
32807
33070
 
32808
33071
  // src/indexer/plugins/language/ruby/index.ts
32809
- import { createRequire as createRequire6 } from "module";
32810
33072
  import { ok as ok15, err as err18 } from "neverthrow";
32811
33073
 
32812
33074
  // src/indexer/plugins/language/ruby/version-features.ts
@@ -33057,17 +33319,6 @@ function extractConstants(body, filePath, containerName, containerSymbolId, name
33057
33319
  }
33058
33320
 
33059
33321
  // src/indexer/plugins/language/ruby/index.ts
33060
- var require7 = createRequire6(import.meta.url);
33061
- var Parser6 = require7("tree-sitter");
33062
- var RubyGrammar = require7("tree-sitter-ruby");
33063
- var parserInstance4 = null;
33064
- function getParser6() {
33065
- if (!parserInstance4) {
33066
- parserInstance4 = new Parser6();
33067
- parserInstance4.setLanguage(RubyGrammar);
33068
- }
33069
- return parserInstance4;
33070
- }
33071
33322
  var RubyLanguagePlugin = class {
33072
33323
  manifest = {
33073
33324
  name: "ruby-language",
@@ -33076,9 +33327,9 @@ var RubyLanguagePlugin = class {
33076
33327
  };
33077
33328
  supportedExtensions = [".rb", ".rake"];
33078
33329
  supportedVersions = ["2.0", "2.3", "2.5", "2.6", "2.7", "3.0", "3.1", "3.2", "3.3"];
33079
- extractSymbols(filePath, content) {
33330
+ async extractSymbols(filePath, content) {
33080
33331
  try {
33081
- const parser = getParser6();
33332
+ const parser = await getParser("ruby");
33082
33333
  const sourceCode = content.toString("utf-8");
33083
33334
  const tree = parser.parse(sourceCode);
33084
33335
  const root = tree.rootNode;
@@ -33215,7 +33466,6 @@ var RubyLanguagePlugin = class {
33215
33466
  };
33216
33467
 
33217
33468
  // src/indexer/plugins/language/go/index.ts
33218
- import { createRequire as createRequire7 } from "module";
33219
33469
  import { ok as ok16, err as err19 } from "neverthrow";
33220
33470
 
33221
33471
  // src/indexer/plugins/language/go/version-features.ts
@@ -33386,17 +33636,6 @@ function extractInterfaceMethods(body, filePath, ifaceName, ifaceSymbolId) {
33386
33636
  }
33387
33637
 
33388
33638
  // src/indexer/plugins/language/go/index.ts
33389
- var require8 = createRequire7(import.meta.url);
33390
- var Parser7 = require8("tree-sitter");
33391
- var GoGrammar = require8("tree-sitter-go");
33392
- var parserInstance5 = null;
33393
- function getParser7() {
33394
- if (!parserInstance5) {
33395
- parserInstance5 = new Parser7();
33396
- parserInstance5.setLanguage(GoGrammar);
33397
- }
33398
- return parserInstance5;
33399
- }
33400
33639
  var GoLanguagePlugin = class {
33401
33640
  manifest = {
33402
33641
  name: "go-language",
@@ -33405,9 +33644,9 @@ var GoLanguagePlugin = class {
33405
33644
  };
33406
33645
  supportedExtensions = [".go"];
33407
33646
  supportedVersions = ["1.11", "1.13", "1.14", "1.16", "1.17", "1.18", "1.19", "1.20", "1.21", "1.22", "1.23"];
33408
- extractSymbols(filePath, content) {
33647
+ async extractSymbols(filePath, content) {
33409
33648
  try {
33410
- const parser = getParser7();
33649
+ const parser = await getParser("go");
33411
33650
  const sourceCode = content.toString("utf-8");
33412
33651
  const tree = parser.parse(sourceCode);
33413
33652
  const root = tree.rootNode;
@@ -33957,7 +34196,6 @@ function lineAt2(source, offset) {
33957
34196
  }
33958
34197
 
33959
34198
  // src/indexer/plugins/language/rust/index.ts
33960
- import { createRequire as createRequire8 } from "module";
33961
34199
  import { ok as ok19, err as err20 } from "neverthrow";
33962
34200
 
33963
34201
  // src/indexer/plugins/language/rust/helpers.ts
@@ -34161,17 +34399,6 @@ function extractTraitMethods(body, filePath, traitName, traitSymbolId) {
34161
34399
  }
34162
34400
 
34163
34401
  // src/indexer/plugins/language/rust/index.ts
34164
- var require9 = createRequire8(import.meta.url);
34165
- var Parser8 = require9("tree-sitter");
34166
- var RustGrammar = require9("tree-sitter-rust");
34167
- var parserInstance6 = null;
34168
- function getParser8() {
34169
- if (!parserInstance6) {
34170
- parserInstance6 = new Parser8();
34171
- parserInstance6.setLanguage(RustGrammar);
34172
- }
34173
- return parserInstance6;
34174
- }
34175
34402
  var RustLanguagePlugin = class {
34176
34403
  manifest = {
34177
34404
  name: "rust-language",
@@ -34179,9 +34406,9 @@ var RustLanguagePlugin = class {
34179
34406
  priority: 5
34180
34407
  };
34181
34408
  supportedExtensions = [".rs"];
34182
- extractSymbols(filePath, content) {
34409
+ async extractSymbols(filePath, content) {
34183
34410
  try {
34184
- const parser = getParser8();
34411
+ const parser = await getParser("rust");
34185
34412
  const sourceCode = content.toString("utf-8");
34186
34413
  const tree = parser.parse(sourceCode);
34187
34414
  const root = tree.rootNode;
@@ -34463,7 +34690,6 @@ var RustLanguagePlugin = class {
34463
34690
  };
34464
34691
 
34465
34692
  // src/indexer/plugins/language/c/index.ts
34466
- import { createRequire as createRequire9 } from "module";
34467
34693
  import { ok as ok20, err as err21 } from "neverthrow";
34468
34694
 
34469
34695
  // src/indexer/plugins/language/c/helpers.ts
@@ -34594,17 +34820,6 @@ function extractEnumConstants2(body, filePath, enumName, enumSymbolId) {
34594
34820
  }
34595
34821
 
34596
34822
  // src/indexer/plugins/language/c/index.ts
34597
- var require10 = createRequire9(import.meta.url);
34598
- var Parser9 = require10("tree-sitter");
34599
- var CGrammar = require10("tree-sitter-c");
34600
- var parserInstance7 = null;
34601
- function getParser9() {
34602
- if (!parserInstance7) {
34603
- parserInstance7 = new Parser9();
34604
- parserInstance7.setLanguage(CGrammar);
34605
- }
34606
- return parserInstance7;
34607
- }
34608
34823
  var CLanguagePlugin = class {
34609
34824
  manifest = {
34610
34825
  name: "c-language",
@@ -34612,9 +34827,9 @@ var CLanguagePlugin = class {
34612
34827
  priority: 5
34613
34828
  };
34614
34829
  supportedExtensions = [".c", ".h"];
34615
- extractSymbols(filePath, content) {
34830
+ async extractSymbols(filePath, content) {
34616
34831
  try {
34617
- const parser = getParser9();
34832
+ const parser = await getParser("c");
34618
34833
  const sourceCode = content.toString("utf-8");
34619
34834
  const tree = parser.parse(sourceCode);
34620
34835
  const root = tree.rootNode;
@@ -34881,7 +35096,6 @@ var CLanguagePlugin = class {
34881
35096
  };
34882
35097
 
34883
35098
  // src/indexer/plugins/language/cpp/index.ts
34884
- import { createRequire as createRequire10 } from "module";
34885
35099
  import { ok as ok21, err as err22 } from "neverthrow";
34886
35100
 
34887
35101
  // src/indexer/plugins/language/cpp/helpers.ts
@@ -35063,17 +35277,6 @@ function isVirtual(node) {
35063
35277
  }
35064
35278
 
35065
35279
  // src/indexer/plugins/language/cpp/index.ts
35066
- var require11 = createRequire10(import.meta.url);
35067
- var Parser10 = require11("tree-sitter");
35068
- var CppGrammar = require11("tree-sitter-cpp");
35069
- var parserInstance8 = null;
35070
- function getParser10() {
35071
- if (!parserInstance8) {
35072
- parserInstance8 = new Parser10();
35073
- parserInstance8.setLanguage(CppGrammar);
35074
- }
35075
- return parserInstance8;
35076
- }
35077
35280
  var CppLanguagePlugin = class {
35078
35281
  manifest = {
35079
35282
  name: "cpp-language",
@@ -35081,9 +35284,9 @@ var CppLanguagePlugin = class {
35081
35284
  priority: 5
35082
35285
  };
35083
35286
  supportedExtensions = [".cpp", ".cxx", ".cc", ".hpp", ".hxx", ".hh", ".h++"];
35084
- extractSymbols(filePath, content) {
35287
+ async extractSymbols(filePath, content) {
35085
35288
  try {
35086
- const parser = getParser10();
35289
+ const parser = await getParser("cpp");
35087
35290
  const sourceCode = content.toString("utf-8");
35088
35291
  const tree = parser.parse(sourceCode);
35089
35292
  const root = tree.rootNode;
@@ -35500,7 +35703,6 @@ var CppLanguagePlugin = class {
35500
35703
  };
35501
35704
 
35502
35705
  // src/indexer/plugins/language/csharp/index.ts
35503
- import { createRequire as createRequire11 } from "module";
35504
35706
  import { ok as ok22, err as err23 } from "neverthrow";
35505
35707
 
35506
35708
  // src/indexer/plugins/language/csharp/helpers.ts
@@ -35853,17 +36055,6 @@ function findChildByType2(node, type) {
35853
36055
  }
35854
36056
 
35855
36057
  // src/indexer/plugins/language/csharp/index.ts
35856
- var require12 = createRequire11(import.meta.url);
35857
- var Parser11 = require12("tree-sitter");
35858
- var CSharpGrammar = require12("tree-sitter-c-sharp");
35859
- var parserInstance9 = null;
35860
- function getParser11() {
35861
- if (!parserInstance9) {
35862
- parserInstance9 = new Parser11();
35863
- parserInstance9.setLanguage(CSharpGrammar);
35864
- }
35865
- return parserInstance9;
35866
- }
35867
36058
  var CSharpLanguagePlugin = class {
35868
36059
  manifest = {
35869
36060
  name: "csharp-language",
@@ -35883,9 +36074,9 @@ var CSharpLanguagePlugin = class {
35883
36074
  "12.0",
35884
36075
  "13.0"
35885
36076
  ];
35886
- extractSymbols(filePath, content) {
36077
+ async extractSymbols(filePath, content) {
35887
36078
  try {
35888
- const parser = getParser11();
36079
+ const parser = await getParser("csharp");
35889
36080
  const sourceCode = content.toString("utf-8");
35890
36081
  const tree = parser.parse(sourceCode);
35891
36082
  const root = tree.rootNode;
@@ -36509,7 +36700,6 @@ var DartLanguagePlugin = class {
36509
36700
  };
36510
36701
 
36511
36702
  // src/indexer/plugins/language/scala/index.ts
36512
- import { createRequire as createRequire12 } from "module";
36513
36703
  import { ok as ok25, err as err24 } from "neverthrow";
36514
36704
 
36515
36705
  // src/indexer/plugins/language/scala/helpers.ts
@@ -36874,17 +37064,6 @@ function extractValVarName(node) {
36874
37064
  }
36875
37065
 
36876
37066
  // src/indexer/plugins/language/scala/index.ts
36877
- var require13 = createRequire12(import.meta.url);
36878
- var Parser12 = require13("tree-sitter");
36879
- var ScalaGrammar = require13("tree-sitter-scala");
36880
- var parserInstance10 = null;
36881
- function getParser12() {
36882
- if (!parserInstance10) {
36883
- parserInstance10 = new Parser12();
36884
- parserInstance10.setLanguage(ScalaGrammar);
36885
- }
36886
- return parserInstance10;
36887
- }
36888
37067
  var ScalaLanguagePlugin = class {
36889
37068
  manifest = {
36890
37069
  name: "scala-language",
@@ -36893,9 +37072,9 @@ var ScalaLanguagePlugin = class {
36893
37072
  };
36894
37073
  supportedExtensions = [".scala", ".sc"];
36895
37074
  supportedVersions = ["2.11", "2.12", "2.13", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5"];
36896
- extractSymbols(filePath, content) {
37075
+ async extractSymbols(filePath, content) {
36897
37076
  try {
36898
- const parser = getParser12();
37077
+ const parser = await getParser("scala");
36899
37078
  const sourceCode = content.toString("utf-8");
36900
37079
  const tree = parser.parse(sourceCode);
36901
37080
  const root = tree.rootNode;
@@ -45363,13 +45542,9 @@ var ExpressPlugin = class {
45363
45542
  };
45364
45543
 
45365
45544
  // src/indexer/plugins/integration/framework/fastapi/index.ts
45366
- import { createRequire as createRequire13 } from "module";
45367
45545
  import fs43 from "fs";
45368
45546
  import path55 from "path";
45369
45547
  import { ok as ok38, err as err25 } from "neverthrow";
45370
- var require14 = createRequire13(import.meta.url);
45371
- var Parser13 = require14("tree-sitter");
45372
- var PythonGrammar2 = require14("tree-sitter-python");
45373
45548
  var HTTP_METHODS3 = /* @__PURE__ */ new Set(["get", "post", "put", "delete", "patch", "options", "head"]);
45374
45549
  function hasPythonDep(ctx, pkg) {
45375
45550
  const lowerPkg = pkg.toLowerCase();
@@ -45416,7 +45591,7 @@ var FastAPIPlugin = class {
45416
45591
  ]
45417
45592
  };
45418
45593
  }
45419
- extractNodes(filePath, content, language) {
45594
+ async extractNodes(filePath, content, language) {
45420
45595
  if (language !== "python") {
45421
45596
  return ok38({ status: "ok", symbols: [] });
45422
45597
  }
@@ -45432,8 +45607,7 @@ var FastAPIPlugin = class {
45432
45607
  warnings: []
45433
45608
  };
45434
45609
  try {
45435
- const parser = new Parser13();
45436
- parser.setLanguage(PythonGrammar2);
45610
+ const parser = await getParser("python");
45437
45611
  const tree = parser.parse(source);
45438
45612
  const root = tree.rootNode;
45439
45613
  this.extractRoutes(root, source, filePath, result);
@@ -45680,13 +45854,9 @@ var FastAPIPlugin = class {
45680
45854
  };
45681
45855
 
45682
45856
  // src/indexer/plugins/integration/framework/flask/index.ts
45683
- import { createRequire as createRequire14 } from "module";
45684
45857
  import fs44 from "fs";
45685
45858
  import path56 from "path";
45686
45859
  import { ok as ok39, err as err26 } from "neverthrow";
45687
- var require15 = createRequire14(import.meta.url);
45688
- var Parser14 = require15("tree-sitter");
45689
- var PythonGrammar3 = require15("tree-sitter-python");
45690
45860
  var DEFAULT_METHODS = ["GET"];
45691
45861
  function hasPythonDep2(ctx, pkg) {
45692
45862
  const lowerPkg = pkg.toLowerCase();
@@ -45732,7 +45902,7 @@ var FlaskPlugin = class {
45732
45902
  ]
45733
45903
  };
45734
45904
  }
45735
- extractNodes(filePath, content, language) {
45905
+ async extractNodes(filePath, content, language) {
45736
45906
  if (language !== "python") {
45737
45907
  return ok39({ status: "ok", symbols: [] });
45738
45908
  }
@@ -45748,8 +45918,7 @@ var FlaskPlugin = class {
45748
45918
  warnings: []
45749
45919
  };
45750
45920
  try {
45751
- const parser = new Parser14();
45752
- parser.setLanguage(PythonGrammar3);
45921
+ const parser = await getParser("python");
45753
45922
  const tree = parser.parse(source);
45754
45923
  const root = tree.rootNode;
45755
45924
  this.extractRoutes(root, source, filePath, result);
@@ -47838,13 +48007,9 @@ function extractRefs(fields, sourceModelName) {
47838
48007
  }
47839
48008
 
47840
48009
  // src/indexer/plugins/integration/orm/sqlalchemy/index.ts
47841
- import { createRequire as createRequire15 } from "module";
47842
48010
  import fs53 from "fs";
47843
48011
  import path65 from "path";
47844
48012
  import { ok as ok43, err as err27 } from "neverthrow";
47845
- var require16 = createRequire15(import.meta.url);
47846
- var Parser15 = require16("tree-sitter");
47847
- var PythonGrammar4 = require16("tree-sitter-python");
47848
48013
  var MODEL_BASES = /* @__PURE__ */ new Set([
47849
48014
  "Base",
47850
48015
  "DeclarativeBase",
@@ -47895,7 +48060,7 @@ var SQLAlchemyPlugin = class {
47895
48060
  ]
47896
48061
  };
47897
48062
  }
47898
- extractNodes(filePath, content, language) {
48063
+ async extractNodes(filePath, content, language) {
47899
48064
  if (language !== "python") {
47900
48065
  return ok43({ status: "ok", symbols: [] });
47901
48066
  }
@@ -47913,8 +48078,7 @@ var SQLAlchemyPlugin = class {
47913
48078
  if (isAlembicMigration) {
47914
48079
  if (source.includes("op.create_table") || source.includes("op.add_column") || source.includes("op.drop_table")) {
47915
48080
  try {
47916
- const parser = new Parser15();
47917
- parser.setLanguage(PythonGrammar4);
48081
+ const parser = await getParser("python");
47918
48082
  const tree = parser.parse(source);
47919
48083
  this.extractAlembicMigrations(tree.rootNode, source, filePath, result);
47920
48084
  } catch (e) {
@@ -47929,8 +48093,7 @@ var SQLAlchemyPlugin = class {
47929
48093
  return ok43({ status: "ok", symbols: [] });
47930
48094
  }
47931
48095
  try {
47932
- const parser = new Parser15();
47933
- parser.setLanguage(PythonGrammar4);
48096
+ const parser = await getParser("python");
47934
48097
  const tree = parser.parse(source);
47935
48098
  const root = tree.rootNode;
47936
48099
  this.extractModels(root, source, filePath, result);
@@ -48550,27 +48713,7 @@ var RawSqlPlugin = class {
48550
48713
  };
48551
48714
 
48552
48715
  // src/indexer/plugins/integration/view/react/index.ts
48553
- import { createRequire as createRequire16 } from "module";
48554
48716
  import { ok as ok45, err as err28 } from "neverthrow";
48555
- var require17 = createRequire16(import.meta.url);
48556
- var Parser16 = require17("tree-sitter");
48557
- var TsGrammar3 = require17("tree-sitter-typescript");
48558
- var tsParser3 = null;
48559
- var tsxParser2 = null;
48560
- function getParser13(tsx) {
48561
- if (tsx) {
48562
- if (!tsxParser2) {
48563
- tsxParser2 = new Parser16();
48564
- tsxParser2.setLanguage(TsGrammar3.tsx);
48565
- }
48566
- return tsxParser2;
48567
- }
48568
- if (!tsParser3) {
48569
- tsParser3 = new Parser16();
48570
- tsParser3.setLanguage(TsGrammar3.typescript);
48571
- }
48572
- return tsParser3;
48573
- }
48574
48717
  var BUILTIN_HOOKS = /* @__PURE__ */ new Set([
48575
48718
  "useState",
48576
48719
  "useEffect",
@@ -48657,7 +48800,7 @@ var ReactPlugin = class {
48657
48800
  ]
48658
48801
  };
48659
48802
  }
48660
- extractNodes(filePath, content, language) {
48803
+ async extractNodes(filePath, content, language) {
48661
48804
  if (!["typescript", "typescriptreact", "javascript", "javascriptreact"].includes(language)) {
48662
48805
  return ok45({ status: "ok", symbols: [] });
48663
48806
  }
@@ -48674,7 +48817,7 @@ var ReactPlugin = class {
48674
48817
  this.extractDirectives(source, result);
48675
48818
  try {
48676
48819
  const useTsx = /\.(tsx|jsx)$/.test(filePath);
48677
- const parser = getParser13(useTsx);
48820
+ const parser = await getParser(useTsx ? "tsx" : "typescript");
48678
48821
  const tree = parser.parse(source);
48679
48822
  const root = tree.rootNode;
48680
48823
  for (const node of walk(root)) {
@@ -52076,21 +52219,9 @@ var TrpcPlugin = class {
52076
52219
  };
52077
52220
 
52078
52221
  // src/indexer/plugins/integration/api/drf/index.ts
52079
- import { createRequire as createRequire17 } from "module";
52080
52222
  import fs64 from "fs";
52081
52223
  import path76 from "path";
52082
52224
  import { ok as ok52, err as err29 } from "neverthrow";
52083
- var require18 = createRequire17(import.meta.url);
52084
- var Parser17 = require18("tree-sitter");
52085
- var PythonGrammar5 = require18("tree-sitter-python");
52086
- var parserInstance11 = null;
52087
- function getParser14() {
52088
- if (!parserInstance11) {
52089
- parserInstance11 = new Parser17();
52090
- parserInstance11.setLanguage(PythonGrammar5);
52091
- }
52092
- return parserInstance11;
52093
- }
52094
52225
  function hasPythonDep4(rootPath, depName) {
52095
52226
  for (const reqFile of ["requirements.txt", "requirements/base.txt", "requirements/prod.txt"]) {
52096
52227
  try {
@@ -52344,7 +52475,7 @@ var DRFPlugin = class {
52344
52475
  ]
52345
52476
  };
52346
52477
  }
52347
- extractNodes(filePath, content, language) {
52478
+ async extractNodes(filePath, content, language) {
52348
52479
  if (language !== "python") {
52349
52480
  return ok52({ status: "ok", symbols: [] });
52350
52481
  }
@@ -52357,7 +52488,7 @@ var DRFPlugin = class {
52357
52488
  };
52358
52489
  let tree;
52359
52490
  try {
52360
- const parser = getParser14();
52491
+ const parser = await getParser("python");
52361
52492
  tree = parser.parse(source);
52362
52493
  } catch (e) {
52363
52494
  return err29(parseError(filePath, `tree-sitter parse failed: ${e}`));
@@ -52620,21 +52751,9 @@ var ZodPlugin = class {
52620
52751
  };
52621
52752
 
52622
52753
  // src/indexer/plugins/integration/validation/pydantic/index.ts
52623
- import { createRequire as createRequire18 } from "module";
52624
52754
  import fs67 from "fs";
52625
52755
  import path79 from "path";
52626
52756
  import { ok as ok53, err as err30 } from "neverthrow";
52627
- var require19 = createRequire18(import.meta.url);
52628
- var Parser18 = require19("tree-sitter");
52629
- var PythonGrammar6 = require19("tree-sitter-python");
52630
- var parserInstance12 = null;
52631
- function getParser15() {
52632
- if (!parserInstance12) {
52633
- parserInstance12 = new Parser18();
52634
- parserInstance12.setLanguage(PythonGrammar6);
52635
- }
52636
- return parserInstance12;
52637
- }
52638
52757
  function hasPythonDep5(rootPath, depName) {
52639
52758
  for (const reqFile of ["requirements.txt", "requirements/base.txt", "requirements/prod.txt"]) {
52640
52759
  try {
@@ -52954,7 +53073,7 @@ var PydanticPlugin = class {
52954
53073
  ]
52955
53074
  };
52956
53075
  }
52957
- extractNodes(filePath, content, language) {
53076
+ async extractNodes(filePath, content, language) {
52958
53077
  if (language !== "python") {
52959
53078
  return ok53({ status: "ok", symbols: [] });
52960
53079
  }
@@ -52966,7 +53085,7 @@ var PydanticPlugin = class {
52966
53085
  };
52967
53086
  let tree;
52968
53087
  try {
52969
- const parser = getParser15();
53088
+ const parser = await getParser("python");
52970
53089
  tree = parser.parse(source);
52971
53090
  } catch (e) {
52972
53091
  return err30(parseError(filePath, `tree-sitter parse failed: ${e}`));
@@ -53492,21 +53611,9 @@ var TestingPlugin = class {
53492
53611
  };
53493
53612
 
53494
53613
  // src/indexer/plugins/integration/tooling/celery/index.ts
53495
- import { createRequire as createRequire19 } from "module";
53496
53614
  import fs70 from "fs";
53497
53615
  import path82 from "path";
53498
53616
  import { ok as ok55, err as err31 } from "neverthrow";
53499
- var require20 = createRequire19(import.meta.url);
53500
- var Parser19 = require20("tree-sitter");
53501
- var PythonGrammar7 = require20("tree-sitter-python");
53502
- var parserInstance13 = null;
53503
- function getParser16() {
53504
- if (!parserInstance13) {
53505
- parserInstance13 = new Parser19();
53506
- parserInstance13.setLanguage(PythonGrammar7);
53507
- }
53508
- return parserInstance13;
53509
- }
53510
53617
  function hasPythonDep6(rootPath, depName) {
53511
53618
  for (const reqFile of ["requirements.txt", "requirements/base.txt", "requirements/prod.txt"]) {
53512
53619
  try {
@@ -53684,7 +53791,7 @@ var CeleryPlugin = class {
53684
53791
  ]
53685
53792
  };
53686
53793
  }
53687
- extractNodes(filePath, content, language) {
53794
+ async extractNodes(filePath, content, language) {
53688
53795
  if (language !== "python") {
53689
53796
  return ok55({ status: "ok", symbols: [] });
53690
53797
  }
@@ -53697,7 +53804,7 @@ var CeleryPlugin = class {
53697
53804
  };
53698
53805
  let tree;
53699
53806
  try {
53700
- const parser = getParser16();
53807
+ const parser = await getParser("python");
53701
53808
  tree = parser.parse(source);
53702
53809
  } catch (e) {
53703
53810
  return err31(parseError(filePath, `tree-sitter parse failed: ${e}`));
@@ -55319,6 +55426,7 @@ import path86 from "path";
55319
55426
  var TREE_SITTER_PACKAGES = [
55320
55427
  "tree-sitter",
55321
55428
  "web-tree-sitter",
55429
+ "tree-sitter-wasms",
55322
55430
  "tree-sitter-typescript",
55323
55431
  "tree-sitter-javascript",
55324
55432
  "tree-sitter-python",
@@ -57667,6 +57775,31 @@ var ROOT_MARKERS = [
57667
57775
  "build.gradle",
57668
57776
  "build.gradle.kts"
57669
57777
  ];
57778
+ var SKIP_DIRS2 = /* @__PURE__ */ new Set([".git", "node_modules", "vendor", ".svn", "__pycache__", ".tox"]);
57779
+ function discoverChildProjects(parentDir) {
57780
+ const absParent = path100.resolve(parentDir);
57781
+ if (!fs87.existsSync(absParent)) return [];
57782
+ let entries;
57783
+ try {
57784
+ entries = fs87.readdirSync(absParent, { withFileTypes: true });
57785
+ } catch {
57786
+ return [];
57787
+ }
57788
+ const children = [];
57789
+ for (const entry of entries) {
57790
+ if (!entry.isDirectory()) continue;
57791
+ if (entry.name.startsWith(".")) continue;
57792
+ if (SKIP_DIRS2.has(entry.name)) continue;
57793
+ const childDir = path100.join(absParent, entry.name);
57794
+ for (const marker of ROOT_MARKERS) {
57795
+ if (fs87.existsSync(path100.join(childDir, marker))) {
57796
+ children.push(childDir);
57797
+ break;
57798
+ }
57799
+ }
57800
+ }
57801
+ return children.sort();
57802
+ }
57670
57803
  function findProjectRoot(from) {
57671
57804
  let dir = path100.resolve(from ?? process.cwd());
57672
57805
  while (true) {
@@ -57939,10 +58072,10 @@ function saveRegistry(reg) {
57939
58072
  fs88.writeFileSync(tmp, JSON.stringify(reg, null, 2) + "\n");
57940
58073
  fs88.renameSync(tmp, REGISTRY_PATH);
57941
58074
  }
57942
- function registerProject(root) {
58075
+ function registerProject(root, opts) {
57943
58076
  const absRoot = path101.resolve(root);
57944
58077
  const reg = loadRegistry2();
57945
- if (reg.projects[absRoot]) {
58078
+ if (reg.projects[absRoot] && !opts) {
57946
58079
  return reg.projects[absRoot];
57947
58080
  }
57948
58081
  const entry = {
@@ -57950,12 +58083,30 @@ function registerProject(root) {
57950
58083
  root: absRoot,
57951
58084
  dbPath: getDbPath(absRoot),
57952
58085
  lastIndexed: null,
57953
- addedAt: (/* @__PURE__ */ new Date()).toISOString()
58086
+ addedAt: (/* @__PURE__ */ new Date()).toISOString(),
58087
+ ...opts?.type && { type: opts.type },
58088
+ ...opts?.children && { children: opts.children }
57954
58089
  };
57955
58090
  reg.projects[absRoot] = entry;
57956
58091
  saveRegistry(reg);
57957
58092
  return entry;
57958
58093
  }
58094
+ function findParentProject(childRoot) {
58095
+ const absChild = path101.resolve(childRoot);
58096
+ const reg = loadRegistry2();
58097
+ for (const entry of Object.values(reg.projects)) {
58098
+ if (entry.type === "multi-root" && entry.children?.includes(absChild)) {
58099
+ return entry;
58100
+ }
58101
+ }
58102
+ return null;
58103
+ }
58104
+ function unregisterProject(root) {
58105
+ const absRoot = path101.resolve(root);
58106
+ const reg = loadRegistry2();
58107
+ delete reg.projects[absRoot];
58108
+ saveRegistry(reg);
58109
+ }
57959
58110
  function getProject(root) {
57960
58111
  const absRoot = path101.resolve(root);
57961
58112
  const reg = loadRegistry2();
@@ -58168,21 +58319,25 @@ var initCommand = new Command("init").description("One-time global setup: config
58168
58319
  steps.push({ target: proj.root, action: "skipped", detail: "Config load failed" });
58169
58320
  continue;
58170
58321
  }
58171
- const dbPath = getDbPath(proj.root);
58172
- const db = initializeDatabase(dbPath);
58173
- const store = new Store(db);
58174
- const registry = new PluginRegistry();
58175
- for (const lp of createAllLanguagePlugins()) registry.registerLanguagePlugin(lp);
58176
- for (const fp of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(fp);
58177
- const pipeline = new IndexingPipeline(store, registry, configResult.value, proj.root);
58178
- const result = await pipeline.indexAll(true);
58179
- steps.push({
58180
- target: proj.root,
58181
- action: "updated",
58182
- detail: `Upgraded: ${result.indexed} files, ${result.skipped} skipped, ${result.errors} errors`
58183
- });
58184
- updateLastIndexed(proj.root);
58185
- db.close();
58322
+ try {
58323
+ const dbPath = getDbPath(proj.root);
58324
+ const db = initializeDatabase(dbPath);
58325
+ const store = new Store(db);
58326
+ const registry = new PluginRegistry();
58327
+ for (const lp of createAllLanguagePlugins()) registry.registerLanguagePlugin(lp);
58328
+ for (const fp of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(fp);
58329
+ const pipeline = new IndexingPipeline(store, registry, configResult.value, proj.root);
58330
+ const result = await pipeline.indexAll(true);
58331
+ steps.push({
58332
+ target: proj.root,
58333
+ action: "updated",
58334
+ detail: `Upgraded: ${result.indexed} files, ${result.skipped} skipped, ${result.errors} errors`
58335
+ });
58336
+ updateLastIndexed(proj.root);
58337
+ db.close();
58338
+ } catch (err32) {
58339
+ steps.push({ target: proj.root, action: "skipped", detail: `Upgrade failed: ${err32.message}` });
58340
+ }
58186
58341
  }
58187
58342
  spin?.stop("Upgrade complete");
58188
58343
  }
@@ -58243,11 +58398,17 @@ function executeSteps(steps, opts) {
58243
58398
  }
58244
58399
  }
58245
58400
  function registerAndIndexProject(dir, opts) {
58246
- let projectRoot;
58401
+ let projectRoot = null;
58247
58402
  try {
58248
58403
  projectRoot = findProjectRoot(dir);
58249
58404
  } catch {
58250
- return { target: dir, action: "skipped", detail: "Could not detect project root" };
58405
+ }
58406
+ if (!projectRoot) {
58407
+ const childRoots = discoverChildProjects(dir);
58408
+ if (childRoots.length === 0) {
58409
+ return { target: dir, action: "skipped", detail: "Could not detect project root or child projects" };
58410
+ }
58411
+ return registerMultiRootProject(dir, childRoots, opts);
58251
58412
  }
58252
58413
  if (opts.dryRun) {
58253
58414
  return { target: projectRoot, action: "skipped", detail: "Would register and index project" };
@@ -58273,6 +58434,52 @@ function registerAndIndexProject(dir, opts) {
58273
58434
  detail: `Registered project: ${entry.name}`
58274
58435
  };
58275
58436
  }
58437
+ function registerMultiRootProject(parentDir, childRoots, opts) {
58438
+ if (opts.dryRun) {
58439
+ return {
58440
+ target: parentDir,
58441
+ action: "skipped",
58442
+ detail: `Would register multi-root with ${childRoots.length} children: ${childRoots.map((r) => path102.basename(r)).join(", ")}`
58443
+ };
58444
+ }
58445
+ const existing = getProject(parentDir);
58446
+ if (existing && !opts.force) {
58447
+ return { target: parentDir, action: "already_configured", detail: `Multi-root already registered: ${existing.name}` };
58448
+ }
58449
+ const allInclude = [];
58450
+ const allExclude = [];
58451
+ for (const childRoot of childRoots) {
58452
+ const relPath = path102.relative(parentDir, childRoot).replace(/\\/g, "/");
58453
+ const detection = detectProject(childRoot);
58454
+ const config = generateConfig(detection);
58455
+ for (const pattern of config.include) allInclude.push(`${relPath}/${pattern}`);
58456
+ for (const pattern of config.exclude) allExclude.push(`${relPath}/${pattern}`);
58457
+ }
58458
+ const allProjects = listProjects();
58459
+ const parentPrefix = parentDir + path102.sep;
58460
+ for (const proj of allProjects) {
58461
+ if (proj.root !== parentDir && proj.root.startsWith(parentPrefix)) {
58462
+ if (fs89.existsSync(proj.dbPath)) fs89.unlinkSync(proj.dbPath);
58463
+ unregisterProject(proj.root);
58464
+ removeProjectConfig(proj.root);
58465
+ }
58466
+ }
58467
+ saveProjectConfig(parentDir, {
58468
+ root: ".",
58469
+ include: allInclude,
58470
+ exclude: allExclude,
58471
+ children: childRoots
58472
+ });
58473
+ const dbPath = getDbPath(parentDir);
58474
+ const db = initializeDatabase(dbPath);
58475
+ db.close();
58476
+ const entry = registerProject(parentDir, { type: "multi-root", children: childRoots });
58477
+ return {
58478
+ target: parentDir,
58479
+ action: existing ? "updated" : "created",
58480
+ detail: `Registered multi-root (${childRoots.length} children): ${childRoots.map((r) => path102.basename(r)).join(", ")}`
58481
+ };
58482
+ }
58276
58483
  function formatClientName(name) {
58277
58484
  const names = {
58278
58485
  "claude-code": "Claude Code",
@@ -58328,29 +58535,34 @@ var upgradeCommand = new Command2("upgrade").description("Upgrade trace-mcp: run
58328
58535
  const dbPath = getDbPath(projectRoot);
58329
58536
  ensureGlobalDirs();
58330
58537
  if (!opts.dryRun) {
58331
- const db = initializeDatabase(dbPath);
58332
- const store = new Store(db);
58333
- const versionRow = db.prepare("SELECT value FROM schema_meta WHERE key = ?").get("schema_version");
58334
- const currentVersion = versionRow ? parseInt(versionRow.value, 10) : 0;
58335
- steps.push({
58336
- target: dbPath,
58337
- action: "updated",
58338
- detail: `Schema v${currentVersion}`
58339
- });
58340
- if (!opts.skipReindex) {
58341
- const registry = new PluginRegistry();
58342
- for (const p4 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p4);
58343
- for (const p4 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p4);
58344
- const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
58345
- const result = await pipeline.indexAll(true);
58538
+ try {
58539
+ const db = initializeDatabase(dbPath);
58540
+ const store = new Store(db);
58541
+ const versionRow = db.prepare("SELECT value FROM schema_meta WHERE key = ?").get("schema_version");
58542
+ const currentVersion = versionRow ? parseInt(versionRow.value, 10) : 0;
58346
58543
  steps.push({
58347
- target: projectRoot,
58544
+ target: dbPath,
58348
58545
  action: "updated",
58349
- detail: `Reindexed: ${result.indexed} files, ${result.skipped} skipped, ${result.errors} errors`
58546
+ detail: `Schema v${currentVersion}`
58350
58547
  });
58351
- updateLastIndexed(projectRoot);
58548
+ if (!opts.skipReindex) {
58549
+ const registry = new PluginRegistry();
58550
+ for (const p4 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p4);
58551
+ for (const p4 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p4);
58552
+ const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
58553
+ const result = await pipeline.indexAll(true);
58554
+ steps.push({
58555
+ target: projectRoot,
58556
+ action: "updated",
58557
+ detail: `Reindexed: ${result.indexed} files, ${result.skipped} skipped, ${result.errors} errors`
58558
+ });
58559
+ updateLastIndexed(projectRoot);
58560
+ }
58561
+ db.close();
58562
+ } catch (err32) {
58563
+ logger.error({ error: err32.message, project: projectRoot }, "Upgrade failed");
58564
+ steps.push({ target: projectRoot, action: "skipped", detail: `Upgrade failed: ${err32.message}` });
58352
58565
  }
58353
- db.close();
58354
58566
  } else {
58355
58567
  steps.push({ target: dbPath, action: "skipped", detail: "Would run migrations" });
58356
58568
  if (!opts.skipReindex) {
@@ -58408,8 +58620,15 @@ var addCommand = new Command3("add").description("Register a project for indexin
58408
58620
  let projectRoot;
58409
58621
  try {
58410
58622
  projectRoot = findProjectRoot(resolvedDir);
58411
- } catch (e) {
58412
- console.error(e instanceof Error ? e.message : String(e));
58623
+ } catch {
58624
+ const children = discoverChildProjects(resolvedDir);
58625
+ if (children.length > 0) {
58626
+ await handleMultiRoot(resolvedDir, children, opts);
58627
+ return;
58628
+ }
58629
+ console.error(
58630
+ `Could not find project root from ${resolvedDir}, and no child projects discovered in subdirectories.`
58631
+ );
58413
58632
  process.exit(1);
58414
58633
  }
58415
58634
  const isInteractive = !opts.json;
@@ -58419,6 +58638,20 @@ var addCommand = new Command3("add").description("Register a project for indexin
58419
58638
  p2.note(`Detected project root: ${projectRoot}`, "Root");
58420
58639
  }
58421
58640
  }
58641
+ const parentEntry = findParentProject(projectRoot);
58642
+ if (parentEntry && !opts.force) {
58643
+ if (opts.json) {
58644
+ console.log(JSON.stringify({ status: "child_of_multi_root", parent: parentEntry }));
58645
+ } else {
58646
+ p2.note(
58647
+ `This project is already part of multi-root index: ${parentEntry.name}
58648
+ Root: ${parentEntry.root}`,
58649
+ "Multi-root"
58650
+ );
58651
+ p2.outro("Use --force to register it separately.");
58652
+ }
58653
+ return;
58654
+ }
58422
58655
  const existing = getProject(projectRoot);
58423
58656
  if (existing && !opts.force) {
58424
58657
  if (opts.json) {
@@ -58486,6 +58719,104 @@ DB: ${shortPath4(existing.dbPath)}`, "Existing");
58486
58719
  p2.outro("Project registered. It will be indexed when trace-mcp serve starts.");
58487
58720
  }
58488
58721
  });
58722
+ async function handleMultiRoot(parentDir, childRoots, opts) {
58723
+ const isInteractive = !opts.json;
58724
+ if (isInteractive) {
58725
+ p2.intro("trace-mcp add (multi-root)");
58726
+ p2.note(
58727
+ `No project root markers in ${parentDir}
58728
+ Discovered ${childRoots.length} child project(s):
58729
+ ` + childRoots.map((r) => ` ${path104.basename(r)}`).join("\n"),
58730
+ "Multi-root"
58731
+ );
58732
+ }
58733
+ const existing = getProject(parentDir);
58734
+ if (existing && !opts.force) {
58735
+ if (opts.json) {
58736
+ console.log(JSON.stringify({ status: "already_registered", project: existing }));
58737
+ } else {
58738
+ p2.note(`Already registered as multi-root: ${existing.name}`, "Existing");
58739
+ p2.outro("Use --force to re-register.");
58740
+ }
58741
+ return;
58742
+ }
58743
+ const mergedInclude = [];
58744
+ const mergedExclude = [];
58745
+ const allLanguages = /* @__PURE__ */ new Set();
58746
+ const allFrameworks = /* @__PURE__ */ new Set();
58747
+ for (const childRoot of childRoots) {
58748
+ const relPath = path104.relative(parentDir, childRoot).replace(/\\/g, "/");
58749
+ const detection = detectProject(childRoot);
58750
+ const config = generateConfig(detection);
58751
+ for (const pattern of config.include) {
58752
+ mergedInclude.push(`${relPath}/${pattern}`);
58753
+ }
58754
+ for (const pattern of config.exclude) {
58755
+ mergedExclude.push(`${relPath}/${pattern}`);
58756
+ }
58757
+ for (const lang of detection.languages) allLanguages.add(lang);
58758
+ for (const fw of detection.frameworks) allFrameworks.add(fw.name);
58759
+ }
58760
+ if (isInteractive) {
58761
+ const detectedLines = [];
58762
+ if (allLanguages.size > 0) {
58763
+ detectedLines.push(`Languages: ${[...allLanguages].join(", ")}`);
58764
+ }
58765
+ if (allFrameworks.size > 0) {
58766
+ detectedLines.push(`Frameworks: ${[...allFrameworks].join(", ")}`);
58767
+ }
58768
+ if (detectedLines.length > 0) {
58769
+ p2.note(detectedLines.join("\n"), "Detected (all children)");
58770
+ }
58771
+ }
58772
+ const allProjects = listProjects();
58773
+ const cleaned = [];
58774
+ for (const proj of allProjects) {
58775
+ if (proj.root.startsWith(parentDir + path104.sep) || proj.root.startsWith(parentDir + "/")) {
58776
+ if (fs91.existsSync(proj.dbPath)) {
58777
+ fs91.unlinkSync(proj.dbPath);
58778
+ }
58779
+ unregisterProject(proj.root);
58780
+ removeProjectConfig(proj.root);
58781
+ cleaned.push(path104.basename(proj.root));
58782
+ }
58783
+ }
58784
+ if (isInteractive && cleaned.length > 0) {
58785
+ p2.note(`Removed individual indexes: ${cleaned.join(", ")}`, "Cleanup");
58786
+ }
58787
+ ensureGlobalDirs();
58788
+ const configForSave = {
58789
+ root: ".",
58790
+ include: mergedInclude,
58791
+ exclude: mergedExclude,
58792
+ children: childRoots
58793
+ };
58794
+ saveProjectConfig(parentDir, configForSave);
58795
+ const dbPath = getDbPath(parentDir);
58796
+ const db = initializeDatabase(dbPath);
58797
+ db.close();
58798
+ const entry = registerProject(parentDir, {
58799
+ type: "multi-root",
58800
+ children: childRoots
58801
+ });
58802
+ if (opts.json) {
58803
+ console.log(JSON.stringify({
58804
+ status: existing ? "re-registered" : "registered",
58805
+ type: "multi-root",
58806
+ project: entry,
58807
+ children: childRoots.map((r) => path104.basename(r)),
58808
+ cleaned
58809
+ }, null, 2));
58810
+ } else {
58811
+ const lines = [];
58812
+ lines.push(`Project: ${entry.name} (multi-root)`);
58813
+ lines.push(`Root: ${parentDir}`);
58814
+ lines.push(`DB: ${shortPath4(dbPath)}`);
58815
+ lines.push(`Children: ${childRoots.map((r) => path104.basename(r)).join(", ")}`);
58816
+ p2.note(lines.join("\n"), existing ? "Re-registered" : "Registered");
58817
+ p2.outro("Multi-root project registered. It will be indexed when trace-mcp serve starts.");
58818
+ }
58819
+ }
58489
58820
  function shortPath4(p4) {
58490
58821
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
58491
58822
  if (home && p4.startsWith(home)) return "~" + p4.slice(home.length);
@@ -59598,7 +59929,7 @@ analyticsCommand.command("trends").description("Show daily usage trends: tokens,
59598
59929
  });
59599
59930
 
59600
59931
  // src/cli.ts
59601
- var PKG_VERSION2 = true ? "1.5.4" : "0.0.0-dev";
59932
+ var PKG_VERSION2 = true ? "1.6.1" : "0.0.0-dev";
59602
59933
  function registerDefaultPlugins(registry) {
59603
59934
  for (const p4 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p4);
59604
59935
  for (const p4 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p4);