depwire-cli 0.9.8 → 0.9.10

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
@@ -401,7 +401,7 @@ depwire docs --output ./docs
401
401
  depwire docs --update --only conventions
402
402
  ```
403
403
 
404
- **Generated Documents (12 total):**
404
+ **Generated Documents (13 total):**
405
405
 
406
406
  | Document | What It Contains |
407
407
  |----------|------------------|
@@ -417,7 +417,7 @@ depwire docs --update --only conventions
417
417
  | `CURRENT.md` | Complete codebase snapshot (every file, symbol, connection) |
418
418
  | `STATUS.md` | TODO/FIXME/HACK inventory with priority matrix |
419
419
  | `HEALTH.md` | Dependency health score (0-100) across 6 dimensions with recommendations |
420
- | `DEAD_CODE.md` | Dead code analysis — unused symbols by confidence level (high/medium/low) |
420
+ | `DEAD_CODE.md` | Unused symbols by confidence level (high/medium/low) with smart exclusions |
421
421
 
422
422
  Documents are stored in `.depwire/` with `metadata.json` tracking generation timestamps for staleness detection.
423
423
 
@@ -625,7 +625,7 @@ See [SECURITY.md](SECURITY.md) for full details.
625
625
  - [x] WASM migration (Windows support)
626
626
 
627
627
  ### 🔜 Coming Next
628
- - [ ] New language support (C — community requested)
628
+ - [ ] New language support (Java, C++, Ruby — community requested)
629
629
  - [ ] "What If" simulation — simulate refactors before touching code
630
630
  - [ ] Cross-language edge detection (API routes ↔ frontend calls)
631
631
  - [ ] Cloud dashboard (first paid feature)
@@ -1,6 +1,7 @@
1
1
  // src/utils/files.ts
2
2
  import { readdirSync, statSync, existsSync, lstatSync } from "fs";
3
3
  import { join, relative } from "path";
4
+ import os from "os";
4
5
  function scanDirectory(rootDir, baseDir = rootDir) {
5
6
  const files = [];
6
7
  try {
@@ -71,9 +72,21 @@ function findProjectRoot(startDir = process.cwd()) {
71
72
  ".git"
72
73
  // Any git repo
73
74
  ];
75
+ const blocklist = ["Library", "System", "Applications", "usr", "bin", "etc", "var", "private"];
74
76
  let currentDir = startDir;
75
77
  const rootDir = "/";
76
- while (currentDir !== rootDir) {
78
+ const maxDepth = 10;
79
+ let depth = 0;
80
+ const home = os.homedir();
81
+ while (currentDir !== rootDir && depth < maxDepth) {
82
+ if (currentDir === home || !currentDir.startsWith(home)) {
83
+ break;
84
+ }
85
+ const dirName = currentDir.split("/").pop();
86
+ if (dirName && blocklist.includes(dirName)) {
87
+ console.warn(`\u26A0\uFE0F Skipping blocked directory: ${dirName}`);
88
+ break;
89
+ }
77
90
  for (const marker of projectMarkers) {
78
91
  const markerPath = join(currentDir, marker);
79
92
  if (existsSync(markerPath)) {
@@ -85,7 +98,9 @@ function findProjectRoot(startDir = process.cwd()) {
85
98
  break;
86
99
  }
87
100
  currentDir = parentDir;
101
+ depth++;
88
102
  }
103
+ console.warn(`\u26A0\uFE0F No project root found within ${maxDepth} levels. Using current directory: ${startDir}`);
89
104
  return startDir;
90
105
  }
91
106
 
@@ -9211,6 +9226,10 @@ function getToolsList() {
9211
9226
  symbol: {
9212
9227
  type: "string",
9213
9228
  description: "Symbol name (e.g., 'Router') or full ID (e.g., 'src/router.ts::Router')"
9229
+ },
9230
+ file: {
9231
+ type: "string",
9232
+ description: "Optional: File path to disambiguate when multiple symbols have the same name (e.g., 'src/router.ts')"
9214
9233
  }
9215
9234
  },
9216
9235
  required: ["symbol"]
@@ -9442,7 +9461,7 @@ async function handleToolCall(name, args, state) {
9442
9461
  result = handleGetDependents(args.symbol, graph);
9443
9462
  break;
9444
9463
  case "impact_analysis":
9445
- result = handleImpactAnalysis(args.symbol, graph);
9464
+ result = handleImpactAnalysis(args.symbol, graph, args.file);
9446
9465
  break;
9447
9466
  case "get_file_context":
9448
9467
  result = handleGetFileContext(args.filePath, graph);
@@ -9502,9 +9521,12 @@ async function handleToolCall(name, args, state) {
9502
9521
  }
9503
9522
  function createDisambiguationResponse(matches, queryName) {
9504
9523
  const suggestion = matches.length > 0 ? matches[0].id : "";
9524
+ const exampleFile = matches.length > 0 ? matches[0].filePath : "";
9505
9525
  return {
9506
9526
  ambiguous: true,
9507
- message: `Found ${matches.length} symbols named '${queryName}'. Please specify which one by using the full ID (e.g., '${suggestion}').`,
9527
+ message: `Found ${matches.length} symbols named '${queryName}'. Disambiguate by:
9528
+ 1. Using full ID: '${suggestion}'
9529
+ 2. Or adding file parameter: { symbol: '${queryName}', file: '${exampleFile}' }`,
9508
9530
  matches: matches.map((m, index) => ({
9509
9531
  id: m.id,
9510
9532
  kind: m.kind,
@@ -9614,7 +9636,7 @@ function handleGetDependents(symbol, graph) {
9614
9636
  totalCount
9615
9637
  };
9616
9638
  }
9617
- function handleImpactAnalysis(symbol, graph) {
9639
+ function handleImpactAnalysis(symbol, graph, file) {
9618
9640
  const matches = findSymbols(graph, symbol);
9619
9641
  if (matches.length === 0) {
9620
9642
  const fuzzyMatches = searchSymbols(graph, symbol).slice(0, 10);
@@ -9623,10 +9645,21 @@ function handleImpactAnalysis(symbol, graph) {
9623
9645
  suggestion: fuzzyMatches.length > 0 ? `Did you mean: ${fuzzyMatches.map((m) => m.name).join(", ")}?` : "Try using search_symbols to find available symbols"
9624
9646
  };
9625
9647
  }
9626
- if (matches.length > 1) {
9627
- return createDisambiguationResponse(matches, symbol);
9648
+ let filteredMatches = matches;
9649
+ if (file) {
9650
+ filteredMatches = matches.filter((m) => m.filePath === file || m.filePath.endsWith(file));
9651
+ if (filteredMatches.length === 0) {
9652
+ return {
9653
+ error: `Symbol '${symbol}' not found in file '${file}'`,
9654
+ availableFiles: matches.map((m) => m.filePath),
9655
+ suggestion: `The symbol exists in: ${matches.map((m) => m.filePath).join(", ")}`
9656
+ };
9657
+ }
9628
9658
  }
9629
- const target = matches[0];
9659
+ if (filteredMatches.length > 1) {
9660
+ return createDisambiguationResponse(filteredMatches, symbol);
9661
+ }
9662
+ const target = filteredMatches[0];
9630
9663
  const impact = getImpact(graph, target.id);
9631
9664
  const directWithKinds = impact.directDependents.map((dep) => {
9632
9665
  let relationship = "unknown";
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  stashChanges,
28
28
  updateFileInGraph,
29
29
  watchProject
30
- } from "./chunk-VVYRHPAE.js";
30
+ } from "./chunk-S3NZMIIU.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-VVYRHPAE.js";
9
+ } from "./chunk-S3NZMIIU.js";
10
10
 
11
11
  // src/mcpb-entry.ts
12
12
  import { resolve } from "path";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "depwire-cli",
3
- "version": "0.9.8",
3
+ "version": "0.9.10",
4
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": {