depwire-cli 0.9.9 → 0.9.12
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 +27 -3
- package/dist/{chunk-VVYRHPAE.js → chunk-S3NZMIIU.js} +40 -7
- package/dist/index.js +31 -1
- package/dist/mcpb-entry.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -78,6 +78,30 @@ Or use directly with `npx`:
|
|
|
78
78
|
npx depwire-cli --help
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
## Telemetry
|
|
82
|
+
|
|
83
|
+
Depwire collects **anonymous usage data** to help us understand which features are most useful and prioritize development.
|
|
84
|
+
|
|
85
|
+
**What we collect:**
|
|
86
|
+
- Command name (e.g. `parse`, `mcp`, `viz`)
|
|
87
|
+
- Depwire version
|
|
88
|
+
- Operating system (mac/linux/windows)
|
|
89
|
+
- Node.js version
|
|
90
|
+
|
|
91
|
+
**What we never collect:**
|
|
92
|
+
- File paths or code content
|
|
93
|
+
- Repo names or URLs
|
|
94
|
+
- Usernames, emails, or any personal data
|
|
95
|
+
|
|
96
|
+
**To opt out**, set this environment variable:
|
|
97
|
+
```bash
|
|
98
|
+
DEPWIRE_NO_TELEMETRY=1 depwire parse
|
|
99
|
+
# Or add to your shell profile:
|
|
100
|
+
export DEPWIRE_NO_TELEMETRY=1
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Telemetry data is used solely to improve Depwire. [View our privacy policy](https://depwire.dev/privacy)
|
|
104
|
+
|
|
81
105
|
## Quick Start
|
|
82
106
|
|
|
83
107
|
### CLI Usage
|
|
@@ -401,7 +425,7 @@ depwire docs --output ./docs
|
|
|
401
425
|
depwire docs --update --only conventions
|
|
402
426
|
```
|
|
403
427
|
|
|
404
|
-
**Generated Documents (
|
|
428
|
+
**Generated Documents (13 total):**
|
|
405
429
|
|
|
406
430
|
| Document | What It Contains |
|
|
407
431
|
|----------|------------------|
|
|
@@ -417,7 +441,7 @@ depwire docs --update --only conventions
|
|
|
417
441
|
| `CURRENT.md` | Complete codebase snapshot (every file, symbol, connection) |
|
|
418
442
|
| `STATUS.md` | TODO/FIXME/HACK inventory with priority matrix |
|
|
419
443
|
| `HEALTH.md` | Dependency health score (0-100) across 6 dimensions with recommendations |
|
|
420
|
-
| `DEAD_CODE.md` |
|
|
444
|
+
| `DEAD_CODE.md` | Unused symbols by confidence level (high/medium/low) with smart exclusions |
|
|
421
445
|
|
|
422
446
|
Documents are stored in `.depwire/` with `metadata.json` tracking generation timestamps for staleness detection.
|
|
423
447
|
|
|
@@ -625,7 +649,7 @@ See [SECURITY.md](SECURITY.md) for full details.
|
|
|
625
649
|
- [x] WASM migration (Windows support)
|
|
626
650
|
|
|
627
651
|
### 🔜 Coming Next
|
|
628
|
-
- [ ] New language support (C — community requested)
|
|
652
|
+
- [ ] New language support (Java, C++, Ruby — community requested)
|
|
629
653
|
- [ ] "What If" simulation — simulate refactors before touching code
|
|
630
654
|
- [ ] Cross-language edge detection (API routes ↔ frontend calls)
|
|
631
655
|
- [ ] 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
|
-
|
|
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}'.
|
|
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
|
-
|
|
9627
|
-
|
|
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
|
-
|
|
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-
|
|
30
|
+
} from "./chunk-S3NZMIIU.js";
|
|
31
31
|
|
|
32
32
|
// src/index.ts
|
|
33
33
|
import { Command } from "commander";
|
|
@@ -474,6 +474,28 @@ function printStats(snapshots) {
|
|
|
474
474
|
Overall Trend: ${trend}`);
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
+
// src/telemetry.ts
|
|
478
|
+
import os from "os";
|
|
479
|
+
var TELEMETRY_URL = "https://telemetry.depwire.dev/event";
|
|
480
|
+
async function trackCommand(command, version = "unknown") {
|
|
481
|
+
if (process.env.DEPWIRE_NO_TELEMETRY === "1" || process.env.DEPWIRE_NO_TELEMETRY === "true" || process.env.DO_NOT_TRACK === "1") {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const payload = {
|
|
485
|
+
command,
|
|
486
|
+
version,
|
|
487
|
+
os: os.platform(),
|
|
488
|
+
node: process.version
|
|
489
|
+
};
|
|
490
|
+
fetch(TELEMETRY_URL, {
|
|
491
|
+
method: "POST",
|
|
492
|
+
headers: { "Content-Type": "application/json" },
|
|
493
|
+
body: JSON.stringify(payload),
|
|
494
|
+
signal: AbortSignal.timeout(2e3)
|
|
495
|
+
}).catch(() => {
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
477
499
|
// src/index.ts
|
|
478
500
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
479
501
|
var __dirname2 = dirname2(__filename2);
|
|
@@ -482,6 +504,7 @@ var packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
|
|
|
482
504
|
var program = new Command();
|
|
483
505
|
program.name("depwire").description("Code cross-reference graph builder for TypeScript projects").version(packageJson.version);
|
|
484
506
|
program.command("parse").description("Parse a TypeScript project and build dependency graph").argument("[directory]", "Project directory to parse (defaults to current directory or auto-detected project root)").option("-o, --output <path>", "Output JSON file path", "depwire-output.json").option("--pretty", "Pretty-print JSON output").option("--stats", "Print summary statistics").option("--exclude <patterns...>", 'Glob patterns to exclude (e.g., "**/*.test.*" "dist/**")').option("--verbose", "Show detailed parsing progress").action(async (directory, options) => {
|
|
507
|
+
trackCommand("parse", packageJson.version);
|
|
485
508
|
const startTime = Date.now();
|
|
486
509
|
try {
|
|
487
510
|
const projectRoot = directory ? resolve(directory) : findProjectRoot();
|
|
@@ -521,6 +544,7 @@ Orphan Files (no cross-references): ${summary.orphanFiles.length}`);
|
|
|
521
544
|
}
|
|
522
545
|
});
|
|
523
546
|
program.command("query").description("Query impact analysis for a symbol").argument("<directory>", "Project directory").argument("<symbol-name>", "Symbol name to query").action(async (directory, symbolName) => {
|
|
547
|
+
trackCommand("query", packageJson.version);
|
|
524
548
|
try {
|
|
525
549
|
const projectRoot = resolve(directory);
|
|
526
550
|
const cacheFile = "depwire-output.json";
|
|
@@ -569,6 +593,7 @@ Total Transitive Dependents: ${impact.transitiveDependents.length}`);
|
|
|
569
593
|
}
|
|
570
594
|
});
|
|
571
595
|
program.command("viz").description("Launch interactive arc diagram visualization").argument("[directory]", "Project directory to visualize (defaults to current directory or auto-detected project root)").option("-p, --port <number>", "Server port", "3333").option("--no-open", "Don't auto-open browser").option("--exclude <patterns...>", 'Glob patterns to exclude (e.g., "**/*.test.*" "dist/**")').option("--verbose", "Show detailed parsing progress").action(async (directory, options) => {
|
|
596
|
+
trackCommand("viz", packageJson.version);
|
|
572
597
|
try {
|
|
573
598
|
const projectRoot = directory ? resolve(directory) : findProjectRoot();
|
|
574
599
|
console.log(`Parsing project: ${projectRoot}`);
|
|
@@ -591,6 +616,7 @@ program.command("viz").description("Launch interactive arc diagram visualization
|
|
|
591
616
|
}
|
|
592
617
|
});
|
|
593
618
|
program.command("temporal").description("Visualize how the dependency graph evolved over git history").argument("[directory]", "Project directory to analyze (defaults to current directory or auto-detected project root)").option("--commits <number>", "Number of commits to sample", "20").option("--strategy <type>", "Sampling strategy: even, weekly, monthly", "even").option("-p, --port <number>", "Server port", "3334").option("--output <path>", "Save snapshots to custom path (default: .depwire/temporal/)").option("--verbose", "Show progress for each commit being parsed").option("--stats", "Show summary statistics at end").action(async (directory, options) => {
|
|
619
|
+
trackCommand("temporal", packageJson.version);
|
|
594
620
|
try {
|
|
595
621
|
const projectRoot = directory ? resolve(directory) : findProjectRoot();
|
|
596
622
|
await runTemporalAnalysis(projectRoot, {
|
|
@@ -607,6 +633,7 @@ program.command("temporal").description("Visualize how the dependency graph evol
|
|
|
607
633
|
}
|
|
608
634
|
});
|
|
609
635
|
program.command("mcp").description("Start MCP server for AI coding tools").argument("[directory]", "Project directory to analyze (optional - auto-detects project root or use connect_repo tool to connect later)").action(async (directory) => {
|
|
636
|
+
trackCommand("mcp", packageJson.version);
|
|
610
637
|
try {
|
|
611
638
|
const state = createEmptyState();
|
|
612
639
|
let projectRootToConnect = null;
|
|
@@ -669,6 +696,7 @@ program.command("mcp").description("Start MCP server for AI coding tools").argum
|
|
|
669
696
|
}
|
|
670
697
|
});
|
|
671
698
|
program.command("docs").description("Generate comprehensive codebase documentation").argument("[directory]", "Project directory to document (defaults to current directory or auto-detected project root)").option("-o, --output <path>", "Output directory (default: .depwire/ inside project)").option("--format <type>", "Output format: markdown | json", "markdown").option("--gitignore", "Add .depwire/ to .gitignore automatically").option("--no-gitignore", "Don't modify .gitignore").option("--include <docs>", "Comma-separated list of docs to generate (default: all)", "all").option("--update", "Regenerate existing docs").option("--only <docs>", "Used with --update, regenerate only specific docs").option("--verbose", "Show generation progress").option("--stats", "Show generation statistics at the end").option("--exclude <patterns...>", 'Glob patterns to exclude (e.g., "**/*.test.*" "dist/**")').action(async (directory, options) => {
|
|
699
|
+
trackCommand("docs", packageJson.version);
|
|
672
700
|
const startTime = Date.now();
|
|
673
701
|
try {
|
|
674
702
|
const projectRoot = directory ? resolve(directory) : findProjectRoot();
|
|
@@ -766,6 +794,7 @@ ${pattern}
|
|
|
766
794
|
}
|
|
767
795
|
}
|
|
768
796
|
program.command("health").description("Analyze dependency architecture health (0-100 score)").argument("[directory]", "Project directory to analyze (defaults to current directory or auto-detected project root)").option("--json", "Output as JSON").option("--verbose", "Show detailed breakdown").action(async (directory, options) => {
|
|
797
|
+
trackCommand("health", packageJson.version);
|
|
769
798
|
try {
|
|
770
799
|
const projectRoot = directory ? resolve(directory) : findProjectRoot();
|
|
771
800
|
const startTime = Date.now();
|
|
@@ -789,6 +818,7 @@ program.command("health").description("Analyze dependency architecture health (0
|
|
|
789
818
|
}
|
|
790
819
|
});
|
|
791
820
|
program.command("dead-code").description("Identify dead code - symbols defined but never referenced").argument("[directory]", "Project directory to analyze (defaults to current directory or auto-detected project root)").option("--confidence <level>", "Minimum confidence level to show: high, medium, low (default: medium)", "medium").option("--json", "Output as JSON (for CI/automation)").option("--verbose", "Show detailed info for each dead symbol").option("--stats", "Show summary statistics").option("--include-tests", "Include test files in analysis").option("--include-low", "Shortcut for --confidence low").option("--debug", "Show debug information (exclusion stats)").action(async (directory, options) => {
|
|
821
|
+
trackCommand("dead-code", packageJson.version);
|
|
792
822
|
try {
|
|
793
823
|
const projectRoot = directory ? resolve(directory) : findProjectRoot();
|
|
794
824
|
const startTime = Date.now();
|
package/dist/mcpb-entry.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "depwire-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
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": {
|