depwire-cli 0.1.0 → 0.2.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/LICENSE CHANGED
@@ -1,21 +1,65 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 CodeGraph
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Business Source License 1.1
2
+
3
+ Parameters
4
+
5
+ Licensor: ATEF ATAYA LLC
6
+ Licensed Work: Depwire
7
+ The Licensed Work is (c) 2026 ATEF ATAYA LLC
8
+ Additional Use Grant: You may make use of the Licensed Work, provided that
9
+ you may not use the Licensed Work for a Code Analysis
10
+ Service. A "Code Analysis Service" is a commercial
11
+ offering that allows third parties to access the
12
+ functionality of the Licensed Work by providing
13
+ dependency graph analysis, code visualization, or
14
+ MCP-based code context as a managed service.
15
+
16
+ Change Date: February 25, 2029
17
+
18
+ Change License: Apache License, Version 2.0
19
+
20
+ For information about alternative licensing arrangements for the Licensed Work,
21
+ please contact: atef@depwire.dev
22
+
23
+ Notice
24
+
25
+ Business Source License 1.1
26
+
27
+ Terms
28
+
29
+ The Licensor hereby grants you the right to copy, modify, create derivative
30
+ works, redistribute, and make non-production use of the Licensed Work. The
31
+ Licensor may make an Additional Use Grant, above, permitting limited production
32
+ use.
33
+
34
+ Effective on the Change Date, or the fourth anniversary of the first publicly
35
+ available distribution of a specific version of the Licensed Work, whichever
36
+ comes first, the Licensor hereby grants you rights under the terms of the
37
+ Change License, and the rights granted in the paragraph above terminate.
38
+
39
+ If your use of the Licensed Work does not comply with the requirements
40
+ currently in effect as described in this License, you must purchase a
41
+ commercial license from the Licensor, its affiliated entities, or authorized
42
+ resellers, or you must refrain from using the Licensed Work.
43
+
44
+ All copies of the original and modified Licensed Work, and derivative works of
45
+ the Licensed Work, are subject to this License. This License applies separately
46
+ for each version of the Licensed Work and the Change Date may vary for each
47
+ version of the Licensed Work released by Licensor.
48
+
49
+ You must conspicuously display this License on each original or modified copy
50
+ of the Licensed Work. If you receive the Licensed Work in original or modified
51
+ form from a third party, the terms and conditions set forth in this License
52
+ apply to your use of that work.
53
+
54
+ Any use of the Licensed Work in violation of this License will automatically
55
+ terminate your rights under this License for the current and all other versions
56
+ of the Licensed Work.
57
+
58
+ This License does not grant you any right in any trademark or logo of Licensor
59
+ or its affiliates (provided that you may use a trademark or logo of Licensor
60
+ as expressly required by this License).
61
+
62
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
63
+ "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS
64
+ OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY,
65
+ FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
package/README.md CHANGED
@@ -15,8 +15,23 @@ Depwire analyzes codebases to build a cross-reference graph showing how every fi
15
15
  ### CLI Usage
16
16
 
17
17
  ```bash
18
- npx depwire viz ./my-project # Open visualization
19
- npx depwire parse ./my-project # Export graph as JSON
18
+ # Visualization (opens in browser)
19
+ npx depwire-cli viz ./my-project
20
+
21
+ # Parse and export as JSON
22
+ npx depwire-cli parse ./my-project
23
+
24
+ # Exclude test files and node_modules
25
+ npx depwire-cli parse ./my-project --exclude "**/*.test.*" "**/node_modules/**"
26
+
27
+ # Show detailed parsing progress
28
+ npx depwire-cli parse ./my-project --verbose
29
+
30
+ # Export with pretty-printed JSON and statistics
31
+ npx depwire-cli parse ./my-project --pretty --stats
32
+
33
+ # Custom output file
34
+ npx depwire-cli parse ./my-project -o my-graph.json
20
35
  ```
21
36
 
22
37
  ### Claude Desktop
@@ -28,7 +43,7 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_
28
43
  "mcpServers": {
29
44
  "depwire": {
30
45
  "command": "npx",
31
- "args": ["-y", "depwire", "mcp"]
46
+ "args": ["-y", "depwire-cli", "mcp"]
32
47
  }
33
48
  }
34
49
  }
@@ -43,7 +58,7 @@ Connect to /path/to/my/project and show me the architecture.
43
58
 
44
59
  Settings → Features → Experimental → Enable MCP → Add Server:
45
60
  - Command: `npx`
46
- - Args: `-y depwire mcp /path/to/project`
61
+ - Args: `-y depwire-cli mcp /path/to/project`
47
62
 
48
63
  ## Available MCP Tools
49
64
 
@@ -58,6 +73,7 @@ Settings → Features → Experimental → Enable MCP → Add Server:
58
73
  | `get_architecture_summary` | High-level project overview |
59
74
  | `list_files` | List all files with stats |
60
75
  | `get_symbol_info` | Look up any symbol's details |
76
+ | `visualize_graph` | Generate interactive arc diagram visualization |
61
77
 
62
78
  ## Supported Languages
63
79
 
@@ -71,7 +87,20 @@ Settings → Features → Experimental → Enable MCP → Add Server:
71
87
  ## Visualization
72
88
 
73
89
  ```bash
90
+ # Open visualization on default port (3456)
74
91
  depwire viz ./my-project
92
+
93
+ # Custom port
94
+ depwire viz ./my-project --port 8080
95
+
96
+ # Exclude test files from visualization
97
+ depwire viz ./my-project --exclude "**/*.test.*"
98
+
99
+ # Verbose mode with detailed parsing logs
100
+ depwire viz ./my-project --verbose
101
+
102
+ # Don't auto-open browser
103
+ depwire viz ./my-project --no-open
75
104
  ```
76
105
 
77
106
  Opens an interactive arc diagram in your browser:
@@ -79,8 +108,9 @@ Opens an interactive arc diagram in your browser:
79
108
  - Hover to explore connections
80
109
  - Click to filter by file
81
110
  - Search by filename
82
- - Live refresh when files change
111
+ - **Live refresh when files change** — Edit code and see the graph update in real-time
83
112
  - Export as SVG or PNG
113
+ - **Port collision handling** — Automatically finds an available port if default is in use
84
114
 
85
115
  ## How It Works
86
116
 
@@ -92,14 +122,83 @@ Opens an interactive arc diagram in your browser:
92
122
  ## Installation
93
123
 
94
124
  ```bash
95
- npm install -g depwire
125
+ npm install -g depwire-cli
96
126
  ```
97
127
 
98
128
  Or use directly with `npx`:
99
129
  ```bash
100
- npx depwire --help
130
+ npx depwire-cli --help
131
+ ```
132
+
133
+ ## CLI Reference
134
+
135
+ ### `depwire parse <directory>`
136
+
137
+ Parse a project and export the dependency graph as JSON.
138
+
139
+ **Options:**
140
+ - `-o, --output <path>` — Output file path (default: `depwire-output.json`)
141
+ - `--exclude <patterns...>` — Glob patterns to exclude (e.g., `"**/*.test.*" "dist/**"`)
142
+ - `--verbose` — Show detailed parsing progress (logs each file as it's parsed)
143
+ - `--pretty` — Pretty-print JSON output with indentation
144
+ - `--stats` — Print summary statistics (file count, symbol count, edges, timing)
145
+
146
+ **Examples:**
147
+ ```bash
148
+ # Basic parse
149
+ depwire parse ./src
150
+
151
+ # Exclude test files and build outputs
152
+ depwire parse ./src --exclude "**/*.test.*" "**/*.spec.*" "dist/**" "build/**"
153
+
154
+ # Full verbosity with stats
155
+ depwire parse ./src --verbose --stats --pretty -o graph.json
101
156
  ```
102
157
 
158
+ ### `depwire viz <directory>`
159
+
160
+ Start visualization server and open arc diagram in browser.
161
+
162
+ **Options:**
163
+ - `--port <number>` — Port number (default: 3456, auto-increments if in use)
164
+ - `--exclude <patterns...>` — Glob patterns to exclude
165
+ - `--verbose` — Show detailed parsing progress
166
+ - `--no-open` — Don't automatically open browser
167
+
168
+ **Examples:**
169
+ ```bash
170
+ # Basic visualization
171
+ depwire viz ./src
172
+
173
+ # Custom port without auto-open
174
+ depwire viz ./src --port 8080 --no-open
175
+
176
+ # Exclude test files with verbose logging
177
+ depwire viz ./src --exclude "**/*.test.*" --verbose
178
+ ```
179
+
180
+ ### `depwire mcp [directory]`
181
+
182
+ Start MCP server for AI tool integration (Cursor, Claude Desktop).
183
+
184
+ **Examples:**
185
+ ```bash
186
+ # Start MCP server on current directory
187
+ depwire mcp
188
+
189
+ # Start on specific project
190
+ depwire mcp /path/to/project
191
+ ```
192
+
193
+ ### Error Handling
194
+
195
+ Depwire gracefully handles parse errors:
196
+ - **Malformed files** — Skipped with warning, parsing continues
197
+ - **Large files** — Files over 1MB are automatically skipped
198
+ - **Port collisions** — Auto-increments to next available port (3456 → 3457 → 3458...)
199
+ - **Protected paths** — Blocks access to sensitive directories (.ssh, .aws, /etc)
200
+
201
+
103
202
  ## Example Workflows
104
203
 
105
204
  ### Refactoring with AI
@@ -158,20 +257,31 @@ See [SECURITY.md](SECURITY.md) for full details.
158
257
 
159
258
  ## Contributing
160
259
 
161
- Contributions welcome! Depwire is open source and community-driven.
260
+ Contributions welcome! Please note:
162
261
 
163
262
  1. Fork the repository
164
263
  2. Create a feature branch
165
264
  3. Add tests for new functionality
166
265
  4. Submit a pull request
266
+ 5. Sign the CLA (handled automatically on your first PR)
267
+
268
+ All contributors must sign the Contributor License Agreement before their PR can be merged.
167
269
 
168
270
  ## License
169
271
 
170
- MIT Copyright (c) 2026 ATEF ATAYA LLC
272
+ Depwire is licensed under the [Business Source License 1.1](LICENSE).
273
+
274
+ - **Use it freely** for personal projects, internal company use, and development
275
+ - **Cannot** be offered as a hosted/managed service to third parties
276
+ - **Converts** to Apache 2.0 on February 25, 2029
277
+
278
+ For commercial licensing inquiries: atef@depwire.dev
171
279
 
172
280
  ## Credits
173
281
 
174
- Built with:
282
+ Built by [ATEF ATAYA LLC](https://depwire.dev)
283
+
284
+ Powered by:
175
285
  - [tree-sitter](https://tree-sitter.github.io/tree-sitter/) — Fast, reliable parsing
176
286
  - [graphology](https://graphology.github.io/) — Powerful graph data structure
177
287
  - [D3.js](https://d3js.org/) — Data visualization
@@ -158,7 +158,7 @@ var tsxParser = new Parser();
158
158
  tsxParser.setLanguage(TypeScript.tsx);
159
159
  function parseTypeScriptFile(filePath, sourceCode, projectRoot) {
160
160
  const parser2 = filePath.endsWith(".tsx") ? tsxParser : tsParser;
161
- const tree = parser2.parse(sourceCode);
161
+ const tree = parser2.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
162
162
  const context = {
163
163
  filePath,
164
164
  projectRoot,
@@ -620,7 +620,7 @@ import { existsSync as existsSync2 } from "fs";
620
620
  var pyParser = new Parser2();
621
621
  pyParser.setLanguage(Python);
622
622
  function parsePythonFile(filePath, sourceCode, projectRoot) {
623
- const tree = pyParser.parse(sourceCode);
623
+ const tree = pyParser.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
624
624
  const context = {
625
625
  filePath,
626
626
  projectRoot,
@@ -989,7 +989,7 @@ import { join as join4, dirname as dirname3, extname as extname2 } from "path";
989
989
  var jsParser = new Parser3();
990
990
  jsParser.setLanguage(JavaScript);
991
991
  function parseJavaScriptFile(filePath, sourceCode, projectRoot) {
992
- const tree = jsParser.parse(sourceCode);
992
+ const tree = jsParser.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
993
993
  const context = {
994
994
  filePath,
995
995
  projectRoot,
@@ -1493,7 +1493,7 @@ import { join as join5, dirname as dirname4 } from "path";
1493
1493
  var parser = new Parser4();
1494
1494
  parser.setLanguage(Go);
1495
1495
  function parseGoFile(filePath, sourceCode, projectRoot) {
1496
- const tree = parser.parse(sourceCode);
1496
+ const tree = parser.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
1497
1497
  const moduleName = readGoModuleName(projectRoot);
1498
1498
  const context = {
1499
1499
  filePath,
@@ -1924,6 +1924,7 @@ function getParserForFile(filePath) {
1924
1924
  }
1925
1925
 
1926
1926
  // src/parser/index.ts
1927
+ import { minimatch } from "minimatch";
1927
1928
  var MAX_FILE_SIZE = 1e6;
1928
1929
  function shouldParseFile(fullPath) {
1929
1930
  try {
@@ -1937,27 +1938,58 @@ function shouldParseFile(fullPath) {
1937
1938
  return false;
1938
1939
  }
1939
1940
  }
1940
- function parseProject(projectRoot) {
1941
+ function parseProject(projectRoot, options) {
1941
1942
  const files = scanDirectory(projectRoot);
1942
1943
  const parsedFiles = [];
1944
+ let skippedFiles = 0;
1945
+ let errorFiles = 0;
1943
1946
  for (const file of files) {
1944
1947
  try {
1945
1948
  const fullPath = join6(projectRoot, file);
1949
+ if (options?.exclude) {
1950
+ const shouldExclude = options.exclude.some(
1951
+ (pattern) => minimatch(file, pattern, { matchBase: true })
1952
+ );
1953
+ if (shouldExclude) {
1954
+ if (options.verbose) {
1955
+ console.error(`[Parser] Excluded: ${file}`);
1956
+ }
1957
+ skippedFiles++;
1958
+ continue;
1959
+ }
1960
+ }
1946
1961
  if (!shouldParseFile(fullPath)) {
1962
+ skippedFiles++;
1947
1963
  continue;
1948
1964
  }
1965
+ if (options?.verbose) {
1966
+ console.error(`[Parser] Parsing: ${file}`);
1967
+ }
1949
1968
  const parser2 = getParserForFile(file);
1950
1969
  if (!parser2) {
1951
1970
  console.error(`No parser found for file: ${file}`);
1971
+ skippedFiles++;
1952
1972
  continue;
1953
1973
  }
1954
1974
  const sourceCode = readFileSync3(fullPath, "utf-8");
1955
1975
  const parsed = parser2.parseFile(file, sourceCode, projectRoot);
1956
1976
  parsedFiles.push(parsed);
1957
1977
  } catch (err) {
1978
+ errorFiles++;
1958
1979
  console.error(`Error parsing file ${file}:`, err instanceof Error ? err.message : err);
1959
1980
  }
1960
1981
  }
1982
+ if (options?.verbose || errorFiles > 0) {
1983
+ console.error(`
1984
+ [Parser] Summary:`);
1985
+ console.error(` Parsed: ${parsedFiles.length} files`);
1986
+ if (skippedFiles > 0) {
1987
+ console.error(` Skipped: ${skippedFiles} files`);
1988
+ }
1989
+ if (errorFiles > 0) {
1990
+ console.error(` Errors: ${errorFiles} files`);
1991
+ }
1992
+ }
1961
1993
  return parsedFiles;
1962
1994
  }
1963
1995
 
@@ -2240,7 +2272,7 @@ function prepareVizData(graph, projectRoot) {
2240
2272
  import chokidar from "chokidar";
2241
2273
  function watchProject(projectRoot, callbacks) {
2242
2274
  console.error(`[Watcher] Creating watcher for: ${projectRoot}`);
2243
- const watcher = chokidar.watch(projectRoot, {
2275
+ const watcherOptions = {
2244
2276
  ignored: [
2245
2277
  "**/node_modules/**",
2246
2278
  "**/vendor/**",
@@ -2251,19 +2283,36 @@ function watchProject(projectRoot, callbacks) {
2251
2283
  "**/coverage/**",
2252
2284
  "**/.next/**",
2253
2285
  "**/.turbo/**",
2254
- "**/.*"
2255
- // Hidden files and directories
2286
+ "**/.DS_Store",
2287
+ // macOS metadata
2288
+ "**/.env",
2289
+ // Environment files
2290
+ "**/.env.*",
2291
+ // Environment variants
2292
+ "**/.eslintcache",
2293
+ // ESLint cache
2294
+ "**/.vscode/**",
2295
+ // VS Code settings
2296
+ "**/.idea/**"
2297
+ // IntelliJ IDEA settings
2256
2298
  ],
2257
2299
  ignoreInitial: true,
2258
2300
  // Don't fire events for existing files
2259
2301
  persistent: true,
2260
2302
  followSymlinks: false,
2303
+ usePolling: true,
2304
+ // Use polling for macOS reliability
2305
+ interval: 1e3,
2306
+ // Poll every second
2307
+ atomic: true,
2308
+ // Handle atomic writes (VS Code, Sublime, etc.)
2261
2309
  awaitWriteFinish: {
2262
2310
  stabilityThreshold: 300,
2263
2311
  // Wait 300ms after last change before firing
2264
2312
  pollInterval: 100
2265
2313
  }
2266
- });
2314
+ };
2315
+ const watcher = chokidar.watch(projectRoot, watcherOptions);
2267
2316
  console.error("[Watcher] Attaching event listeners...");
2268
2317
  watcher.on("change", (absolutePath) => {
2269
2318
  const validExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go"];
@@ -2305,9 +2354,6 @@ function watchProject(projectRoot, callbacks) {
2305
2354
  }
2306
2355
  console.error(`[Watcher] Watching ${fileCount} TypeScript/JavaScript/Python/Go files in ${dirs.length} directories`);
2307
2356
  });
2308
- watcher.on("all", (event, path) => {
2309
- console.error(`[Watcher] ALL event: ${event} ${path}`);
2310
- });
2311
2357
  return watcher;
2312
2358
  }
2313
2359
 
@@ -2320,7 +2366,31 @@ import { WebSocketServer } from "ws";
2320
2366
  var __filename = fileURLToPath(import.meta.url);
2321
2367
  var __dirname = dirname5(__filename);
2322
2368
  var activeServer = null;
2323
- function startVizServer(initialVizData, graph, projectRoot, port = 3333, shouldOpen = true) {
2369
+ async function findAvailablePort(startPort, maxAttempts = 10) {
2370
+ const net = await import("net");
2371
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
2372
+ const testPort = startPort + attempt;
2373
+ const isAvailable = await new Promise((resolve3) => {
2374
+ const server = net.createServer();
2375
+ server.once("error", () => {
2376
+ resolve3(false);
2377
+ });
2378
+ server.once("listening", () => {
2379
+ server.close();
2380
+ resolve3(true);
2381
+ });
2382
+ server.listen(testPort, "127.0.0.1");
2383
+ });
2384
+ if (isAvailable) {
2385
+ if (attempt > 0) {
2386
+ console.error(`Port ${startPort} in use, using port ${testPort} instead`);
2387
+ }
2388
+ return testPort;
2389
+ }
2390
+ }
2391
+ throw new Error(`No available ports found between ${startPort} and ${startPort + maxAttempts - 1}`);
2392
+ }
2393
+ async function startVizServer(initialVizData, graph, projectRoot, port = 3333, shouldOpen = true, options) {
2324
2394
  if (activeServer) {
2325
2395
  console.error(`Visualization server already running at ${activeServer.url}`);
2326
2396
  return {
@@ -2329,6 +2399,7 @@ function startVizServer(initialVizData, graph, projectRoot, port = 3333, shouldO
2329
2399
  alreadyRunning: true
2330
2400
  };
2331
2401
  }
2402
+ const availablePort = await findAvailablePort(port);
2332
2403
  const app = express();
2333
2404
  let vizData = initialVizData;
2334
2405
  const publicDir = join7(__dirname, "viz", "public");
@@ -2336,12 +2407,12 @@ function startVizServer(initialVizData, graph, projectRoot, port = 3333, shouldO
2336
2407
  app.get("/api/graph", (req, res) => {
2337
2408
  res.json(vizData);
2338
2409
  });
2339
- const server = app.listen(port, "127.0.0.1", () => {
2340
- const url2 = `http://127.0.0.1:${port}`;
2410
+ const server = app.listen(availablePort, "127.0.0.1", () => {
2411
+ const url2 = `http://127.0.0.1:${availablePort}`;
2341
2412
  console.error(`
2342
2413
  Depwire visualization running at ${url2}`);
2343
2414
  console.error("Press Ctrl+C to stop\n");
2344
- activeServer = { server, port, url: url2 };
2415
+ activeServer = { server, port: availablePort, url: url2 };
2345
2416
  if (shouldOpen) {
2346
2417
  open(url2);
2347
2418
  }
@@ -2365,7 +2436,7 @@ Depwire visualization running at ${url2}`);
2365
2436
  onFileChanged: async (filePath) => {
2366
2437
  console.error(`File changed: ${filePath} \u2014 re-parsing project...`);
2367
2438
  try {
2368
- const parsedFiles = parseProject(projectRoot);
2439
+ const parsedFiles = parseProject(projectRoot, options);
2369
2440
  const newGraph = buildGraph(parsedFiles);
2370
2441
  graph.clear();
2371
2442
  newGraph.forEachNode((node, attrs) => {
@@ -2384,7 +2455,7 @@ Depwire visualization running at ${url2}`);
2384
2455
  onFileAdded: async (filePath) => {
2385
2456
  console.error(`File added: ${filePath} \u2014 re-parsing project...`);
2386
2457
  try {
2387
- const parsedFiles = parseProject(projectRoot);
2458
+ const parsedFiles = parseProject(projectRoot, options);
2388
2459
  const newGraph = buildGraph(parsedFiles);
2389
2460
  graph.clear();
2390
2461
  newGraph.forEachNode((node, attrs) => {
@@ -2403,7 +2474,7 @@ Depwire visualization running at ${url2}`);
2403
2474
  onFileDeleted: (filePath) => {
2404
2475
  console.error(`File deleted: ${filePath} \u2014 re-parsing project...`);
2405
2476
  try {
2406
- const parsedFiles = parseProject(projectRoot);
2477
+ const parsedFiles = parseProject(projectRoot, options);
2407
2478
  const newGraph = buildGraph(parsedFiles);
2408
2479
  graph.clear();
2409
2480
  newGraph.forEachNode((node, attrs) => {
@@ -2429,7 +2500,7 @@ Depwire visualization running at ${url2}`);
2429
2500
  process.exit(0);
2430
2501
  });
2431
2502
  });
2432
- const url = `http://127.0.0.1:${port}`;
2503
+ const url = `http://127.0.0.1:${availablePort}`;
2433
2504
  return { server, url, alreadyRunning: false };
2434
2505
  }
2435
2506
 
@@ -3220,7 +3291,7 @@ function handleListFiles(directory, graph) {
3220
3291
  }
3221
3292
  async function handleVisualizeGraph(highlight, maxFiles, state) {
3222
3293
  const vizData = prepareVizData(state.graph, state.projectRoot);
3223
- const { url, alreadyRunning } = startVizServer(
3294
+ const { url, alreadyRunning } = await startVizServer(
3224
3295
  vizData,
3225
3296
  state.graph,
3226
3297
  state.projectRoot,
package/dist/index.js CHANGED
@@ -11,12 +11,13 @@ import {
11
11
  startVizServer,
12
12
  updateFileInGraph,
13
13
  watchProject
14
- } from "./chunk-2XOJSBSD.js";
14
+ } from "./chunk-V3SB37U3.js";
15
15
 
16
16
  // src/index.ts
17
17
  import { Command } from "commander";
18
- import { resolve } from "path";
18
+ import { resolve, dirname, join } from "path";
19
19
  import { writeFileSync, readFileSync, existsSync } from "fs";
20
+ import { fileURLToPath } from "url";
20
21
 
21
22
  // src/graph/serializer.ts
22
23
  import { DirectedGraph } from "graphology";
@@ -85,14 +86,21 @@ function importFromJSON(json) {
85
86
  }
86
87
 
87
88
  // src/index.ts
89
+ var __filename = fileURLToPath(import.meta.url);
90
+ var __dirname = dirname(__filename);
91
+ var packageJsonPath = join(__dirname, "../package.json");
92
+ var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
88
93
  var program = new Command();
89
- program.name("depwire").description("Code cross-reference graph builder for TypeScript projects").version("0.1.0");
90
- program.command("parse").description("Parse a TypeScript project and build dependency graph").argument("<directory>", "Project directory to parse").option("-o, --output <path>", "Output JSON file path", "depwire-output.json").option("--pretty", "Pretty-print JSON output").option("--stats", "Print summary statistics").action(async (directory, options) => {
94
+ program.name("depwire").description("Code cross-reference graph builder for TypeScript projects").version(packageJson.version);
95
+ program.command("parse").description("Parse a TypeScript project and build dependency graph").argument("<directory>", "Project directory to parse").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) => {
91
96
  const startTime = Date.now();
92
97
  try {
93
98
  const projectRoot = resolve(directory);
94
99
  console.log(`Parsing project: ${projectRoot}`);
95
- const parsedFiles = parseProject(projectRoot);
100
+ const parsedFiles = parseProject(projectRoot, {
101
+ exclude: options.exclude,
102
+ verbose: options.verbose
103
+ });
96
104
  console.log(`Parsed ${parsedFiles.length} files`);
97
105
  const graph = buildGraph(parsedFiles);
98
106
  const projectGraph = exportToJSON(graph, projectRoot);
@@ -171,17 +179,23 @@ Total Transitive Dependents: ${impact.transitiveDependents.length}`);
171
179
  process.exit(1);
172
180
  }
173
181
  });
174
- program.command("viz").description("Launch interactive arc diagram visualization").argument("<directory>", "Project directory to visualize").option("-p, --port <number>", "Server port", "3333").option("--no-open", "Don't auto-open browser").action(async (directory, options) => {
182
+ program.command("viz").description("Launch interactive arc diagram visualization").argument("<directory>", "Project directory to visualize").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) => {
175
183
  try {
176
184
  const projectRoot = resolve(directory);
177
185
  console.log(`Parsing project: ${projectRoot}`);
178
- const parsedFiles = parseProject(projectRoot);
186
+ const parsedFiles = parseProject(projectRoot, {
187
+ exclude: options.exclude,
188
+ verbose: options.verbose
189
+ });
179
190
  console.log(`Parsed ${parsedFiles.length} files`);
180
191
  const graph = buildGraph(parsedFiles);
181
192
  const vizData = prepareVizData(graph, projectRoot);
182
193
  console.log(`Found ${vizData.stats.totalSymbols} symbols, ${vizData.stats.totalCrossFileEdges} cross-file edges`);
183
194
  const port = parseInt(options.port, 10);
184
- startVizServer(vizData, graph, projectRoot, port, options.open);
195
+ await startVizServer(vizData, graph, projectRoot, port, options.open, {
196
+ exclude: options.exclude,
197
+ verbose: options.verbose
198
+ });
185
199
  } catch (err) {
186
200
  console.error("Error starting visualization:", err);
187
201
  process.exit(1);
@@ -6,7 +6,7 @@ import {
6
6
  startMcpServer,
7
7
  updateFileInGraph,
8
8
  watchProject
9
- } from "./chunk-2XOJSBSD.js";
9
+ } from "./chunk-V3SB37U3.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.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Code cross-reference visualization and AI context engine for TypeScript. Analyzes codebases to show dependencies, enables AI tools with MCP, and renders beautiful arc diagrams.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,15 +31,15 @@
31
31
  "cross-reference"
32
32
  ],
33
33
  "author": "Depwire",
34
- "license": "MIT",
34
+ "license": "BSL-1.1",
35
35
  "repository": {
36
36
  "type": "git",
37
- "url": "git+https://github.com/depwire-dev/depwire.git"
37
+ "url": "git+https://github.com/depwire/depwire.git"
38
38
  },
39
39
  "bugs": {
40
- "url": "https://github.com/depwire-dev/depwire/issues"
40
+ "url": "https://github.com/depwire/depwire/issues"
41
41
  },
42
- "homepage": "https://github.com/depwire-dev/depwire#readme",
42
+ "homepage": "https://depwire.dev",
43
43
  "files": [
44
44
  "dist",
45
45
  "README.md",
@@ -56,6 +56,7 @@
56
56
  "express": "5.2.1",
57
57
  "graphology": "0.26.0",
58
58
  "graphology-types": "0.24.8",
59
+ "minimatch": "^10.2.4",
59
60
  "open": "11.0.0",
60
61
  "simple-git": "3.31.1",
61
62
  "tree-sitter": "0.21.1",