archtracker-mcp 0.5.0 → 0.6.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/cli/index.js +1709 -1473
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +101 -101
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.js +148 -134
- package/dist/mcp/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/arch-analyze/SKILL.md +2 -0
- package/skills/arch-check/SKILL.md +1 -0
- package/skills/arch-search/SKILL.md +4 -0
- package/skills/arch-snapshot/SKILL.md +1 -0
package/dist/mcp/index.js
CHANGED
|
@@ -2226,44 +2226,139 @@ function mergeLayerGraphs(projectRoot, layers) {
|
|
|
2226
2226
|
};
|
|
2227
2227
|
}
|
|
2228
2228
|
|
|
2229
|
-
// src/storage/
|
|
2230
|
-
import {
|
|
2229
|
+
// src/storage/layers.ts
|
|
2230
|
+
import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
|
|
2231
2231
|
import { join as join5 } from "path";
|
|
2232
2232
|
import { z } from "zod";
|
|
2233
|
+
var ARCHTRACKER_DIR = ".archtracker";
|
|
2234
|
+
var LAYERS_FILE = "layers.json";
|
|
2235
|
+
var LayerDefinitionSchema = z.object({
|
|
2236
|
+
name: z.string().min(1).regex(
|
|
2237
|
+
/^[a-zA-Z0-9_-]+$/,
|
|
2238
|
+
"Layer name must be alphanumeric (hyphens/underscores allowed)"
|
|
2239
|
+
),
|
|
2240
|
+
targetDir: z.string().min(1),
|
|
2241
|
+
language: z.enum(LANGUAGE_IDS).optional(),
|
|
2242
|
+
exclude: z.array(z.string()).optional(),
|
|
2243
|
+
color: z.string().optional(),
|
|
2244
|
+
description: z.string().optional()
|
|
2245
|
+
});
|
|
2246
|
+
var CrossLayerConnectionSchema = z.object({
|
|
2247
|
+
fromLayer: z.string(),
|
|
2248
|
+
fromFile: z.string(),
|
|
2249
|
+
toLayer: z.string(),
|
|
2250
|
+
toFile: z.string(),
|
|
2251
|
+
type: z.enum(["api-call", "event", "data-flow", "manual"]),
|
|
2252
|
+
label: z.string().optional()
|
|
2253
|
+
});
|
|
2254
|
+
var LayerConfigSchema = z.object({
|
|
2255
|
+
version: z.literal("1.0"),
|
|
2256
|
+
layers: z.array(LayerDefinitionSchema).min(1).refine(
|
|
2257
|
+
(layers) => {
|
|
2258
|
+
const names = layers.map((l) => l.name);
|
|
2259
|
+
return new Set(names).size === names.length;
|
|
2260
|
+
},
|
|
2261
|
+
{ message: "Layer names must be unique" }
|
|
2262
|
+
),
|
|
2263
|
+
connections: z.array(CrossLayerConnectionSchema).optional()
|
|
2264
|
+
});
|
|
2265
|
+
async function loadLayerConfig(projectRoot) {
|
|
2266
|
+
const filePath = join5(projectRoot, ARCHTRACKER_DIR, LAYERS_FILE);
|
|
2267
|
+
let raw;
|
|
2268
|
+
try {
|
|
2269
|
+
raw = await readFile2(filePath, "utf-8");
|
|
2270
|
+
} catch (error) {
|
|
2271
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
2272
|
+
return null;
|
|
2273
|
+
}
|
|
2274
|
+
throw new Error(`Failed to read ${filePath}`);
|
|
2275
|
+
}
|
|
2276
|
+
let parsed;
|
|
2277
|
+
try {
|
|
2278
|
+
parsed = JSON.parse(raw);
|
|
2279
|
+
} catch {
|
|
2280
|
+
throw new Error(`Invalid JSON in ${filePath}`);
|
|
2281
|
+
}
|
|
2282
|
+
const result = LayerConfigSchema.safeParse(parsed);
|
|
2283
|
+
if (!result.success) {
|
|
2284
|
+
const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).slice(0, 5).join("\n");
|
|
2285
|
+
throw new Error(`layers.json validation failed:
|
|
2286
|
+
${issues}`);
|
|
2287
|
+
}
|
|
2288
|
+
return result.data;
|
|
2289
|
+
}
|
|
2290
|
+
function isNodeError(error) {
|
|
2291
|
+
return error instanceof Error && "code" in error;
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
// src/analyzer/resolve.ts
|
|
2295
|
+
async function resolveGraph(opts) {
|
|
2296
|
+
const layerConfig = await loadLayerConfig(opts.projectRoot);
|
|
2297
|
+
if (layerConfig) {
|
|
2298
|
+
const multi = await analyzeMultiLayer(opts.projectRoot, layerConfig.layers);
|
|
2299
|
+
const autoConnections = detectCrossLayerConnections(multi.layers, layerConfig.layers);
|
|
2300
|
+
const manualConnections = layerConfig.connections ?? [];
|
|
2301
|
+
const manualKeys = new Set(manualConnections.map(
|
|
2302
|
+
(c) => `${c.fromLayer}/${c.fromFile}\u2192${c.toLayer}/${c.toFile}`
|
|
2303
|
+
));
|
|
2304
|
+
const merged = [
|
|
2305
|
+
...manualConnections,
|
|
2306
|
+
...autoConnections.filter(
|
|
2307
|
+
(c) => !manualKeys.has(`${c.fromLayer}/${c.fromFile}\u2192${c.toLayer}/${c.toFile}`)
|
|
2308
|
+
)
|
|
2309
|
+
];
|
|
2310
|
+
return {
|
|
2311
|
+
graph: multi.merged,
|
|
2312
|
+
multiLayer: multi,
|
|
2313
|
+
layerMetadata: multi.layerMetadata,
|
|
2314
|
+
crossLayerEdges: merged
|
|
2315
|
+
};
|
|
2316
|
+
}
|
|
2317
|
+
const graph = await analyzeProject(opts.targetDir, {
|
|
2318
|
+
exclude: opts.exclude,
|
|
2319
|
+
language: opts.language
|
|
2320
|
+
});
|
|
2321
|
+
return { graph };
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
// src/storage/snapshot.ts
|
|
2325
|
+
import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile3, access } from "fs/promises";
|
|
2326
|
+
import { join as join6 } from "path";
|
|
2327
|
+
import { z as z2 } from "zod";
|
|
2233
2328
|
|
|
2234
2329
|
// src/types/schema.ts
|
|
2235
2330
|
var SCHEMA_VERSION = "1.1";
|
|
2236
2331
|
|
|
2237
2332
|
// src/storage/snapshot.ts
|
|
2238
|
-
var
|
|
2333
|
+
var ARCHTRACKER_DIR2 = ".archtracker";
|
|
2239
2334
|
var SNAPSHOT_FILE = "snapshot.json";
|
|
2240
|
-
var FileNodeSchema =
|
|
2241
|
-
path:
|
|
2242
|
-
exists:
|
|
2243
|
-
dependencies:
|
|
2244
|
-
dependents:
|
|
2335
|
+
var FileNodeSchema = z2.object({
|
|
2336
|
+
path: z2.string(),
|
|
2337
|
+
exists: z2.boolean(),
|
|
2338
|
+
dependencies: z2.array(z2.string()),
|
|
2339
|
+
dependents: z2.array(z2.string())
|
|
2245
2340
|
});
|
|
2246
|
-
var DependencyGraphSchema =
|
|
2247
|
-
rootDir:
|
|
2248
|
-
files:
|
|
2249
|
-
edges:
|
|
2250
|
-
source:
|
|
2251
|
-
target:
|
|
2252
|
-
type:
|
|
2341
|
+
var DependencyGraphSchema = z2.object({
|
|
2342
|
+
rootDir: z2.string(),
|
|
2343
|
+
files: z2.record(z2.string(), FileNodeSchema),
|
|
2344
|
+
edges: z2.array(z2.object({
|
|
2345
|
+
source: z2.string(),
|
|
2346
|
+
target: z2.string(),
|
|
2347
|
+
type: z2.enum(["static", "dynamic", "type-only"])
|
|
2253
2348
|
})),
|
|
2254
|
-
circularDependencies:
|
|
2255
|
-
totalFiles:
|
|
2256
|
-
totalEdges:
|
|
2349
|
+
circularDependencies: z2.array(z2.object({ cycle: z2.array(z2.string()) })),
|
|
2350
|
+
totalFiles: z2.number(),
|
|
2351
|
+
totalEdges: z2.number()
|
|
2257
2352
|
});
|
|
2258
|
-
var SnapshotSchema =
|
|
2259
|
-
version:
|
|
2260
|
-
timestamp:
|
|
2261
|
-
rootDir:
|
|
2353
|
+
var SnapshotSchema = z2.object({
|
|
2354
|
+
version: z2.enum([SCHEMA_VERSION, "1.0"]),
|
|
2355
|
+
timestamp: z2.string(),
|
|
2356
|
+
rootDir: z2.string(),
|
|
2262
2357
|
graph: DependencyGraphSchema
|
|
2263
2358
|
});
|
|
2264
2359
|
async function saveSnapshot(projectRoot, graph, multiLayer) {
|
|
2265
|
-
const dirPath =
|
|
2266
|
-
const filePath =
|
|
2360
|
+
const dirPath = join6(projectRoot, ARCHTRACKER_DIR2);
|
|
2361
|
+
const filePath = join6(dirPath, SNAPSHOT_FILE);
|
|
2267
2362
|
const snapshot = {
|
|
2268
2363
|
version: SCHEMA_VERSION,
|
|
2269
2364
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2271,17 +2366,17 @@ async function saveSnapshot(projectRoot, graph, multiLayer) {
|
|
|
2271
2366
|
graph,
|
|
2272
2367
|
...multiLayer ? { multiLayer } : {}
|
|
2273
2368
|
};
|
|
2274
|
-
await
|
|
2275
|
-
await
|
|
2369
|
+
await mkdir2(dirPath, { recursive: true });
|
|
2370
|
+
await writeFile2(filePath, JSON.stringify(snapshot, null, 2), "utf-8");
|
|
2276
2371
|
return snapshot;
|
|
2277
2372
|
}
|
|
2278
2373
|
async function loadSnapshot(projectRoot) {
|
|
2279
|
-
const filePath =
|
|
2374
|
+
const filePath = join6(projectRoot, ARCHTRACKER_DIR2, SNAPSHOT_FILE);
|
|
2280
2375
|
let raw;
|
|
2281
2376
|
try {
|
|
2282
|
-
raw = await
|
|
2377
|
+
raw = await readFile3(filePath, "utf-8");
|
|
2283
2378
|
} catch (error) {
|
|
2284
|
-
if (
|
|
2379
|
+
if (isNodeError2(error) && error.code === "ENOENT") {
|
|
2285
2380
|
return null;
|
|
2286
2381
|
}
|
|
2287
2382
|
throw new StorageError(
|
|
@@ -2312,7 +2407,7 @@ var StorageError = class extends Error {
|
|
|
2312
2407
|
this.name = "StorageError";
|
|
2313
2408
|
}
|
|
2314
2409
|
};
|
|
2315
|
-
function
|
|
2410
|
+
function isNodeError2(error) {
|
|
2316
2411
|
return error instanceof Error && "code" in error;
|
|
2317
2412
|
}
|
|
2318
2413
|
|
|
@@ -2413,71 +2508,6 @@ function arraysEqual(a, b) {
|
|
|
2413
2508
|
return true;
|
|
2414
2509
|
}
|
|
2415
2510
|
|
|
2416
|
-
// src/storage/layers.ts
|
|
2417
|
-
import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
2418
|
-
import { join as join6 } from "path";
|
|
2419
|
-
import { z as z2 } from "zod";
|
|
2420
|
-
var ARCHTRACKER_DIR2 = ".archtracker";
|
|
2421
|
-
var LAYERS_FILE = "layers.json";
|
|
2422
|
-
var LayerDefinitionSchema = z2.object({
|
|
2423
|
-
name: z2.string().min(1).regex(
|
|
2424
|
-
/^[a-zA-Z0-9_-]+$/,
|
|
2425
|
-
"Layer name must be alphanumeric (hyphens/underscores allowed)"
|
|
2426
|
-
),
|
|
2427
|
-
targetDir: z2.string().min(1),
|
|
2428
|
-
language: z2.enum(LANGUAGE_IDS).optional(),
|
|
2429
|
-
exclude: z2.array(z2.string()).optional(),
|
|
2430
|
-
color: z2.string().optional(),
|
|
2431
|
-
description: z2.string().optional()
|
|
2432
|
-
});
|
|
2433
|
-
var CrossLayerConnectionSchema = z2.object({
|
|
2434
|
-
fromLayer: z2.string(),
|
|
2435
|
-
fromFile: z2.string(),
|
|
2436
|
-
toLayer: z2.string(),
|
|
2437
|
-
toFile: z2.string(),
|
|
2438
|
-
type: z2.enum(["api-call", "event", "data-flow", "manual"]),
|
|
2439
|
-
label: z2.string().optional()
|
|
2440
|
-
});
|
|
2441
|
-
var LayerConfigSchema = z2.object({
|
|
2442
|
-
version: z2.literal("1.0"),
|
|
2443
|
-
layers: z2.array(LayerDefinitionSchema).min(1).refine(
|
|
2444
|
-
(layers) => {
|
|
2445
|
-
const names = layers.map((l) => l.name);
|
|
2446
|
-
return new Set(names).size === names.length;
|
|
2447
|
-
},
|
|
2448
|
-
{ message: "Layer names must be unique" }
|
|
2449
|
-
),
|
|
2450
|
-
connections: z2.array(CrossLayerConnectionSchema).optional()
|
|
2451
|
-
});
|
|
2452
|
-
async function loadLayerConfig(projectRoot) {
|
|
2453
|
-
const filePath = join6(projectRoot, ARCHTRACKER_DIR2, LAYERS_FILE);
|
|
2454
|
-
let raw;
|
|
2455
|
-
try {
|
|
2456
|
-
raw = await readFile3(filePath, "utf-8");
|
|
2457
|
-
} catch (error) {
|
|
2458
|
-
if (isNodeError2(error) && error.code === "ENOENT") {
|
|
2459
|
-
return null;
|
|
2460
|
-
}
|
|
2461
|
-
throw new Error(`Failed to read ${filePath}`);
|
|
2462
|
-
}
|
|
2463
|
-
let parsed;
|
|
2464
|
-
try {
|
|
2465
|
-
parsed = JSON.parse(raw);
|
|
2466
|
-
} catch {
|
|
2467
|
-
throw new Error(`Invalid JSON in ${filePath}`);
|
|
2468
|
-
}
|
|
2469
|
-
const result = LayerConfigSchema.safeParse(parsed);
|
|
2470
|
-
if (!result.success) {
|
|
2471
|
-
const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).slice(0, 5).join("\n");
|
|
2472
|
-
throw new Error(`layers.json validation failed:
|
|
2473
|
-
${issues}`);
|
|
2474
|
-
}
|
|
2475
|
-
return result.data;
|
|
2476
|
-
}
|
|
2477
|
-
function isNodeError2(error) {
|
|
2478
|
-
return error instanceof Error && "code" in error;
|
|
2479
|
-
}
|
|
2480
|
-
|
|
2481
2511
|
// src/utils/path-guard.ts
|
|
2482
2512
|
import { resolve as resolve5 } from "path";
|
|
2483
2513
|
function validatePath(inputPath, boundary) {
|
|
@@ -2527,30 +2557,13 @@ var LANG_DISPLAY = {
|
|
|
2527
2557
|
"c-sharp": "C#"
|
|
2528
2558
|
};
|
|
2529
2559
|
var languageList = LANGUAGE_IDS.map((id) => LANG_DISPLAY[id] ?? id.charAt(0).toUpperCase() + id.slice(1)).join(", ");
|
|
2530
|
-
async function
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
const multi = await analyzeMultiLayer(opts.projectRoot, layerConfig.layers);
|
|
2535
|
-
const autoConnections = detectCrossLayerConnections(multi.layers, layerConfig.layers);
|
|
2536
|
-
const manualConnections = layerConfig.connections ?? [];
|
|
2537
|
-
const manualKeys = new Set(manualConnections.map(
|
|
2538
|
-
(c) => `${c.fromLayer}/${c.fromFile}\u2192${c.toLayer}/${c.toFile}`
|
|
2539
|
-
));
|
|
2540
|
-
const allConnections = [
|
|
2541
|
-
...manualConnections,
|
|
2542
|
-
...autoConnections.filter(
|
|
2543
|
-
(c) => !manualKeys.has(`${c.fromLayer}/${c.fromFile}\u2192${c.toLayer}/${c.toFile}`)
|
|
2544
|
-
)
|
|
2545
|
-
];
|
|
2546
|
-
return { graph: multi.merged, multiLayer: multi, layerMetadata: multi.layerMetadata, crossEdges: allConnections };
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
const graph = await analyzeProject(opts.targetDir, {
|
|
2560
|
+
async function resolveGraphMcp(opts) {
|
|
2561
|
+
return resolveGraph({
|
|
2562
|
+
targetDir: opts.targetDir,
|
|
2563
|
+
projectRoot: opts.projectRoot,
|
|
2550
2564
|
exclude: opts.exclude,
|
|
2551
2565
|
language: opts.language
|
|
2552
2566
|
});
|
|
2553
|
-
return { graph };
|
|
2554
2567
|
}
|
|
2555
2568
|
function formatLayerSummary(metadata) {
|
|
2556
2569
|
return metadata.map(
|
|
@@ -2564,14 +2577,13 @@ server.tool(
|
|
|
2564
2577
|
targetDir: z3.string().default("src").describe("Target directory path (default: src). When layers.json exists and this is 'src', multi-layer analysis is used automatically."),
|
|
2565
2578
|
projectRoot: z3.string().default(".").describe("Project root (where .archtracker/ is located)"),
|
|
2566
2579
|
exclude: z3.array(z3.string()).optional().describe("Array of regex patterns to exclude (e.g. ['test', 'mock'])"),
|
|
2567
|
-
maxDepth: z3.number().int().min(0).optional().describe("Max analysis depth (0 = unlimited)"),
|
|
2568
2580
|
language: languageEnum.optional().describe("Target language (auto-detected if omitted)")
|
|
2569
2581
|
},
|
|
2570
|
-
async ({ targetDir, projectRoot, exclude,
|
|
2582
|
+
async ({ targetDir, projectRoot, exclude, language }) => {
|
|
2571
2583
|
try {
|
|
2572
2584
|
validatePath(targetDir);
|
|
2573
2585
|
validatePath(projectRoot);
|
|
2574
|
-
const { graph, layerMetadata,
|
|
2586
|
+
const { graph, layerMetadata, crossLayerEdges } = await resolveGraphMcp({
|
|
2575
2587
|
targetDir,
|
|
2576
2588
|
projectRoot,
|
|
2577
2589
|
exclude,
|
|
@@ -2581,11 +2593,11 @@ server.tool(
|
|
|
2581
2593
|
t("mcp.analyzeComplete", { files: graph.totalFiles, edges: graph.totalEdges }),
|
|
2582
2594
|
graph.circularDependencies.length > 0 ? t("mcp.circularFound", { count: graph.circularDependencies.length }) : t("mcp.circularNone"),
|
|
2583
2595
|
...layerMetadata ? ["\nLayers:\n" + formatLayerSummary(layerMetadata)] : [],
|
|
2584
|
-
...
|
|
2585
|
-
Cross-layer connections: ${
|
|
2596
|
+
...crossLayerEdges?.length ? [`
|
|
2597
|
+
Cross-layer connections: ${crossLayerEdges.length}`] : []
|
|
2586
2598
|
].join("\n");
|
|
2587
2599
|
const result = { ...graph };
|
|
2588
|
-
if (
|
|
2600
|
+
if (crossLayerEdges?.length) result.crossLayerConnections = crossLayerEdges;
|
|
2589
2601
|
return {
|
|
2590
2602
|
content: [
|
|
2591
2603
|
{ type: "text", text: summary },
|
|
@@ -2599,19 +2611,20 @@ Cross-layer connections: ${crossEdges.length}`] : []
|
|
|
2599
2611
|
);
|
|
2600
2612
|
server.tool(
|
|
2601
2613
|
"analyze_existing_architecture",
|
|
2602
|
-
`Comprehensive architecture analysis for existing projects. Shows critical components, circular dependencies, orphan files, coupling hotspots, and directory breakdown. Supports ${
|
|
2614
|
+
`Comprehensive architecture analysis for existing projects. Shows critical components, circular dependencies, orphan files, coupling hotspots, and directory breakdown. Supports ${languageList}.`,
|
|
2603
2615
|
{
|
|
2604
2616
|
targetDir: z3.string().default("src").describe("Target directory path (default: src)"),
|
|
2605
2617
|
exclude: z3.array(z3.string()).optional().describe("Array of regex patterns to exclude"),
|
|
2606
2618
|
topN: z3.number().int().min(1).max(50).optional().describe("Number of top items to show in each section (default: 10)"),
|
|
2607
2619
|
saveSnapshot: z3.boolean().optional().describe("Also save a snapshot after analysis (default: false)"),
|
|
2608
|
-
projectRoot: z3.string().default(".").describe("Project root (
|
|
2620
|
+
projectRoot: z3.string().default(".").describe("Project root (where .archtracker/ is located)"),
|
|
2609
2621
|
language: languageEnum.optional().describe("Target language (auto-detected if omitted)")
|
|
2610
2622
|
},
|
|
2611
2623
|
async ({ targetDir, exclude, topN, saveSnapshot: doSave, projectRoot, language }) => {
|
|
2612
2624
|
try {
|
|
2613
2625
|
validatePath(targetDir);
|
|
2614
|
-
|
|
2626
|
+
validatePath(projectRoot);
|
|
2627
|
+
const { graph, multiLayer, layerMetadata, crossLayerEdges } = await resolveGraphMcp({
|
|
2615
2628
|
targetDir,
|
|
2616
2629
|
projectRoot,
|
|
2617
2630
|
exclude,
|
|
@@ -2624,16 +2637,15 @@ server.tool(
|
|
|
2624
2637
|
if (layerMetadata) {
|
|
2625
2638
|
content.push({ type: "text", text: "\nLayers:\n" + formatLayerSummary(layerMetadata) });
|
|
2626
2639
|
}
|
|
2627
|
-
if (
|
|
2628
|
-
const crossSummary =
|
|
2640
|
+
if (crossLayerEdges?.length) {
|
|
2641
|
+
const crossSummary = crossLayerEdges.map(
|
|
2629
2642
|
(c) => ` ${c.fromLayer}/${c.fromFile} \u2192 ${c.toLayer}/${c.toFile} [${c.type}] ${c.label ?? ""}`
|
|
2630
2643
|
).join("\n");
|
|
2631
2644
|
content.push({ type: "text", text: `
|
|
2632
|
-
Cross-layer connections (${
|
|
2645
|
+
Cross-layer connections (${crossLayerEdges.length}):
|
|
2633
2646
|
${crossSummary}` });
|
|
2634
2647
|
}
|
|
2635
2648
|
if (doSave) {
|
|
2636
|
-
validatePath(projectRoot);
|
|
2637
2649
|
await saveSnapshot(projectRoot, graph, multiLayer);
|
|
2638
2650
|
content.push({ type: "text", text: t("analyze.snapshotSaved") });
|
|
2639
2651
|
}
|
|
@@ -2655,7 +2667,7 @@ server.tool(
|
|
|
2655
2667
|
try {
|
|
2656
2668
|
validatePath(targetDir);
|
|
2657
2669
|
validatePath(projectRoot);
|
|
2658
|
-
const { graph, multiLayer, layerMetadata } = await
|
|
2670
|
+
const { graph, multiLayer, layerMetadata } = await resolveGraphMcp({
|
|
2659
2671
|
targetDir,
|
|
2660
2672
|
projectRoot,
|
|
2661
2673
|
language
|
|
@@ -2692,7 +2704,7 @@ server.tool(
|
|
|
2692
2704
|
validatePath(projectRoot);
|
|
2693
2705
|
const existingSnapshot = await loadSnapshot(projectRoot);
|
|
2694
2706
|
if (!existingSnapshot) {
|
|
2695
|
-
const { graph, multiLayer } = await
|
|
2707
|
+
const { graph, multiLayer } = await resolveGraphMcp({
|
|
2696
2708
|
targetDir,
|
|
2697
2709
|
projectRoot,
|
|
2698
2710
|
language
|
|
@@ -2711,7 +2723,7 @@ server.tool(
|
|
|
2711
2723
|
]
|
|
2712
2724
|
};
|
|
2713
2725
|
}
|
|
2714
|
-
const { graph: currentGraph } = await
|
|
2726
|
+
const { graph: currentGraph } = await resolveGraphMcp({
|
|
2715
2727
|
targetDir,
|
|
2716
2728
|
projectRoot,
|
|
2717
2729
|
language
|
|
@@ -2734,9 +2746,11 @@ server.tool(
|
|
|
2734
2746
|
},
|
|
2735
2747
|
async ({ targetDir, projectRoot, language }) => {
|
|
2736
2748
|
try {
|
|
2749
|
+
validatePath(targetDir);
|
|
2750
|
+
validatePath(projectRoot);
|
|
2737
2751
|
let snapshot = await loadSnapshot(projectRoot);
|
|
2738
2752
|
if (!snapshot) {
|
|
2739
|
-
const { graph: graph2, multiLayer } = await
|
|
2753
|
+
const { graph: graph2, multiLayer } = await resolveGraphMcp({
|
|
2740
2754
|
targetDir,
|
|
2741
2755
|
projectRoot,
|
|
2742
2756
|
language
|
|
@@ -2802,7 +2816,7 @@ server.tool(
|
|
|
2802
2816
|
validatePath(projectRoot);
|
|
2803
2817
|
let snapshot = await loadSnapshot(projectRoot);
|
|
2804
2818
|
if (!snapshot) {
|
|
2805
|
-
const { graph: graph2, multiLayer } = await
|
|
2819
|
+
const { graph: graph2, multiLayer } = await resolveGraphMcp({
|
|
2806
2820
|
targetDir,
|
|
2807
2821
|
projectRoot,
|
|
2808
2822
|
language
|