depwire-cli 0.9.19 → 0.9.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,37 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- analyzeDeadCode,
4
- buildGraph,
5
- calculateHealthScore,
6
3
  checkoutCommit,
7
4
  createEmptyState,
8
5
  createSnapshot,
9
- findProjectRoot,
10
- generateDocs,
11
- getArchitectureSummary,
12
6
  getCommitLog,
13
7
  getCurrentBranch,
14
- getHealthTrend,
15
- getImpact,
16
8
  isGitRepo,
17
9
  loadSnapshot,
18
- parseProject,
19
10
  popStash,
20
11
  prepareVizData,
21
12
  restoreOriginal,
22
13
  sampleCommits,
23
14
  saveSnapshot,
24
- searchSymbols,
25
15
  startMcpServer,
26
16
  startVizServer,
27
17
  stashChanges,
28
18
  updateFileInGraph,
29
19
  watchProject
30
- } from "./chunk-S3NZMIIU.js";
20
+ } from "./chunk-XBCQPU63.js";
21
+ import {
22
+ SimulationEngine,
23
+ analyzeDeadCode,
24
+ buildGraph,
25
+ calculateHealthScore,
26
+ findProjectRoot,
27
+ generateDocs,
28
+ getArchitectureSummary,
29
+ getHealthTrend,
30
+ getImpact,
31
+ parseProject,
32
+ searchSymbols
33
+ } from "./chunk-QHVWDUSX.js";
31
34
 
32
35
  // src/index.ts
33
36
  import { Command } from "commander";
34
- import { resolve, dirname as dirname2, join as join3 } from "path";
37
+ import { resolve as resolve2, dirname as dirname2, join as join3 } from "path";
35
38
  import { writeFileSync, readFileSync as readFileSync2, existsSync } from "fs";
36
39
  import { fileURLToPath as fileURLToPath2 } from "url";
37
40
 
@@ -302,10 +305,10 @@ async function findAvailablePort(startPort) {
302
305
  const net = await import("net");
303
306
  for (let attempt = 0; attempt < 10; attempt++) {
304
307
  const testPort = startPort + attempt;
305
- const isAvailable = await new Promise((resolve2) => {
306
- const server = net.createServer().once("error", () => resolve2(false)).once("listening", () => {
308
+ const isAvailable = await new Promise((resolve3) => {
309
+ const server = net.createServer().once("error", () => resolve3(false)).once("listening", () => {
307
310
  server.close();
308
- resolve2(true);
311
+ resolve3(true);
309
312
  }).listen(testPort, "127.0.0.1");
310
313
  });
311
314
  if (isAvailable) {
@@ -346,13 +349,13 @@ async function startTemporalServer(snapshots, projectRoot, preferredPort = 3334)
346
349
  console.log(" (Could not open browser automatically)");
347
350
  });
348
351
  });
349
- await new Promise((resolve2, reject) => {
352
+ await new Promise((resolve3, reject) => {
350
353
  server.on("error", reject);
351
354
  process.on("SIGINT", () => {
352
355
  console.log("\n\nShutting down temporal server...");
353
356
  server.close(() => {
354
357
  console.log("Server stopped");
355
- resolve2();
358
+ resolve3();
356
359
  process.exit(0);
357
360
  });
358
361
  });
@@ -496,6 +499,138 @@ async function trackCommand(command, version = "unknown") {
496
499
  });
497
500
  }
498
501
 
502
+ // src/commands/whatif.ts
503
+ import { resolve } from "path";
504
+ import chalk from "chalk";
505
+ async function whatif(dir, options) {
506
+ if (!options.simulate) {
507
+ console.log("Usage: depwire whatif [dir] --simulate <action> --target <file> [options]");
508
+ console.log("");
509
+ console.log("Actions: move, delete, rename, split, merge");
510
+ console.log("");
511
+ console.log("Run without --simulate to open interactive browser UI (Phase B)");
512
+ return;
513
+ }
514
+ const validActions = ["move", "delete", "rename", "split", "merge"];
515
+ if (!validActions.includes(options.simulate)) {
516
+ console.error(chalk.red(`Invalid action: ${options.simulate}. Must be one of: ${validActions.join(", ")}`));
517
+ process.exit(1);
518
+ }
519
+ if (!options.target) {
520
+ console.error(chalk.red("--target is required for all simulation actions"));
521
+ process.exit(1);
522
+ }
523
+ const action = buildAction(options);
524
+ const projectRoot = dir === "." ? findProjectRoot() : resolve(dir);
525
+ console.log(`Parsing project: ${projectRoot}`);
526
+ const parsedFiles = await parseProject(projectRoot);
527
+ const graph = buildGraph(parsedFiles);
528
+ console.log(`Built graph: ${graph.order} symbols, ${graph.size} edges`);
529
+ console.log("");
530
+ const engine = new SimulationEngine(graph);
531
+ try {
532
+ const result = engine.simulate(action);
533
+ printResult(result);
534
+ } catch (err) {
535
+ console.error(chalk.red(`Simulation failed: ${err.message}`));
536
+ process.exit(1);
537
+ }
538
+ }
539
+ function buildAction(options) {
540
+ const type = options.simulate;
541
+ const target = options.target;
542
+ switch (type) {
543
+ case "move":
544
+ if (!options.destination) {
545
+ console.error(chalk.red("--destination is required for move action"));
546
+ process.exit(1);
547
+ }
548
+ return { type: "move", target, destination: options.destination };
549
+ case "delete":
550
+ return { type: "delete", target };
551
+ case "rename":
552
+ if (!options.newName) {
553
+ console.error(chalk.red("--new-name is required for rename action"));
554
+ process.exit(1);
555
+ }
556
+ return { type: "rename", target, newName: options.newName };
557
+ case "split":
558
+ if (!options.newFile) {
559
+ console.error(chalk.red("--new-file is required for split action"));
560
+ process.exit(1);
561
+ }
562
+ if (!options.symbols) {
563
+ console.error(chalk.red("--symbols is required for split action (comma-separated)"));
564
+ process.exit(1);
565
+ }
566
+ return {
567
+ type: "split",
568
+ target,
569
+ newFile: options.newFile,
570
+ symbols: options.symbols.split(",").map((s) => s.trim())
571
+ };
572
+ case "merge":
573
+ if (!options.source) {
574
+ console.error(chalk.red("--source is required for merge action"));
575
+ process.exit(1);
576
+ }
577
+ return { type: "merge", target, source: options.source };
578
+ default:
579
+ console.error(chalk.red(`Unknown action: ${type}`));
580
+ process.exit(1);
581
+ }
582
+ }
583
+ function printResult(result) {
584
+ const { action, healthDelta, diff } = result;
585
+ const line = "\u2500".repeat(45);
586
+ console.log(chalk.bold("What If Simulation"));
587
+ console.log(chalk.dim(line));
588
+ const actionStr = formatAction(action);
589
+ console.log(`${chalk.bold("Action:")} ${actionStr}`);
590
+ console.log(chalk.dim(line));
591
+ const deltaSign = healthDelta.delta >= 0 ? "+" : "";
592
+ const deltaColor = healthDelta.improved ? chalk.green : healthDelta.delta === 0 ? chalk.yellow : chalk.red;
593
+ const deltaIcon = healthDelta.improved ? "\u2713 improved" : healthDelta.delta === 0 ? "\u2192 unchanged" : "\u2717 degraded";
594
+ console.log(
595
+ `${chalk.bold("Health Score:")} ${healthDelta.before} \u2192 ${healthDelta.after} ${deltaColor(`(${deltaSign}${healthDelta.delta} ${deltaIcon})`)}`
596
+ );
597
+ const changed = healthDelta.dimensionChanges.filter((d) => d.delta !== 0);
598
+ if (changed.length > 0) {
599
+ for (const d of changed) {
600
+ const dSign = d.delta >= 0 ? "+" : "";
601
+ const dColor = d.delta > 0 ? chalk.green : chalk.red;
602
+ console.log(` ${chalk.dim("\u2022")} ${d.name}: ${d.before} \u2192 ${d.after} ${dColor(`(${dSign}${d.delta})`)}`);
603
+ }
604
+ }
605
+ console.log(`${chalk.bold("Affected Nodes:")} ${diff.affectedNodes.length}`);
606
+ console.log(`${chalk.bold("Broken Imports:")} ${diff.brokenImports.length}`);
607
+ if (diff.brokenImports.length > 0) {
608
+ for (const bi of diff.brokenImports) {
609
+ console.log(` ${chalk.yellow("\u2022")} ${bi.file} ${bi.reason}`);
610
+ }
611
+ }
612
+ console.log(
613
+ `${chalk.bold("Circular Deps:")} ${diff.circularDepsIntroduced.length} introduced, ${diff.circularDepsResolved.length} resolved`
614
+ );
615
+ console.log(`${chalk.bold("Added Edges:")} ${diff.addedEdges.length}`);
616
+ console.log(`${chalk.bold("Removed Edges:")} ${diff.removedEdges.length}`);
617
+ console.log(chalk.dim(line));
618
+ }
619
+ function formatAction(action) {
620
+ switch (action.type) {
621
+ case "move":
622
+ return `MOVE ${action.target} \u2192 ${action.destination}`;
623
+ case "delete":
624
+ return `DELETE ${action.target}`;
625
+ case "rename":
626
+ return `RENAME ${action.target} \u2192 ${action.newName}`;
627
+ case "split":
628
+ return `SPLIT ${action.target} \u2192 ${action.newFile} (${action.symbols.join(", ")})`;
629
+ case "merge":
630
+ return `MERGE ${action.source} \u2192 ${action.target}`;
631
+ }
632
+ }
633
+
499
634
  // src/index.ts
500
635
  var __filename2 = fileURLToPath2(import.meta.url);
501
636
  var __dirname2 = dirname2(__filename2);
@@ -507,7 +642,7 @@ program.command("parse").description("Parse a TypeScript project and build depen
507
642
  trackCommand("parse", packageJson.version);
508
643
  const startTime = Date.now();
509
644
  try {
510
- const projectRoot = directory ? resolve(directory) : findProjectRoot();
645
+ const projectRoot = directory ? resolve2(directory) : findProjectRoot();
511
646
  console.log(`Parsing project: ${projectRoot}`);
512
647
  const parsedFiles = await parseProject(projectRoot, {
513
648
  exclude: options.exclude,
@@ -546,7 +681,7 @@ Orphan Files (no cross-references): ${summary.orphanFiles.length}`);
546
681
  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
682
  trackCommand("query", packageJson.version);
548
683
  try {
549
- const projectRoot = resolve(directory);
684
+ const projectRoot = resolve2(directory);
550
685
  const cacheFile = "depwire-output.json";
551
686
  let graph;
552
687
  if (existsSync(cacheFile)) {
@@ -595,7 +730,7 @@ Total Transitive Dependents: ${impact.transitiveDependents.length}`);
595
730
  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
731
  trackCommand("viz", packageJson.version);
597
732
  try {
598
- const projectRoot = directory ? resolve(directory) : findProjectRoot();
733
+ const projectRoot = directory ? resolve2(directory) : findProjectRoot();
599
734
  console.log(`Parsing project: ${projectRoot}`);
600
735
  const parsedFiles = await parseProject(projectRoot, {
601
736
  exclude: options.exclude,
@@ -618,7 +753,7 @@ program.command("viz").description("Launch interactive arc diagram visualization
618
753
  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
754
  trackCommand("temporal", packageJson.version);
620
755
  try {
621
- const projectRoot = directory ? resolve(directory) : findProjectRoot();
756
+ const projectRoot = directory ? resolve2(directory) : findProjectRoot();
622
757
  await runTemporalAnalysis(projectRoot, {
623
758
  commits: parseInt(options.commits, 10),
624
759
  strategy: options.strategy,
@@ -638,7 +773,7 @@ program.command("mcp").description("Start MCP server for AI coding tools").argum
638
773
  const state = createEmptyState();
639
774
  let projectRootToConnect = null;
640
775
  if (directory) {
641
- projectRootToConnect = resolve(directory);
776
+ projectRootToConnect = resolve2(directory);
642
777
  } else {
643
778
  const detectedRoot = findProjectRoot();
644
779
  const cwd = process.cwd();
@@ -699,8 +834,8 @@ program.command("docs").description("Generate comprehensive codebase documentati
699
834
  trackCommand("docs", packageJson.version);
700
835
  const startTime = Date.now();
701
836
  try {
702
- const projectRoot = directory ? resolve(directory) : findProjectRoot();
703
- const outputDir = options.output ? resolve(options.output) : join3(projectRoot, ".depwire");
837
+ const projectRoot = directory ? resolve2(directory) : findProjectRoot();
838
+ const outputDir = options.output ? resolve2(options.output) : join3(projectRoot, ".depwire");
704
839
  const includeList = options.include.split(",").map((s) => s.trim());
705
840
  const onlyList = options.only ? options.only.split(",").map((s) => s.trim()) : void 0;
706
841
  if (options.gitignore === void 0 && !existsSyncNode(outputDir)) {
@@ -762,11 +897,11 @@ async function promptGitignore() {
762
897
  input: process.stdin,
763
898
  output: process.stdout
764
899
  });
765
- return new Promise((resolve2) => {
900
+ return new Promise((resolve3) => {
766
901
  rl.question("Add .depwire/ to .gitignore? [Y/n] ", (answer) => {
767
902
  rl.close();
768
903
  const normalized = answer.trim().toLowerCase();
769
- resolve2(normalized === "" || normalized === "y" || normalized === "yes");
904
+ resolve3(normalized === "" || normalized === "y" || normalized === "yes");
770
905
  });
771
906
  });
772
907
  }
@@ -796,7 +931,7 @@ ${pattern}
796
931
  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
932
  trackCommand("health", packageJson.version);
798
933
  try {
799
- const projectRoot = directory ? resolve(directory) : findProjectRoot();
934
+ const projectRoot = directory ? resolve2(directory) : findProjectRoot();
800
935
  const startTime = Date.now();
801
936
  const parsedFiles = await parseProject(projectRoot);
802
937
  const graph = buildGraph(parsedFiles);
@@ -820,7 +955,7 @@ program.command("health").description("Analyze dependency architecture health (0
820
955
  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
956
  trackCommand("dead-code", packageJson.version);
822
957
  try {
823
- const projectRoot = directory ? resolve(directory) : findProjectRoot();
958
+ const projectRoot = directory ? resolve2(directory) : findProjectRoot();
824
959
  const startTime = Date.now();
825
960
  const parsedFiles = await parseProject(projectRoot);
826
961
  const graph = buildGraph(parsedFiles);
@@ -847,4 +982,13 @@ Analysis completed in ${(totalTime / 1e3).toFixed(2)}s
847
982
  process.exit(1);
848
983
  }
849
984
  });
985
+ program.command("whatif").description("Simulate architectural changes before touching code").argument("[directory]", "Project directory (defaults to auto-detected project root)").option("--simulate <action>", "Action to simulate: move, delete, rename, split, merge").option("--target <file>", "File to apply the action to").option("--destination <file>", "Destination path (for move action)").option("--new-name <name>", "New name (for rename action)").option("--source <file>", "Source file (for merge action)").option("--new-file <file>", "New file path (for split action)").option("--symbols <symbols>", "Comma-separated symbol names (for split action)").action(async (directory, options) => {
986
+ trackCommand("whatif", packageJson.version);
987
+ try {
988
+ await whatif(directory || ".", options);
989
+ } catch (err) {
990
+ console.error("Error running simulation:", err);
991
+ process.exit(1);
992
+ }
993
+ });
850
994
  program.parse();
@@ -1,12 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- buildGraph,
4
3
  createEmptyState,
5
- parseProject,
6
4
  startMcpServer,
7
5
  updateFileInGraph,
8
6
  watchProject
9
- } from "./chunk-S3NZMIIU.js";
7
+ } from "./chunk-XBCQPU63.js";
8
+ import {
9
+ buildGraph,
10
+ parseProject
11
+ } from "./chunk-QHVWDUSX.js";
10
12
 
11
13
  // src/mcpb-entry.ts
12
14
  import { resolve } from "path";
package/dist/sdk.d.ts ADDED
@@ -0,0 +1,237 @@
1
+ import { DirectedGraph } from 'graphology';
2
+
3
+ type SymbolKind = 'function' | 'class' | 'variable' | 'constant' | 'type_alias' | 'interface' | 'enum' | 'import' | 'export' | 'method' | 'property' | 'decorator' | 'module';
4
+ interface SymbolNode {
5
+ id: string;
6
+ name: string;
7
+ kind: SymbolKind;
8
+ filePath: string;
9
+ startLine: number;
10
+ endLine: number;
11
+ exported: boolean;
12
+ scope?: string;
13
+ }
14
+ type EdgeKind = 'imports' | 'calls' | 'extends' | 'implements' | 'inherits' | 'decorates' | 'references' | 'type_references';
15
+ interface SymbolEdge {
16
+ source: string;
17
+ target: string;
18
+ kind: EdgeKind;
19
+ filePath: string;
20
+ line: number;
21
+ }
22
+ interface ParsedFile {
23
+ filePath: string;
24
+ symbols: SymbolNode[];
25
+ edges: SymbolEdge[];
26
+ }
27
+
28
+ /**
29
+ * SECURITY: All parser operations are READ-ONLY.
30
+ * Depwire never writes to, modifies, or deletes any file in the user's project.
31
+ * The only file system writes are to os.tmpdir() for cloned repos.
32
+ */
33
+
34
+ declare function parseProject(projectRoot: string, options?: {
35
+ exclude?: string[];
36
+ verbose?: boolean;
37
+ }): Promise<ParsedFile[]>;
38
+
39
+ declare function buildGraph(parsedFiles: ParsedFile[]): DirectedGraph;
40
+
41
+ /**
42
+ * Health Score Type Definitions
43
+ */
44
+ interface HealthDimension {
45
+ name: string;
46
+ score: number;
47
+ weight: number;
48
+ grade: string;
49
+ details: string;
50
+ metrics: Record<string, number | string>;
51
+ }
52
+ interface HealthReport {
53
+ overall: number;
54
+ grade: string;
55
+ dimensions: HealthDimension[];
56
+ summary: string;
57
+ recommendations: string[];
58
+ projectStats: {
59
+ files: number;
60
+ symbols: number;
61
+ edges: number;
62
+ languages: Record<string, number>;
63
+ };
64
+ timestamp: string;
65
+ }
66
+
67
+ /**
68
+ * Calculate the overall health score for a project
69
+ */
70
+ declare function calculateHealthScore(graph: DirectedGraph, projectRoot: string): HealthReport;
71
+
72
+ type ConfidenceLevel = "high" | "medium" | "low";
73
+ interface DeadSymbol {
74
+ name: string;
75
+ kind: string;
76
+ file: string;
77
+ line: number;
78
+ exported: boolean;
79
+ dependents: number;
80
+ confidence: ConfidenceLevel;
81
+ reason: string;
82
+ }
83
+ interface DeadCodeReport {
84
+ totalSymbols: number;
85
+ deadSymbols: number;
86
+ deadPercentage: number;
87
+ byConfidence: {
88
+ high: number;
89
+ medium: number;
90
+ low: number;
91
+ };
92
+ symbols: DeadSymbol[];
93
+ }
94
+ interface DeadCodeOptions {
95
+ confidence: ConfidenceLevel;
96
+ includeTests: boolean;
97
+ verbose: boolean;
98
+ stats: boolean;
99
+ json: boolean;
100
+ debug: boolean;
101
+ }
102
+
103
+ declare function analyzeDeadCode(graph: DirectedGraph, projectRoot: string, options?: Partial<DeadCodeOptions>): DeadCodeReport;
104
+
105
+ interface GeneratorOptions {
106
+ outputDir: string;
107
+ format: 'markdown' | 'json';
108
+ include: string[];
109
+ update: boolean;
110
+ only?: string[];
111
+ verbose: boolean;
112
+ stats: boolean;
113
+ }
114
+ interface GenerationResult {
115
+ success: boolean;
116
+ generated: string[];
117
+ errors: string[];
118
+ stats?: {
119
+ totalTime: number;
120
+ filesGenerated: number;
121
+ };
122
+ }
123
+ /**
124
+ * Main documentation generator
125
+ */
126
+ declare function generateDocs(graph: DirectedGraph, projectRoot: string, version: string, parseTime: number, options: GeneratorOptions): Promise<GenerationResult>;
127
+
128
+ declare function getImpact(graph: DirectedGraph, symbolId: string): {
129
+ directDependents: SymbolNode[];
130
+ transitiveDependents: SymbolNode[];
131
+ affectedFiles: string[];
132
+ };
133
+ declare function searchSymbols(graph: DirectedGraph, query: string): SymbolNode[];
134
+ declare function getArchitectureSummary(graph: DirectedGraph): {
135
+ fileCount: number;
136
+ symbolCount: number;
137
+ edgeCount: number;
138
+ mostConnectedFiles: {
139
+ filePath: string;
140
+ connections: number;
141
+ }[];
142
+ orphanFiles: string[];
143
+ };
144
+
145
+ type SimulationAction = {
146
+ type: 'move';
147
+ target: string;
148
+ destination: string;
149
+ } | {
150
+ type: 'delete';
151
+ target: string;
152
+ } | {
153
+ type: 'rename';
154
+ target: string;
155
+ newName: string;
156
+ } | {
157
+ type: 'split';
158
+ target: string;
159
+ newFile: string;
160
+ symbols: string[];
161
+ } | {
162
+ type: 'merge';
163
+ target: string;
164
+ source: string;
165
+ };
166
+ interface SimulationResult {
167
+ action: SimulationAction;
168
+ originalGraph: GraphSnapshot;
169
+ simulatedGraph: GraphSnapshot;
170
+ diff: GraphDiff;
171
+ healthDelta: HealthDelta;
172
+ }
173
+ interface GraphSnapshot {
174
+ nodeCount: number;
175
+ edgeCount: number;
176
+ healthScore: number;
177
+ }
178
+ interface GraphDiff {
179
+ addedEdges: EdgeInfo[];
180
+ removedEdges: EdgeInfo[];
181
+ affectedNodes: string[];
182
+ brokenImports: BrokenImport[];
183
+ circularDepsIntroduced: string[][];
184
+ circularDepsResolved: string[][];
185
+ }
186
+ interface HealthDelta {
187
+ before: number;
188
+ after: number;
189
+ delta: number;
190
+ improved: boolean;
191
+ dimensionChanges: DimensionChange[];
192
+ }
193
+ interface DimensionChange {
194
+ name: string;
195
+ before: number;
196
+ after: number;
197
+ delta: number;
198
+ }
199
+ interface BrokenImport {
200
+ file: string;
201
+ importedSymbol: string;
202
+ reason: string;
203
+ }
204
+ interface EdgeInfo {
205
+ source: string;
206
+ target: string;
207
+ kind?: string;
208
+ }
209
+ declare class SimulationEngine {
210
+ private readonly original;
211
+ constructor(graph: DirectedGraph);
212
+ simulate(action: SimulationAction): SimulationResult;
213
+ private applyMove;
214
+ private applyDelete;
215
+ private applyRename;
216
+ private applySplit;
217
+ private applyMerge;
218
+ private computeDiff;
219
+ private collectEdges;
220
+ private edgeKey;
221
+ private detectCycles;
222
+ private computeHealthScore;
223
+ }
224
+
225
+ /**
226
+ * depwire-cli SDK — Public API Surface
227
+ *
228
+ * This is the ONLY file the cloud (Railway parser) should import from.
229
+ * Never import from internal paths like depwire-cli/dist/graph/index.js.
230
+ *
231
+ * Rule: if the cloud needs something not exported here, add it here —
232
+ * do not reach into internal paths.
233
+ */
234
+ /** Current SDK version — matches depwire-cli npm version */
235
+ declare const DepwireSDKVersion: string;
236
+
237
+ export { type BrokenImport, DepwireSDKVersion, type GraphDiff, type HealthDelta, type SimulationAction, SimulationEngine, type SimulationResult, analyzeDeadCode, buildGraph, calculateHealthScore, generateDocs, getArchitectureSummary, getImpact, parseProject, searchSymbols };
package/dist/sdk.js ADDED
@@ -0,0 +1,32 @@
1
+ import {
2
+ SimulationEngine,
3
+ analyzeDeadCode,
4
+ buildGraph,
5
+ calculateHealthScore,
6
+ generateDocs,
7
+ getArchitectureSummary,
8
+ getImpact,
9
+ parseProject,
10
+ searchSymbols
11
+ } from "./chunk-QHVWDUSX.js";
12
+
13
+ // src/sdk.ts
14
+ import { readFileSync } from "fs";
15
+ import { dirname, join } from "path";
16
+ import { fileURLToPath } from "url";
17
+ var __filename = fileURLToPath(import.meta.url);
18
+ var __dirname = dirname(__filename);
19
+ var packageJson = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
20
+ var DepwireSDKVersion = packageJson.version;
21
+ export {
22
+ DepwireSDKVersion,
23
+ SimulationEngine,
24
+ analyzeDeadCode,
25
+ buildGraph,
26
+ calculateHealthScore,
27
+ generateDocs,
28
+ getArchitectureSummary,
29
+ getImpact,
30
+ parseProject,
31
+ searchSymbols
32
+ };
package/package.json CHANGED
@@ -1,17 +1,22 @@
1
1
  {
2
2
  "name": "depwire-cli",
3
- "version": "0.9.19",
3
+ "version": "0.9.21",
4
4
  "description": "The missing context layer for AI coding assistants. Dependency graph, MCP server, architecture health, dead code detection.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "depwire": "dist/index.js"
8
8
  },
9
+ "exports": {
10
+ ".": "./dist/index.js",
11
+ "./sdk": "./dist/sdk.js"
12
+ },
9
13
  "scripts": {
10
- "build": "tsup src/index.ts src/mcpb-entry.ts --format esm --dts --clean && npm run copy-static",
14
+ "build": "tsup src/index.ts src/mcpb-entry.ts src/sdk.ts --format esm --dts --clean && npm run copy-static",
11
15
  "copy-static": "mkdir -p dist/viz/public dist/parser/grammars && cp -r src/viz/public/* dist/viz/public/ && cp src/parser/grammars/*.wasm dist/parser/grammars/",
12
16
  "dev": "tsup src/index.ts --format esm --watch",
13
17
  "start": "node dist/index.js",
14
- "build:mcpb": "npm run build && ./scripts/build-mcpb.sh"
18
+ "build:mcpb": "npm run build && ./scripts/build-mcpb.sh",
19
+ "postversion": "node -e \"const fs=require('fs');const p=JSON.parse(fs.readFileSync('./package.json','utf8'));const s=JSON.parse(fs.readFileSync('./server.json','utf8'));s.version=p.version;s.packages[0].version=p.version;fs.writeFileSync('./server.json',JSON.stringify(s,null,2)+'\\n');console.log('server.json updated to '+p.version);\" && git add server.json"
15
20
  },
16
21
  "keywords": [
17
22
  "typescript",
@@ -28,7 +33,14 @@
28
33
  "impact-analysis",
29
34
  "refactoring",
30
35
  "arc-diagram",
31
- "cross-reference"
36
+ "cross-reference",
37
+ "whatif",
38
+ "simulation",
39
+ "architectural-simulation",
40
+ "what-if-analysis",
41
+ "refactor-simulation",
42
+ "blast-radius",
43
+ "deterministic-graph"
32
44
  ],
33
45
  "author": "Atef Ataya (https://www.youtube.com/@atefataya)",
34
46
  "license": "BUSL-1.1",