depwire-cli 0.9.0 โ†’ 0.9.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/README.md CHANGED
@@ -39,7 +39,7 @@ Depwire analyzes codebases to build a cross-reference graph showing how every fi
39
39
  - ๐Ÿ” **Impact analysis** โ€” "What breaks if I rename this function?" answered precisely
40
40
  - ๐Ÿงน **Dead code detection** โ€” Find symbols that are defined but never referenced, categorized by confidence level
41
41
  - ๐Ÿ‘€ **Live updates** โ€” Graph stays current as you edit code
42
- - ๐ŸŒ **Multi-language** โ€” TypeScript, JavaScript, Python, Go, and Rust
42
+ - ๐ŸŒ **Multi-language** โ€” TypeScript, JavaScript, Python, Go, Rust, and C
43
43
 
44
44
  ## Why Depwire?
45
45
 
@@ -178,6 +178,7 @@ Settings โ†’ Features โ†’ Experimental โ†’ Enable MCP โ†’ Add Server:
178
178
  | Python | `.py` | Imports, classes, decorators, inheritance |
179
179
  | Go | `.go` | go.mod resolution, structs, interfaces, methods |
180
180
  | Rust | `.rs` | Functions, structs, enums, traits, impl blocks, use declarations |
181
+ | C | `.c`, `.h` | Functions, structs, enums, typedefs, macros, #include directives |
181
182
 
182
183
  ## Visualization
183
184
 
@@ -616,7 +617,7 @@ See [SECURITY.md](SECURITY.md) for full details.
616
617
  ### โœ… Shipped
617
618
  - [x] Arc diagram visualization
618
619
  - [x] MCP server (15 tools)
619
- - [x] Multi-language support (TypeScript, JavaScript, Python, Go, Rust)
620
+ - [x] Multi-language support (TypeScript, JavaScript, Python, Go, Rust, C)
620
621
  - [x] File watching + live refresh
621
622
  - [x] Auto-generated documentation (13 documents)
622
623
  - [x] Dependency health score (0-100)
@@ -30,7 +30,8 @@ function scanDirectory(rootDir, baseDir = rootDir) {
30
30
  const isPython = entry.endsWith(".py");
31
31
  const isGo = entry.endsWith(".go") && !entry.endsWith("_test.go");
32
32
  const isRust = entry.endsWith(".rs");
33
- if (isTypeScript || isJavaScript || isPython || isGo || isRust) {
33
+ const isC = entry.endsWith(".c") || entry.endsWith(".h");
34
+ if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC) {
34
35
  files.push(relative(rootDir, fullPath));
35
36
  }
36
37
  }
@@ -61,6 +62,12 @@ function findProjectRoot(startDir = process.cwd()) {
61
62
  // Python (modern)
62
63
  "setup.py",
63
64
  // Python (legacy)
65
+ "Makefile",
66
+ // C/C++ (make-based)
67
+ "CMakeLists.txt",
68
+ // C/C++ (cmake-based)
69
+ "configure.ac",
70
+ // C/C++ (autotools)
64
71
  ".git"
65
72
  // Any git repo
66
73
  ];
@@ -83,8 +90,8 @@ function findProjectRoot(startDir = process.cwd()) {
83
90
  }
84
91
 
85
92
  // src/parser/index.ts
86
- import { readFileSync as readFileSync4, statSync as statSync2 } from "fs";
87
- import { join as join7 } from "path";
93
+ import { readFileSync as readFileSync5, statSync as statSync2 } from "fs";
94
+ import { join as join8 } from "path";
88
95
 
89
96
  // src/parser/detect.ts
90
97
  import { extname as extname3 } from "path";
@@ -113,7 +120,8 @@ async function initParser() {
113
120
  "javascript": "tree-sitter-javascript.wasm",
114
121
  "python": "tree-sitter-python.wasm",
115
122
  "go": "tree-sitter-go.wasm",
116
- "rust": "tree-sitter-rust.wasm"
123
+ "rust": "tree-sitter-rust.wasm",
124
+ "c": "tree-sitter-c.wasm"
117
125
  };
118
126
  for (const [name, file] of Object.entries(grammarFiles)) {
119
127
  const wasmPath = path.join(grammarsDir, file);
@@ -2392,13 +2400,383 @@ var rustParser = {
2392
2400
  parseFile: parseRustFile
2393
2401
  };
2394
2402
 
2403
+ // src/parser/c.ts
2404
+ import { existsSync as existsSync7 } from "fs";
2405
+ import { join as join7, dirname as dirname6, relative as relative4 } from "path";
2406
+ function parseCFile(filePath, sourceCode, projectRoot) {
2407
+ const parser = getParser("c");
2408
+ const tree = parser.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
2409
+ const context = {
2410
+ filePath,
2411
+ projectRoot,
2412
+ sourceCode,
2413
+ symbols: [],
2414
+ edges: [],
2415
+ currentScope: []
2416
+ };
2417
+ walkNode6(tree.rootNode, context);
2418
+ return {
2419
+ filePath,
2420
+ symbols: context.symbols,
2421
+ edges: context.edges
2422
+ };
2423
+ }
2424
+ function walkNode6(node, context) {
2425
+ processNode6(node, context);
2426
+ for (let i = 0; i < node.childCount; i++) {
2427
+ const child = node.child(i);
2428
+ if (child) {
2429
+ walkNode6(child, context);
2430
+ }
2431
+ }
2432
+ }
2433
+ function processNode6(node, context) {
2434
+ const type = node.type;
2435
+ switch (type) {
2436
+ case "function_definition":
2437
+ processFunctionDefinition2(node, context);
2438
+ break;
2439
+ case "struct_specifier":
2440
+ processStructSpecifier(node, context);
2441
+ break;
2442
+ case "enum_specifier":
2443
+ processEnumSpecifier(node, context);
2444
+ break;
2445
+ case "type_definition":
2446
+ processTypeDefinition(node, context);
2447
+ break;
2448
+ case "declaration":
2449
+ processDeclaration(node, context);
2450
+ break;
2451
+ case "preproc_def":
2452
+ case "preproc_function_def":
2453
+ processMacroDefinition(node, context);
2454
+ break;
2455
+ case "preproc_include":
2456
+ processIncludeDirective(node, context);
2457
+ break;
2458
+ case "call_expression":
2459
+ processCallExpression6(node, context);
2460
+ break;
2461
+ }
2462
+ }
2463
+ function processFunctionDefinition2(node, context) {
2464
+ const declarator = node.childForFieldName("declarator");
2465
+ if (!declarator) return;
2466
+ const nameNode = extractFunctionName(declarator);
2467
+ if (!nameNode) return;
2468
+ const name = nodeText5(nameNode, context);
2469
+ const exported = !hasStorageClass(node, "static", context);
2470
+ const symbolId = `${context.filePath}::${name}`;
2471
+ context.symbols.push({
2472
+ id: symbolId,
2473
+ name,
2474
+ kind: "function",
2475
+ filePath: context.filePath,
2476
+ startLine: node.startPosition.row + 1,
2477
+ endLine: node.endPosition.row + 1,
2478
+ exported
2479
+ });
2480
+ context.currentScope.push(name);
2481
+ const body = node.childForFieldName("body");
2482
+ if (body) {
2483
+ walkNode6(body, context);
2484
+ }
2485
+ context.currentScope.pop();
2486
+ }
2487
+ function processStructSpecifier(node, context) {
2488
+ const parent = node.parent;
2489
+ let name = null;
2490
+ if (parent && parent.type === "type_definition") {
2491
+ const typedefName = parent.childForFieldName("declarator");
2492
+ if (typedefName) {
2493
+ name = extractIdentifierFromDeclarator(typedefName, context);
2494
+ }
2495
+ }
2496
+ if (!name) {
2497
+ const nameNode = node.childForFieldName("name");
2498
+ if (nameNode) {
2499
+ name = nodeText5(nameNode, context);
2500
+ }
2501
+ }
2502
+ if (!name) return;
2503
+ const symbolId = `${context.filePath}::${name}`;
2504
+ context.symbols.push({
2505
+ id: symbolId,
2506
+ name,
2507
+ kind: "class",
2508
+ filePath: context.filePath,
2509
+ startLine: node.startPosition.row + 1,
2510
+ endLine: node.endPosition.row + 1,
2511
+ exported: true
2512
+ });
2513
+ }
2514
+ function processEnumSpecifier(node, context) {
2515
+ const parent = node.parent;
2516
+ let name = null;
2517
+ if (parent && parent.type === "type_definition") {
2518
+ const typedefName = parent.childForFieldName("declarator");
2519
+ if (typedefName) {
2520
+ name = extractIdentifierFromDeclarator(typedefName, context);
2521
+ }
2522
+ }
2523
+ if (!name) {
2524
+ const nameNode = node.childForFieldName("name");
2525
+ if (nameNode) {
2526
+ name = nodeText5(nameNode, context);
2527
+ }
2528
+ }
2529
+ if (!name) return;
2530
+ const symbolId = `${context.filePath}::${name}`;
2531
+ context.symbols.push({
2532
+ id: symbolId,
2533
+ name,
2534
+ kind: "enum",
2535
+ filePath: context.filePath,
2536
+ startLine: node.startPosition.row + 1,
2537
+ endLine: node.endPosition.row + 1,
2538
+ exported: true
2539
+ });
2540
+ }
2541
+ function processTypeDefinition(node, context) {
2542
+ const typeNode = node.childForFieldName("type");
2543
+ if (!typeNode) return;
2544
+ if (typeNode.type === "struct_specifier" || typeNode.type === "enum_specifier") {
2545
+ return;
2546
+ }
2547
+ const declarator = node.childForFieldName("declarator");
2548
+ if (!declarator) return;
2549
+ const name = extractIdentifierFromDeclarator(declarator, context);
2550
+ if (!name) return;
2551
+ const symbolId = `${context.filePath}::${name}`;
2552
+ context.symbols.push({
2553
+ id: symbolId,
2554
+ name,
2555
+ kind: "type_alias",
2556
+ filePath: context.filePath,
2557
+ startLine: node.startPosition.row + 1,
2558
+ endLine: node.endPosition.row + 1,
2559
+ exported: true
2560
+ });
2561
+ }
2562
+ function processDeclaration(node, context) {
2563
+ if (context.currentScope.length > 0) {
2564
+ return;
2565
+ }
2566
+ const parent = node.parent;
2567
+ if (!parent || parent.type !== "translation_unit") {
2568
+ return;
2569
+ }
2570
+ const hasStatic = hasStorageClass(node, "static", context);
2571
+ const declarator = node.childForFieldName("declarator");
2572
+ if (!declarator) return;
2573
+ const name = extractIdentifierFromDeclarator(declarator, context);
2574
+ if (!name) return;
2575
+ const symbolId = `${context.filePath}::${name}`;
2576
+ context.symbols.push({
2577
+ id: symbolId,
2578
+ name,
2579
+ kind: "variable",
2580
+ filePath: context.filePath,
2581
+ startLine: node.startPosition.row + 1,
2582
+ endLine: node.endPosition.row + 1,
2583
+ exported: !hasStatic
2584
+ });
2585
+ }
2586
+ function processMacroDefinition(node, context) {
2587
+ const nameNode = node.childForFieldName("name");
2588
+ if (!nameNode) return;
2589
+ const name = nodeText5(nameNode, context);
2590
+ const kind = node.type === "preproc_function_def" ? "function" : "constant";
2591
+ const symbolId = `${context.filePath}::${name}`;
2592
+ context.symbols.push({
2593
+ id: symbolId,
2594
+ name,
2595
+ kind,
2596
+ filePath: context.filePath,
2597
+ startLine: node.startPosition.row + 1,
2598
+ endLine: node.endPosition.row + 1,
2599
+ exported: true
2600
+ });
2601
+ }
2602
+ function processIncludeDirective(node, context) {
2603
+ const pathNode = node.childForFieldName("path");
2604
+ if (!pathNode) return;
2605
+ const pathText = nodeText5(pathNode, context);
2606
+ const isLocalInclude = pathText.startsWith('"') && pathText.endsWith('"');
2607
+ if (!isLocalInclude) {
2608
+ return;
2609
+ }
2610
+ const includePath = pathText.slice(1, -1);
2611
+ const resolvedFiles = resolveIncludePath(includePath, context.filePath, context.projectRoot);
2612
+ if (resolvedFiles.length === 0) return;
2613
+ const sourceId = `${context.filePath}::__file__`;
2614
+ for (const targetPath of resolvedFiles) {
2615
+ const targetId = `${targetPath}::__file__`;
2616
+ context.edges.push({
2617
+ source: sourceId,
2618
+ target: targetId,
2619
+ kind: "imports",
2620
+ filePath: context.filePath,
2621
+ line: node.startPosition.row + 1
2622
+ });
2623
+ }
2624
+ }
2625
+ function processCallExpression6(node, context) {
2626
+ if (context.currentScope.length === 0) return;
2627
+ const functionNode = node.childForFieldName("function");
2628
+ if (!functionNode) return;
2629
+ const calleeName = nodeText5(functionNode, context);
2630
+ const builtins = /* @__PURE__ */ new Set(["printf", "scanf", "malloc", "free", "memcpy", "strlen", "strcmp", "strcpy", "strcat"]);
2631
+ if (builtins.has(calleeName)) return;
2632
+ const callerId = getCurrentSymbolId6(context);
2633
+ if (!callerId) return;
2634
+ const calleeId = resolveSymbol5(calleeName, context);
2635
+ if (!calleeId) return;
2636
+ context.edges.push({
2637
+ source: callerId,
2638
+ target: calleeId,
2639
+ kind: "calls",
2640
+ filePath: context.filePath,
2641
+ line: node.startPosition.row + 1
2642
+ });
2643
+ }
2644
+ function resolveIncludePath(includePath, currentFile, projectRoot) {
2645
+ const currentFileAbs = join7(projectRoot, currentFile);
2646
+ const currentDir = dirname6(currentFileAbs);
2647
+ const possibleFiles = [
2648
+ join7(currentDir, includePath),
2649
+ join7(projectRoot, includePath)
2650
+ ];
2651
+ const resolvedFiles = [];
2652
+ for (const absPath of possibleFiles) {
2653
+ if (existsSync7(absPath)) {
2654
+ const relPath = relative4(projectRoot, absPath);
2655
+ resolvedFiles.push(relPath);
2656
+ }
2657
+ }
2658
+ return resolvedFiles;
2659
+ }
2660
+ function hasStorageClass(node, className, context) {
2661
+ for (let i = 0; i < node.childCount; i++) {
2662
+ const child = node.child(i);
2663
+ if (child && child.type === "storage_class_specifier") {
2664
+ const text = nodeText5(child, context);
2665
+ if (text === className) {
2666
+ return true;
2667
+ }
2668
+ }
2669
+ }
2670
+ let parent = node.parent;
2671
+ while (parent) {
2672
+ for (let i = 0; i < parent.childCount; i++) {
2673
+ const child = parent.child(i);
2674
+ if (child && child.type === "storage_class_specifier") {
2675
+ const text = nodeText5(child, context);
2676
+ if (text === className) {
2677
+ return true;
2678
+ }
2679
+ }
2680
+ }
2681
+ parent = parent.parent;
2682
+ }
2683
+ return false;
2684
+ }
2685
+ function extractFunctionName(declarator) {
2686
+ if (declarator.type === "identifier") {
2687
+ return declarator;
2688
+ }
2689
+ if (declarator.type === "function_declarator") {
2690
+ const innerDeclarator = declarator.childForFieldName("declarator");
2691
+ if (innerDeclarator) {
2692
+ return extractFunctionName(innerDeclarator);
2693
+ }
2694
+ }
2695
+ if (declarator.type === "pointer_declarator") {
2696
+ const innerDeclarator = declarator.childForFieldName("declarator");
2697
+ if (innerDeclarator) {
2698
+ return extractFunctionName(innerDeclarator);
2699
+ }
2700
+ }
2701
+ for (let i = 0; i < declarator.childCount; i++) {
2702
+ const child = declarator.child(i);
2703
+ if (child && child.type === "identifier") {
2704
+ return child;
2705
+ }
2706
+ }
2707
+ return null;
2708
+ }
2709
+ function extractIdentifierFromDeclarator(declarator, context) {
2710
+ if (declarator.type === "identifier") {
2711
+ return nodeText5(declarator, context);
2712
+ }
2713
+ if (declarator.type === "type_identifier") {
2714
+ return nodeText5(declarator, context);
2715
+ }
2716
+ const identifierNode = findChildByType6(declarator, "identifier");
2717
+ if (identifierNode) {
2718
+ return nodeText5(identifierNode, context);
2719
+ }
2720
+ const typeIdNode = findChildByType6(declarator, "type_identifier");
2721
+ if (typeIdNode) {
2722
+ return nodeText5(typeIdNode, context);
2723
+ }
2724
+ for (let i = 0; i < declarator.childCount; i++) {
2725
+ const child = declarator.child(i);
2726
+ if (child) {
2727
+ const name = extractIdentifierFromDeclarator(child, context);
2728
+ if (name) return name;
2729
+ }
2730
+ }
2731
+ return null;
2732
+ }
2733
+ function resolveSymbol5(name, context) {
2734
+ const currentFileId = `${context.filePath}::__file__`;
2735
+ const symbol = context.symbols.find(
2736
+ (s) => s.name === name && (s.filePath === context.filePath || s.exported)
2737
+ );
2738
+ if (symbol) {
2739
+ return symbol.id;
2740
+ }
2741
+ for (let i = context.currentScope.length - 1; i >= 0; i--) {
2742
+ const scopedId = `${context.filePath}::${context.currentScope.slice(0, i + 1).join("::")}::${name}`;
2743
+ const scopedSymbol = context.symbols.find((s) => s.id === scopedId);
2744
+ if (scopedSymbol) {
2745
+ return scopedSymbol.id;
2746
+ }
2747
+ }
2748
+ return null;
2749
+ }
2750
+ function findChildByType6(node, type) {
2751
+ for (let i = 0; i < node.childCount; i++) {
2752
+ const child = node.child(i);
2753
+ if (child && child.type === type) {
2754
+ return child;
2755
+ }
2756
+ }
2757
+ return null;
2758
+ }
2759
+ function nodeText5(node, context) {
2760
+ return context.sourceCode.slice(node.startIndex, node.endIndex);
2761
+ }
2762
+ function getCurrentSymbolId6(context) {
2763
+ if (context.currentScope.length === 0) return null;
2764
+ return `${context.filePath}::${context.currentScope.join("::")}`;
2765
+ }
2766
+ var cParser = {
2767
+ name: "c",
2768
+ extensions: [".c", ".h"],
2769
+ parseFile: parseCFile
2770
+ };
2771
+
2395
2772
  // src/parser/detect.ts
2396
2773
  var parsers = [
2397
2774
  typescriptParser,
2398
2775
  pythonParser,
2399
2776
  javascriptParser,
2400
2777
  goParser,
2401
- rustParser
2778
+ rustParser,
2779
+ cParser
2402
2780
  ];
2403
2781
  function getParserForFile(filePath) {
2404
2782
  const ext = extname3(filePath).toLowerCase();
@@ -2428,7 +2806,7 @@ async function parseProject(projectRoot, options) {
2428
2806
  let errorFiles = 0;
2429
2807
  for (const file of files) {
2430
2808
  try {
2431
- const fullPath = join7(projectRoot, file);
2809
+ const fullPath = join8(projectRoot, file);
2432
2810
  if (options?.exclude) {
2433
2811
  const shouldExclude2 = options.exclude.some(
2434
2812
  (pattern) => minimatch(file, pattern, { matchBase: true })
@@ -2454,7 +2832,7 @@ async function parseProject(projectRoot, options) {
2454
2832
  skippedFiles++;
2455
2833
  continue;
2456
2834
  }
2457
- const sourceCode = readFileSync4(fullPath, "utf-8");
2835
+ const sourceCode = readFileSync5(fullPath, "utf-8");
2458
2836
  const parsed = parser.parseFile(file, sourceCode, projectRoot);
2459
2837
  parsedFiles.push(parsed);
2460
2838
  } catch (err) {
@@ -2847,7 +3225,7 @@ function watchProject(projectRoot, callbacks) {
2847
3225
  const watcher = chokidar.watch(projectRoot, watcherOptions);
2848
3226
  console.error("[Watcher] Attaching event listeners...");
2849
3227
  watcher.on("change", (absolutePath) => {
2850
- const validExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs"];
3228
+ const validExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".c", ".h"];
2851
3229
  if (!validExtensions.some((ext) => absolutePath.endsWith(ext))) return;
2852
3230
  if (absolutePath.endsWith("_test.go")) return;
2853
3231
  const relativePath = absolutePath.replace(projectRoot + "/", "");
@@ -2855,7 +3233,7 @@ function watchProject(projectRoot, callbacks) {
2855
3233
  callbacks.onFileChanged(relativePath);
2856
3234
  });
2857
3235
  watcher.on("add", (absolutePath) => {
2858
- const validExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs"];
3236
+ const validExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".c", ".h"];
2859
3237
  if (!validExtensions.some((ext) => absolutePath.endsWith(ext))) return;
2860
3238
  if (absolutePath.endsWith("_test.go")) return;
2861
3239
  const relativePath = absolutePath.replace(projectRoot + "/", "");
@@ -2863,7 +3241,7 @@ function watchProject(projectRoot, callbacks) {
2863
3241
  callbacks.onFileAdded(relativePath);
2864
3242
  });
2865
3243
  watcher.on("unlink", (absolutePath) => {
2866
- const validExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs"];
3244
+ const validExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".c", ".h"];
2867
3245
  if (!validExtensions.some((ext) => absolutePath.endsWith(ext))) return;
2868
3246
  if (absolutePath.endsWith("_test.go")) return;
2869
3247
  const relativePath = absolutePath.replace(projectRoot + "/", "");
@@ -2881,10 +3259,10 @@ function watchProject(projectRoot, callbacks) {
2881
3259
  for (const dir of dirs) {
2882
3260
  const files = watched[dir];
2883
3261
  fileCount += files.filter(
2884
- (f) => f.endsWith(".ts") || f.endsWith(".tsx") || f.endsWith(".js") || f.endsWith(".jsx") || f.endsWith(".mjs") || f.endsWith(".cjs") || f.endsWith(".py") || f.endsWith(".go") && !f.endsWith("_test.go")
3262
+ (f) => f.endsWith(".ts") || f.endsWith(".tsx") || f.endsWith(".js") || f.endsWith(".jsx") || f.endsWith(".mjs") || f.endsWith(".cjs") || f.endsWith(".py") || f.endsWith(".go") && !f.endsWith("_test.go") || f.endsWith(".rs") || f.endsWith(".c") || f.endsWith(".h")
2885
3263
  ).length;
2886
3264
  }
2887
- console.error(`[Watcher] Watching ${fileCount} TypeScript/JavaScript/Python/Go files in ${dirs.length} directories`);
3265
+ console.error(`[Watcher] Watching ${fileCount} TypeScript/JavaScript/Python/Go/Rust/C files in ${dirs.length} directories`);
2888
3266
  });
2889
3267
  return watcher;
2890
3268
  }
@@ -2893,10 +3271,10 @@ function watchProject(projectRoot, callbacks) {
2893
3271
  import express from "express";
2894
3272
  import open from "open";
2895
3273
  import { fileURLToPath as fileURLToPath2 } from "url";
2896
- import { dirname as dirname6, join as join8 } from "path";
3274
+ import { dirname as dirname7, join as join9 } from "path";
2897
3275
  import { WebSocketServer } from "ws";
2898
3276
  var __filename = fileURLToPath2(import.meta.url);
2899
- var __dirname2 = dirname6(__filename);
3277
+ var __dirname2 = dirname7(__filename);
2900
3278
  var activeServer = null;
2901
3279
  async function findAvailablePort(startPort, maxAttempts = 10) {
2902
3280
  const net = await import("net");
@@ -2934,7 +3312,7 @@ async function startVizServer(initialVizData, graph, projectRoot, port = 3333, s
2934
3312
  const availablePort = await findAvailablePort(port);
2935
3313
  const app = express();
2936
3314
  let vizData = initialVizData;
2937
- const publicDir = join8(__dirname2, "viz", "public");
3315
+ const publicDir = join9(__dirname2, "viz", "public");
2938
3316
  app.use(express.static(publicDir));
2939
3317
  app.get("/api/graph", (req, res) => {
2940
3318
  res.json(vizData);
@@ -3050,7 +3428,7 @@ function isProjectLoaded(state) {
3050
3428
  }
3051
3429
 
3052
3430
  // src/graph/updater.ts
3053
- import { join as join9 } from "path";
3431
+ import { join as join10 } from "path";
3054
3432
  function removeFileFromGraph(graph, filePath) {
3055
3433
  const nodesToRemove = [];
3056
3434
  graph.forEachNode((node, attrs) => {
@@ -3094,7 +3472,7 @@ function addFileToGraph(graph, parsedFile) {
3094
3472
  }
3095
3473
  async function updateFileInGraph(graph, projectRoot, relativeFilePath) {
3096
3474
  removeFileFromGraph(graph, relativeFilePath);
3097
- const absolutePath = join9(projectRoot, relativeFilePath);
3475
+ const absolutePath = join10(projectRoot, relativeFilePath);
3098
3476
  try {
3099
3477
  const parsedFile = parseTypeScriptFile(absolutePath, relativeFilePath);
3100
3478
  addFileToGraph(graph, parsedFile);
@@ -3104,7 +3482,7 @@ async function updateFileInGraph(graph, projectRoot, relativeFilePath) {
3104
3482
  }
3105
3483
 
3106
3484
  // src/health/metrics.ts
3107
- import { dirname as dirname7 } from "path";
3485
+ import { dirname as dirname8 } from "path";
3108
3486
  function scoreToGrade(score) {
3109
3487
  if (score >= 90) return "A";
3110
3488
  if (score >= 80) return "B";
@@ -3137,8 +3515,8 @@ function calculateCouplingScore(graph) {
3137
3515
  totalEdges++;
3138
3516
  fileConnections.set(sourceAttrs.filePath, (fileConnections.get(sourceAttrs.filePath) || 0) + 1);
3139
3517
  fileConnections.set(targetAttrs.filePath, (fileConnections.get(targetAttrs.filePath) || 0) + 1);
3140
- const sourceDir = dirname7(sourceAttrs.filePath).split("/")[0];
3141
- const targetDir = dirname7(targetAttrs.filePath).split("/")[0];
3518
+ const sourceDir = dirname8(sourceAttrs.filePath).split("/")[0];
3519
+ const targetDir = dirname8(targetAttrs.filePath).split("/")[0];
3142
3520
  if (sourceDir !== targetDir) {
3143
3521
  crossDirEdges++;
3144
3522
  }
@@ -3185,8 +3563,8 @@ function calculateCohesionScore(graph) {
3185
3563
  const sourceAttrs = graph.getNodeAttributes(source);
3186
3564
  const targetAttrs = graph.getNodeAttributes(target);
3187
3565
  if (sourceAttrs.filePath !== targetAttrs.filePath) {
3188
- const sourceDir = dirname7(sourceAttrs.filePath);
3189
- const targetDir = dirname7(targetAttrs.filePath);
3566
+ const sourceDir = dirname8(sourceAttrs.filePath);
3567
+ const targetDir = dirname8(targetAttrs.filePath);
3190
3568
  if (!dirEdges.has(sourceDir)) {
3191
3569
  dirEdges.set(sourceDir, { internal: 0, total: 0 });
3192
3570
  }
@@ -3468,8 +3846,8 @@ function calculateDepthScore(graph) {
3468
3846
  }
3469
3847
 
3470
3848
  // src/health/index.ts
3471
- import { readFileSync as readFileSync5, writeFileSync, existsSync as existsSync7, mkdirSync } from "fs";
3472
- import { join as join10, dirname as dirname8 } from "path";
3849
+ import { readFileSync as readFileSync6, writeFileSync, existsSync as existsSync8, mkdirSync } from "fs";
3850
+ import { join as join11, dirname as dirname9 } from "path";
3473
3851
  function calculateHealthScore(graph, projectRoot) {
3474
3852
  const coupling = calculateCouplingScore(graph);
3475
3853
  const cohesion = calculateCohesionScore(graph);
@@ -3568,7 +3946,7 @@ function getHealthTrend(projectRoot, currentScore) {
3568
3946
  }
3569
3947
  }
3570
3948
  function saveHealthHistory(projectRoot, report) {
3571
- const historyFile = join10(projectRoot, ".depwire", "health-history.json");
3949
+ const historyFile = join11(projectRoot, ".depwire", "health-history.json");
3572
3950
  const entry = {
3573
3951
  timestamp: report.timestamp,
3574
3952
  score: report.overall,
@@ -3580,9 +3958,9 @@ function saveHealthHistory(projectRoot, report) {
3580
3958
  }))
3581
3959
  };
3582
3960
  let history = [];
3583
- if (existsSync7(historyFile)) {
3961
+ if (existsSync8(historyFile)) {
3584
3962
  try {
3585
- const content = readFileSync5(historyFile, "utf-8");
3963
+ const content = readFileSync6(historyFile, "utf-8");
3586
3964
  history = JSON.parse(content);
3587
3965
  } catch {
3588
3966
  }
@@ -3591,16 +3969,16 @@ function saveHealthHistory(projectRoot, report) {
3591
3969
  if (history.length > 50) {
3592
3970
  history = history.slice(-50);
3593
3971
  }
3594
- mkdirSync(dirname8(historyFile), { recursive: true });
3972
+ mkdirSync(dirname9(historyFile), { recursive: true });
3595
3973
  writeFileSync(historyFile, JSON.stringify(history, null, 2), "utf-8");
3596
3974
  }
3597
3975
  function loadHealthHistory(projectRoot) {
3598
- const historyFile = join10(projectRoot, ".depwire", "health-history.json");
3599
- if (!existsSync7(historyFile)) {
3976
+ const historyFile = join11(projectRoot, ".depwire", "health-history.json");
3977
+ if (!existsSync8(historyFile)) {
3600
3978
  return [];
3601
3979
  }
3602
3980
  try {
3603
- const content = readFileSync5(historyFile, "utf-8");
3981
+ const content = readFileSync6(historyFile, "utf-8");
3604
3982
  return JSON.parse(content);
3605
3983
  } catch {
3606
3984
  return [];
@@ -3906,11 +4284,11 @@ function filterByConfidence(symbols, minConfidence) {
3906
4284
  }
3907
4285
 
3908
4286
  // src/docs/generator.ts
3909
- import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync10 } from "fs";
3910
- import { join as join13 } from "path";
4287
+ import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync11 } from "fs";
4288
+ import { join as join14 } from "path";
3911
4289
 
3912
4290
  // src/docs/architecture.ts
3913
- import { dirname as dirname9 } from "path";
4291
+ import { dirname as dirname10 } from "path";
3914
4292
 
3915
4293
  // src/docs/templates.ts
3916
4294
  function header(text, level = 1) {
@@ -4061,7 +4439,7 @@ function generateModuleStructure(graph) {
4061
4439
  function getDirectoryStats(graph) {
4062
4440
  const dirMap = /* @__PURE__ */ new Map();
4063
4441
  graph.forEachNode((node, attrs) => {
4064
- const dir = dirname9(attrs.filePath);
4442
+ const dir = dirname10(attrs.filePath);
4065
4443
  if (dir === ".") return;
4066
4444
  if (!dirMap.has(dir)) {
4067
4445
  dirMap.set(dir, {
@@ -4086,7 +4464,7 @@ function getDirectoryStats(graph) {
4086
4464
  });
4087
4465
  const filesPerDir = /* @__PURE__ */ new Map();
4088
4466
  graph.forEachNode((node, attrs) => {
4089
- const dir = dirname9(attrs.filePath);
4467
+ const dir = dirname10(attrs.filePath);
4090
4468
  if (!filesPerDir.has(dir)) {
4091
4469
  filesPerDir.set(dir, /* @__PURE__ */ new Set());
4092
4470
  }
@@ -4101,8 +4479,8 @@ function getDirectoryStats(graph) {
4101
4479
  graph.forEachEdge((edge, attrs, source, target) => {
4102
4480
  const sourceAttrs = graph.getNodeAttributes(source);
4103
4481
  const targetAttrs = graph.getNodeAttributes(target);
4104
- const sourceDir = dirname9(sourceAttrs.filePath);
4105
- const targetDir = dirname9(targetAttrs.filePath);
4482
+ const sourceDir = dirname10(sourceAttrs.filePath);
4483
+ const targetDir = dirname10(targetAttrs.filePath);
4106
4484
  if (sourceDir !== targetDir) {
4107
4485
  if (!dirEdges.has(sourceDir)) {
4108
4486
  dirEdges.set(sourceDir, { in: 0, out: 0 });
@@ -5083,7 +5461,7 @@ function detectCyclesDetailed(graph) {
5083
5461
  }
5084
5462
 
5085
5463
  // src/docs/onboarding.ts
5086
- import { dirname as dirname10 } from "path";
5464
+ import { dirname as dirname11 } from "path";
5087
5465
  function generateOnboarding(graph, projectRoot, version) {
5088
5466
  let output = "";
5089
5467
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -5142,7 +5520,7 @@ function generateQuickOrientation(graph) {
5142
5520
  const primaryLang = Object.entries(languages2).sort((a, b) => b[1] - a[1])[0];
5143
5521
  const dirs = /* @__PURE__ */ new Set();
5144
5522
  graph.forEachNode((node, attrs) => {
5145
- const dir = dirname10(attrs.filePath);
5523
+ const dir = dirname11(attrs.filePath);
5146
5524
  if (dir !== ".") {
5147
5525
  const topLevel = dir.split("/")[0];
5148
5526
  dirs.add(topLevel);
@@ -5246,7 +5624,7 @@ function generateModuleMap(graph) {
5246
5624
  function getDirectoryStats2(graph) {
5247
5625
  const dirMap = /* @__PURE__ */ new Map();
5248
5626
  graph.forEachNode((node, attrs) => {
5249
- const dir = dirname10(attrs.filePath);
5627
+ const dir = dirname11(attrs.filePath);
5250
5628
  if (dir === ".") return;
5251
5629
  if (!dirMap.has(dir)) {
5252
5630
  dirMap.set(dir, {
@@ -5261,7 +5639,7 @@ function getDirectoryStats2(graph) {
5261
5639
  });
5262
5640
  const filesPerDir = /* @__PURE__ */ new Map();
5263
5641
  graph.forEachNode((node, attrs) => {
5264
- const dir = dirname10(attrs.filePath);
5642
+ const dir = dirname11(attrs.filePath);
5265
5643
  if (!filesPerDir.has(dir)) {
5266
5644
  filesPerDir.set(dir, /* @__PURE__ */ new Set());
5267
5645
  }
@@ -5276,8 +5654,8 @@ function getDirectoryStats2(graph) {
5276
5654
  graph.forEachEdge((edge, attrs, source, target) => {
5277
5655
  const sourceAttrs = graph.getNodeAttributes(source);
5278
5656
  const targetAttrs = graph.getNodeAttributes(target);
5279
- const sourceDir = dirname10(sourceAttrs.filePath);
5280
- const targetDir = dirname10(targetAttrs.filePath);
5657
+ const sourceDir = dirname11(sourceAttrs.filePath);
5658
+ const targetDir = dirname11(targetAttrs.filePath);
5281
5659
  if (sourceDir !== targetDir) {
5282
5660
  if (!dirEdges.has(sourceDir)) {
5283
5661
  dirEdges.set(sourceDir, { in: 0, out: 0 });
@@ -5358,7 +5736,7 @@ function detectClusters(graph) {
5358
5736
  const dirFiles = /* @__PURE__ */ new Map();
5359
5737
  const fileEdges = /* @__PURE__ */ new Map();
5360
5738
  graph.forEachNode((node, attrs) => {
5361
- const dir = dirname10(attrs.filePath);
5739
+ const dir = dirname11(attrs.filePath);
5362
5740
  if (!dirFiles.has(dir)) {
5363
5741
  dirFiles.set(dir, /* @__PURE__ */ new Set());
5364
5742
  }
@@ -5412,8 +5790,8 @@ function inferClusterName(files) {
5412
5790
  if (sortedWords.length > 0 && sortedWords[0][1] > 1) {
5413
5791
  return capitalizeFirst2(sortedWords[0][0]);
5414
5792
  }
5415
- const commonDir = dirname10(files[0]);
5416
- if (files.every((f) => dirname10(f) === commonDir)) {
5793
+ const commonDir = dirname11(files[0]);
5794
+ if (files.every((f) => dirname11(f) === commonDir)) {
5417
5795
  return capitalizeFirst2(commonDir.split("/").pop() || "Core");
5418
5796
  }
5419
5797
  return "Core";
@@ -5471,7 +5849,7 @@ function generateDepwireUsage(projectRoot) {
5471
5849
  }
5472
5850
 
5473
5851
  // src/docs/files.ts
5474
- import { dirname as dirname11, basename as basename3 } from "path";
5852
+ import { dirname as dirname12, basename as basename3 } from "path";
5475
5853
  function generateFiles(graph, projectRoot, version) {
5476
5854
  let output = "";
5477
5855
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -5575,7 +5953,7 @@ function generateDirectoryBreakdown(graph) {
5575
5953
  const fileStats = getFileStats2(graph);
5576
5954
  const dirMap = /* @__PURE__ */ new Map();
5577
5955
  for (const file of fileStats) {
5578
- const dir = dirname11(file.filePath);
5956
+ const dir = dirname12(file.filePath);
5579
5957
  const topDir = dir === "." ? "." : dir.split("/")[0];
5580
5958
  if (!dirMap.has(topDir)) {
5581
5959
  dirMap.set(topDir, {
@@ -6218,7 +6596,7 @@ function generateRecommendations(graph) {
6218
6596
  }
6219
6597
 
6220
6598
  // src/docs/tests.ts
6221
- import { basename as basename4, dirname as dirname12 } from "path";
6599
+ import { basename as basename4, dirname as dirname13 } from "path";
6222
6600
  function generateTests(graph, projectRoot, version) {
6223
6601
  let output = "";
6224
6602
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -6247,7 +6625,7 @@ function getFileCount8(graph) {
6247
6625
  }
6248
6626
  function isTestFile3(filePath) {
6249
6627
  const fileName = basename4(filePath).toLowerCase();
6250
- const dirPath = dirname12(filePath).toLowerCase();
6628
+ const dirPath = dirname13(filePath).toLowerCase();
6251
6629
  if (dirPath.includes("test") || dirPath.includes("spec") || dirPath.includes("__tests__")) {
6252
6630
  return true;
6253
6631
  }
@@ -6306,12 +6684,12 @@ function generateTestFileInventory(graph) {
6306
6684
  }
6307
6685
  function matchTestToSource(testFile) {
6308
6686
  const testFileName = basename4(testFile);
6309
- const testDir = dirname12(testFile);
6687
+ const testDir = dirname13(testFile);
6310
6688
  let sourceFileName = testFileName.replace(/\.test\./g, ".").replace(/\.spec\./g, ".").replace(/_test\./g, ".").replace(/_spec\./g, ".");
6311
6689
  const possiblePaths = [];
6312
6690
  possiblePaths.push(testDir + "/" + sourceFileName);
6313
6691
  if (testDir.endsWith("/test") || testDir.endsWith("/tests") || testDir.endsWith("/__tests__")) {
6314
- const parentDir = dirname12(testDir);
6692
+ const parentDir = dirname13(testDir);
6315
6693
  possiblePaths.push(parentDir + "/" + sourceFileName);
6316
6694
  }
6317
6695
  if (testDir.includes("test")) {
@@ -6508,7 +6886,7 @@ function generateTestStatistics(graph) {
6508
6886
  `;
6509
6887
  const dirTestCoverage = /* @__PURE__ */ new Map();
6510
6888
  for (const sourceFile of sourceFiles) {
6511
- const dir = dirname12(sourceFile).split("/")[0];
6889
+ const dir = dirname13(sourceFile).split("/")[0];
6512
6890
  if (!dirTestCoverage.has(dir)) {
6513
6891
  dirTestCoverage.set(dir, { total: 0, tested: 0 });
6514
6892
  }
@@ -6531,7 +6909,7 @@ function generateTestStatistics(graph) {
6531
6909
  }
6532
6910
 
6533
6911
  // src/docs/history.ts
6534
- import { dirname as dirname13 } from "path";
6912
+ import { dirname as dirname14 } from "path";
6535
6913
  import { execSync } from "child_process";
6536
6914
  function generateHistory(graph, projectRoot, version) {
6537
6915
  let output = "";
@@ -6812,7 +7190,7 @@ function generateFeatureClusters(graph) {
6812
7190
  const dirFiles = /* @__PURE__ */ new Map();
6813
7191
  const fileEdges = /* @__PURE__ */ new Map();
6814
7192
  graph.forEachNode((node, attrs) => {
6815
- const dir = dirname13(attrs.filePath);
7193
+ const dir = dirname14(attrs.filePath);
6816
7194
  if (!dirFiles.has(dir)) {
6817
7195
  dirFiles.set(dir, /* @__PURE__ */ new Set());
6818
7196
  }
@@ -6894,7 +7272,7 @@ function capitalizeFirst3(str) {
6894
7272
  }
6895
7273
 
6896
7274
  // src/docs/current.ts
6897
- import { dirname as dirname14 } from "path";
7275
+ import { dirname as dirname15 } from "path";
6898
7276
  function generateCurrent(graph, projectRoot, version) {
6899
7277
  let output = "";
6900
7278
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -7032,7 +7410,7 @@ function generateCompleteFileIndex(graph) {
7032
7410
  fileInfos.sort((a, b) => a.filePath.localeCompare(b.filePath));
7033
7411
  const dirGroups = /* @__PURE__ */ new Map();
7034
7412
  for (const info of fileInfos) {
7035
- const dir = dirname14(info.filePath);
7413
+ const dir = dirname15(info.filePath);
7036
7414
  const topDir = dir === "." ? "root" : dir.split("/")[0];
7037
7415
  if (!dirGroups.has(topDir)) {
7038
7416
  dirGroups.set(topDir, []);
@@ -7243,8 +7621,8 @@ function getTopLevelDir2(filePath) {
7243
7621
  }
7244
7622
 
7245
7623
  // src/docs/status.ts
7246
- import { readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
7247
- import { join as join11 } from "path";
7624
+ import { readFileSync as readFileSync7, existsSync as existsSync9 } from "fs";
7625
+ import { join as join12 } from "path";
7248
7626
  function generateStatus(graph, projectRoot, version) {
7249
7627
  let output = "";
7250
7628
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -7277,12 +7655,12 @@ function getFileCount11(graph) {
7277
7655
  }
7278
7656
  function extractComments(projectRoot, filePath) {
7279
7657
  const comments = [];
7280
- const fullPath = join11(projectRoot, filePath);
7281
- if (!existsSync8(fullPath)) {
7658
+ const fullPath = join12(projectRoot, filePath);
7659
+ if (!existsSync9(fullPath)) {
7282
7660
  return comments;
7283
7661
  }
7284
7662
  try {
7285
- const content = readFileSync6(fullPath, "utf-8");
7663
+ const content = readFileSync7(fullPath, "utf-8");
7286
7664
  const lines = content.split("\n");
7287
7665
  const patterns = [
7288
7666
  { type: "TODO", regex: /(?:\/\/|#|\/\*)\s*TODO:?\s*(.+)/i },
@@ -7844,15 +8222,15 @@ function generateConfidenceSection(title, description, symbols, projectRoot) {
7844
8222
  }
7845
8223
 
7846
8224
  // src/docs/metadata.ts
7847
- import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "fs";
7848
- import { join as join12 } from "path";
8225
+ import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "fs";
8226
+ import { join as join13 } from "path";
7849
8227
  function loadMetadata(outputDir) {
7850
- const metadataPath = join12(outputDir, "metadata.json");
7851
- if (!existsSync9(metadataPath)) {
8228
+ const metadataPath = join13(outputDir, "metadata.json");
8229
+ if (!existsSync10(metadataPath)) {
7852
8230
  return null;
7853
8231
  }
7854
8232
  try {
7855
- const content = readFileSync7(metadataPath, "utf-8");
8233
+ const content = readFileSync8(metadataPath, "utf-8");
7856
8234
  return JSON.parse(content);
7857
8235
  } catch (err) {
7858
8236
  console.error("Failed to load metadata:", err);
@@ -7860,7 +8238,7 @@ function loadMetadata(outputDir) {
7860
8238
  }
7861
8239
  }
7862
8240
  function saveMetadata(outputDir, metadata) {
7863
- const metadataPath = join12(outputDir, "metadata.json");
8241
+ const metadataPath = join13(outputDir, "metadata.json");
7864
8242
  writeFileSync2(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
7865
8243
  }
7866
8244
  function createMetadata(version, projectPath, fileCount, symbolCount, edgeCount, docTypes) {
@@ -7903,7 +8281,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
7903
8281
  const generated = [];
7904
8282
  const errors = [];
7905
8283
  try {
7906
- if (!existsSync10(options.outputDir)) {
8284
+ if (!existsSync11(options.outputDir)) {
7907
8285
  mkdirSync2(options.outputDir, { recursive: true });
7908
8286
  if (options.verbose) {
7909
8287
  console.log(`Created output directory: ${options.outputDir}`);
@@ -7942,7 +8320,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
7942
8320
  try {
7943
8321
  if (options.verbose) console.log("Generating ARCHITECTURE.md...");
7944
8322
  const content = generateArchitecture(graph, projectRoot, version, parseTime);
7945
- const filePath = join13(options.outputDir, "ARCHITECTURE.md");
8323
+ const filePath = join14(options.outputDir, "ARCHITECTURE.md");
7946
8324
  writeFileSync3(filePath, content, "utf-8");
7947
8325
  generated.push("ARCHITECTURE.md");
7948
8326
  } catch (err) {
@@ -7953,7 +8331,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
7953
8331
  try {
7954
8332
  if (options.verbose) console.log("Generating CONVENTIONS.md...");
7955
8333
  const content = generateConventions(graph, projectRoot, version);
7956
- const filePath = join13(options.outputDir, "CONVENTIONS.md");
8334
+ const filePath = join14(options.outputDir, "CONVENTIONS.md");
7957
8335
  writeFileSync3(filePath, content, "utf-8");
7958
8336
  generated.push("CONVENTIONS.md");
7959
8337
  } catch (err) {
@@ -7964,7 +8342,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
7964
8342
  try {
7965
8343
  if (options.verbose) console.log("Generating DEPENDENCIES.md...");
7966
8344
  const content = generateDependencies(graph, projectRoot, version);
7967
- const filePath = join13(options.outputDir, "DEPENDENCIES.md");
8345
+ const filePath = join14(options.outputDir, "DEPENDENCIES.md");
7968
8346
  writeFileSync3(filePath, content, "utf-8");
7969
8347
  generated.push("DEPENDENCIES.md");
7970
8348
  } catch (err) {
@@ -7975,7 +8353,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
7975
8353
  try {
7976
8354
  if (options.verbose) console.log("Generating ONBOARDING.md...");
7977
8355
  const content = generateOnboarding(graph, projectRoot, version);
7978
- const filePath = join13(options.outputDir, "ONBOARDING.md");
8356
+ const filePath = join14(options.outputDir, "ONBOARDING.md");
7979
8357
  writeFileSync3(filePath, content, "utf-8");
7980
8358
  generated.push("ONBOARDING.md");
7981
8359
  } catch (err) {
@@ -7986,7 +8364,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
7986
8364
  try {
7987
8365
  if (options.verbose) console.log("Generating FILES.md...");
7988
8366
  const content = generateFiles(graph, projectRoot, version);
7989
- const filePath = join13(options.outputDir, "FILES.md");
8367
+ const filePath = join14(options.outputDir, "FILES.md");
7990
8368
  writeFileSync3(filePath, content, "utf-8");
7991
8369
  generated.push("FILES.md");
7992
8370
  } catch (err) {
@@ -7997,7 +8375,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
7997
8375
  try {
7998
8376
  if (options.verbose) console.log("Generating API_SURFACE.md...");
7999
8377
  const content = generateApiSurface(graph, projectRoot, version);
8000
- const filePath = join13(options.outputDir, "API_SURFACE.md");
8378
+ const filePath = join14(options.outputDir, "API_SURFACE.md");
8001
8379
  writeFileSync3(filePath, content, "utf-8");
8002
8380
  generated.push("API_SURFACE.md");
8003
8381
  } catch (err) {
@@ -8008,7 +8386,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
8008
8386
  try {
8009
8387
  if (options.verbose) console.log("Generating ERRORS.md...");
8010
8388
  const content = generateErrors(graph, projectRoot, version);
8011
- const filePath = join13(options.outputDir, "ERRORS.md");
8389
+ const filePath = join14(options.outputDir, "ERRORS.md");
8012
8390
  writeFileSync3(filePath, content, "utf-8");
8013
8391
  generated.push("ERRORS.md");
8014
8392
  } catch (err) {
@@ -8019,7 +8397,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
8019
8397
  try {
8020
8398
  if (options.verbose) console.log("Generating TESTS.md...");
8021
8399
  const content = generateTests(graph, projectRoot, version);
8022
- const filePath = join13(options.outputDir, "TESTS.md");
8400
+ const filePath = join14(options.outputDir, "TESTS.md");
8023
8401
  writeFileSync3(filePath, content, "utf-8");
8024
8402
  generated.push("TESTS.md");
8025
8403
  } catch (err) {
@@ -8030,7 +8408,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
8030
8408
  try {
8031
8409
  if (options.verbose) console.log("Generating HISTORY.md...");
8032
8410
  const content = generateHistory(graph, projectRoot, version);
8033
- const filePath = join13(options.outputDir, "HISTORY.md");
8411
+ const filePath = join14(options.outputDir, "HISTORY.md");
8034
8412
  writeFileSync3(filePath, content, "utf-8");
8035
8413
  generated.push("HISTORY.md");
8036
8414
  } catch (err) {
@@ -8041,7 +8419,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
8041
8419
  try {
8042
8420
  if (options.verbose) console.log("Generating CURRENT.md...");
8043
8421
  const content = generateCurrent(graph, projectRoot, version);
8044
- const filePath = join13(options.outputDir, "CURRENT.md");
8422
+ const filePath = join14(options.outputDir, "CURRENT.md");
8045
8423
  writeFileSync3(filePath, content, "utf-8");
8046
8424
  generated.push("CURRENT.md");
8047
8425
  } catch (err) {
@@ -8052,7 +8430,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
8052
8430
  try {
8053
8431
  if (options.verbose) console.log("Generating STATUS.md...");
8054
8432
  const content = generateStatus(graph, projectRoot, version);
8055
- const filePath = join13(options.outputDir, "STATUS.md");
8433
+ const filePath = join14(options.outputDir, "STATUS.md");
8056
8434
  writeFileSync3(filePath, content, "utf-8");
8057
8435
  generated.push("STATUS.md");
8058
8436
  } catch (err) {
@@ -8063,7 +8441,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
8063
8441
  try {
8064
8442
  if (options.verbose) console.log("Generating HEALTH.md...");
8065
8443
  const content = generateHealth(graph, projectRoot, version);
8066
- const filePath = join13(options.outputDir, "HEALTH.md");
8444
+ const filePath = join14(options.outputDir, "HEALTH.md");
8067
8445
  writeFileSync3(filePath, content, "utf-8");
8068
8446
  generated.push("HEALTH.md");
8069
8447
  } catch (err) {
@@ -8074,7 +8452,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
8074
8452
  try {
8075
8453
  if (options.verbose) console.log("Generating DEAD_CODE.md...");
8076
8454
  const content = generateDeadCode(graph, projectRoot, version);
8077
- const filePath = join13(options.outputDir, "DEAD_CODE.md");
8455
+ const filePath = join14(options.outputDir, "DEAD_CODE.md");
8078
8456
  writeFileSync3(filePath, content, "utf-8");
8079
8457
  generated.push("DEAD_CODE.md");
8080
8458
  } catch (err) {
@@ -8122,13 +8500,13 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8122
8500
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8123
8501
 
8124
8502
  // src/mcp/tools.ts
8125
- import { dirname as dirname15, join as join16 } from "path";
8126
- import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
8503
+ import { dirname as dirname16, join as join17 } from "path";
8504
+ import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
8127
8505
 
8128
8506
  // src/mcp/connect.ts
8129
8507
  import simpleGit from "simple-git";
8130
- import { existsSync as existsSync11 } from "fs";
8131
- import { join as join14, basename as basename5, resolve as resolve2 } from "path";
8508
+ import { existsSync as existsSync12 } from "fs";
8509
+ import { join as join15, basename as basename5, resolve as resolve2 } from "path";
8132
8510
  import { tmpdir, homedir } from "os";
8133
8511
  function validateProjectPath(source) {
8134
8512
  const resolved = resolve2(source);
@@ -8141,11 +8519,11 @@ function validateProjectPath(source) {
8141
8519
  "/boot",
8142
8520
  "/proc",
8143
8521
  "/sys",
8144
- join14(homedir(), ".ssh"),
8145
- join14(homedir(), ".gnupg"),
8146
- join14(homedir(), ".aws"),
8147
- join14(homedir(), ".config"),
8148
- join14(homedir(), ".env")
8522
+ join15(homedir(), ".ssh"),
8523
+ join15(homedir(), ".gnupg"),
8524
+ join15(homedir(), ".aws"),
8525
+ join15(homedir(), ".config"),
8526
+ join15(homedir(), ".env")
8149
8527
  ];
8150
8528
  for (const blocked of blockedPaths) {
8151
8529
  if (resolved.startsWith(blocked)) {
@@ -8168,11 +8546,11 @@ async function connectToRepo(source, subdirectory, state) {
8168
8546
  };
8169
8547
  }
8170
8548
  projectName = match[1];
8171
- const reposDir = join14(tmpdir(), "depwire-repos");
8172
- const cloneDir = join14(reposDir, projectName);
8549
+ const reposDir = join15(tmpdir(), "depwire-repos");
8550
+ const cloneDir = join15(reposDir, projectName);
8173
8551
  console.error(`Connecting to GitHub repo: ${source}`);
8174
8552
  const git = simpleGit();
8175
- if (existsSync11(cloneDir)) {
8553
+ if (existsSync12(cloneDir)) {
8176
8554
  console.error(`Repo already cloned at ${cloneDir}, pulling latest changes...`);
8177
8555
  try {
8178
8556
  await git.cwd(cloneDir).pull();
@@ -8190,7 +8568,7 @@ async function connectToRepo(source, subdirectory, state) {
8190
8568
  };
8191
8569
  }
8192
8570
  }
8193
- projectRoot = subdirectory ? join14(cloneDir, subdirectory) : cloneDir;
8571
+ projectRoot = subdirectory ? join15(cloneDir, subdirectory) : cloneDir;
8194
8572
  } else {
8195
8573
  const validation2 = validateProjectPath(source);
8196
8574
  if (!validation2.valid) {
@@ -8199,13 +8577,13 @@ async function connectToRepo(source, subdirectory, state) {
8199
8577
  message: validation2.error
8200
8578
  };
8201
8579
  }
8202
- if (!existsSync11(source)) {
8580
+ if (!existsSync12(source)) {
8203
8581
  return {
8204
8582
  error: "Directory not found",
8205
8583
  message: `Directory does not exist: ${source}`
8206
8584
  };
8207
8585
  }
8208
- projectRoot = subdirectory ? join14(source, subdirectory) : source;
8586
+ projectRoot = subdirectory ? join15(source, subdirectory) : source;
8209
8587
  projectName = basename5(projectRoot);
8210
8588
  }
8211
8589
  const validation = validateProjectPath(projectRoot);
@@ -8215,7 +8593,7 @@ async function connectToRepo(source, subdirectory, state) {
8215
8593
  message: validation.error
8216
8594
  };
8217
8595
  }
8218
- if (!existsSync11(projectRoot)) {
8596
+ if (!existsSync12(projectRoot)) {
8219
8597
  return {
8220
8598
  error: "Project root not found",
8221
8599
  message: `Directory does not exist: ${projectRoot}`
@@ -8496,24 +8874,24 @@ function getWeekNumber(date) {
8496
8874
  }
8497
8875
 
8498
8876
  // src/temporal/snapshots.ts
8499
- import { writeFileSync as writeFileSync4, readFileSync as readFileSync8, mkdirSync as mkdirSync3, existsSync as existsSync12, readdirSync as readdirSync4 } from "fs";
8500
- import { join as join15 } from "path";
8877
+ import { writeFileSync as writeFileSync4, readFileSync as readFileSync9, mkdirSync as mkdirSync3, existsSync as existsSync13, readdirSync as readdirSync5 } from "fs";
8878
+ import { join as join16 } from "path";
8501
8879
  function saveSnapshot(snapshot, outputDir) {
8502
- if (!existsSync12(outputDir)) {
8880
+ if (!existsSync13(outputDir)) {
8503
8881
  mkdirSync3(outputDir, { recursive: true });
8504
8882
  }
8505
8883
  const filename = `${snapshot.commitHash.substring(0, 8)}.json`;
8506
- const filepath = join15(outputDir, filename);
8884
+ const filepath = join16(outputDir, filename);
8507
8885
  writeFileSync4(filepath, JSON.stringify(snapshot, null, 2), "utf-8");
8508
8886
  }
8509
8887
  function loadSnapshot(commitHash, outputDir) {
8510
8888
  const shortHash = commitHash.substring(0, 8);
8511
- const filepath = join15(outputDir, `${shortHash}.json`);
8512
- if (!existsSync12(filepath)) {
8889
+ const filepath = join16(outputDir, `${shortHash}.json`);
8890
+ if (!existsSync13(filepath)) {
8513
8891
  return null;
8514
8892
  }
8515
8893
  try {
8516
- const content = readFileSync8(filepath, "utf-8");
8894
+ const content = readFileSync9(filepath, "utf-8");
8517
8895
  return JSON.parse(content);
8518
8896
  } catch {
8519
8897
  return null;
@@ -9200,7 +9578,7 @@ function handleGetArchitectureSummary(graph) {
9200
9578
  const dirMap = /* @__PURE__ */ new Map();
9201
9579
  const languageBreakdown = {};
9202
9580
  fileSummary.forEach((f) => {
9203
- const dir = f.filePath.includes("/") ? dirname15(f.filePath) : ".";
9581
+ const dir = f.filePath.includes("/") ? dirname16(f.filePath) : ".";
9204
9582
  if (!dirMap.has(dir)) {
9205
9583
  dirMap.set(dir, { fileCount: 0, symbolCount: 0 });
9206
9584
  }
@@ -9287,8 +9665,8 @@ The server will keep running until you end the MCP session or press Ctrl+C.`;
9287
9665
  };
9288
9666
  }
9289
9667
  async function handleGetProjectDocs(docType, state) {
9290
- const docsDir = join16(state.projectRoot, ".depwire");
9291
- if (!existsSync13(docsDir)) {
9668
+ const docsDir = join17(state.projectRoot, ".depwire");
9669
+ if (!existsSync14(docsDir)) {
9292
9670
  const errorMessage = `Project documentation has not been generated yet.
9293
9671
 
9294
9672
  Run \`depwire docs ${state.projectRoot}\` to generate codebase documentation.
@@ -9318,12 +9696,12 @@ Available document types:
9318
9696
  missing.push(doc);
9319
9697
  continue;
9320
9698
  }
9321
- const filePath = join16(docsDir, metadata.documents[doc].file);
9322
- if (!existsSync13(filePath)) {
9699
+ const filePath = join17(docsDir, metadata.documents[doc].file);
9700
+ if (!existsSync14(filePath)) {
9323
9701
  missing.push(doc);
9324
9702
  continue;
9325
9703
  }
9326
- const content = readFileSync9(filePath, "utf-8");
9704
+ const content = readFileSync10(filePath, "utf-8");
9327
9705
  if (docsToReturn.length > 1) {
9328
9706
  output += `
9329
9707
 
@@ -9348,16 +9726,16 @@ Available document types:
9348
9726
  }
9349
9727
  async function handleUpdateProjectDocs(docType, state) {
9350
9728
  const startTime = Date.now();
9351
- const docsDir = join16(state.projectRoot, ".depwire");
9729
+ const docsDir = join17(state.projectRoot, ".depwire");
9352
9730
  console.error("Regenerating project documentation...");
9353
9731
  const parsedFiles = await parseProject(state.projectRoot);
9354
9732
  const graph = buildGraph(parsedFiles);
9355
9733
  const parseTime = (Date.now() - startTime) / 1e3;
9356
9734
  state.graph = graph;
9357
- const packageJsonPath = join16(__dirname, "../../package.json");
9358
- const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
9735
+ const packageJsonPath = join17(__dirname, "../../package.json");
9736
+ const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
9359
9737
  const docsToGenerate = docType === "all" ? ["architecture", "conventions", "dependencies", "onboarding"] : [docType];
9360
- const docsExist = existsSync13(docsDir);
9738
+ const docsExist = existsSync14(docsDir);
9361
9739
  const result = await generateDocs(graph, state.projectRoot, packageJson.version, parseTime, {
9362
9740
  outputDir: docsDir,
9363
9741
  format: "markdown",
@@ -9416,7 +9794,7 @@ async function handleGetTemporalGraph(state, commits, strategy) {
9416
9794
  }
9417
9795
  const sampledCommits = sampleCommits(allCommits, commits, strategy);
9418
9796
  const snapshots = [];
9419
- const outputDir = join16(projectRoot, ".depwire", "temporal");
9797
+ const outputDir = join17(projectRoot, ".depwire", "temporal");
9420
9798
  for (const commit of sampledCommits) {
9421
9799
  const existing = loadSnapshot(commit.hash, outputDir);
9422
9800
  if (existing) {
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  stashChanges,
28
28
  updateFileInGraph,
29
29
  watchProject
30
- } from "./chunk-MGMDHXPB.js";
30
+ } from "./chunk-UPAZDLUB.js";
31
31
 
32
32
  // src/index.ts
33
33
  import { Command } from "commander";
@@ -6,7 +6,7 @@ import {
6
6
  startMcpServer,
7
7
  updateFileInGraph,
8
8
  watchProject
9
- } from "./chunk-MGMDHXPB.js";
9
+ } from "./chunk-UPAZDLUB.js";
10
10
 
11
11
  // src/mcpb-entry.ts
12
12
  import { resolve } from "path";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "depwire-cli",
3
- "version": "0.9.0",
4
- "description": "Code cross-reference visualization and AI context engine for TypeScript, JavaScript, Python, Go, and Rust. Zero native dependencies โ€” works on Windows, macOS, and Linux.",
3
+ "version": "0.9.1",
4
+ "description": "Code cross-reference visualization and AI context engine for TypeScript, JavaScript, Python, Go, Rust, and C. Zero native dependencies โ€” works on Windows, macOS, and Linux.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "depwire": "dist/index.js"