@vohongtho.infotech/code-intel 0.7.0 → 0.9.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'module';
2
2
  import { fileURLToPath } from 'url';
3
- import path29 from 'path';
4
- import fs23, { existsSync } from 'fs';
3
+ import path31 from 'path';
4
+ import fs24, { existsSync } from 'fs';
5
5
  import { Parser, Language, Query } from 'web-tree-sitter';
6
6
  import { NodeSDK } from '@opentelemetry/sdk-node';
7
7
  import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
@@ -11,7 +11,8 @@ import { SEMRESATTRS_DEPLOYMENT_ENVIRONMENT, SEMRESATTRS_SERVICE_NAME } from '@o
11
11
  import { trace, context, SpanStatusCode } from '@opentelemetry/api';
12
12
  import winston from 'winston';
13
13
  import DailyRotateFile from 'winston-daily-rotate-file';
14
- import os12 from 'os';
14
+ import os13 from 'os';
15
+ import { execSync } from 'child_process';
15
16
  import Database3 from 'better-sqlite3';
16
17
  import bcrypt from 'bcrypt';
17
18
  import crypto5 from 'crypto';
@@ -24,7 +25,6 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
24
25
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
25
26
  import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
26
27
  import { Database, Connection } from '@ladybugdb/core';
27
- import { execSync } from 'child_process';
28
28
  import express from 'express';
29
29
  import compression from 'compression';
30
30
  import cors from 'cors';
@@ -126,11 +126,11 @@ var init_shared = __esm({
126
126
  }
127
127
  });
128
128
  function findBundledWasmDir() {
129
- const fileDir = path29.dirname(fileURLToPath(import.meta.url));
129
+ const fileDir = path31.dirname(fileURLToPath(import.meta.url));
130
130
  const candidates = [
131
- path29.join(fileDir, "wasm"),
131
+ path31.join(fileDir, "wasm"),
132
132
  // dist/index.js → dist/wasm/
133
- path29.join(fileDir, "../wasm")
133
+ path31.join(fileDir, "../wasm")
134
134
  // dist/cli/main.js → dist/wasm/
135
135
  ];
136
136
  for (const candidate of candidates) {
@@ -171,7 +171,7 @@ function wasmPath(lang) {
171
171
  }
172
172
  const bundled = BUNDLED_WASM_MAP[lang];
173
173
  if (bundled) {
174
- const bundledPath = path29.join(_bundledWasmDir, bundled);
174
+ const bundledPath = path31.join(_bundledWasmDir, bundled);
175
175
  if (existsSync(bundledPath)) return bundledPath;
176
176
  }
177
177
  return null;
@@ -184,14 +184,14 @@ async function initParser() {
184
184
  }
185
185
  async function getLanguage(lang) {
186
186
  if (languageCache.has(lang)) return languageCache.get(lang);
187
- const path30 = wasmPath(lang);
188
- if (!path30) {
187
+ const path32 = wasmPath(lang);
188
+ if (!path32) {
189
189
  languageCache.set(lang, null);
190
190
  return null;
191
191
  }
192
192
  try {
193
193
  await initParser();
194
- const language = await Language.load(path30);
194
+ const language = await Language.load(path32);
195
195
  languageCache.set(lang, language);
196
196
  return language;
197
197
  } catch {
@@ -1162,7 +1162,7 @@ var init_logger = __esm({
1162
1162
  };
1163
1163
  }
1164
1164
  /** Global log directory: ~/.code-intel/logs */
1165
- static LOG_DIR = path29.join(os12.homedir(), ".code-intel", "logs");
1165
+ static LOG_DIR = path31.join(os13.homedir(), ".code-intel", "logs");
1166
1166
  static getLogger() {
1167
1167
  if (!_Logger.instance) {
1168
1168
  const isProduction = process.env.NODE_ENV === "production";
@@ -1171,12 +1171,12 @@ var init_logger = __esm({
1171
1171
  transports.push(new winston.transports.Console());
1172
1172
  if (!isProduction) {
1173
1173
  try {
1174
- if (!fs23.existsSync(_Logger.LOG_DIR)) {
1175
- fs23.mkdirSync(_Logger.LOG_DIR, { recursive: true });
1174
+ if (!fs24.existsSync(_Logger.LOG_DIR)) {
1175
+ fs24.mkdirSync(_Logger.LOG_DIR, { recursive: true });
1176
1176
  }
1177
1177
  transports.push(
1178
1178
  new DailyRotateFile({
1179
- filename: path29.join(_Logger.LOG_DIR, "%DATE%-code-intel.log"),
1179
+ filename: path31.join(_Logger.LOG_DIR, "%DATE%-code-intel.log"),
1180
1180
  datePattern: "YYYY-MM-DD",
1181
1181
  maxSize: "20m",
1182
1182
  maxFiles: "14d"
@@ -1961,7 +1961,7 @@ var init_parse_phase = __esm({
1961
1961
  const batch = filePaths.slice(i, i + CONCURRENCY);
1962
1962
  await Promise.all(batch.map(async (filePath) => {
1963
1963
  try {
1964
- const source = await fs23.promises.readFile(filePath, "utf-8");
1964
+ const source = await fs24.promises.readFile(filePath, "utf-8");
1965
1965
  context2.fileCache.set(filePath, source);
1966
1966
  } catch {
1967
1967
  }
@@ -1974,14 +1974,14 @@ var init_parse_phase = __esm({
1974
1974
  const lang = detectLanguage(filePath);
1975
1975
  if (!lang) {
1976
1976
  if (context2.verbose) {
1977
- const relativePath2 = path29.relative(context2.workspaceRoot, filePath);
1977
+ const relativePath2 = path31.relative(context2.workspaceRoot, filePath);
1978
1978
  logger_default.info(` [parse] skipped (no parser): ${relativePath2}`);
1979
1979
  }
1980
1980
  continue;
1981
1981
  }
1982
1982
  const source = context2.fileCache.get(filePath);
1983
1983
  if (!source) continue;
1984
- const relativePath = path29.relative(context2.workspaceRoot, filePath);
1984
+ const relativePath = path31.relative(context2.workspaceRoot, filePath);
1985
1985
  const fileNodeId = generateNodeId("file", relativePath, relativePath);
1986
1986
  const fileNode = context2.graph.getNode(fileNodeId);
1987
1987
  if (fileNode) {
@@ -2221,11 +2221,11 @@ var init_resolve_phase = __esm({
2221
2221
  let heritageEdges = 0;
2222
2222
  const fileIndex = /* @__PURE__ */ new Map();
2223
2223
  for (const fp of filePaths) {
2224
- const rel = path29.relative(workspaceRoot, fp);
2224
+ const rel = path31.relative(workspaceRoot, fp);
2225
2225
  fileIndex.set(rel, fp);
2226
2226
  const noExt = rel.replace(/\.\w+$/, "");
2227
2227
  if (!fileIndex.has(noExt)) fileIndex.set(noExt, fp);
2228
- const base = path29.basename(rel, path29.extname(rel));
2228
+ const base = path31.basename(rel, path31.extname(rel));
2229
2229
  if (!fileIndex.has(base)) fileIndex.set(base, fp);
2230
2230
  }
2231
2231
  const symbolIndex = /* @__PURE__ */ new Map();
@@ -2256,7 +2256,7 @@ var init_resolve_phase = __esm({
2256
2256
  for (const filePath of filePaths) {
2257
2257
  const lang = detectLanguage(filePath);
2258
2258
  if (!lang) continue;
2259
- const relativePath = path29.relative(workspaceRoot, filePath);
2259
+ const relativePath = path31.relative(workspaceRoot, filePath);
2260
2260
  const fileNodeId = generateNodeId("file", relativePath, relativePath);
2261
2261
  const source = fileCache.get(filePath);
2262
2262
  if (!source) continue;
@@ -2269,13 +2269,13 @@ var init_resolve_phase = __esm({
2269
2269
  let resolvedRelPath = null;
2270
2270
  if (cleaned.startsWith(".")) {
2271
2271
  const cleanedNoJs = cleaned.replace(/\.(js|jsx)$/, "");
2272
- const fromDir = path29.dirname(relativePath);
2272
+ const fromDir = path31.dirname(relativePath);
2273
2273
  for (const ext of ["", ".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go", "/index.ts", "/index.js"]) {
2274
- const candidate = path29.join(fromDir, cleanedNoJs + ext);
2275
- const normalized = path29.normalize(candidate);
2274
+ const candidate = path31.join(fromDir, cleanedNoJs + ext);
2275
+ const normalized = path31.normalize(candidate);
2276
2276
  if (fileIndex.has(normalized)) {
2277
2277
  const absPath = fileIndex.get(normalized);
2278
- resolvedRelPath = path29.relative(workspaceRoot, absPath);
2278
+ resolvedRelPath = path31.relative(workspaceRoot, absPath);
2279
2279
  break;
2280
2280
  }
2281
2281
  }
@@ -2589,27 +2589,27 @@ __export(group_registry_exports, {
2589
2589
  saveSyncResult: () => saveSyncResult
2590
2590
  });
2591
2591
  function groupFile(name) {
2592
- return path29.join(GROUPS_DIR, `${name}.json`);
2592
+ return path31.join(GROUPS_DIR, `${name}.json`);
2593
2593
  }
2594
2594
  function loadGroup(name) {
2595
2595
  try {
2596
- return JSON.parse(fs23.readFileSync(groupFile(name), "utf-8"));
2596
+ return JSON.parse(fs24.readFileSync(groupFile(name), "utf-8"));
2597
2597
  } catch {
2598
2598
  return null;
2599
2599
  }
2600
2600
  }
2601
2601
  function saveGroup(group) {
2602
- fs23.mkdirSync(GROUPS_DIR, { recursive: true });
2603
- fs23.writeFileSync(groupFile(group.name), JSON.stringify(group, null, 2) + "\n");
2602
+ fs24.mkdirSync(GROUPS_DIR, { recursive: true });
2603
+ fs24.writeFileSync(groupFile(group.name), JSON.stringify(group, null, 2) + "\n");
2604
2604
  }
2605
2605
  function listGroups() {
2606
2606
  const groups = [];
2607
2607
  try {
2608
- for (const file of fs23.readdirSync(GROUPS_DIR)) {
2608
+ for (const file of fs24.readdirSync(GROUPS_DIR)) {
2609
2609
  if (!file.endsWith(".json") || file.endsWith(".sync.json")) continue;
2610
2610
  try {
2611
2611
  const g = JSON.parse(
2612
- fs23.readFileSync(path29.join(GROUPS_DIR, file), "utf-8")
2612
+ fs24.readFileSync(path31.join(GROUPS_DIR, file), "utf-8")
2613
2613
  );
2614
2614
  groups.push(g);
2615
2615
  } catch {
@@ -2621,16 +2621,16 @@ function listGroups() {
2621
2621
  }
2622
2622
  function deleteGroup(name) {
2623
2623
  try {
2624
- fs23.unlinkSync(groupFile(name));
2624
+ fs24.unlinkSync(groupFile(name));
2625
2625
  } catch {
2626
2626
  }
2627
2627
  try {
2628
- fs23.unlinkSync(path29.join(GROUPS_DIR, `${name}.sync.json`));
2628
+ fs24.unlinkSync(path31.join(GROUPS_DIR, `${name}.sync.json`));
2629
2629
  } catch {
2630
2630
  }
2631
2631
  }
2632
2632
  function groupExists(name) {
2633
- return fs23.existsSync(groupFile(name));
2633
+ return fs24.existsSync(groupFile(name));
2634
2634
  }
2635
2635
  function addMember(groupName, member) {
2636
2636
  const group = loadGroup(groupName);
@@ -2656,16 +2656,16 @@ function removeMember(groupName, groupPath) {
2656
2656
  return group;
2657
2657
  }
2658
2658
  function saveSyncResult(result) {
2659
- fs23.mkdirSync(GROUPS_DIR, { recursive: true });
2660
- fs23.writeFileSync(
2661
- path29.join(GROUPS_DIR, `${result.groupName}.sync.json`),
2659
+ fs24.mkdirSync(GROUPS_DIR, { recursive: true });
2660
+ fs24.writeFileSync(
2661
+ path31.join(GROUPS_DIR, `${result.groupName}.sync.json`),
2662
2662
  JSON.stringify(result, null, 2) + "\n"
2663
2663
  );
2664
2664
  }
2665
2665
  function loadSyncResult(groupName) {
2666
2666
  try {
2667
2667
  return JSON.parse(
2668
- fs23.readFileSync(path29.join(GROUPS_DIR, `${groupName}.sync.json`), "utf-8")
2668
+ fs24.readFileSync(path31.join(GROUPS_DIR, `${groupName}.sync.json`), "utf-8")
2669
2669
  );
2670
2670
  } catch {
2671
2671
  return null;
@@ -2674,7 +2674,7 @@ function loadSyncResult(groupName) {
2674
2674
  var GROUPS_DIR;
2675
2675
  var init_group_registry = __esm({
2676
2676
  "src/multi-repo/group-registry.ts"() {
2677
- GROUPS_DIR = path29.join(os12.homedir(), ".code-intel", "groups");
2677
+ GROUPS_DIR = path31.join(os13.homedir(), ".code-intel", "groups");
2678
2678
  }
2679
2679
  });
2680
2680
 
@@ -2696,14 +2696,14 @@ function detectDeadCode(graph) {
2696
2696
  if (meta?.deprecated === true) continue;
2697
2697
  if (ENTRY_POINT_NAME_RE.test(node.name)) continue;
2698
2698
  if (entryPointIds.has(node.id)) continue;
2699
- let hasCallers = false;
2699
+ let hasCallers2 = false;
2700
2700
  for (const edge of graph.findEdgesTo(node.id)) {
2701
2701
  if (edge.kind === "calls") {
2702
- hasCallers = true;
2702
+ hasCallers2 = true;
2703
2703
  break;
2704
2704
  }
2705
2705
  }
2706
- if (hasCallers) continue;
2706
+ if (hasCallers2) continue;
2707
2707
  let hasImporters = false;
2708
2708
  for (const edge of graph.findEdgesTo(node.id)) {
2709
2709
  if (edge.kind === "imports") {
@@ -3702,11 +3702,554 @@ var init_gql_executor = __esm({
3702
3702
  }
3703
3703
  });
3704
3704
 
3705
- // src/errors/codes.ts
3705
+ // src/analysis/deprecated-detector.ts
3706
+ var deprecated_detector_exports = {};
3707
+ __export(deprecated_detector_exports, {
3708
+ DeprecatedDetector: () => DeprecatedDetector
3709
+ });
3710
+ var BUILTIN_DEPRECATED, DeprecatedDetector;
3711
+ var init_deprecated_detector = __esm({
3712
+ "src/analysis/deprecated-detector.ts"() {
3713
+ BUILTIN_DEPRECATED = [
3714
+ { pattern: "url.parse", message: "deprecated in Node.js v11.0.0 \u2014 use the WHATWG URL API instead" },
3715
+ { pattern: "url.resolve", message: "deprecated in Node.js v11.0.0 \u2014 use the WHATWG URL API instead" },
3716
+ { pattern: "url.format", message: "deprecated in Node.js v11.0.0 \u2014 use the WHATWG URL API instead" },
3717
+ { pattern: "fs.exists", message: "deprecated \u2014 use fs.access instead" },
3718
+ { pattern: "crypto.createCipher", message: "deprecated \u2014 use crypto.createCipheriv instead" },
3719
+ { pattern: "crypto.createDecipher", message: "deprecated \u2014 use crypto.createDecipheriv instead" },
3720
+ { pattern: "new Buffer()", message: "deprecated \u2014 use Buffer.from() instead" },
3721
+ { pattern: "domain.create", message: "deprecated \u2014 the domain module is discouraged" },
3722
+ { pattern: "process.binding", message: "deprecated internal API" }
3723
+ ];
3724
+ DeprecatedDetector = class {
3725
+ tagDeprecated(graph) {
3726
+ for (const node of graph.allNodes()) {
3727
+ if (!node.metadata) node.metadata = {};
3728
+ if (node.metadata["deprecated"] === true) continue;
3729
+ let message;
3730
+ const jsdoc = node.metadata["jsdoc"];
3731
+ const comment = node.metadata["comment"];
3732
+ if (jsdoc?.includes("@deprecated") || comment?.includes("@deprecated")) {
3733
+ const src = jsdoc ?? comment ?? "";
3734
+ const match = src.match(/@deprecated\s+(.*)/);
3735
+ message = match?.[1]?.trim() || "deprecated";
3736
+ }
3737
+ if (!message && node.metadata["deprecated"] === true) {
3738
+ message = node.metadata["deprecationMessage"] ?? "deprecated";
3739
+ }
3740
+ if (!message) {
3741
+ const annotations = node.metadata["annotations"];
3742
+ if (Array.isArray(annotations) && annotations.includes("Deprecated")) {
3743
+ message = "marked @Deprecated";
3744
+ }
3745
+ }
3746
+ if (!message) {
3747
+ const attributes = node.metadata["attributes"];
3748
+ if (Array.isArray(attributes) && attributes.includes("deprecated")) {
3749
+ message = "marked #[deprecated]";
3750
+ }
3751
+ }
3752
+ if (!message) {
3753
+ for (const entry of BUILTIN_DEPRECATED) {
3754
+ if (node.name === entry.pattern || node.name.includes(entry.pattern)) {
3755
+ message = entry.message;
3756
+ break;
3757
+ }
3758
+ }
3759
+ }
3760
+ if (message) {
3761
+ node.metadata["deprecated"] = true;
3762
+ node.metadata["deprecationMessage"] = message;
3763
+ }
3764
+ }
3765
+ }
3766
+ detect(graph, scope) {
3767
+ const findings = [];
3768
+ for (const node of graph.allNodes()) {
3769
+ if (!node.metadata?.["deprecated"]) continue;
3770
+ const callers = [];
3771
+ for (const edge of graph.findEdgesTo(node.id)) {
3772
+ if (edge.kind !== "calls" && edge.kind !== "deprecated_use") continue;
3773
+ const caller = graph.getNode(edge.source);
3774
+ if (!caller) continue;
3775
+ if (scope && !caller.filePath.includes(scope)) continue;
3776
+ callers.push({ name: caller.name, filePath: caller.filePath });
3777
+ const edgeId = `dep_use_${edge.source}_${node.id}`;
3778
+ if (!graph.getEdge(edgeId)) {
3779
+ graph.addEdge({ id: edgeId, source: edge.source, target: node.id, kind: "deprecated_use" });
3780
+ }
3781
+ }
3782
+ findings.push({
3783
+ symbol: node.name,
3784
+ filePath: node.filePath,
3785
+ deprecationMessage: node.metadata?.["deprecationMessage"] ?? "deprecated",
3786
+ callers
3787
+ });
3788
+ }
3789
+ return findings;
3790
+ }
3791
+ };
3792
+ }
3793
+ });
3794
+
3795
+ // src/analysis/complexity.ts
3796
+ var complexity_exports = {};
3797
+ __export(complexity_exports, {
3798
+ computeComplexity: () => computeComplexity
3799
+ });
3800
+ function getSeverity(cyclomatic) {
3801
+ if (cyclomatic <= 5) return "LOW";
3802
+ if (cyclomatic <= 10) return "MEDIUM";
3803
+ if (cyclomatic <= 20) return "HIGH";
3804
+ return "CRITICAL";
3805
+ }
3806
+ function computeComplexity(graph, scope) {
3807
+ const results = [];
3808
+ for (const node of graph.allNodes()) {
3809
+ if (node.kind !== "function" && node.kind !== "method") continue;
3810
+ if (scope && !node.filePath.startsWith(scope)) continue;
3811
+ let outgoingCalls = 0;
3812
+ for (const edge of graph.findEdgesFrom(node.id)) {
3813
+ if (edge.kind === "calls") outgoingCalls++;
3814
+ }
3815
+ let cyclomatic;
3816
+ const meta = node.metadata;
3817
+ const metaComplexity = meta?.complexity;
3818
+ if (typeof metaComplexity?.cyclomatic === "number") {
3819
+ cyclomatic = metaComplexity.cyclomatic;
3820
+ } else {
3821
+ cyclomatic = 1 + Math.floor(outgoingCalls / 2);
3822
+ }
3823
+ cyclomatic = Math.min(cyclomatic, 50);
3824
+ let cognitive;
3825
+ if (typeof metaComplexity?.cognitive === "number") {
3826
+ cognitive = metaComplexity.cognitive;
3827
+ } else {
3828
+ cognitive = Math.ceil(cyclomatic * 1.3);
3829
+ }
3830
+ results.push({
3831
+ nodeId: node.id,
3832
+ name: node.name,
3833
+ filePath: node.filePath,
3834
+ cyclomatic,
3835
+ cognitive,
3836
+ severity: getSeverity(cyclomatic)
3837
+ });
3838
+ }
3839
+ return results.sort((a, b) => b.cyclomatic - a.cyclomatic);
3840
+ }
3841
+ var init_complexity = __esm({
3842
+ "src/analysis/complexity.ts"() {
3843
+ }
3844
+ });
3845
+
3846
+ // src/analysis/test-coverage.ts
3847
+ var test_coverage_exports = {};
3848
+ __export(test_coverage_exports, {
3849
+ computeCoverage: () => computeCoverage
3850
+ });
3851
+ function isTestFile(filePath) {
3852
+ if (filePath.includes(".test.") || filePath.includes(".spec.")) return true;
3853
+ if (filePath.includes("_test.") || filePath.endsWith("_test.go")) return true;
3854
+ if (filePath.includes("__tests__")) return true;
3855
+ const base = path31.basename(filePath);
3856
+ if (base.startsWith("Test") && filePath.endsWith(".java")) return true;
3857
+ return false;
3858
+ }
3859
+ function computeBlastRadius(graph, nodeId) {
3860
+ const visited = /* @__PURE__ */ new Set();
3861
+ const queue = [{ id: nodeId, depth: 0 }];
3862
+ while (queue.length > 0) {
3863
+ const { id, depth } = queue.shift();
3864
+ if (visited.has(id)) continue;
3865
+ visited.add(id);
3866
+ if (depth >= 3) continue;
3867
+ for (const edge of graph.findEdgesTo(id)) {
3868
+ if (edge.kind === "calls" || edge.kind === "imports") {
3869
+ if (!visited.has(edge.source)) {
3870
+ queue.push({ id: edge.source, depth: depth + 1 });
3871
+ }
3872
+ }
3873
+ }
3874
+ }
3875
+ return Math.max(0, visited.size - 1);
3876
+ }
3877
+ function getRisk(blastRadius) {
3878
+ if (blastRadius > 20) return "HIGH";
3879
+ if (blastRadius >= 5) return "MEDIUM";
3880
+ return "LOW";
3881
+ }
3882
+ function computeCoverage(graph, scope) {
3883
+ const testFilePaths = /* @__PURE__ */ new Set();
3884
+ for (const node of graph.allNodes()) {
3885
+ if (isTestFile(node.filePath)) testFilePaths.add(node.filePath);
3886
+ }
3887
+ const nodesImportedByTests = /* @__PURE__ */ new Set();
3888
+ for (const edge of graph.findEdgesByKind("imports")) {
3889
+ const sourceNode = graph.getNode(edge.source);
3890
+ if (sourceNode && isTestFile(sourceNode.filePath)) {
3891
+ nodesImportedByTests.add(edge.target);
3892
+ }
3893
+ }
3894
+ const nodesWithTestedBy = /* @__PURE__ */ new Set();
3895
+ for (const edge of graph.findEdgesByKind("tested_by")) {
3896
+ nodesWithTestedBy.add(edge.source);
3897
+ }
3898
+ const baseNameToTestFiles = /* @__PURE__ */ new Map();
3899
+ for (const testPath of testFilePaths) {
3900
+ const base = path31.basename(testPath);
3901
+ const stripped = base.replace(/\.test\.[^.]+$/, "").replace(/\.spec\.[^.]+$/, "").replace(/_test\.[^.]+$/, "").replace(/_test$/, "");
3902
+ const existing = baseNameToTestFiles.get(stripped) ?? [];
3903
+ existing.push(testPath);
3904
+ baseNameToTestFiles.set(stripped, existing);
3905
+ }
3906
+ const exportedKinds = /* @__PURE__ */ new Set(["function", "method", "class"]);
3907
+ const results = [];
3908
+ for (const node of graph.allNodes()) {
3909
+ if (!exportedKinds.has(node.kind)) continue;
3910
+ if (node.exported !== true) continue;
3911
+ if (scope && !node.filePath.startsWith(scope)) continue;
3912
+ const testFiles = [];
3913
+ if (nodesWithTestedBy.has(node.id)) {
3914
+ for (const edge of graph.findEdgesFrom(node.id)) {
3915
+ if (edge.kind === "tested_by") {
3916
+ const testNode = graph.getNode(edge.target);
3917
+ if (testNode && !testFiles.includes(testNode.filePath)) {
3918
+ testFiles.push(testNode.filePath);
3919
+ }
3920
+ }
3921
+ }
3922
+ }
3923
+ if (nodesImportedByTests.has(node.id)) {
3924
+ for (const edge of graph.findEdgesTo(node.id)) {
3925
+ if (edge.kind === "imports") {
3926
+ const sourceNode = graph.getNode(edge.source);
3927
+ if (sourceNode && isTestFile(sourceNode.filePath) && !testFiles.includes(sourceNode.filePath)) {
3928
+ testFiles.push(sourceNode.filePath);
3929
+ }
3930
+ }
3931
+ }
3932
+ }
3933
+ const nodeBase = path31.basename(node.filePath).replace(/\.[^.]+$/, "");
3934
+ const matchingTestFiles = baseNameToTestFiles.get(nodeBase) ?? [];
3935
+ for (const tf of matchingTestFiles) {
3936
+ if (!testFiles.includes(tf)) testFiles.push(tf);
3937
+ }
3938
+ const tested = testFiles.length > 0;
3939
+ const blastRadius = computeBlastRadius(graph, node.id);
3940
+ const risk = getRisk(blastRadius);
3941
+ results.push({
3942
+ nodeId: node.id,
3943
+ name: node.name,
3944
+ filePath: node.filePath,
3945
+ exported: true,
3946
+ tested,
3947
+ testFiles,
3948
+ blastRadius,
3949
+ risk
3950
+ });
3951
+ }
3952
+ const totalExported = results.length;
3953
+ const testedExported = results.filter((r) => r.tested).length;
3954
+ const coveragePct = totalExported === 0 ? 100 : Math.round(testedExported / totalExported * 100);
3955
+ const untestedByRisk = results.filter((r) => !r.tested).sort((a, b) => b.blastRadius - a.blastRadius);
3956
+ return { totalExported, testedExported, coveragePct, untestedByRisk };
3957
+ }
3958
+ var init_test_coverage = __esm({
3959
+ "src/analysis/test-coverage.ts"() {
3960
+ }
3961
+ });
3962
+
3963
+ // src/security/secret-scanner.ts
3964
+ var secret_scanner_exports = {};
3965
+ __export(secret_scanner_exports, {
3966
+ SecretScanner: () => SecretScanner
3967
+ });
3968
+ function shannonEntropy(s) {
3969
+ const freq = /* @__PURE__ */ new Map();
3970
+ for (const c of s) freq.set(c, (freq.get(c) ?? 0) + 1);
3971
+ let entropy = 0;
3972
+ for (const count of freq.values()) {
3973
+ const p = count / s.length;
3974
+ entropy -= p * Math.log2(p);
3975
+ }
3976
+ return entropy;
3977
+ }
3978
+ function isTestFile2(filePath) {
3979
+ return filePath.includes(".test.") || filePath.includes(".spec.") || filePath.includes("fixtures/") || filePath.includes("mocks/");
3980
+ }
3981
+ var ENV_VAR_RE, SENSITIVE_NAME_RE, VALUE_PATTERNS, SecretScanner;
3982
+ var init_secret_scanner = __esm({
3983
+ "src/security/secret-scanner.ts"() {
3984
+ ENV_VAR_RE = /^process\.env\./;
3985
+ SENSITIVE_NAME_RE = /_SECRET$|_PASSWORD$|_TOKEN$|_KEY$|_API_KEY$/i;
3986
+ VALUE_PATTERNS = [
3987
+ [/sk-[A-Za-z0-9]{6,}/, "openai-api-key", "HIGH"],
3988
+ [/pk_live_[A-Za-z0-9]{20,}/, "stripe-key", "HIGH"],
3989
+ [/AKIA[0-9A-Z]{16}|aws.access.key/i, "aws-access-key", "HIGH"],
3990
+ [/xoxb-[0-9]{11}-[0-9]{11}-[A-Za-z0-9]{24}/, "slack-token", "HIGH"],
3991
+ [/postgres:\/\/[^@]+:[^@]+@/, "db-url-with-credentials", "HIGH"],
3992
+ [/mysql:\/\/[^@]+:[^@]+@/, "db-url-with-credentials", "HIGH"],
3993
+ [/-----BEGIN RSA PRIVATE KEY-----/, "rsa-private-key", "HIGH"]
3994
+ ];
3995
+ SecretScanner = class {
3996
+ scan(graph, options) {
3997
+ const findings = [];
3998
+ const includeTests = options?.includeTestFiles ?? false;
3999
+ const scope = options?.scope;
4000
+ const ignorePatterns = [...options?.ignorePatterns ?? []];
4001
+ if (options?.workspaceRoot) {
4002
+ try {
4003
+ const raw = fs24.readFileSync(path31.join(options.workspaceRoot, ".codeintelignore"), "utf-8");
4004
+ for (const line of raw.split("\n")) {
4005
+ const trimmed = line.trim();
4006
+ if (trimmed && !trimmed.startsWith("#")) ignorePatterns.push(trimmed);
4007
+ }
4008
+ } catch {
4009
+ }
4010
+ }
4011
+ for (const node of graph.allNodes()) {
4012
+ const filePath = node.filePath;
4013
+ if (scope && !filePath.startsWith(scope)) continue;
4014
+ if (!includeTests && isTestFile2(filePath)) continue;
4015
+ if (ignorePatterns.length > 0 && ignorePatterns.some((p) => filePath.includes(p))) continue;
4016
+ const meta = node.metadata;
4017
+ const rawValue = meta?.value ?? meta?.literalValue;
4018
+ if (typeof rawValue !== "string" || rawValue.trim() === "") continue;
4019
+ const value = rawValue.trim();
4020
+ if (ENV_VAR_RE.test(value)) continue;
4021
+ let matched = false;
4022
+ for (const [re, label, severity] of VALUE_PATTERNS) {
4023
+ if (re.test(value)) {
4024
+ node.metadata = {
4025
+ ...node.metadata ?? {},
4026
+ security: { secretRisk: true, secretPattern: label }
4027
+ };
4028
+ findings.push({
4029
+ file: filePath,
4030
+ line: node.startLine,
4031
+ symbol: node.name,
4032
+ pattern: label,
4033
+ severity
4034
+ });
4035
+ matched = true;
4036
+ break;
4037
+ }
4038
+ }
4039
+ if (matched) continue;
4040
+ if (SENSITIVE_NAME_RE.test(node.name)) {
4041
+ node.metadata = {
4042
+ ...node.metadata ?? {},
4043
+ security: { secretRisk: true, secretPattern: "sensitive-name-with-value" }
4044
+ };
4045
+ findings.push({
4046
+ file: filePath,
4047
+ line: node.startLine,
4048
+ symbol: node.name,
4049
+ pattern: "sensitive-name-with-value",
4050
+ severity: "MEDIUM"
4051
+ });
4052
+ continue;
4053
+ }
4054
+ if (SENSITIVE_NAME_RE.test(node.name) && value.length > 20 && shannonEntropy(value) > 4.5) {
4055
+ node.metadata = {
4056
+ ...node.metadata ?? {},
4057
+ security: { secretRisk: true, secretPattern: "high-entropy-string" }
4058
+ };
4059
+ findings.push({
4060
+ file: filePath,
4061
+ line: node.startLine,
4062
+ symbol: node.name,
4063
+ pattern: "high-entropy-string",
4064
+ severity: "MEDIUM"
4065
+ });
4066
+ }
4067
+ }
4068
+ return findings;
4069
+ }
4070
+ };
4071
+ }
4072
+ });
4073
+
4074
+ // src/security/vulnerability-detector.ts
4075
+ var vulnerability_detector_exports = {};
4076
+ __export(vulnerability_detector_exports, {
4077
+ VulnerabilityDetector: () => VulnerabilityDetector
4078
+ });
4079
+ function hasCallers(graph, nodeId) {
4080
+ for (const edge of graph.findEdgesTo(nodeId)) {
4081
+ if (edge.kind === "calls") return true;
4082
+ }
4083
+ return false;
4084
+ }
4085
+ var CWE, SQL_PATTERN, XSS_PATTERN, SSRF_PATTERN, PATH_PATTERN, CMD_PATTERN, VulnerabilityDetector;
4086
+ var init_vulnerability_detector = __esm({
4087
+ "src/security/vulnerability-detector.ts"() {
4088
+ CWE = {
4089
+ SQL_INJECTION: "CWE-89",
4090
+ XSS: "CWE-79",
4091
+ SSRF: "CWE-918",
4092
+ PATH_TRAVERSAL: "CWE-22",
4093
+ COMMAND_INJECTION: "CWE-78"
4094
+ };
4095
+ SQL_PATTERN = /(db|database|connection|knex|sequelize|pool)\.(query|execute|raw)/i;
4096
+ XSS_PATTERN = /innerHTML|outerHTML|document\.write|insertAdjacentHTML/i;
4097
+ SSRF_PATTERN = /^(fetch|axios|http\.request|got)$/i;
4098
+ PATH_PATTERN = /^(fs\.readFile|fs\.writeFile|path\.join|createReadStream)$/i;
4099
+ CMD_PATTERN = /^(exec|execSync|spawn|eval)$/i;
4100
+ VulnerabilityDetector = class {
4101
+ detect(graph, options) {
4102
+ const findings = [];
4103
+ const scope = options?.scope;
4104
+ const types = options?.types ? new Set(options.types) : null;
4105
+ const want = (t) => !types || types.has(t);
4106
+ const nodes = [...graph.allNodes()];
4107
+ for (const node of nodes) {
4108
+ if (node.kind === "vulnerability") continue;
4109
+ const filePath = node.filePath;
4110
+ if (scope && !filePath.startsWith(scope)) continue;
4111
+ const nodeName = node.name;
4112
+ const meta = node.metadata;
4113
+ if (want("SQL_INJECTION") && SQL_PATTERN.test(nodeName)) {
4114
+ const hasDynamic = meta?.hasStringConcatenation === true || hasCallers(graph, node.id);
4115
+ if (hasDynamic) {
4116
+ findings.push({
4117
+ type: "SQL_INJECTION",
4118
+ severity: "MEDIUM",
4119
+ file: filePath,
4120
+ line: node.startLine,
4121
+ symbol: nodeName,
4122
+ description: `Potential SQL injection: ${nodeName} may execute unsanitized user input`,
4123
+ cweId: CWE["SQL_INJECTION"]
4124
+ });
4125
+ this._tagNode(graph, node.id, "SQL_INJECTION");
4126
+ }
4127
+ }
4128
+ if (want("XSS") && XSS_PATTERN.test(nodeName)) {
4129
+ findings.push({
4130
+ type: "XSS",
4131
+ severity: "HIGH",
4132
+ file: filePath,
4133
+ line: node.startLine,
4134
+ symbol: nodeName,
4135
+ description: `Potential XSS: ${nodeName} writes to DOM sink`,
4136
+ cweId: CWE["XSS"]
4137
+ });
4138
+ this._tagNode(graph, node.id, "XSS");
4139
+ }
4140
+ if (want("XSS")) {
4141
+ for (const edge of graph.findEdgesFrom(node.id)) {
4142
+ if (edge.kind === "calls") {
4143
+ const callee = graph.getNode(edge.target);
4144
+ if (callee && XSS_PATTERN.test(callee.name)) {
4145
+ findings.push({
4146
+ type: "XSS",
4147
+ severity: "HIGH",
4148
+ file: filePath,
4149
+ line: node.startLine,
4150
+ symbol: node.name,
4151
+ description: `Potential XSS: ${node.name} calls ${callee.name}`,
4152
+ cweId: CWE["XSS"]
4153
+ });
4154
+ this._tagNode(graph, node.id, "XSS");
4155
+ }
4156
+ }
4157
+ }
4158
+ }
4159
+ if (want("SSRF") && SSRF_PATTERN.test(nodeName)) {
4160
+ const isDynamic = meta?.dynamicUrl === true;
4161
+ if (isDynamic) {
4162
+ findings.push({
4163
+ type: "SSRF",
4164
+ severity: "HIGH",
4165
+ file: filePath,
4166
+ line: node.startLine,
4167
+ symbol: nodeName,
4168
+ description: `Potential SSRF: ${nodeName} uses a dynamic URL`,
4169
+ cweId: CWE["SSRF"]
4170
+ });
4171
+ this._tagNode(graph, node.id, "SSRF");
4172
+ }
4173
+ }
4174
+ if (want("PATH_TRAVERSAL") && PATH_PATTERN.test(nodeName)) {
4175
+ const isDynamic = meta?.dynamicPath === true;
4176
+ if (isDynamic) {
4177
+ findings.push({
4178
+ type: "PATH_TRAVERSAL",
4179
+ severity: "HIGH",
4180
+ file: filePath,
4181
+ line: node.startLine,
4182
+ symbol: nodeName,
4183
+ description: `Potential path traversal: ${nodeName} uses a dynamic path`,
4184
+ cweId: CWE["PATH_TRAVERSAL"]
4185
+ });
4186
+ this._tagNode(graph, node.id, "PATH_TRAVERSAL");
4187
+ }
4188
+ }
4189
+ if (want("COMMAND_INJECTION") && CMD_PATTERN.test(nodeName)) {
4190
+ const isDynamic = meta?.dynamicArgs === true;
4191
+ if (isDynamic) {
4192
+ findings.push({
4193
+ type: "COMMAND_INJECTION",
4194
+ severity: "HIGH",
4195
+ file: filePath,
4196
+ line: node.startLine,
4197
+ symbol: nodeName,
4198
+ description: `Potential command injection: ${nodeName} uses dynamic arguments`,
4199
+ cweId: CWE["COMMAND_INJECTION"]
4200
+ });
4201
+ this._tagNode(graph, node.id, "COMMAND_INJECTION");
4202
+ }
4203
+ }
4204
+ }
4205
+ const seen = /* @__PURE__ */ new Set();
4206
+ return findings.filter((f) => {
4207
+ const key = `${f.type}:${f.file}:${f.line}:${f.symbol}`;
4208
+ if (seen.has(key)) return false;
4209
+ seen.add(key);
4210
+ return true;
4211
+ });
4212
+ }
4213
+ _tagNode(graph, nodeId, vulnType) {
4214
+ const node = graph.getNode(nodeId);
4215
+ if (!node) return;
4216
+ const meta = node.metadata ?? {};
4217
+ node.metadata = {
4218
+ ...meta,
4219
+ security: {
4220
+ ...meta["security"] ?? {},
4221
+ vulnerability: vulnType
4222
+ }
4223
+ };
4224
+ const vulnNodeId = `vuln:${vulnType}:${nodeId}`;
4225
+ if (!graph.getNode(vulnNodeId)) {
4226
+ graph.addNode({
4227
+ id: vulnNodeId,
4228
+ kind: "vulnerability",
4229
+ name: `${vulnType}:${node.name}`,
4230
+ filePath: node.filePath,
4231
+ startLine: node.startLine,
4232
+ metadata: { cweId: CWE[vulnType], vulnType }
4233
+ });
4234
+ }
4235
+ const edgeId = `has_vulnerability:${nodeId}:${vulnNodeId}`;
4236
+ if (!graph.getEdge(edgeId)) {
4237
+ graph.addEdge({
4238
+ id: edgeId,
4239
+ source: nodeId,
4240
+ target: vulnNodeId,
4241
+ kind: "has_vulnerability"
4242
+ });
4243
+ }
4244
+ }
4245
+ };
4246
+ }
4247
+ });
3706
4248
  var ErrorCodes, AppError;
3707
4249
  var init_codes = __esm({
3708
4250
  "src/errors/codes.ts"() {
3709
4251
  ErrorCodes = {
4252
+ // Auth (CI-1xxx)
3710
4253
  UNAUTHORIZED: "CI-1000",
3711
4254
  FORBIDDEN: "CI-1001",
3712
4255
  NOT_FOUND: "CI-1002",
@@ -3716,6 +4259,16 @@ var init_codes = __esm({
3716
4259
  RATE_LIMIT_EXCEEDED: "CI-1100",
3717
4260
  PAYLOAD_TOO_LARGE: "CI-1101",
3718
4261
  INVALID_REQUEST: "CI-1200",
4262
+ // Config (CI-2xxx)
4263
+ CONFIG_INVALID: "CI-2000",
4264
+ CONFIG_NOT_FOUND: "CI-2001",
4265
+ // Analysis (CI-3xxx)
4266
+ ANALYSIS_FAILED: "CI-3000",
4267
+ // DB (CI-4xxx)
4268
+ DB_ERROR: "CI-4000",
4269
+ // Network (CI-5xxx)
4270
+ NETWORK_ERROR: "CI-5001",
4271
+ // Internal (CI-9xxx)
3719
4272
  INTERNAL_ERROR: "CI-5000"
3720
4273
  };
3721
4274
  AppError = class extends Error {
@@ -3735,10 +4288,10 @@ var init_codes = __esm({
3735
4288
  }
3736
4289
  });
3737
4290
  function secureMkdir(dir) {
3738
- fs23.mkdirSync(dir, { recursive: true, mode: SECURE_DIR_MODE });
4291
+ fs24.mkdirSync(dir, { recursive: true, mode: SECURE_DIR_MODE });
3739
4292
  if (process.platform !== "win32") {
3740
4293
  try {
3741
- fs23.chmodSync(dir, SECURE_DIR_MODE);
4294
+ fs24.chmodSync(dir, SECURE_DIR_MODE);
3742
4295
  } catch {
3743
4296
  }
3744
4297
  }
@@ -3746,17 +4299,17 @@ function secureMkdir(dir) {
3746
4299
  function secureChmodFile(file) {
3747
4300
  if (process.platform === "win32") return;
3748
4301
  try {
3749
- fs23.chmodSync(file, SECURE_FILE_MODE);
4302
+ fs24.chmodSync(file, SECURE_FILE_MODE);
3750
4303
  } catch {
3751
4304
  }
3752
4305
  }
3753
4306
  function tightenDbFiles(dir) {
3754
4307
  if (process.platform === "win32") return;
3755
- if (!fs23.existsSync(dir)) return;
3756
- for (const name of fs23.readdirSync(dir)) {
4308
+ if (!fs24.existsSync(dir)) return;
4309
+ for (const name of fs24.readdirSync(dir)) {
3757
4310
  if (name.endsWith(".db") || name.endsWith(".db-wal") || name.endsWith(".db-shm")) {
3758
4311
  try {
3759
- fs23.chmodSync(path29.join(dir, name), SECURE_FILE_MODE);
4312
+ fs24.chmodSync(path31.join(dir, name), SECURE_FILE_MODE);
3760
4313
  } catch {
3761
4314
  }
3762
4315
  }
@@ -3770,7 +4323,7 @@ var init_fs_secure = __esm({
3770
4323
  }
3771
4324
  });
3772
4325
  function getUsersDBPath() {
3773
- return process.env["CODE_INTEL_USERS_DB_PATH"] ?? path29.join(os12.homedir(), ".code-intel", "users.db");
4326
+ return process.env["CODE_INTEL_USERS_DB_PATH"] ?? path31.join(os13.homedir(), ".code-intel", "users.db");
3774
4327
  }
3775
4328
  function getOrCreateUsersDB() {
3776
4329
  if (!_usersDB) {
@@ -3786,7 +4339,7 @@ var init_users_db = __esm({
3786
4339
  UsersDB = class {
3787
4340
  db;
3788
4341
  constructor(dbPath) {
3789
- const dir = path29.dirname(dbPath);
4342
+ const dir = path31.dirname(dbPath);
3790
4343
  secureMkdir(dir);
3791
4344
  this.db = new Database3(dbPath);
3792
4345
  this.db.pragma("journal_mode = WAL");
@@ -4063,17 +4616,17 @@ function getScryptN() {
4063
4616
  return Number.isInteger(v) && v >= 1024 ? v : 1 << 14;
4064
4617
  }
4065
4618
  function getSecretsPath() {
4066
- return process.env["CODE_INTEL_SECRETS_PATH"] ?? path29.join(os12.homedir(), ".code-intel", ".secrets");
4619
+ return process.env["CODE_INTEL_SECRETS_PATH"] ?? path31.join(os13.homedir(), ".code-intel", ".secrets");
4067
4620
  }
4068
4621
  function getMasterPassword() {
4069
4622
  const fromEnv = process.env["CODE_INTEL_SECRET_KEY"];
4070
4623
  if (fromEnv && fromEnv.length >= 16) return fromEnv;
4071
4624
  let username = "unknown";
4072
4625
  try {
4073
- username = os12.userInfo().username;
4626
+ username = os13.userInfo().username;
4074
4627
  } catch {
4075
4628
  }
4076
- return `code-intel-machine:${os12.hostname()}:${username}:${os12.platform()}`;
4629
+ return `code-intel-machine:${os13.hostname()}:${username}:${os13.platform()}`;
4077
4630
  }
4078
4631
  function deriveKey(password, salt) {
4079
4632
  return crypto5.scryptSync(password, salt, KEY_LEN, { N: getScryptN(), r: 8, p: 1 });
@@ -4094,8 +4647,8 @@ function decryptSecrets(encrypted) {
4094
4647
  return JSON.parse(plaintext.toString("utf8"));
4095
4648
  }
4096
4649
  function loadSecrets(secretsPath = getSecretsPath()) {
4097
- if (!fs23.existsSync(secretsPath)) return {};
4098
- const blob = fs23.readFileSync(secretsPath);
4650
+ if (!fs24.existsSync(secretsPath)) return {};
4651
+ const blob = fs24.readFileSync(secretsPath);
4099
4652
  return decryptSecrets(blob);
4100
4653
  }
4101
4654
  function getSecret(key, secretsPath = getSecretsPath()) {
@@ -4662,7 +5215,7 @@ init_shared();
4662
5215
  init_shared();
4663
5216
  init_typescript();
4664
5217
  function resolveRelative(rawPath, fromFile, workspace) {
4665
- const fromDir = path29.dirname(fromFile);
5218
+ const fromDir = path31.dirname(fromFile);
4666
5219
  const cleaned = rawPath.replace(/['"]/g, "");
4667
5220
  const extensions = [".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.js"];
4668
5221
  const resolved = workspace.resolve(fromDir, cleaned);
@@ -4714,7 +5267,7 @@ var pythonModule = {
4714
5267
  resolveImport(rawPath, fromFile, workspace) {
4715
5268
  const cleaned = rawPath.replace(/['"]/g, "");
4716
5269
  const parts = cleaned.split(".");
4717
- const fromDir = path29.dirname(fromFile);
5270
+ const fromDir = path31.dirname(fromFile);
4718
5271
  const relPath = parts.join("/");
4719
5272
  for (const suffix of ["/__init__.py", ".py"]) {
4720
5273
  const r = workspace.resolve(fromDir, relPath + suffix);
@@ -4793,7 +5346,7 @@ var cModule = {
4793
5346
  inheritanceStrategy: "none",
4794
5347
  resolveImport(rawPath, fromFile, workspace) {
4795
5348
  const cleaned = rawPath.replace(/[<>"']/g, "");
4796
- const fromDir = path29.dirname(fromFile);
5349
+ const fromDir = path31.dirname(fromFile);
4797
5350
  return workspace.resolve(fromDir, cleaned);
4798
5351
  },
4799
5352
  isExported(_node) {
@@ -4816,7 +5369,7 @@ var cppModule = {
4816
5369
  inheritanceStrategy: "depth-first",
4817
5370
  resolveImport(rawPath, fromFile, workspace) {
4818
5371
  const cleaned = rawPath.replace(/[<>"']/g, "");
4819
- const fromDir = path29.dirname(fromFile);
5372
+ const fromDir = path31.dirname(fromFile);
4820
5373
  return workspace.resolve(fromDir, cleaned);
4821
5374
  },
4822
5375
  isExported(_node) {
@@ -4978,7 +5531,7 @@ var dartModule = {
4978
5531
  const pkg = cleaned.replace("package:", "");
4979
5532
  return workspace.findByPackage(pkg);
4980
5533
  }
4981
- const fromDir = path29.dirname(fromFile);
5534
+ const fromDir = path31.dirname(fromFile);
4982
5535
  return workspace.resolve(fromDir, cleaned);
4983
5536
  },
4984
5537
  isExported(node) {
@@ -5333,25 +5886,25 @@ function validateDAG(phases) {
5333
5886
  const visiting = /* @__PURE__ */ new Set();
5334
5887
  const visited = /* @__PURE__ */ new Set();
5335
5888
  const phaseMap = new Map(phases.map((p) => [p.name, p]));
5336
- function dfs(name, path30) {
5889
+ function dfs(name, path32) {
5337
5890
  if (visiting.has(name)) {
5338
- const cycleStart = path30.indexOf(name);
5339
- const cycle = path30.slice(cycleStart).concat(name);
5891
+ const cycleStart = path32.indexOf(name);
5892
+ const cycle = path32.slice(cycleStart).concat(name);
5340
5893
  errors.push({ type: "cycle", message: `Cycle detected: ${cycle.join(" \u2192 ")}` });
5341
5894
  return true;
5342
5895
  }
5343
5896
  if (visited.has(name)) return false;
5344
5897
  visiting.add(name);
5345
- path30.push(name);
5898
+ path32.push(name);
5346
5899
  const phase = phaseMap.get(name);
5347
5900
  if (phase) {
5348
5901
  for (const dep of phase.dependencies) {
5349
- if (dfs(dep, path30)) return true;
5902
+ if (dfs(dep, path32)) return true;
5350
5903
  }
5351
5904
  }
5352
5905
  visiting.delete(name);
5353
5906
  visited.add(name);
5354
- path30.pop();
5907
+ path32.pop();
5355
5908
  return false;
5356
5909
  }
5357
5910
  for (const phase of phases) {
@@ -5564,7 +6117,7 @@ var IGNORED_DIRS = /* @__PURE__ */ new Set([
5564
6117
  ]);
5565
6118
  function loadIgnorePatterns(workspaceRoot) {
5566
6119
  try {
5567
- const raw = fs23.readFileSync(path29.join(workspaceRoot, ".codeintelignore"), "utf-8");
6120
+ const raw = fs24.readFileSync(path31.join(workspaceRoot, ".codeintelignore"), "utf-8");
5568
6121
  const extras = /* @__PURE__ */ new Set();
5569
6122
  for (const line of raw.split("\n")) {
5570
6123
  const trimmed = line.trim();
@@ -5588,7 +6141,7 @@ var scanPhase = {
5588
6141
  function walk(dir) {
5589
6142
  let entries;
5590
6143
  try {
5591
- entries = fs23.readdirSync(dir, { withFileTypes: true });
6144
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
5592
6145
  } catch {
5593
6146
  return;
5594
6147
  }
@@ -5597,15 +6150,15 @@ var scanPhase = {
5597
6150
  if (entry.name.startsWith(".")) continue;
5598
6151
  if (IGNORED_DIRS.has(entry.name)) continue;
5599
6152
  if (extraIgnore.has(entry.name)) continue;
5600
- walk(path29.join(dir, entry.name));
6153
+ walk(path31.join(dir, entry.name));
5601
6154
  } else if (entry.isFile()) {
5602
6155
  const name = entry.name;
5603
6156
  if (IGNORED_FILE_SUFFIXES.some((s) => name.endsWith(s))) continue;
5604
- const ext = path29.extname(name);
6157
+ const ext = path31.extname(name);
5605
6158
  if (!extensions.has(ext)) continue;
5606
- const fullPath = path29.join(dir, name);
6159
+ const fullPath = path31.join(dir, name);
5607
6160
  try {
5608
- const stat = fs23.statSync(fullPath);
6161
+ const stat = fs24.statSync(fullPath);
5609
6162
  if (stat.size > MAX_FILE_SIZE_BYTES) continue;
5610
6163
  } catch {
5611
6164
  continue;
@@ -5632,20 +6185,20 @@ var structurePhase = {
5632
6185
  const dirs = /* @__PURE__ */ new Set();
5633
6186
  let structDone = 0;
5634
6187
  for (const filePath of context2.filePaths) {
5635
- const relativePath = path29.relative(context2.workspaceRoot, filePath);
6188
+ const relativePath = path31.relative(context2.workspaceRoot, filePath);
5636
6189
  const lang = detectLanguage(filePath);
5637
6190
  context2.graph.addNode({
5638
6191
  id: generateNodeId("file", relativePath, relativePath),
5639
6192
  kind: "file",
5640
- name: path29.basename(filePath),
6193
+ name: path31.basename(filePath),
5641
6194
  filePath: relativePath,
5642
6195
  metadata: lang ? { language: lang } : void 0
5643
6196
  });
5644
- let dir = path29.dirname(relativePath);
6197
+ let dir = path31.dirname(relativePath);
5645
6198
  while (dir && dir !== "." && dir !== "") {
5646
6199
  if (dirs.has(dir)) break;
5647
6200
  dirs.add(dir);
5648
- dir = path29.dirname(dir);
6201
+ dir = path31.dirname(dir);
5649
6202
  }
5650
6203
  structDone++;
5651
6204
  context2.onPhaseProgress?.("structure", structDone, context2.filePaths.length);
@@ -5654,7 +6207,7 @@ var structurePhase = {
5654
6207
  context2.graph.addNode({
5655
6208
  id: generateNodeId("directory", dir, dir),
5656
6209
  kind: "directory",
5657
- name: path29.basename(dir),
6210
+ name: path31.basename(dir),
5658
6211
  filePath: dir
5659
6212
  });
5660
6213
  }
@@ -5741,9 +6294,9 @@ var flowPhase = {
5741
6294
  for (const node of graph.allNodes()) {
5742
6295
  if (!["function", "method"].includes(node.kind)) continue;
5743
6296
  let score = 0;
5744
- const hasCallers = calledNodes.has(node.id);
6297
+ const hasCallers2 = calledNodes.has(node.id);
5745
6298
  const outCalls = [...graph.findEdgesFrom(node.id)].filter((e) => e.kind === "calls");
5746
- if (!hasCallers && outCalls.length > 0) score += 10;
6299
+ if (!hasCallers2 && outCalls.length > 0) score += 10;
5747
6300
  if (node.exported) score += 5;
5748
6301
  if (/^(main|handle|init|start|run|execute|process|serve|listen|bootstrap)/.test(node.name)) score += 3;
5749
6302
  if (node.filePath.includes("test") || node.filePath.includes("spec") || node.filePath.includes("__test")) score -= 20;
@@ -5765,22 +6318,22 @@ var flowPhase = {
5765
6318
  const queue = [{ nodeId: ep.id, path: [ep.id] }];
5766
6319
  const visited = /* @__PURE__ */ new Set();
5767
6320
  while (queue.length > 0 && flowCount < maxFlows) {
5768
- const { nodeId, path: path30 } = queue.shift();
5769
- if (path30.length > maxDepth) continue;
6321
+ const { nodeId, path: path32 } = queue.shift();
6322
+ if (path32.length > maxDepth) continue;
5770
6323
  const callEdges = [...graph.findEdgesFrom(nodeId)].filter((e) => e.kind === "calls").slice(0, maxBranching);
5771
- if (callEdges.length === 0 && path30.length >= 3) {
6324
+ if (callEdges.length === 0 && path32.length >= 3) {
5772
6325
  const flowId = generateNodeId("flow", ep.filePath, `flow-${flowCount}`);
5773
6326
  graph.addNode({
5774
6327
  id: flowId,
5775
6328
  kind: "flow",
5776
6329
  name: `${ep.name} flow ${flowCount}`,
5777
6330
  filePath: ep.filePath,
5778
- metadata: { steps: path30, entryPoint: ep.name }
6331
+ metadata: { steps: path32, entryPoint: ep.name }
5779
6332
  });
5780
- for (let i = 0; i < path30.length; i++) {
6333
+ for (let i = 0; i < path32.length; i++) {
5781
6334
  graph.addEdge({
5782
- id: generateEdgeId(path30[i], flowId, `step_of_${i}`),
5783
- source: path30[i],
6335
+ id: generateEdgeId(path32[i], flowId, `step_of_${i}`),
6336
+ source: path32[i],
5784
6337
  target: flowId,
5785
6338
  kind: "step_of",
5786
6339
  weight: 1,
@@ -5793,7 +6346,7 @@ var flowPhase = {
5793
6346
  for (const edge of callEdges) {
5794
6347
  if (visited.has(edge.target)) continue;
5795
6348
  visited.add(edge.target);
5796
- queue.push({ nodeId: edge.target, path: [...path30, edge.target] });
6349
+ queue.push({ nodeId: edge.target, path: [...path32, edge.target] });
5797
6350
  }
5798
6351
  }
5799
6352
  }
@@ -5811,7 +6364,7 @@ var LLMGovernanceLogger = class {
5811
6364
  }
5812
6365
  /** Path to the JSONL log file. */
5813
6366
  getLogPath() {
5814
- return process.env["CODE_INTEL_GOVERNANCE_LOG_PATH"] ?? path29.join(os12.homedir(), ".code-intel", "llm-governance.jsonl");
6367
+ return process.env["CODE_INTEL_GOVERNANCE_LOG_PATH"] ?? path31.join(os13.homedir(), ".code-intel", "llm-governance.jsonl");
5815
6368
  }
5816
6369
  /**
5817
6370
  * Append an entry to the governance log.
@@ -5827,8 +6380,8 @@ var LLMGovernanceLogger = class {
5827
6380
  ...entry
5828
6381
  };
5829
6382
  const logPath = this.getLogPath();
5830
- fs23.mkdirSync(path29.dirname(logPath), { recursive: true });
5831
- fs23.appendFileSync(logPath, JSON.stringify(full) + "\n", "utf-8");
6383
+ fs24.mkdirSync(path31.dirname(logPath), { recursive: true });
6384
+ fs24.appendFileSync(logPath, JSON.stringify(full) + "\n", "utf-8");
5832
6385
  } catch {
5833
6386
  }
5834
6387
  }
@@ -5838,7 +6391,7 @@ var LLMGovernanceLogger = class {
5838
6391
  */
5839
6392
  readLog(limit = 100) {
5840
6393
  try {
5841
- const raw = fs23.readFileSync(this.getLogPath(), "utf-8");
6394
+ const raw = fs24.readFileSync(this.getLogPath(), "utf-8");
5842
6395
  const lines = raw.split("\n").filter((l) => l.trim().length > 0).slice(-limit);
5843
6396
  return lines.map((l) => JSON.parse(l));
5844
6397
  } catch {
@@ -5982,17 +6535,17 @@ function traceFlow(entryId, graph, maxDepth = 10, maxBranching = 4) {
5982
6535
  const queue = [{ nodeId: entryId, path: [entryId] }];
5983
6536
  const visited = /* @__PURE__ */ new Set();
5984
6537
  while (queue.length > 0 && flows.length < maxFlows) {
5985
- const { nodeId, path: path30 } = queue.shift();
5986
- if (path30.length > maxDepth) continue;
6538
+ const { nodeId, path: path32 } = queue.shift();
6539
+ if (path32.length > maxDepth) continue;
5987
6540
  const callEdges = [...graph.findEdgesFrom(nodeId)].filter((e) => e.kind === "calls").slice(0, maxBranching);
5988
- if (callEdges.length === 0 && path30.length >= 3) {
5989
- flows.push({ entryPointId: entryId, steps: [...path30] });
6541
+ if (callEdges.length === 0 && path32.length >= 3) {
6542
+ flows.push({ entryPointId: entryId, steps: [...path32] });
5990
6543
  continue;
5991
6544
  }
5992
6545
  for (const edge of callEdges) {
5993
6546
  if (visited.has(edge.target)) continue;
5994
6547
  visited.add(edge.target);
5995
- queue.push({ nodeId: edge.target, path: [...path30, edge.target] });
6548
+ queue.push({ nodeId: edge.target, path: [...path32, edge.target] });
5996
6549
  }
5997
6550
  }
5998
6551
  }
@@ -6226,7 +6779,7 @@ init_embedder();
6226
6779
  async function hybridSearch(graph, query, limit, options = {}) {
6227
6780
  const { vectorDbPath, bm25Limit = 50, vectorLimit = 50 } = options;
6228
6781
  const bm25Promise = Promise.resolve(textSearch(graph, query, bm25Limit));
6229
- const hasVectorDb = Boolean(vectorDbPath && fs23.existsSync(vectorDbPath));
6782
+ const hasVectorDb = Boolean(vectorDbPath && fs24.existsSync(vectorDbPath));
6230
6783
  if (!hasVectorDb) {
6231
6784
  const bm25Results2 = await bm25Promise;
6232
6785
  return {
@@ -6283,7 +6836,7 @@ var DbManager = class {
6283
6836
  this.dbPath = dbPath;
6284
6837
  }
6285
6838
  async init() {
6286
- fs23.mkdirSync(path29.dirname(this.dbPath), { recursive: true });
6839
+ fs24.mkdirSync(path31.dirname(this.dbPath), { recursive: true });
6287
6840
  this.db = new Database(this.dbPath);
6288
6841
  await this.db.init();
6289
6842
  this.conn = new Connection(this.db);
@@ -6373,7 +6926,7 @@ function getCreateEdgeTableDDL() {
6373
6926
  )`];
6374
6927
  }
6375
6928
  function writeNodeCSVs(graph, outputDir) {
6376
- fs23.mkdirSync(outputDir, { recursive: true });
6929
+ fs24.mkdirSync(outputDir, { recursive: true });
6377
6930
  const header = "id,name,file_path,start_line,end_line,exported,content,metadata\n";
6378
6931
  const tableBuffers = /* @__PURE__ */ new Map();
6379
6932
  const tableFilePaths = /* @__PURE__ */ new Map();
@@ -6381,7 +6934,7 @@ function writeNodeCSVs(graph, outputDir) {
6381
6934
  const table = NODE_TABLE_MAP[node.kind];
6382
6935
  if (!tableBuffers.has(table)) {
6383
6936
  tableBuffers.set(table, [header]);
6384
- tableFilePaths.set(table, path29.join(outputDir, `${table}.csv`));
6937
+ tableFilePaths.set(table, path31.join(outputDir, `${table}.csv`));
6385
6938
  }
6386
6939
  tableBuffers.get(table).push(
6387
6940
  csvRow([
@@ -6401,12 +6954,12 @@ function writeNodeCSVs(graph, outputDir) {
6401
6954
  );
6402
6955
  }
6403
6956
  for (const [table, lines] of tableBuffers) {
6404
- fs23.writeFileSync(tableFilePaths.get(table), lines.join(""), "utf-8");
6957
+ fs24.writeFileSync(tableFilePaths.get(table), lines.join(""), "utf-8");
6405
6958
  }
6406
6959
  return tableFilePaths;
6407
6960
  }
6408
6961
  function writeEdgeCSV(graph, outputDir) {
6409
- fs23.mkdirSync(outputDir, { recursive: true });
6962
+ fs24.mkdirSync(outputDir, { recursive: true });
6410
6963
  const header = "from_id,to_id,kind,weight,label\n";
6411
6964
  const groups = /* @__PURE__ */ new Map();
6412
6965
  for (const edge of graph.allEdges()) {
@@ -6417,7 +6970,7 @@ function writeEdgeCSV(graph, outputDir) {
6417
6970
  const toTable = NODE_TABLE_MAP[targetNode.kind];
6418
6971
  const key = `${fromTable}->${toTable}`;
6419
6972
  if (!groups.has(key)) {
6420
- const filePath = path29.join(outputDir, `edges_${fromTable}_${toTable}.csv`);
6973
+ const filePath = path31.join(outputDir, `edges_${fromTable}_${toTable}.csv`);
6421
6974
  groups.set(key, { lines: [header], from: fromTable, to: toTable, filePath });
6422
6975
  }
6423
6976
  groups.get(key).lines.push(
@@ -6432,7 +6985,7 @@ function writeEdgeCSV(graph, outputDir) {
6432
6985
  }
6433
6986
  const result = [];
6434
6987
  for (const group of groups.values()) {
6435
- fs23.writeFileSync(group.filePath, group.lines.join(""), "utf-8");
6988
+ fs24.writeFileSync(group.filePath, group.lines.join(""), "utf-8");
6436
6989
  result.push({ fromTable: group.from, toTable: group.to, filePath: group.filePath });
6437
6990
  }
6438
6991
  return result;
@@ -6460,7 +7013,7 @@ async function loadGraphToDB(graph, dbManager) {
6460
7013
  } catch {
6461
7014
  }
6462
7015
  }
6463
- const tmpDir = fs23.mkdtempSync(path29.join(os12.tmpdir(), "code-intel-csv-"));
7016
+ const tmpDir = fs24.mkdtempSync(path31.join(os13.tmpdir(), "code-intel-csv-"));
6464
7017
  try {
6465
7018
  const nodeTableFiles = writeNodeCSVs(graph, tmpDir);
6466
7019
  const edgeGroups = writeEdgeCSV(graph, tmpDir);
@@ -6479,8 +7032,8 @@ async function loadGraphToDB(graph, dbManager) {
6479
7032
  }
6480
7033
  let nodeCount = 0;
6481
7034
  for (const [table, csvPath] of nodeTableFiles) {
6482
- if (!fs23.existsSync(csvPath)) continue;
6483
- const stat = fs23.statSync(csvPath);
7035
+ if (!fs24.existsSync(csvPath)) continue;
7036
+ const stat = fs24.statSync(csvPath);
6484
7037
  if (stat.size < 50) continue;
6485
7038
  try {
6486
7039
  await dbManager.execute(
@@ -6493,8 +7046,8 @@ async function loadGraphToDB(graph, dbManager) {
6493
7046
  }
6494
7047
  let edgeCount = 0;
6495
7048
  for (const group of edgeGroups) {
6496
- if (!fs23.existsSync(group.filePath)) continue;
6497
- const stat = fs23.statSync(group.filePath);
7049
+ if (!fs24.existsSync(group.filePath)) continue;
7050
+ const stat = fs24.statSync(group.filePath);
6498
7051
  if (stat.size < 50) continue;
6499
7052
  try {
6500
7053
  await dbManager.execute(
@@ -6508,7 +7061,7 @@ async function loadGraphToDB(graph, dbManager) {
6508
7061
  return { nodeCount, edgeCount };
6509
7062
  } finally {
6510
7063
  try {
6511
- fs23.rmSync(tmpDir, { recursive: true, force: true });
7064
+ fs24.rmSync(tmpDir, { recursive: true, force: true });
6512
7065
  } catch {
6513
7066
  }
6514
7067
  }
@@ -6560,19 +7113,19 @@ function buildNodeProps(node) {
6560
7113
  function escCypher(s) {
6561
7114
  return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "");
6562
7115
  }
6563
- var GLOBAL_DIR = path29.join(os12.homedir(), ".code-intel");
6564
- var REPOS_FILE = path29.join(GLOBAL_DIR, "repos.json");
7116
+ var GLOBAL_DIR = path31.join(os13.homedir(), ".code-intel");
7117
+ var REPOS_FILE = path31.join(GLOBAL_DIR, "repos.json");
6565
7118
  function loadRegistry() {
6566
7119
  try {
6567
- const data = fs23.readFileSync(REPOS_FILE, "utf-8");
7120
+ const data = fs24.readFileSync(REPOS_FILE, "utf-8");
6568
7121
  return JSON.parse(data);
6569
7122
  } catch {
6570
7123
  return [];
6571
7124
  }
6572
7125
  }
6573
7126
  function saveRegistry(entries) {
6574
- fs23.mkdirSync(GLOBAL_DIR, { recursive: true });
6575
- fs23.writeFileSync(REPOS_FILE, JSON.stringify(entries, null, 2));
7127
+ fs24.mkdirSync(GLOBAL_DIR, { recursive: true });
7128
+ fs24.writeFileSync(REPOS_FILE, JSON.stringify(entries, null, 2));
6576
7129
  }
6577
7130
  function upsertRepo(entry) {
6578
7131
  const entries = loadRegistry();
@@ -6589,23 +7142,23 @@ function removeRepo(repoPath) {
6589
7142
  saveRegistry(entries);
6590
7143
  }
6591
7144
  function saveMetadata(repoDir, metadata) {
6592
- const metaDir = path29.join(repoDir, ".code-intel");
6593
- fs23.mkdirSync(metaDir, { recursive: true });
6594
- fs23.writeFileSync(path29.join(metaDir, "meta.json"), JSON.stringify(metadata, null, 2));
7145
+ const metaDir = path31.join(repoDir, ".code-intel");
7146
+ fs24.mkdirSync(metaDir, { recursive: true });
7147
+ fs24.writeFileSync(path31.join(metaDir, "meta.json"), JSON.stringify(metadata, null, 2));
6595
7148
  }
6596
7149
  function loadMetadata(repoDir) {
6597
7150
  try {
6598
- const data = fs23.readFileSync(path29.join(repoDir, ".code-intel", "meta.json"), "utf-8");
7151
+ const data = fs24.readFileSync(path31.join(repoDir, ".code-intel", "meta.json"), "utf-8");
6599
7152
  return JSON.parse(data);
6600
7153
  } catch {
6601
7154
  return null;
6602
7155
  }
6603
7156
  }
6604
7157
  function getDbPath(repoDir) {
6605
- return path29.join(repoDir, ".code-intel", "graph.db");
7158
+ return path31.join(repoDir, ".code-intel", "graph.db");
6606
7159
  }
6607
7160
  function getVectorDbPath(repoDir) {
6608
- return path29.join(repoDir, ".code-intel", "vector.db");
7161
+ return path31.join(repoDir, ".code-intel", "vector.db");
6609
7162
  }
6610
7163
 
6611
7164
  // src/mcp-server/server.ts
@@ -6689,12 +7242,12 @@ function scanForFiles(root, matcher, maxDepth = 2) {
6689
7242
  if (depth > maxDepth) return;
6690
7243
  let entries;
6691
7244
  try {
6692
- entries = fs23.readdirSync(dir, { withFileTypes: true });
7245
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
6693
7246
  } catch {
6694
7247
  return;
6695
7248
  }
6696
7249
  for (const entry of entries) {
6697
- const full = path29.join(dir, entry.name);
7250
+ const full = path31.join(dir, entry.name);
6698
7251
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
6699
7252
  walk(full, depth + 1);
6700
7253
  } else if (entry.isFile() && matcher(entry.name)) {
@@ -6717,8 +7270,8 @@ var OPENAPI_FILENAMES = /* @__PURE__ */ new Set([
6717
7270
  ]);
6718
7271
  var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options"];
6719
7272
  function tryParseFile(filePath) {
6720
- const ext = path29.extname(filePath).toLowerCase();
6721
- const content = fs23.readFileSync(filePath, "utf-8");
7273
+ const ext = path31.extname(filePath).toLowerCase();
7274
+ const content = fs24.readFileSync(filePath, "utf-8");
6722
7275
  if (ext === ".json") {
6723
7276
  try {
6724
7277
  return JSON.parse(content);
@@ -6772,7 +7325,7 @@ async function parseGraphQLContracts(repoRoot) {
6772
7325
  const files = scanForFiles(repoRoot, (name) => name.endsWith(".graphql") || name.endsWith(".gql"));
6773
7326
  const contracts = [];
6774
7327
  for (const filePath of files) {
6775
- const content = fs23.readFileSync(filePath, "utf-8");
7328
+ const content = fs24.readFileSync(filePath, "utf-8");
6776
7329
  const typeRegex = /type\s+(\w+)\s*\{([^}]+)\}/g;
6777
7330
  let match;
6778
7331
  while ((match = typeRegex.exec(content)) !== null) {
@@ -6803,7 +7356,7 @@ async function parseProtoContracts(repoRoot) {
6803
7356
  const files = scanForFiles(repoRoot, (name) => name.endsWith(".proto"));
6804
7357
  const contracts = [];
6805
7358
  for (const filePath of files) {
6806
- const content = fs23.readFileSync(filePath, "utf-8");
7359
+ const content = fs24.readFileSync(filePath, "utf-8");
6807
7360
  const serviceRegex = /service\s+(\w+)\s*\{([^}]+)\}/g;
6808
7361
  let serviceMatch;
6809
7362
  while ((serviceMatch = serviceRegex.exec(content)) !== null) {
@@ -7008,8 +7561,8 @@ async function syncGroup(group) {
7008
7561
  logger_default.warn(` \u26A0 Registry entry "${member.registryName}" not found \u2014 skipping ${member.groupPath}`);
7009
7562
  continue;
7010
7563
  }
7011
- const dbPath = path29.join(regEntry.path, ".code-intel", "graph.db");
7012
- if (!fs23.existsSync(dbPath)) {
7564
+ const dbPath = path31.join(regEntry.path, ".code-intel", "graph.db");
7565
+ if (!fs24.existsSync(dbPath)) {
7013
7566
  logger_default.warn(` \u26A0 No index at ${dbPath} \u2014 run \`code-intel analyze ${regEntry.path}\` first`);
7014
7567
  continue;
7015
7568
  }
@@ -7082,8 +7635,8 @@ async function queryGroup(group, query, limit = 20) {
7082
7635
  for (const member of group.members) {
7083
7636
  const regEntry = registry.find((r) => r.name === member.registryName);
7084
7637
  if (!regEntry) continue;
7085
- const dbPath = path29.join(regEntry.path, ".code-intel", "graph.db");
7086
- if (!fs23.existsSync(dbPath)) continue;
7638
+ const dbPath = path31.join(regEntry.path, ".code-intel", "graph.db");
7639
+ if (!fs24.existsSync(dbPath)) continue;
7087
7640
  const graph = createKnowledgeGraph();
7088
7641
  const db = new DbManager(dbPath);
7089
7642
  try {
@@ -7583,22 +8136,22 @@ function suggestTests(graph, symbolName) {
7583
8136
  const callPaths = [];
7584
8137
  const pathQueue = [{ id: targetId, path: [symbolName], depth: 0 }];
7585
8138
  while (pathQueue.length > 0 && callPaths.length < 5) {
7586
- const { id, path: path30, depth } = pathQueue.shift();
7587
- let hasCallers = false;
8139
+ const { id, path: path32, depth } = pathQueue.shift();
8140
+ let hasCallers2 = false;
7588
8141
  for (const edge of graph.findEdgesTo(id)) {
7589
8142
  if (edge.kind !== "calls") continue;
7590
8143
  const callerNode = graph.getNode(edge.source);
7591
8144
  if (!callerNode) continue;
7592
- hasCallers = true;
7593
- const newPath = [callerNode.name, ...path30];
8145
+ hasCallers2 = true;
8146
+ const newPath = [callerNode.name, ...path32];
7594
8147
  if (depth + 1 >= 3 || callPaths.length >= 5) {
7595
8148
  if (callPaths.length < 5) callPaths.push(newPath);
7596
8149
  continue;
7597
8150
  }
7598
8151
  pathQueue.push({ id: edge.source, path: newPath, depth: depth + 1 });
7599
8152
  }
7600
- if (!hasCallers && path30.length > 1) {
7601
- callPaths.push(path30);
8153
+ if (!hasCallers2 && path32.length > 1) {
8154
+ callPaths.push(path32);
7602
8155
  }
7603
8156
  }
7604
8157
  if (callPaths.length === 0) {
@@ -8073,6 +8626,70 @@ function createMcpServer(graph, repoName, workspaceRoot) {
8073
8626
  },
8074
8627
  required: ["cluster"]
8075
8628
  }
8629
+ },
8630
+ {
8631
+ name: "deprecated_usage",
8632
+ description: "Find usages of deprecated APIs in the codebase",
8633
+ inputSchema: {
8634
+ type: "object",
8635
+ properties: {
8636
+ scope: { type: "string", description: "Directory scope filter" },
8637
+ ..._tokenProp
8638
+ }
8639
+ }
8640
+ },
8641
+ {
8642
+ name: "complexity_hotspots",
8643
+ description: "Ranked list of functions/methods by cyclomatic complexity. Useful for identifying refactoring candidates.",
8644
+ inputSchema: {
8645
+ type: "object",
8646
+ properties: {
8647
+ scope: { type: "string", description: "Limit to a file path prefix (optional)" },
8648
+ limit: { type: "number", description: "Maximum number of results (default: 20)" },
8649
+ ..._tokenProp
8650
+ }
8651
+ }
8652
+ },
8653
+ {
8654
+ name: "coverage_gaps",
8655
+ description: "Find exported symbols with no test coverage, ranked by blast radius. Useful for prioritizing test writing.",
8656
+ inputSchema: {
8657
+ type: "object",
8658
+ properties: {
8659
+ scope: { type: "string", description: "Limit to a file path prefix (optional)" },
8660
+ limit: { type: "number", description: "Maximum number of untested results to return (default: 20)" },
8661
+ ..._tokenProp
8662
+ }
8663
+ }
8664
+ },
8665
+ {
8666
+ name: "secrets",
8667
+ description: "Scan the knowledge graph for hardcoded secrets: API keys, passwords, tokens, private keys, high-entropy strings",
8668
+ inputSchema: {
8669
+ type: "object",
8670
+ properties: {
8671
+ scope: { type: "string", description: "Limit scan to files under this path prefix" },
8672
+ includeTestFiles: { type: "boolean", description: "Include test/spec/fixture files (default: false)" },
8673
+ ..._tokenProp
8674
+ }
8675
+ }
8676
+ },
8677
+ {
8678
+ name: "vulnerability_scan",
8679
+ description: "Scan the knowledge graph for OWASP vulnerabilities: SQL injection, XSS, SSRF, path traversal, command injection",
8680
+ inputSchema: {
8681
+ type: "object",
8682
+ properties: {
8683
+ scope: { type: "string", description: "Limit scan to files under this path prefix" },
8684
+ types: {
8685
+ type: "array",
8686
+ items: { type: "string", enum: ["SQL_INJECTION", "XSS", "SSRF", "PATH_TRAVERSAL", "COMMAND_INJECTION"] },
8687
+ description: "Vulnerability types to detect (default: all)"
8688
+ },
8689
+ severity: { type: "string", description: "Minimum severity to report: HIGH|MEDIUM|LOW (default: LOW)" },
8690
+ ..._tokenProp
8691
+ }
8692
+ }
8076
8693
  }
8077
8694
  ]
8078
8695
  }));
@@ -8496,7 +9113,7 @@ async function dispatchTool(name, a, graph, repoName, workspaceRoot) {
8496
9113
  for (const { filePath: changedFile, changedLines } of changedFiles) {
8497
9114
  for (const node of graph.allNodes()) {
8498
9115
  if (!node.filePath) continue;
8499
- const normNode = node.filePath.replace(repoRoot + "/", "").replace(repoRoot + path29.sep, "");
9116
+ const normNode = node.filePath.replace(repoRoot + "/", "").replace(repoRoot + path31.sep, "");
8500
9117
  const normChanged = changedFile.replace(/^a\/|^b\//, "");
8501
9118
  if (!normNode.endsWith(normChanged) && !normChanged.endsWith(normNode)) continue;
8502
9119
  if (node.startLine !== void 0 && node.endLine !== void 0) {
@@ -8769,6 +9386,63 @@ async function dispatchTool(name, a, graph, repoName, workspaceRoot) {
8769
9386
  const result = summarizeCluster(graph, cluster);
8770
9387
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
8771
9388
  }
9389
+ case "deprecated_usage": {
9390
+ const scope = a.scope;
9391
+ const { DeprecatedDetector: DeprecatedDetector2 } = await Promise.resolve().then(() => (init_deprecated_detector(), deprecated_detector_exports));
9392
+ const detector = new DeprecatedDetector2();
9393
+ detector.tagDeprecated(graph);
9394
+ const findings = detector.detect(graph, scope);
9395
+ return { content: [{ type: "text", text: JSON.stringify({ findings, total: findings.length }, null, 2) }] };
9396
+ }
9397
+ // ── complexity_hotspots ────────────────────────────────────────────────
9398
+ case "complexity_hotspots": {
9399
+ const { computeComplexity: computeComplexity2 } = await Promise.resolve().then(() => (init_complexity(), complexity_exports));
9400
+ const scope = a.scope;
9401
+ const limit = typeof a.limit === "number" ? a.limit : 20;
9402
+ const hotspots = computeComplexity2(graph, scope).slice(0, limit);
9403
+ return { content: [{ type: "text", text: JSON.stringify({ hotspots, total: hotspots.length }, null, 2) }] };
9404
+ }
9405
+ // ── coverage_gaps ──────────────────────────────────────────────────────
9406
+ case "coverage_gaps": {
9407
+ const { computeCoverage: computeCoverage2 } = await Promise.resolve().then(() => (init_test_coverage(), test_coverage_exports));
9408
+ const scope = a.scope;
9409
+ const limit = typeof a.limit === "number" ? a.limit : 20;
9410
+ const summary = computeCoverage2(graph, scope);
9411
+ const untestedByRisk = summary.untestedByRisk.slice(0, limit);
9412
+ return {
9413
+ content: [{
9414
+ type: "text",
9415
+ text: JSON.stringify({
9416
+ untestedByRisk,
9417
+ coveragePct: summary.coveragePct,
9418
+ totalExported: summary.totalExported,
9419
+ testedExported: summary.testedExported
9420
+ }, null, 2)
9421
+ }]
9422
+ };
9423
+ }
9424
+ // ── secrets ────────────────────────────────────────────────────────────
9425
+ case "secrets": {
9426
+ const { SecretScanner: SecretScanner2 } = await Promise.resolve().then(() => (init_secret_scanner(), secret_scanner_exports));
9427
+ const scanner = new SecretScanner2();
9428
+ const scope = a.scope;
9429
+ const includeTestFiles = a.includeTestFiles ?? false;
9430
+ const findings = scanner.scan(graph, { scope, includeTestFiles });
9431
+ return { content: [{ type: "text", text: JSON.stringify({ findings, total: findings.length }, null, 2) }] };
9432
+ }
9433
+ // ── vulnerability_scan ─────────────────────────────────────────────────
9434
+ case "vulnerability_scan": {
9435
+ const { VulnerabilityDetector: VulnerabilityDetector2 } = await Promise.resolve().then(() => (init_vulnerability_detector(), vulnerability_detector_exports));
9436
+ const detector = new VulnerabilityDetector2();
9437
+ const scope = a.scope;
9438
+ const types = a.types;
9439
+ const minSev = (a.severity ?? "LOW").toUpperCase();
9440
+ const sevRank = { HIGH: 3, MEDIUM: 2, LOW: 1 };
9441
+ const minRank = sevRank[minSev] ?? 1;
9442
+ let findings = detector.detect(graph, { scope, types });
9443
+ findings = findings.filter((f) => (sevRank[f.severity] ?? 1) >= minRank);
9444
+ return { content: [{ type: "text", text: JSON.stringify({ findings, total: findings.length }, null, 2) }] };
9445
+ }
8772
9446
  default:
8773
9447
  return { content: [{ type: "text", text: `Unknown tool: ${name}` }] };
8774
9448
  }
@@ -8862,7 +9536,7 @@ var STUCK_THRESHOLD_MINUTES = 30;
8862
9536
  var JobsDB = class {
8863
9537
  db;
8864
9538
  constructor(dbPath) {
8865
- fs23.mkdirSync(path29.dirname(dbPath), { recursive: true });
9539
+ fs24.mkdirSync(path31.dirname(dbPath), { recursive: true });
8866
9540
  this.db = new Database3(dbPath);
8867
9541
  this.db.pragma("journal_mode = WAL");
8868
9542
  this.db.pragma("foreign_keys = ON");
@@ -9004,7 +9678,7 @@ var JobsDB = class {
9004
9678
  }
9005
9679
  };
9006
9680
  function getJobsDBPath() {
9007
- return path29.join(os12.homedir(), ".code-intel", "jobs.db");
9681
+ return path31.join(os13.homedir(), ".code-intel", "jobs.db");
9008
9682
  }
9009
9683
  var _jobsDB = null;
9010
9684
  function getOrCreateJobsDB() {
@@ -9096,14 +9770,14 @@ var BACKUP_VERSION = "1.0";
9096
9770
  var ALGORITHM = "aes-256-gcm";
9097
9771
  var IV_LENGTH = 16;
9098
9772
  function getBackupDir() {
9099
- return path29.join(os12.homedir(), ".code-intel", "backups");
9773
+ return path31.join(os13.homedir(), ".code-intel", "backups");
9100
9774
  }
9101
9775
  function getBackupKey() {
9102
9776
  const keyHex = process.env["CODE_INTEL_BACKUP_KEY"];
9103
9777
  if (keyHex && keyHex.length >= 64) {
9104
9778
  return Buffer.from(keyHex.slice(0, 64), "hex");
9105
9779
  }
9106
- const seed = `code-intel-backup-${os12.hostname()}-${os12.homedir()}`;
9780
+ const seed = `code-intel-backup-${os13.hostname()}-${os13.homedir()}`;
9107
9781
  return crypto5.createHash("sha256").update(seed).digest();
9108
9782
  }
9109
9783
  function encryptBuffer(data, key) {
@@ -9127,30 +9801,30 @@ var BackupService = class {
9127
9801
  constructor(backupDir) {
9128
9802
  this.backupDir = backupDir ?? getBackupDir();
9129
9803
  this.key = getBackupKey();
9130
- fs23.mkdirSync(this.backupDir, { recursive: true });
9804
+ fs24.mkdirSync(this.backupDir, { recursive: true });
9131
9805
  }
9132
9806
  /**
9133
9807
  * Create a backup for a repository.
9134
9808
  * Returns the backup entry.
9135
9809
  */
9136
9810
  createBackup(repoPath) {
9137
- const codeIntelDir = path29.join(repoPath, ".code-intel");
9811
+ const codeIntelDir = path31.join(repoPath, ".code-intel");
9138
9812
  const id = v4();
9139
9813
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
9140
9814
  const filesToBackup = [];
9141
9815
  const candidates = ["graph.db", "vector.db", "meta.json"];
9142
9816
  for (const f of candidates) {
9143
- const fp = path29.join(codeIntelDir, f);
9144
- if (fs23.existsSync(fp)) {
9817
+ const fp = path31.join(codeIntelDir, f);
9818
+ if (fs24.existsSync(fp)) {
9145
9819
  filesToBackup.push({ name: f, localPath: fp });
9146
9820
  }
9147
9821
  }
9148
- const registryPath = path29.join(os12.homedir(), ".code-intel", "registry.json");
9149
- if (fs23.existsSync(registryPath)) {
9822
+ const registryPath = path31.join(os13.homedir(), ".code-intel", "registry.json");
9823
+ if (fs24.existsSync(registryPath)) {
9150
9824
  filesToBackup.push({ name: "registry.json", localPath: registryPath });
9151
9825
  }
9152
- const usersDbPath = path29.join(os12.homedir(), ".code-intel", "users.db");
9153
- if (fs23.existsSync(usersDbPath)) {
9826
+ const usersDbPath = path31.join(os13.homedir(), ".code-intel", "users.db");
9827
+ if (fs24.existsSync(usersDbPath)) {
9154
9828
  filesToBackup.push({ name: "users.db", localPath: usersDbPath });
9155
9829
  }
9156
9830
  if (filesToBackup.length === 0) {
@@ -9161,7 +9835,7 @@ var BackupService = class {
9161
9835
  createdAt,
9162
9836
  version: BACKUP_VERSION,
9163
9837
  files: filesToBackup.map((f) => {
9164
- const data = fs23.readFileSync(f.localPath);
9838
+ const data = fs24.readFileSync(f.localPath);
9165
9839
  return {
9166
9840
  name: f.name,
9167
9841
  sha256: crypto5.createHash("sha256").update(data).digest("hex"),
@@ -9175,7 +9849,7 @@ var BackupService = class {
9175
9849
  manifestLenBuf.writeUInt32BE(manifestBuf.length, 0);
9176
9850
  parts.push(manifestLenBuf, manifestBuf);
9177
9851
  for (const f of filesToBackup) {
9178
- const data = fs23.readFileSync(f.localPath);
9852
+ const data = fs24.readFileSync(f.localPath);
9179
9853
  const nameBuf = Buffer.from(f.name, "utf-8");
9180
9854
  const nameLenBuf = Buffer.alloc(2);
9181
9855
  nameLenBuf.writeUInt16BE(nameBuf.length, 0);
@@ -9186,8 +9860,8 @@ var BackupService = class {
9186
9860
  const plaintext = Buffer.concat(parts);
9187
9861
  const encrypted = encryptBuffer(plaintext, this.key);
9188
9862
  const backupFileName = `backup-${id}.cib`;
9189
- const backupPath = path29.join(this.backupDir, backupFileName);
9190
- fs23.writeFileSync(backupPath, encrypted);
9863
+ const backupPath = path31.join(this.backupDir, backupFileName);
9864
+ fs24.writeFileSync(backupPath, encrypted);
9191
9865
  const entry = {
9192
9866
  id,
9193
9867
  createdAt,
@@ -9214,9 +9888,9 @@ var BackupService = class {
9214
9888
  async uploadToS3(entry) {
9215
9889
  const cfg = getS3Config();
9216
9890
  if (!cfg) throw new Error("S3 not configured. Set CODE_INTEL_BACKUP_S3_BUCKET, CODE_INTEL_BACKUP_S3_ACCESS_KEY_ID, CODE_INTEL_BACKUP_S3_SECRET_ACCESS_KEY.");
9217
- const fileName = path29.basename(entry.path);
9891
+ const fileName = path31.basename(entry.path);
9218
9892
  const s3Key = `${cfg.prefix}${fileName}`;
9219
- const body = fs23.readFileSync(entry.path);
9893
+ const body = fs24.readFileSync(entry.path);
9220
9894
  const result = await s3Request({ method: "PUT", cfg, key: s3Key, body });
9221
9895
  if (result.statusCode < 200 || result.statusCode >= 300) {
9222
9896
  throw new Error(`S3 upload failed (HTTP ${result.statusCode}): ${result.body.slice(0, 200)}`);
@@ -9233,8 +9907,8 @@ var BackupService = class {
9233
9907
  if (result.statusCode < 200 || result.statusCode >= 300) {
9234
9908
  throw new Error(`S3 download failed (HTTP ${result.statusCode}): ${result.body.slice(0, 200)}`);
9235
9909
  }
9236
- fs23.mkdirSync(path29.dirname(destPath), { recursive: true });
9237
- fs23.writeFileSync(destPath, Buffer.from(result.body, "binary"));
9910
+ fs24.mkdirSync(path31.dirname(destPath), { recursive: true });
9911
+ fs24.writeFileSync(destPath, Buffer.from(result.body, "binary"));
9238
9912
  }
9239
9913
  /**
9240
9914
  * List backup objects in S3 with the configured prefix.
@@ -9280,10 +9954,10 @@ var BackupService = class {
9280
9954
  if (!entry) {
9281
9955
  throw new Error(`Backup "${backupId}" not found.`);
9282
9956
  }
9283
- if (!fs23.existsSync(entry.path)) {
9957
+ if (!fs24.existsSync(entry.path)) {
9284
9958
  throw new Error(`Backup file not found at: ${entry.path}`);
9285
9959
  }
9286
- const encrypted = fs23.readFileSync(entry.path);
9960
+ const encrypted = fs24.readFileSync(entry.path);
9287
9961
  let plaintext;
9288
9962
  try {
9289
9963
  plaintext = decryptBuffer(encrypted, this.key);
@@ -9297,8 +9971,8 @@ var BackupService = class {
9297
9971
  offset += manifestLen;
9298
9972
  const manifest = JSON.parse(manifestStr);
9299
9973
  const restoreBase = targetRepoPath ?? entry.repoPath;
9300
- const codeIntelDir = path29.join(restoreBase, ".code-intel");
9301
- fs23.mkdirSync(codeIntelDir, { recursive: true });
9974
+ const codeIntelDir = path31.join(restoreBase, ".code-intel");
9975
+ fs24.mkdirSync(codeIntelDir, { recursive: true });
9302
9976
  for (const fileEntry of manifest.files) {
9303
9977
  const nameLen = plaintext.readUInt16BE(offset);
9304
9978
  offset += 2;
@@ -9315,18 +9989,18 @@ var BackupService = class {
9315
9989
  }
9316
9990
  let destPath;
9317
9991
  if (name === "registry.json" || name === "users.db") {
9318
- destPath = path29.join(os12.homedir(), ".code-intel", name);
9992
+ destPath = path31.join(os13.homedir(), ".code-intel", name);
9319
9993
  } else {
9320
- destPath = path29.join(codeIntelDir, name);
9994
+ destPath = path31.join(codeIntelDir, name);
9321
9995
  }
9322
- fs23.writeFileSync(destPath, data);
9996
+ fs24.writeFileSync(destPath, data);
9323
9997
  }
9324
9998
  }
9325
9999
  /**
9326
10000
  * Apply retention policy: keep N daily, M weekly, L monthly backups.
9327
10001
  */
9328
10002
  applyRetention(options = { daily: 7, weekly: 4, monthly: 12 }) {
9329
- const entries = this._loadIndex().filter((e) => fs23.existsSync(e.path)).sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
10003
+ const entries = this._loadIndex().filter((e) => fs24.existsSync(e.path)).sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
9330
10004
  const keep = /* @__PURE__ */ new Set();
9331
10005
  const now = /* @__PURE__ */ new Date();
9332
10006
  const dailyCutoff = new Date(now);
@@ -9356,7 +10030,7 @@ var BackupService = class {
9356
10030
  for (const e of entries) {
9357
10031
  if (!keep.has(e.id)) {
9358
10032
  try {
9359
- fs23.unlinkSync(e.path);
10033
+ fs24.unlinkSync(e.path);
9360
10034
  deleted++;
9361
10035
  } catch {
9362
10036
  }
@@ -9368,17 +10042,17 @@ var BackupService = class {
9368
10042
  }
9369
10043
  // ── Index helpers ──────────────────────────────────────────────────────────
9370
10044
  _indexPath() {
9371
- return path29.join(this.backupDir, "index.json");
10045
+ return path31.join(this.backupDir, "index.json");
9372
10046
  }
9373
10047
  _loadIndex() {
9374
10048
  try {
9375
- return JSON.parse(fs23.readFileSync(this._indexPath(), "utf-8"));
10049
+ return JSON.parse(fs24.readFileSync(this._indexPath(), "utf-8"));
9376
10050
  } catch {
9377
10051
  return [];
9378
10052
  }
9379
10053
  }
9380
10054
  _saveIndex(entries) {
9381
- fs23.writeFileSync(this._indexPath(), JSON.stringify(entries, null, 2));
10055
+ fs24.writeFileSync(this._indexPath(), JSON.stringify(entries, null, 2));
9382
10056
  }
9383
10057
  _appendIndex(entry) {
9384
10058
  const entries = this._loadIndex();
@@ -10171,11 +10845,11 @@ var openApiSpec = {
10171
10845
  };
10172
10846
 
10173
10847
  // src/http/app.ts
10174
- var __dirname$1 = path29.dirname(fileURLToPath(import.meta.url));
10848
+ var __dirname$1 = path31.dirname(fileURLToPath(import.meta.url));
10175
10849
  var WEB_DIST = (() => {
10176
- const bundled = path29.resolve(__dirname$1, "..", "web");
10177
- if (fs23.existsSync(bundled)) return bundled;
10178
- return path29.resolve(__dirname$1, "..", "..", "..", "web", "dist");
10850
+ const bundled = path31.resolve(__dirname$1, "..", "web");
10851
+ if (fs24.existsSync(bundled)) return bundled;
10852
+ return path31.resolve(__dirname$1, "..", "..", "..", "web", "dist");
10179
10853
  })();
10180
10854
  function getAllowedOrigins() {
10181
10855
  const env = process.env["CODE_INTEL_CORS_ORIGINS"];
@@ -10706,8 +11380,8 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
10706
11380
  const registry = loadRegistry();
10707
11381
  const entry = registry.find((r) => r.name === requestedRepo || r.path === requestedRepo);
10708
11382
  if (!entry) return null;
10709
- const dbPath = path29.join(entry.path, ".code-intel", "graph.db");
10710
- if (!fs23.existsSync(dbPath)) return null;
11383
+ const dbPath = path31.join(entry.path, ".code-intel", "graph.db");
11384
+ if (!fs24.existsSync(dbPath)) return null;
10711
11385
  const repoGraph = createKnowledgeGraph();
10712
11386
  const db = new DbManager(dbPath);
10713
11387
  try {
@@ -10794,7 +11468,7 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
10794
11468
  return;
10795
11469
  }
10796
11470
  try {
10797
- const content = fs23.readFileSync(file_path, "utf-8");
11471
+ const content = fs24.readFileSync(file_path, "utf-8");
10798
11472
  res.json({ content });
10799
11473
  } catch {
10800
11474
  res.status(404).json({ error: { code: ErrorCodes.NOT_FOUND, message: "File not found" } });
@@ -11052,8 +11726,8 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
11052
11726
  for (const member of group.members) {
11053
11727
  const regEntry = registry.find((r) => r.name === member.registryName);
11054
11728
  if (!regEntry) continue;
11055
- const dbPath = path29.join(regEntry.path, ".code-intel", "graph.db");
11056
- if (!fs23.existsSync(dbPath)) continue;
11729
+ const dbPath = path31.join(regEntry.path, ".code-intel", "graph.db");
11730
+ if (!fs24.existsSync(dbPath)) continue;
11057
11731
  const db = new DbManager(dbPath);
11058
11732
  try {
11059
11733
  await db.init();
@@ -11079,8 +11753,8 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
11079
11753
  let nodeCount = 0;
11080
11754
  let edgeCount = 0;
11081
11755
  if (regEntry) {
11082
- const dbPath = path29.join(regEntry.path, ".code-intel", "graph.db");
11083
- if (fs23.existsSync(dbPath)) {
11756
+ const dbPath = path31.join(regEntry.path, ".code-intel", "graph.db");
11757
+ if (fs24.existsSync(dbPath)) {
11084
11758
  try {
11085
11759
  const db = new DbManager(dbPath);
11086
11760
  await db.init();
@@ -11129,14 +11803,14 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
11129
11803
  });
11130
11804
  return;
11131
11805
  }
11132
- let rawResolved = path29.normalize(file);
11133
- if (!path29.isAbsolute(rawResolved) && workspaceRoot) {
11134
- rawResolved = path29.join(workspaceRoot, rawResolved);
11806
+ let rawResolved = path31.normalize(file);
11807
+ if (!path31.isAbsolute(rawResolved) && workspaceRoot) {
11808
+ rawResolved = path31.join(workspaceRoot, rawResolved);
11135
11809
  }
11136
- const resolvedFile = path29.resolve(rawResolved);
11810
+ const resolvedFile = path31.resolve(rawResolved);
11137
11811
  function isInsideDir(fileAbs, dir) {
11138
- const rel = path29.relative(path29.resolve(dir), fileAbs);
11139
- return !rel.startsWith("..") && !path29.isAbsolute(rel);
11812
+ const rel = path31.relative(path31.resolve(dir), fileAbs);
11813
+ return !rel.startsWith("..") && !path31.isAbsolute(rel);
11140
11814
  }
11141
11815
  if (workspaceRoot) {
11142
11816
  if (!isInsideDir(resolvedFile, workspaceRoot)) {
@@ -11173,7 +11847,7 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
11173
11847
  }
11174
11848
  let fileContent;
11175
11849
  try {
11176
- fileContent = fs23.readFileSync(resolvedFile, "utf-8");
11850
+ fileContent = fs24.readFileSync(resolvedFile, "utf-8");
11177
11851
  } catch {
11178
11852
  res.status(404).json({
11179
11853
  error: {
@@ -11204,7 +11878,7 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
11204
11878
  const contextStart = Math.max(1, startLine - 20);
11205
11879
  const contextEnd = Math.min(lines.length, endLine + 20);
11206
11880
  const content = lines.slice(contextStart - 1, contextEnd).join("\n");
11207
- const ext = path29.extname(resolvedFile).toLowerCase();
11881
+ const ext = path31.extname(resolvedFile).toLowerCase();
11208
11882
  const languageMap = {
11209
11883
  ".ts": "typescript",
11210
11884
  ".tsx": "typescript",
@@ -11339,10 +12013,10 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
11339
12013
  res.status(500).json({ error: { code: ErrorCodes.INTERNAL_ERROR, message: err instanceof Error ? err.message : String(err), requestId: req.requestId, timestamp: (/* @__PURE__ */ new Date()).toISOString() } });
11340
12014
  }
11341
12015
  });
11342
- if (fs23.existsSync(WEB_DIST)) {
12016
+ if (fs24.existsSync(WEB_DIST)) {
11343
12017
  app.use(express.static(WEB_DIST));
11344
12018
  app.get("/{*path}", (_req, res) => {
11345
- res.sendFile(path29.join(WEB_DIST, "index.html"));
12019
+ res.sendFile(path31.join(WEB_DIST, "index.html"));
11346
12020
  });
11347
12021
  }
11348
12022
  app.use("/admin", requireRole("admin"));