@vibecheckai/cli 3.2.6 → 3.3.0
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/bin/registry.js +192 -5
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
- package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
- package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
- package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
- package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
- package/bin/runners/lib/agent-firewall/logger.js +141 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
- package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
- package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
- package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
- package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
- package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
- package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
- package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
- package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
- package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
- package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
- package/bin/runners/lib/analyzers.js +81 -18
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/cli-output.js +7 -1
- package/bin/runners/lib/error-handler.js +16 -9
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/global-flags.js +37 -0
- package/bin/runners/lib/help-formatter.js +413 -0
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/unified-cli-output.js +604 -0
- package/bin/runners/lib/upsell.js +148 -0
- package/bin/runners/runApprove.js +1200 -0
- package/bin/runners/runAuth.js +324 -95
- package/bin/runners/runCheckpoint.js +39 -21
- package/bin/runners/runClassify.js +859 -0
- package/bin/runners/runContext.js +136 -24
- package/bin/runners/runDoctor.js +108 -68
- package/bin/runners/runFix.js +6 -5
- package/bin/runners/runGuard.js +212 -118
- package/bin/runners/runInit.js +3 -2
- package/bin/runners/runMcp.js +130 -52
- package/bin/runners/runPolish.js +43 -20
- package/bin/runners/runProve.js +1 -2
- package/bin/runners/runReport.js +3 -2
- package/bin/runners/runScan.js +63 -44
- package/bin/runners/runShip.js +3 -4
- package/bin/runners/runValidate.js +19 -2
- package/bin/runners/runWatch.js +104 -53
- package/bin/vibecheck.js +106 -19
- package/mcp-server/HARDENING_SUMMARY.md +299 -0
- package/mcp-server/agent-firewall-interceptor.js +367 -31
- package/mcp-server/authority-tools.js +569 -0
- package/mcp-server/conductor/conflict-resolver.js +588 -0
- package/mcp-server/conductor/execution-planner.js +544 -0
- package/mcp-server/conductor/index.js +377 -0
- package/mcp-server/conductor/lock-manager.js +615 -0
- package/mcp-server/conductor/request-queue.js +550 -0
- package/mcp-server/conductor/session-manager.js +500 -0
- package/mcp-server/conductor/tools.js +510 -0
- package/mcp-server/index.js +1149 -243
- package/mcp-server/lib/{api-client.js → api-client.cjs} +40 -4
- package/mcp-server/lib/logger.cjs +30 -0
- package/mcp-server/logger.js +173 -0
- package/mcp-server/package.json +2 -2
- package/mcp-server/premium-tools.js +2 -2
- package/mcp-server/tier-auth.js +245 -35
- package/mcp-server/truth-firewall-tools.js +145 -15
- package/mcp-server/vibecheck-tools.js +2 -2
- package/package.json +2 -3
- package/mcp-server/index.old.js +0 -4137
- package/mcp-server/package-lock.json +0 -165
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import Resolver
|
|
3
|
+
*
|
|
4
|
+
* Resolves and validates import statements in JavaScript/TypeScript code.
|
|
5
|
+
* Used by the diff simulator to detect broken imports.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const path = require("path");
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Extract imports from source code
|
|
15
|
+
* @param {string} content - File content
|
|
16
|
+
* @returns {Array} Array of import objects
|
|
17
|
+
*/
|
|
18
|
+
function extractImports(content) {
|
|
19
|
+
const imports = [];
|
|
20
|
+
|
|
21
|
+
// ES6 imports: import X from 'Y', import { X } from 'Y', import 'Y'
|
|
22
|
+
const importRegex = /import\s+(?:(?:(\w+)(?:\s*,\s*)?)?(?:\{([^}]+)\})?\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
23
|
+
let match;
|
|
24
|
+
|
|
25
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
26
|
+
const [, defaultImport, namedImports, source] = match;
|
|
27
|
+
imports.push({
|
|
28
|
+
type: "esm",
|
|
29
|
+
source,
|
|
30
|
+
defaultImport: defaultImport || null,
|
|
31
|
+
namedImports: namedImports ? namedImports.split(",").map(s => s.trim()) : [],
|
|
32
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Dynamic imports: import('X'), await import('X')
|
|
37
|
+
const dynamicRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
38
|
+
while ((match = dynamicRegex.exec(content)) !== null) {
|
|
39
|
+
imports.push({
|
|
40
|
+
type: "dynamic",
|
|
41
|
+
source: match[1],
|
|
42
|
+
defaultImport: null,
|
|
43
|
+
namedImports: [],
|
|
44
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// CommonJS requires: require('X'), require("X")
|
|
49
|
+
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
50
|
+
while ((match = requireRegex.exec(content)) !== null) {
|
|
51
|
+
imports.push({
|
|
52
|
+
type: "commonjs",
|
|
53
|
+
source: match[1],
|
|
54
|
+
defaultImport: null,
|
|
55
|
+
namedImports: [],
|
|
56
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return imports;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Extract exports from source code
|
|
65
|
+
* @param {string} content - File content
|
|
66
|
+
* @returns {Array} Array of export objects
|
|
67
|
+
*/
|
|
68
|
+
function extractExports(content) {
|
|
69
|
+
const exports = [];
|
|
70
|
+
|
|
71
|
+
// Named exports: export const X, export function X, export class X
|
|
72
|
+
const namedRegex = /export\s+(?:const|let|var|function|class|interface|type|enum)\s+(\w+)/g;
|
|
73
|
+
let match;
|
|
74
|
+
|
|
75
|
+
while ((match = namedRegex.exec(content)) !== null) {
|
|
76
|
+
exports.push({
|
|
77
|
+
type: "named",
|
|
78
|
+
name: match[1],
|
|
79
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Export list: export { X, Y as Z }
|
|
84
|
+
const listRegex = /export\s+\{([^}]+)\}/g;
|
|
85
|
+
while ((match = listRegex.exec(content)) !== null) {
|
|
86
|
+
const names = match[1].split(",").map(s => {
|
|
87
|
+
const parts = s.trim().split(/\s+as\s+/);
|
|
88
|
+
return { original: parts[0].trim(), alias: parts[1]?.trim() || parts[0].trim() };
|
|
89
|
+
});
|
|
90
|
+
for (const name of names) {
|
|
91
|
+
exports.push({
|
|
92
|
+
type: "named",
|
|
93
|
+
name: name.alias,
|
|
94
|
+
originalName: name.original,
|
|
95
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Default export: export default X
|
|
101
|
+
const defaultRegex = /export\s+default\s+(?:class\s+(\w+)|function\s+(\w+)|(\w+))/g;
|
|
102
|
+
while ((match = defaultRegex.exec(content)) !== null) {
|
|
103
|
+
const name = match[1] || match[2] || match[3];
|
|
104
|
+
exports.push({
|
|
105
|
+
type: "default",
|
|
106
|
+
name: name || "default",
|
|
107
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Re-exports: export * from 'X', export { X } from 'X'
|
|
112
|
+
const reExportRegex = /export\s+(?:\*|{[^}]+})\s+from\s+['"]([^'"]+)['"]/g;
|
|
113
|
+
while ((match = reExportRegex.exec(content)) !== null) {
|
|
114
|
+
exports.push({
|
|
115
|
+
type: "reexport",
|
|
116
|
+
source: match[1],
|
|
117
|
+
line: content.substring(0, match.index).split("\n").length,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// module.exports
|
|
122
|
+
if (content.includes("module.exports")) {
|
|
123
|
+
exports.push({
|
|
124
|
+
type: "commonjs",
|
|
125
|
+
name: "module.exports",
|
|
126
|
+
line: content.indexOf("module.exports"),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return exports;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Resolve import path to actual file
|
|
135
|
+
* @param {string} importPath - Import path
|
|
136
|
+
* @param {string} fromFile - File containing the import
|
|
137
|
+
* @param {string} projectRoot - Project root directory
|
|
138
|
+
* @param {Map} virtualFiles - Virtual file system (for simulation)
|
|
139
|
+
* @returns {Object} Resolution result
|
|
140
|
+
*/
|
|
141
|
+
function resolveImportPath(importPath, fromFile, projectRoot, virtualFiles = new Map()) {
|
|
142
|
+
// Node built-ins
|
|
143
|
+
const builtins = [
|
|
144
|
+
"fs", "path", "os", "http", "https", "crypto", "util", "events",
|
|
145
|
+
"stream", "buffer", "url", "querystring", "child_process", "net",
|
|
146
|
+
"assert", "zlib", "readline", "cluster", "dns", "tls", "dgram",
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
if (builtins.includes(importPath) || importPath.startsWith("node:")) {
|
|
150
|
+
return { resolved: true, type: "builtin", path: importPath };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// External packages (don't start with . or /)
|
|
154
|
+
if (!importPath.startsWith(".") && !importPath.startsWith("/") && !importPath.startsWith("@/")) {
|
|
155
|
+
// Check if it looks like a scoped package
|
|
156
|
+
const isScoped = importPath.startsWith("@") && !importPath.startsWith("@/");
|
|
157
|
+
return { resolved: true, type: "external", path: importPath, isScoped };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Resolve relative imports
|
|
161
|
+
const fromDir = path.dirname(fromFile);
|
|
162
|
+
let resolvedPath;
|
|
163
|
+
|
|
164
|
+
// Handle alias imports (@/)
|
|
165
|
+
if (importPath.startsWith("@/")) {
|
|
166
|
+
resolvedPath = path.join(projectRoot, "src", importPath.slice(2));
|
|
167
|
+
} else if (importPath.startsWith("~/")) {
|
|
168
|
+
resolvedPath = path.join(projectRoot, importPath.slice(2));
|
|
169
|
+
} else {
|
|
170
|
+
resolvedPath = path.resolve(fromDir, importPath);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Try different extensions
|
|
174
|
+
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".json", "/index.ts", "/index.tsx", "/index.js", "/index.jsx"];
|
|
175
|
+
|
|
176
|
+
for (const ext of extensions) {
|
|
177
|
+
const fullPath = resolvedPath + ext;
|
|
178
|
+
const relativePath = path.relative(projectRoot, fullPath).replace(/\\/g, "/");
|
|
179
|
+
|
|
180
|
+
// Check virtual files first
|
|
181
|
+
if (virtualFiles.has(relativePath)) {
|
|
182
|
+
return { resolved: true, type: "internal", path: relativePath, virtual: true };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Check real file system
|
|
186
|
+
if (fs.existsSync(fullPath)) {
|
|
187
|
+
return { resolved: true, type: "internal", path: relativePath };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Unresolved
|
|
192
|
+
return {
|
|
193
|
+
resolved: false,
|
|
194
|
+
type: "unresolved",
|
|
195
|
+
path: importPath,
|
|
196
|
+
attemptedPaths: extensions.map(ext => resolvedPath + ext),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check if an import can be resolved with changes applied
|
|
202
|
+
* @param {Object} importObj - Import object
|
|
203
|
+
* @param {string} fromFile - Source file
|
|
204
|
+
* @param {string} projectRoot - Project root
|
|
205
|
+
* @param {Map} virtualFiles - Virtual file system state
|
|
206
|
+
* @param {Set} deletedFiles - Deleted files
|
|
207
|
+
* @returns {Object} Validation result
|
|
208
|
+
*/
|
|
209
|
+
function validateImport(importObj, fromFile, projectRoot, virtualFiles, deletedFiles) {
|
|
210
|
+
const resolution = resolveImportPath(importObj.source, fromFile, projectRoot, virtualFiles);
|
|
211
|
+
|
|
212
|
+
// Check if resolved file is deleted
|
|
213
|
+
if (resolution.resolved && resolution.type === "internal") {
|
|
214
|
+
if (deletedFiles.has(resolution.path)) {
|
|
215
|
+
return {
|
|
216
|
+
valid: false,
|
|
217
|
+
import: importObj,
|
|
218
|
+
resolution,
|
|
219
|
+
error: `Import '${importObj.source}' resolves to deleted file '${resolution.path}'`,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Check if import is unresolved
|
|
225
|
+
if (!resolution.resolved) {
|
|
226
|
+
return {
|
|
227
|
+
valid: false,
|
|
228
|
+
import: importObj,
|
|
229
|
+
resolution,
|
|
230
|
+
error: `Cannot resolve import '${importObj.source}' from '${fromFile}'`,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
valid: true,
|
|
236
|
+
import: importObj,
|
|
237
|
+
resolution,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Build import graph from files
|
|
243
|
+
* @param {Map} files - Map of file path to content
|
|
244
|
+
* @param {string} projectRoot - Project root
|
|
245
|
+
* @returns {Object} Import graph
|
|
246
|
+
*/
|
|
247
|
+
function buildImportGraph(files, projectRoot) {
|
|
248
|
+
const graph = {
|
|
249
|
+
nodes: new Map(),
|
|
250
|
+
edges: [],
|
|
251
|
+
circularDeps: [],
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// Build nodes and edges
|
|
255
|
+
for (const [filePath, content] of files) {
|
|
256
|
+
const imports = extractImports(content);
|
|
257
|
+
const exports = extractExports(content);
|
|
258
|
+
|
|
259
|
+
graph.nodes.set(filePath, {
|
|
260
|
+
path: filePath,
|
|
261
|
+
imports,
|
|
262
|
+
exports,
|
|
263
|
+
importCount: imports.length,
|
|
264
|
+
exportCount: exports.length,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Add edges
|
|
268
|
+
for (const imp of imports) {
|
|
269
|
+
const resolution = resolveImportPath(imp.source, filePath, projectRoot, files);
|
|
270
|
+
if (resolution.type === "internal") {
|
|
271
|
+
graph.edges.push({
|
|
272
|
+
from: filePath,
|
|
273
|
+
to: resolution.path,
|
|
274
|
+
import: imp,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Detect circular dependencies
|
|
281
|
+
graph.circularDeps = detectCircularDeps(graph.edges);
|
|
282
|
+
|
|
283
|
+
return graph;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Detect circular dependencies in import graph
|
|
288
|
+
* @param {Array} edges - Graph edges
|
|
289
|
+
* @returns {Array} Array of circular dependency chains
|
|
290
|
+
*/
|
|
291
|
+
function detectCircularDeps(edges) {
|
|
292
|
+
const graph = new Map();
|
|
293
|
+
|
|
294
|
+
// Build adjacency list
|
|
295
|
+
for (const edge of edges) {
|
|
296
|
+
if (!graph.has(edge.from)) {
|
|
297
|
+
graph.set(edge.from, []);
|
|
298
|
+
}
|
|
299
|
+
graph.get(edge.from).push(edge.to);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const visited = new Set();
|
|
303
|
+
const inStack = new Set();
|
|
304
|
+
const cycles = [];
|
|
305
|
+
|
|
306
|
+
function dfs(node, path) {
|
|
307
|
+
if (inStack.has(node)) {
|
|
308
|
+
// Found cycle
|
|
309
|
+
const cycleStart = path.indexOf(node);
|
|
310
|
+
const cycle = path.slice(cycleStart);
|
|
311
|
+
cycle.push(node);
|
|
312
|
+
cycles.push(cycle);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (visited.has(node)) return;
|
|
317
|
+
|
|
318
|
+
visited.add(node);
|
|
319
|
+
inStack.add(node);
|
|
320
|
+
path.push(node);
|
|
321
|
+
|
|
322
|
+
const neighbors = graph.get(node) || [];
|
|
323
|
+
for (const neighbor of neighbors) {
|
|
324
|
+
dfs(neighbor, [...path]);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
inStack.delete(node);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
for (const node of graph.keys()) {
|
|
331
|
+
if (!visited.has(node)) {
|
|
332
|
+
dfs(node, []);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return cycles;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
module.exports = {
|
|
340
|
+
extractImports,
|
|
341
|
+
extractExports,
|
|
342
|
+
resolveImportPath,
|
|
343
|
+
validateImport,
|
|
344
|
+
buildImportGraph,
|
|
345
|
+
detectCircularDeps,
|
|
346
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff Simulator Module
|
|
3
|
+
*
|
|
4
|
+
* Entry point for the diff simulation engine.
|
|
5
|
+
* Validates changes in memory before applying to disk.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const { simulator } = require('./simulator');
|
|
9
|
+
*
|
|
10
|
+
* const result = simulator.simulate(projectRoot, [
|
|
11
|
+
* { type: 'create', path: 'src/new.ts', content: '...' },
|
|
12
|
+
* { type: 'modify', path: 'src/existing.ts', content: '...' },
|
|
13
|
+
* { type: 'delete', path: 'src/old.ts' },
|
|
14
|
+
* ]);
|
|
15
|
+
*
|
|
16
|
+
* if (!result.passed) {
|
|
17
|
+
* console.log('Simulation failed:', result.errors);
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
"use strict";
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
simulate,
|
|
25
|
+
quickSimulate,
|
|
26
|
+
buildVirtualFS,
|
|
27
|
+
validateImportsAfterChanges,
|
|
28
|
+
detectOrphanedFiles,
|
|
29
|
+
formatResult,
|
|
30
|
+
} = require("./diff-simulator");
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
extractImports,
|
|
34
|
+
extractExports,
|
|
35
|
+
resolveImportPath,
|
|
36
|
+
validateImport,
|
|
37
|
+
buildImportGraph,
|
|
38
|
+
detectCircularDeps,
|
|
39
|
+
} = require("./import-resolver");
|
|
40
|
+
|
|
41
|
+
const {
|
|
42
|
+
extractRoutes,
|
|
43
|
+
validateRoutes,
|
|
44
|
+
findRouteReferences,
|
|
45
|
+
} = require("./route-validator");
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Simulator singleton
|
|
49
|
+
*/
|
|
50
|
+
const simulator = {
|
|
51
|
+
/**
|
|
52
|
+
* Run full simulation
|
|
53
|
+
* @param {string} projectRoot - Project root directory
|
|
54
|
+
* @param {Array} changes - Array of change operations
|
|
55
|
+
* @param {Object} options - Simulation options
|
|
56
|
+
* @returns {Object} Simulation result
|
|
57
|
+
*/
|
|
58
|
+
simulate(projectRoot, changes, options = {}) {
|
|
59
|
+
return simulate(projectRoot, changes, options);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Quick simulation for single file
|
|
64
|
+
* @param {string} projectRoot - Project root
|
|
65
|
+
* @param {string} filePath - File path
|
|
66
|
+
* @param {string} newContent - New content
|
|
67
|
+
* @param {string} oldContent - Old content (optional)
|
|
68
|
+
* @returns {Object} Simulation result
|
|
69
|
+
*/
|
|
70
|
+
quick(projectRoot, filePath, newContent, oldContent = null) {
|
|
71
|
+
return quickSimulate(projectRoot, filePath, newContent, oldContent);
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Validate imports only
|
|
76
|
+
* @param {string} projectRoot - Project root
|
|
77
|
+
* @param {Array} changes - Change operations
|
|
78
|
+
* @returns {Object} Import validation result
|
|
79
|
+
*/
|
|
80
|
+
validateImports(projectRoot, changes) {
|
|
81
|
+
const vfs = buildVirtualFS(projectRoot, changes);
|
|
82
|
+
return validateImportsAfterChanges(projectRoot, vfs);
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Validate routes only
|
|
87
|
+
* @param {Array} existingRoutes - Current routes
|
|
88
|
+
* @param {Map} changedFiles - Changed files
|
|
89
|
+
* @param {Set} deletedFiles - Deleted files
|
|
90
|
+
* @returns {Object} Route validation result
|
|
91
|
+
*/
|
|
92
|
+
validateRoutes(existingRoutes, changedFiles, deletedFiles) {
|
|
93
|
+
return validateRoutes(existingRoutes, changedFiles, deletedFiles);
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Extract imports from content
|
|
98
|
+
* @param {string} content - File content
|
|
99
|
+
* @returns {Array} Imports
|
|
100
|
+
*/
|
|
101
|
+
extractImports(content) {
|
|
102
|
+
return extractImports(content);
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Extract exports from content
|
|
107
|
+
* @param {string} content - File content
|
|
108
|
+
* @returns {Array} Exports
|
|
109
|
+
*/
|
|
110
|
+
extractExports(content) {
|
|
111
|
+
return extractExports(content);
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Extract routes from content
|
|
116
|
+
* @param {string} content - File content
|
|
117
|
+
* @param {string} filePath - File path
|
|
118
|
+
* @returns {Array} Routes
|
|
119
|
+
*/
|
|
120
|
+
extractRoutes(content, filePath) {
|
|
121
|
+
return extractRoutes(content, filePath);
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Build import graph
|
|
126
|
+
* @param {Map} files - File map
|
|
127
|
+
* @param {string} projectRoot - Project root
|
|
128
|
+
* @returns {Object} Import graph
|
|
129
|
+
*/
|
|
130
|
+
buildImportGraph(files, projectRoot) {
|
|
131
|
+
return buildImportGraph(files, projectRoot);
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Detect circular dependencies
|
|
136
|
+
* @param {Array} edges - Graph edges
|
|
137
|
+
* @returns {Array} Cycles found
|
|
138
|
+
*/
|
|
139
|
+
detectCircularDeps(edges) {
|
|
140
|
+
return detectCircularDeps(edges);
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Format result for display
|
|
145
|
+
* @param {Object} result - Simulation result
|
|
146
|
+
* @returns {string} Formatted output
|
|
147
|
+
*/
|
|
148
|
+
format(result) {
|
|
149
|
+
return formatResult(result);
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Build virtual file system from changes
|
|
154
|
+
* @param {string} projectRoot - Project root
|
|
155
|
+
* @param {Array} changes - Changes
|
|
156
|
+
* @returns {Object} Virtual FS state
|
|
157
|
+
*/
|
|
158
|
+
buildVirtualFS(projectRoot, changes) {
|
|
159
|
+
return buildVirtualFS(projectRoot, changes);
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
module.exports = {
|
|
164
|
+
simulator,
|
|
165
|
+
// Direct exports
|
|
166
|
+
simulate,
|
|
167
|
+
quickSimulate,
|
|
168
|
+
buildVirtualFS,
|
|
169
|
+
validateImportsAfterChanges,
|
|
170
|
+
detectOrphanedFiles,
|
|
171
|
+
formatResult,
|
|
172
|
+
extractImports,
|
|
173
|
+
extractExports,
|
|
174
|
+
resolveImportPath,
|
|
175
|
+
validateImport,
|
|
176
|
+
buildImportGraph,
|
|
177
|
+
detectCircularDeps,
|
|
178
|
+
extractRoutes,
|
|
179
|
+
validateRoutes,
|
|
180
|
+
findRouteReferences,
|
|
181
|
+
};
|