archtracker-mcp 0.5.0 → 0.7.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/dist/index.d.ts CHANGED
@@ -56,6 +56,12 @@ interface ArchSnapshot {
56
56
  graph: DependencyGraph;
57
57
  /** Present only when layers.json was used */
58
58
  multiLayer?: MultiLayerGraph;
59
+ /** Analysis options used to generate this snapshot (for diff consistency checks) */
60
+ analysisOptions?: {
61
+ targetDir?: string;
62
+ language?: string;
63
+ exclude?: string[];
64
+ };
59
65
  }
60
66
  /** Diff result between two snapshots */
61
67
  interface ArchDiff {
@@ -156,7 +162,7 @@ declare function formatAnalysisReport(graph: DependencyGraph, options?: {
156
162
  * Each layer is analyzed independently via analyzeProject().
157
163
  * Results are merged into a unified graph with layer-prefixed node paths.
158
164
  */
159
- declare function analyzeMultiLayer(projectRoot: string, layerDefs: LayerDefinition[]): Promise<MultiLayerGraph>;
165
+ declare function analyzeMultiLayer(projectRoot: string, layerDefs: LayerDefinition[], globalExclude?: string[]): Promise<MultiLayerGraph>;
160
166
  /**
161
167
  * Auto-detect cross-layer connections by scanning file contents
162
168
  * for references to identifiers defined in other layers.
@@ -180,7 +186,11 @@ declare function detectCrossLayerConnections(layers: Record<string, DependencyGr
180
186
  * Creates .archtracker/ directory if it doesn't exist.
181
187
  * Writes snapshot.json with schema version and timestamp.
182
188
  */
183
- declare function saveSnapshot(projectRoot: string, graph: DependencyGraph, multiLayer?: MultiLayerGraph): Promise<ArchSnapshot>;
189
+ declare function saveSnapshot(projectRoot: string, graph: DependencyGraph, multiLayer?: MultiLayerGraph, analysisOptions?: {
190
+ targetDir?: string;
191
+ language?: string;
192
+ exclude?: string[];
193
+ }): Promise<ArchSnapshot>;
184
194
  /**
185
195
  * Load the most recent snapshot from .archtracker/snapshot.json.
186
196
  *
package/dist/index.js CHANGED
@@ -1564,6 +1564,8 @@ var en = {
1564
1564
  "diff.reasonRemoved": 'Dependency "{file}" was removed',
1565
1565
  "diff.reasonModified": 'Dependency "{file}" had its dependencies changed',
1566
1566
  "diff.reasonAdded": 'New dependency "{file}" was added',
1567
+ "diff.testSummary": " ... and {count} test/fixture file(s)",
1568
+ "diff.testAffectedSummary": " ... and {count} test/fixture-related review(s)",
1567
1569
  // Search
1568
1570
  "search.pathMatch": 'Path matches "{pattern}"',
1569
1571
  "search.affected": 'May be affected by changes to "{file}" (via: {via})',
@@ -1625,6 +1627,12 @@ var en = {
1625
1627
  "web.watching": "Watching {dir}/ for changes...",
1626
1628
  "web.reloading": "File change detected, reloading...",
1627
1629
  "web.reloaded": "Graph reloaded",
1630
+ // History
1631
+ "history.title": "# Snapshot History\n",
1632
+ "history.empty": "No snapshots found. Run `archtracker init` to create one.",
1633
+ "history.entry": " {ts} | {files} files, {edges} edges, {circular} circular{layers}",
1634
+ "history.count": "{count} snapshot(s) recorded",
1635
+ "history.snapshotNotFound": "Snapshot not found for timestamp: {ts}",
1628
1636
  // Errors
1629
1637
  "error.analyzer": "[Analysis Error] {message}",
1630
1638
  "error.storage": "[Storage Error] {message}",
@@ -1657,6 +1665,8 @@ var ja = {
1657
1665
  "diff.reasonRemoved": '\u4F9D\u5B58\u5148 "{file}" \u304C\u524A\u9664\u3055\u308C\u307E\u3057\u305F',
1658
1666
  "diff.reasonModified": '\u4F9D\u5B58\u5148 "{file}" \u306E\u4F9D\u5B58\u95A2\u4FC2\u304C\u5909\u66F4\u3055\u308C\u307E\u3057\u305F',
1659
1667
  "diff.reasonAdded": '\u65B0\u3057\u3044\u4F9D\u5B58\u5148 "{file}" \u304C\u8FFD\u52A0\u3055\u308C\u307E\u3057\u305F',
1668
+ "diff.testSummary": " ... \u4ED6 {count}\u4EF6\u306E\u30C6\u30B9\u30C8/\u30D5\u30A3\u30AF\u30B9\u30C1\u30E3\u30D5\u30A1\u30A4\u30EB",
1669
+ "diff.testAffectedSummary": " ... \u4ED6 {count}\u4EF6\u306E\u30C6\u30B9\u30C8/\u30D5\u30A3\u30AF\u30B9\u30C1\u30E3\u95A2\u9023\u306E\u78BA\u8A8D\u9805\u76EE",
1660
1670
  // Search
1661
1671
  "search.pathMatch": '\u30D1\u30B9\u304C "{pattern}" \u306B\u30DE\u30C3\u30C1',
1662
1672
  "search.affected": '"{file}" \u306E\u5909\u66F4\u306B\u3088\u308A\u5F71\u97FF\u3092\u53D7\u3051\u308B\u53EF\u80FD\u6027\uFF08\u7D4C\u7531: {via}\uFF09',
@@ -1718,6 +1728,12 @@ var ja = {
1718
1728
  "web.watching": "{dir}/ \u3092\u76E3\u8996\u4E2D...",
1719
1729
  "web.reloading": "\u30D5\u30A1\u30A4\u30EB\u5909\u66F4\u3092\u691C\u51FA\u3001\u30EA\u30ED\u30FC\u30C9\u4E2D...",
1720
1730
  "web.reloaded": "\u30B0\u30E9\u30D5\u3092\u66F4\u65B0\u3057\u307E\u3057\u305F",
1731
+ // History
1732
+ "history.title": "# \u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u5C65\u6B74\n",
1733
+ "history.empty": "\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002`archtracker init` \u3067\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1734
+ "history.entry": " {ts} | {files}\u30D5\u30A1\u30A4\u30EB, {edges}\u30A8\u30C3\u30B8, \u5FAA\u74B0{circular}\u4EF6{layers}",
1735
+ "history.count": "{count}\u4EF6\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3092\u8A18\u9332",
1736
+ "history.snapshotNotFound": "\u6307\u5B9A\u306E\u30BF\u30A4\u30E0\u30B9\u30BF\u30F3\u30D7\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: {ts}",
1721
1737
  // Errors
1722
1738
  "error.analyzer": "[\u89E3\u6790\u30A8\u30E9\u30FC] {message}",
1723
1739
  "error.storage": "[\u30B9\u30C8\u30EC\u30FC\u30B8\u30A8\u30E9\u30FC] {message}",
@@ -1802,14 +1818,14 @@ var LAYER_COLORS = [
1802
1818
  "#ffa657",
1803
1819
  "#7ee787"
1804
1820
  ];
1805
- async function analyzeMultiLayer(projectRoot, layerDefs) {
1821
+ async function analyzeMultiLayer(projectRoot, layerDefs, globalExclude) {
1806
1822
  const layers = {};
1807
1823
  const layerMetadata = [];
1808
1824
  for (let idx = 0; idx < layerDefs.length; idx++) {
1809
1825
  const def = layerDefs[idx];
1810
1826
  const targetDir = resolve4(projectRoot, def.targetDir);
1811
1827
  const graph = await analyzeProject(targetDir, {
1812
- exclude: def.exclude,
1828
+ exclude: def.exclude ?? globalExclude,
1813
1829
  language: def.language
1814
1830
  });
1815
1831
  const language = def.language ?? await detectLanguage(targetDir) ?? "javascript";
@@ -2170,57 +2186,144 @@ function mergeLayerGraphs(projectRoot, layers) {
2170
2186
  };
2171
2187
  }
2172
2188
 
2173
- // src/storage/snapshot.ts
2174
- import { mkdir, writeFile, readFile as readFile2, access } from "fs/promises";
2189
+ // src/storage/layers.ts
2190
+ import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
2175
2191
  import { join as join5 } from "path";
2176
2192
  import { z } from "zod";
2177
2193
  var ARCHTRACKER_DIR = ".archtracker";
2194
+ var LAYERS_FILE = "layers.json";
2195
+ var LayerDefinitionSchema = z.object({
2196
+ name: z.string().min(1).regex(
2197
+ /^[a-zA-Z0-9_-]+$/,
2198
+ "Layer name must be alphanumeric (hyphens/underscores allowed)"
2199
+ ),
2200
+ targetDir: z.string().min(1),
2201
+ language: z.enum(LANGUAGE_IDS).optional(),
2202
+ exclude: z.array(z.string()).optional(),
2203
+ color: z.string().optional(),
2204
+ description: z.string().optional()
2205
+ });
2206
+ var CrossLayerConnectionSchema = z.object({
2207
+ fromLayer: z.string(),
2208
+ fromFile: z.string(),
2209
+ toLayer: z.string(),
2210
+ toFile: z.string(),
2211
+ type: z.enum(["api-call", "event", "data-flow", "manual"]),
2212
+ label: z.string().optional()
2213
+ });
2214
+ var LayerConfigSchema = z.object({
2215
+ version: z.literal("1.0"),
2216
+ layers: z.array(LayerDefinitionSchema).min(1).refine(
2217
+ (layers) => {
2218
+ const names = layers.map((l) => l.name);
2219
+ return new Set(names).size === names.length;
2220
+ },
2221
+ { message: "Layer names must be unique" }
2222
+ ),
2223
+ connections: z.array(CrossLayerConnectionSchema).optional()
2224
+ });
2225
+ async function loadLayerConfig(projectRoot) {
2226
+ const filePath = join5(projectRoot, ARCHTRACKER_DIR, LAYERS_FILE);
2227
+ let raw;
2228
+ try {
2229
+ raw = await readFile2(filePath, "utf-8");
2230
+ } catch (error) {
2231
+ if (isNodeError(error) && error.code === "ENOENT") {
2232
+ return null;
2233
+ }
2234
+ throw new Error(`Failed to read ${filePath}`);
2235
+ }
2236
+ let parsed;
2237
+ try {
2238
+ parsed = JSON.parse(raw);
2239
+ } catch {
2240
+ throw new Error(`Invalid JSON in ${filePath}`);
2241
+ }
2242
+ const result = LayerConfigSchema.safeParse(parsed);
2243
+ if (!result.success) {
2244
+ const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).slice(0, 5).join("\n");
2245
+ throw new Error(`layers.json validation failed:
2246
+ ${issues}`);
2247
+ }
2248
+ return result.data;
2249
+ }
2250
+ async function saveLayerConfig(projectRoot, config) {
2251
+ const dirPath = join5(projectRoot, ARCHTRACKER_DIR);
2252
+ const filePath = join5(dirPath, LAYERS_FILE);
2253
+ await mkdir(dirPath, { recursive: true });
2254
+ await writeFile(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
2255
+ }
2256
+ function isNodeError(error) {
2257
+ return error instanceof Error && "code" in error;
2258
+ }
2259
+
2260
+ // src/storage/graph-cache.ts
2261
+ import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2, stat as stat4 } from "fs/promises";
2262
+ import { join as join6, resolve as resolve5 } from "path";
2263
+ import { readdir as readdir3 } from "fs/promises";
2264
+ import { createHash } from "crypto";
2265
+
2266
+ // src/storage/snapshot.ts
2267
+ import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile4, readdir as readdir4, access } from "fs/promises";
2268
+ import { join as join7 } from "path";
2269
+ import { z as z2 } from "zod";
2270
+ var ARCHTRACKER_DIR2 = ".archtracker";
2178
2271
  var SNAPSHOT_FILE = "snapshot.json";
2179
- var FileNodeSchema = z.object({
2180
- path: z.string(),
2181
- exists: z.boolean(),
2182
- dependencies: z.array(z.string()),
2183
- dependents: z.array(z.string())
2272
+ var HISTORY_DIR = "history";
2273
+ var FileNodeSchema = z2.object({
2274
+ path: z2.string(),
2275
+ exists: z2.boolean(),
2276
+ dependencies: z2.array(z2.string()),
2277
+ dependents: z2.array(z2.string())
2184
2278
  });
2185
- var DependencyGraphSchema = z.object({
2186
- rootDir: z.string(),
2187
- files: z.record(z.string(), FileNodeSchema),
2188
- edges: z.array(z.object({
2189
- source: z.string(),
2190
- target: z.string(),
2191
- type: z.enum(["static", "dynamic", "type-only"])
2279
+ var DependencyGraphSchema = z2.object({
2280
+ rootDir: z2.string(),
2281
+ files: z2.record(z2.string(), FileNodeSchema),
2282
+ edges: z2.array(z2.object({
2283
+ source: z2.string(),
2284
+ target: z2.string(),
2285
+ type: z2.enum(["static", "dynamic", "type-only"])
2192
2286
  })),
2193
- circularDependencies: z.array(z.object({ cycle: z.array(z.string()) })),
2194
- totalFiles: z.number(),
2195
- totalEdges: z.number()
2287
+ circularDependencies: z2.array(z2.object({ cycle: z2.array(z2.string()) })),
2288
+ totalFiles: z2.number(),
2289
+ totalEdges: z2.number()
2196
2290
  });
2197
- var SnapshotSchema = z.object({
2198
- version: z.enum([SCHEMA_VERSION, "1.0"]),
2199
- timestamp: z.string(),
2200
- rootDir: z.string(),
2291
+ var SnapshotSchema = z2.object({
2292
+ version: z2.enum([SCHEMA_VERSION, "1.0"]),
2293
+ timestamp: z2.string(),
2294
+ rootDir: z2.string(),
2201
2295
  graph: DependencyGraphSchema
2202
2296
  });
2203
- async function saveSnapshot(projectRoot, graph, multiLayer) {
2204
- const dirPath = join5(projectRoot, ARCHTRACKER_DIR);
2205
- const filePath = join5(dirPath, SNAPSHOT_FILE);
2297
+ async function saveSnapshot(projectRoot, graph, multiLayer, analysisOptions) {
2298
+ const dirPath = join7(projectRoot, ARCHTRACKER_DIR2);
2299
+ const filePath = join7(dirPath, SNAPSHOT_FILE);
2206
2300
  const snapshot = {
2207
2301
  version: SCHEMA_VERSION,
2208
2302
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2209
2303
  rootDir: graph.rootDir,
2210
2304
  graph,
2211
- ...multiLayer ? { multiLayer } : {}
2305
+ ...multiLayer ? { multiLayer } : {},
2306
+ ...analysisOptions ? { analysisOptions } : {}
2212
2307
  };
2213
- await mkdir(dirPath, { recursive: true });
2214
- await writeFile(filePath, JSON.stringify(snapshot, null, 2), "utf-8");
2308
+ await mkdir3(dirPath, { recursive: true });
2309
+ const json = JSON.stringify(snapshot, null, 2);
2310
+ await writeFile3(filePath, json, "utf-8");
2311
+ try {
2312
+ const historyPath = join7(dirPath, HISTORY_DIR);
2313
+ await mkdir3(historyPath, { recursive: true });
2314
+ const safeTs = snapshot.timestamp.replace(/[:.]/g, "-");
2315
+ await writeFile3(join7(historyPath, `${safeTs}.json`), json, "utf-8");
2316
+ } catch {
2317
+ }
2215
2318
  return snapshot;
2216
2319
  }
2217
2320
  async function loadSnapshot(projectRoot) {
2218
- const filePath = join5(projectRoot, ARCHTRACKER_DIR, SNAPSHOT_FILE);
2321
+ const filePath = join7(projectRoot, ARCHTRACKER_DIR2, SNAPSHOT_FILE);
2219
2322
  let raw;
2220
2323
  try {
2221
- raw = await readFile2(filePath, "utf-8");
2324
+ raw = await readFile4(filePath, "utf-8");
2222
2325
  } catch (error) {
2223
- if (isNodeError(error) && error.code === "ENOENT") {
2326
+ if (isNodeError2(error) && error.code === "ENOENT") {
2224
2327
  return null;
2225
2328
  }
2226
2329
  throw new StorageError(
@@ -2247,7 +2350,7 @@ async function loadSnapshot(projectRoot) {
2247
2350
  }
2248
2351
  async function hasArchtrackerDir(projectRoot) {
2249
2352
  try {
2250
- await access(join5(projectRoot, ARCHTRACKER_DIR));
2353
+ await access(join7(projectRoot, ARCHTRACKER_DIR2));
2251
2354
  return true;
2252
2355
  } catch {
2253
2356
  return false;
@@ -2259,7 +2362,7 @@ var StorageError = class extends Error {
2259
2362
  this.name = "StorageError";
2260
2363
  }
2261
2364
  };
2262
- function isNodeError(error) {
2365
+ function isNodeError2(error) {
2263
2366
  return error instanceof Error && "code" in error;
2264
2367
  }
2265
2368
 
@@ -2314,6 +2417,17 @@ function computeDiff(oldGraph, newGraph) {
2314
2417
  }
2315
2418
  return { added, removed, modified, affectedDependents };
2316
2419
  }
2420
+ function isTestOrFixture(path) {
2421
+ return /(__fixtures__|__tests__|__mocks__|\.test\.|\.spec\.|\.e2e\.)/.test(path);
2422
+ }
2423
+ function partition(arr, pred) {
2424
+ const yes = [];
2425
+ const no = [];
2426
+ for (const item of arr) {
2427
+ (pred(item) ? yes : no).push(item);
2428
+ }
2429
+ return [yes, no];
2430
+ }
2317
2431
  function formatDiffReport(diff) {
2318
2432
  const lines = [];
2319
2433
  lines.push(t("diff.title"));
@@ -2322,32 +2436,51 @@ function formatDiffReport(diff) {
2322
2436
  return lines.join("\n");
2323
2437
  }
2324
2438
  if (diff.added.length > 0) {
2439
+ const [testFiles, srcFiles] = partition(diff.added, isTestOrFixture);
2325
2440
  lines.push(t("diff.added", { count: diff.added.length }));
2326
- for (const f of diff.added) {
2441
+ for (const f of srcFiles) {
2327
2442
  lines.push(` + ${f}`);
2328
2443
  }
2444
+ if (testFiles.length > 0) {
2445
+ lines.push(t("diff.testSummary", { count: testFiles.length }));
2446
+ }
2329
2447
  lines.push("");
2330
2448
  }
2331
2449
  if (diff.removed.length > 0) {
2450
+ const [testFiles, srcFiles] = partition(diff.removed, isTestOrFixture);
2332
2451
  lines.push(t("diff.removed", { count: diff.removed.length }));
2333
- for (const f of diff.removed) {
2452
+ for (const f of srcFiles) {
2334
2453
  lines.push(` - ${f}`);
2335
2454
  }
2455
+ if (testFiles.length > 0) {
2456
+ lines.push(t("diff.testSummary", { count: testFiles.length }));
2457
+ }
2336
2458
  lines.push("");
2337
2459
  }
2338
2460
  if (diff.modified.length > 0) {
2461
+ const [testFiles, srcFiles] = partition(diff.modified, isTestOrFixture);
2339
2462
  lines.push(t("diff.modified", { count: diff.modified.length }));
2340
- for (const f of diff.modified) {
2463
+ for (const f of srcFiles) {
2341
2464
  lines.push(` ~ ${f}`);
2342
2465
  }
2466
+ if (testFiles.length > 0) {
2467
+ lines.push(t("diff.testSummary", { count: testFiles.length }));
2468
+ }
2343
2469
  lines.push("");
2344
2470
  }
2345
2471
  if (diff.affectedDependents.length > 0) {
2472
+ const [testEntries, srcEntries] = partition(
2473
+ diff.affectedDependents,
2474
+ (a) => isTestOrFixture(a.file) || isTestOrFixture(a.dependsOn)
2475
+ );
2346
2476
  lines.push(t("diff.affected", { count: diff.affectedDependents.length }));
2347
- for (const a of diff.affectedDependents) {
2477
+ for (const a of srcEntries) {
2348
2478
  lines.push(` ! ${a.file}`);
2349
2479
  lines.push(` ${a.reason}`);
2350
2480
  }
2481
+ if (testEntries.length > 0) {
2482
+ lines.push(t("diff.testAffectedSummary", { count: testEntries.length }));
2483
+ }
2351
2484
  lines.push("");
2352
2485
  }
2353
2486
  return lines.join("\n");
@@ -2359,77 +2492,6 @@ function arraysEqual(a, b) {
2359
2492
  }
2360
2493
  return true;
2361
2494
  }
2362
-
2363
- // src/storage/layers.ts
2364
- import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
2365
- import { join as join6 } from "path";
2366
- import { z as z2 } from "zod";
2367
- var ARCHTRACKER_DIR2 = ".archtracker";
2368
- var LAYERS_FILE = "layers.json";
2369
- var LayerDefinitionSchema = z2.object({
2370
- name: z2.string().min(1).regex(
2371
- /^[a-zA-Z0-9_-]+$/,
2372
- "Layer name must be alphanumeric (hyphens/underscores allowed)"
2373
- ),
2374
- targetDir: z2.string().min(1),
2375
- language: z2.enum(LANGUAGE_IDS).optional(),
2376
- exclude: z2.array(z2.string()).optional(),
2377
- color: z2.string().optional(),
2378
- description: z2.string().optional()
2379
- });
2380
- var CrossLayerConnectionSchema = z2.object({
2381
- fromLayer: z2.string(),
2382
- fromFile: z2.string(),
2383
- toLayer: z2.string(),
2384
- toFile: z2.string(),
2385
- type: z2.enum(["api-call", "event", "data-flow", "manual"]),
2386
- label: z2.string().optional()
2387
- });
2388
- var LayerConfigSchema = z2.object({
2389
- version: z2.literal("1.0"),
2390
- layers: z2.array(LayerDefinitionSchema).min(1).refine(
2391
- (layers) => {
2392
- const names = layers.map((l) => l.name);
2393
- return new Set(names).size === names.length;
2394
- },
2395
- { message: "Layer names must be unique" }
2396
- ),
2397
- connections: z2.array(CrossLayerConnectionSchema).optional()
2398
- });
2399
- async function loadLayerConfig(projectRoot) {
2400
- const filePath = join6(projectRoot, ARCHTRACKER_DIR2, LAYERS_FILE);
2401
- let raw;
2402
- try {
2403
- raw = await readFile3(filePath, "utf-8");
2404
- } catch (error) {
2405
- if (isNodeError2(error) && error.code === "ENOENT") {
2406
- return null;
2407
- }
2408
- throw new Error(`Failed to read ${filePath}`);
2409
- }
2410
- let parsed;
2411
- try {
2412
- parsed = JSON.parse(raw);
2413
- } catch {
2414
- throw new Error(`Invalid JSON in ${filePath}`);
2415
- }
2416
- const result = LayerConfigSchema.safeParse(parsed);
2417
- if (!result.success) {
2418
- const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).slice(0, 5).join("\n");
2419
- throw new Error(`layers.json validation failed:
2420
- ${issues}`);
2421
- }
2422
- return result.data;
2423
- }
2424
- async function saveLayerConfig(projectRoot, config) {
2425
- const dirPath = join6(projectRoot, ARCHTRACKER_DIR2);
2426
- const filePath = join6(dirPath, LAYERS_FILE);
2427
- await mkdir2(dirPath, { recursive: true });
2428
- await writeFile2(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
2429
- }
2430
- function isNodeError2(error) {
2431
- return error instanceof Error && "code" in error;
2432
- }
2433
2495
  export {
2434
2496
  AnalyzerError,
2435
2497
  SCHEMA_VERSION,