@documentation-robotics/cli 0.1.12 → 0.2.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/README.md +39 -1
- package/dist/analyzers/verify-engine.js +22 -19
- package/dist/analyzers/verify-engine.js.map +2 -2
- package/dist/cli.js +101 -27
- package/dist/cli.js.map +3 -3
- package/dist/coding-agents/agents/claude-code.js +3 -1
- package/dist/coding-agents/agents/claude-code.js.map +2 -2
- package/dist/coding-agents/claude-code-client.js +2 -1
- package/dist/coding-agents/claude-code-client.js.map +2 -2
- package/dist/coding-agents/copilot-client.js +17 -12
- package/dist/coding-agents/copilot-client.js.map +2 -2
- package/dist/coding-agents/default-permissions.js +122 -0
- package/dist/coding-agents/default-permissions.js.map +7 -0
- package/dist/commands/add.js +10 -6
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +18 -10
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/audit.js +6 -6
- package/dist/commands/audit.js.map +2 -2
- package/dist/commands/changeset.js +238 -145
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/delete.js +45 -18
- package/dist/commands/delete.js.map +3 -3
- package/dist/commands/element.js +3 -2
- package/dist/commands/element.js.map +2 -2
- package/dist/commands/farm.js +657 -0
- package/dist/commands/farm.js.map +7 -0
- package/dist/commands/init.js +11 -1
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +107 -0
- package/dist/commands/mcp.js.map +7 -0
- package/dist/commands/relationship.js +53 -30
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +19 -6
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/validate.js +41 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +2 -2
- package/dist/commands/version.js.map +2 -2
- package/dist/config.js +83 -0
- package/dist/config.js.map +7 -0
- package/dist/core/annotation-store.js +138 -0
- package/dist/core/annotation-store.js.map +7 -0
- package/dist/core/farm-manifest.js +134 -0
- package/dist/core/farm-manifest.js.map +7 -0
- package/dist/core/farm-sync-engine.js +346 -0
- package/dist/core/farm-sync-engine.js.map +7 -0
- package/dist/core/farm-sync-state.js +159 -0
- package/dist/core/farm-sync-state.js.map +7 -0
- package/dist/core/manifest.js +6 -3
- package/dist/core/manifest.js.map +2 -2
- package/dist/core/migration-registry.js +55 -1
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/model.js +177 -16
- package/dist/core/model.js.map +3 -3
- package/dist/core/virtual-projection.js +1 -0
- package/dist/core/virtual-projection.js.map +2 -2
- package/dist/generated/node-types.js +1 -1
- package/dist/generated/node-types.js.map +2 -2
- package/dist/generated/relationship-index.js +45 -9
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/docs/MCP_SERVER.md +55 -0
- package/dist/integrations/claude_code/docs/README.md +4 -0
- package/dist/mcp/api-key-manager.js +98 -0
- package/dist/mcp/api-key-manager.js.map +7 -0
- package/dist/mcp/http-transport.js +176 -0
- package/dist/mcp/http-transport.js.map +7 -0
- package/dist/mcp/resource-registry.js +97 -0
- package/dist/mcp/resource-registry.js.map +7 -0
- package/dist/mcp/tool-registry.js +44 -0
- package/dist/mcp/tool-registry.js.map +7 -0
- package/dist/mcp/tools/annotation-create.js +39 -0
- package/dist/mcp/tools/annotation-create.js.map +7 -0
- package/dist/mcp/tools/annotation-delete.js +29 -0
- package/dist/mcp/tools/annotation-delete.js.map +7 -0
- package/dist/mcp/tools/annotation-get.js +29 -0
- package/dist/mcp/tools/annotation-get.js.map +7 -0
- package/dist/mcp/tools/annotation-list.js +24 -0
- package/dist/mcp/tools/annotation-list.js.map +7 -0
- package/dist/mcp/tools/annotation-reply.js +34 -0
- package/dist/mcp/tools/annotation-reply.js.map +7 -0
- package/dist/mcp/tools/annotation-shared.js +10 -0
- package/dist/mcp/tools/annotation-shared.js.map +7 -0
- package/dist/mcp/tools/annotation-update.js +39 -0
- package/dist/mcp/tools/annotation-update.js.map +7 -0
- package/dist/mcp/tools/changeset-list.js +33 -0
- package/dist/mcp/tools/changeset-list.js.map +7 -0
- package/dist/mcp/tools/changeset-show.js +39 -0
- package/dist/mcp/tools/changeset-show.js.map +7 -0
- package/dist/mcp/tools/chat-launch.js +50 -0
- package/dist/mcp/tools/chat-launch.js.map +7 -0
- package/dist/mcp/tools/chat-status.js +26 -0
- package/dist/mcp/tools/chat-status.js.map +7 -0
- package/dist/mcp/tools/index.js +47 -0
- package/dist/mcp/tools/index.js.map +7 -0
- package/dist/mcp/tools/model-add.js +106 -0
- package/dist/mcp/tools/model-add.js.map +7 -0
- package/dist/mcp/tools/model-delete.js +99 -0
- package/dist/mcp/tools/model-delete.js.map +7 -0
- package/dist/mcp/tools/model-export.js +72 -0
- package/dist/mcp/tools/model-export.js.map +7 -0
- package/dist/mcp/tools/model-info.js +51 -0
- package/dist/mcp/tools/model-info.js.map +7 -0
- package/dist/mcp/tools/model-list.js +53 -0
- package/dist/mcp/tools/model-list.js.map +7 -0
- package/dist/mcp/tools/model-reload.js +34 -0
- package/dist/mcp/tools/model-reload.js.map +7 -0
- package/dist/mcp/tools/model-search.js +88 -0
- package/dist/mcp/tools/model-search.js.map +7 -0
- package/dist/mcp/tools/model-show.js +41 -0
- package/dist/mcp/tools/model-show.js.map +7 -0
- package/dist/mcp/tools/model-stats.js +22 -0
- package/dist/mcp/tools/model-stats.js.map +7 -0
- package/dist/mcp/tools/model-trace.js +55 -0
- package/dist/mcp/tools/model-trace.js.map +7 -0
- package/dist/mcp/tools/model-update.js +105 -0
- package/dist/mcp/tools/model-update.js.map +7 -0
- package/dist/mcp/tools/model-validate.js +78 -0
- package/dist/mcp/tools/model-validate.js.map +7 -0
- package/dist/mcp/tools/shared.js +103 -0
- package/dist/mcp/tools/shared.js.map +7 -0
- package/dist/reports/model-layer-report-generator.js +5 -3
- package/dist/reports/model-layer-report-generator.js.map +2 -2
- package/dist/reports/model-readme-generator.js +116 -0
- package/dist/reports/model-readme-generator.js.map +7 -0
- package/dist/reports/model-report-data.js +37 -1
- package/dist/reports/model-report-data.js.map +2 -2
- package/dist/reports/model-report-orchestrator.js +29 -6
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/reports/model-report-utils.js +9 -0
- package/dist/reports/model-report-utils.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +2 -2
- package/dist/schemas/bundled/analyzers/manifest.json +2 -2
- package/dist/schemas/bundled/api.json +1 -1
- package/dist/schemas/bundled/apm.json +1 -1
- package/dist/schemas/bundled/application.json +12 -1
- package/dist/schemas/bundled/base.json +1 -1
- package/dist/schemas/bundled/business.json +1 -1
- package/dist/schemas/bundled/data-model.json +38 -2
- package/dist/schemas/bundled/data-store.json +1 -1
- package/dist/schemas/bundled/manifest.json +4 -4
- package/dist/schemas/bundled/motivation.json +1 -1
- package/dist/schemas/bundled/navigation.json +1 -1
- package/dist/schemas/bundled/product.json +1 -1
- package/dist/schemas/bundled/security.json +1 -1
- package/dist/schemas/bundled/technology.json +1 -1
- package/dist/schemas/bundled/testing.json +1 -1
- package/dist/schemas/bundled/ux.json +1 -1
- package/dist/server/server.js +45 -7
- package/dist/server/server.js.map +2 -2
- package/dist/telemetry/config.js +2 -40
- package/dist/telemetry/config.js.map +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/types/index.js.map +2 -2
- package/dist/utils/ansi-suppressor.js +25 -0
- package/dist/utils/ansi-suppressor.js.map +7 -0
- package/dist/utils/color-utils.js +34 -0
- package/dist/utils/color-utils.js.map +7 -0
- package/dist/utils/element-reference-shape.js +15 -1
- package/dist/utils/element-reference-shape.js.map +3 -3
- package/dist/utils/errors.js +69 -10
- package/dist/utils/errors.js.map +2 -2
- package/dist/utils/globals.js +17 -1
- package/dist/utils/globals.js.map +2 -2
- package/dist/utils/project-paths.js +24 -2
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/reference-path-parser.js +49 -0
- package/dist/utils/reference-path-parser.js.map +7 -0
- package/dist/utils/source-reference.js +5 -0
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +10 -2
- package/dist/utils/spec-version.js.map +2 -2
- package/dist/validators/composed-reference-validator.js +262 -0
- package/dist/validators/composed-reference-validator.js.map +7 -0
- package/dist/validators/reference-validator.js +59 -8
- package/dist/validators/reference-validator.js.map +3 -3
- package/dist/validators/relationship-schema-validator.js +30 -2
- package/dist/validators/relationship-schema-validator.js.map +3 -3
- package/dist/viewer/README.md +6 -6
- package/dist/viewer/assets/main-B7AOQXXX.js +81 -0
- package/dist/viewer/assets/main-vdrFrG7q.css +1 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/manifest.json +10 -10
- package/dist/viewer/version.json +1 -1
- package/package.json +6 -3
- package/dist/viewer/assets/main-BRPZyc36.css +0 -1
- package/dist/viewer/assets/main-BrpLargo.js +0 -81
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/model-stats.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * model_stats \u2014 aggregate statistics about the architecture model. Mirrors `dr stats`.\n */\n\nimport type { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { StatsCollector } from \"../../core/stats-collector.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n rootPath: rootPathSchema,\n};\n\nexport type ModelStatsArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelStatsHandler(args: ModelStatsArgs): Promise<CallToolResult> {\n return runTool(async () => {\n const model = await loadModel(args.rootPath);\n const collector = new StatsCollector(model);\n const stats = await collector.collect();\n return jsonResult(stats);\n });\n}\n\nexport const modelStatsTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_stats\",\n description: \"Get aggregate statistics about the architecture model: element counts, relationships, coverage, and orphans.\",\n inputSchema,\n handler: modelStatsHandler,\n};\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,sBAAsB;AAC/B,SAAS,YAAY,WAAW,gBAAgB,eAAuC;AAEvF,MAAM,cAAc;EAClB,UAAU;;AAKZ,eAAsB,kBAAkB,MAAoB;AAC1D,SAAO,QAAQ,YAAW;AACxB,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GAErC,QAAQ,MADI,IAAI,eAAe,KAAK,EACZ,QAAO;AACrC,WAAO,WAAW,KAAK;EACzB,CAAC;AACH;AAEO,MAAM,iBAAwD;EACnE,MAAM;EACN,aAAa;EACb;EACA,SAAS;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { DependencyTracker, TraceDirection } from "../../core/dependency-tracker.js";
|
|
3
|
+
import { ReferenceRegistry } from "../../core/reference-registry.js";
|
|
4
|
+
import { findElementLayer } from "../../utils/element-utils.js";
|
|
5
|
+
import { CLIError, ErrorCategory } from "../../utils/errors.js";
|
|
6
|
+
import { jsonResult, loadModel, rootPathSchema, runTool } from "./shared.js";
|
|
7
|
+
const inputSchema = {
|
|
8
|
+
id: z.string().describe("Element ID or path to trace."),
|
|
9
|
+
direction: z.enum(["up", "down", "both"]).optional().describe("'up' = what depends on this element (dependents), 'down' = what this element depends on (dependencies), 'both' (default)."),
|
|
10
|
+
depth: z.number().int().positive().optional().describe("Maximum trace depth. Omit for unlimited."),
|
|
11
|
+
rootPath: rootPathSchema
|
|
12
|
+
};
|
|
13
|
+
async function modelTraceHandler(args) {
|
|
14
|
+
return runTool(async () => {
|
|
15
|
+
const model = await loadModel(args.rootPath), layerName = await findElementLayer(model, args.id);
|
|
16
|
+
if (!layerName)
|
|
17
|
+
throw new CLIError(`Element ${args.id} not found`, ErrorCategory.NOT_FOUND, [
|
|
18
|
+
'Use "model_search" to find similar elements'
|
|
19
|
+
]);
|
|
20
|
+
const registry = new ReferenceRegistry();
|
|
21
|
+
for (const layer of model.layers.values())
|
|
22
|
+
for (const element of layer.listElements())
|
|
23
|
+
registry.registerElement(element);
|
|
24
|
+
const graph = registry.getDependencyGraph();
|
|
25
|
+
for (const rel of model.relationships.getAll())
|
|
26
|
+
graph.hasNode(rel.source) || graph.addNode(rel.source), graph.hasNode(rel.target) || graph.addNode(rel.target), graph.hasEdge(rel.source, rel.target) || graph.addEdge(rel.source, rel.target, { type: rel.predicate });
|
|
27
|
+
const tracker = new DependencyTracker(graph, model), direction = args.direction ?? "both", maxDepth = args.depth ?? null, result = { id: args.id, layer: layerName, direction };
|
|
28
|
+
if (direction === "up" || direction === "both") {
|
|
29
|
+
const direct = tracker.traceDependencies(args.id, TraceDirection.DOWN, 1), transitiveAll = tracker.traceDependencies(args.id, TraceDirection.DOWN, maxDepth);
|
|
30
|
+
result.dependents = {
|
|
31
|
+
direct,
|
|
32
|
+
transitive: transitiveAll.filter((d) => !direct.includes(d))
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (direction === "down" || direction === "both") {
|
|
36
|
+
const direct = tracker.traceDependencies(args.id, TraceDirection.UP, 1), transitiveAll = tracker.traceDependencies(args.id, TraceDirection.UP, maxDepth);
|
|
37
|
+
result.dependencies = {
|
|
38
|
+
direct,
|
|
39
|
+
transitive: transitiveAll.filter((d) => !direct.includes(d))
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return jsonResult(result);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const modelTraceTool = {
|
|
46
|
+
name: "model_trace",
|
|
47
|
+
description: "Trace dependents and/or dependencies of an element across cross-layer references and relationships.",
|
|
48
|
+
inputSchema,
|
|
49
|
+
handler: modelTraceHandler
|
|
50
|
+
};
|
|
51
|
+
export {
|
|
52
|
+
modelTraceHandler,
|
|
53
|
+
modelTraceTool
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=model-trace.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/model-trace.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * model_trace \u2014 dependency trace for an element. Mirrors `dr trace`.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { DependencyTracker, TraceDirection } from \"../../core/dependency-tracker.js\";\nimport { ReferenceRegistry } from \"../../core/reference-registry.js\";\nimport { findElementLayer } from \"../../utils/element-utils.js\";\nimport { CLIError, ErrorCategory } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n id: z.string().describe(\"Element ID or path to trace.\"),\n direction: z\n .enum([\"up\", \"down\", \"both\"])\n .optional()\n .describe(\"'up' = what depends on this element (dependents), 'down' = what this element depends on (dependencies), 'both' (default).\"),\n depth: z.number().int().positive().optional().describe(\"Maximum trace depth. Omit for unlimited.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelTraceArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelTraceHandler(args: ModelTraceArgs): Promise<CallToolResult> {\n return runTool(async () => {\n const model = await loadModel(args.rootPath);\n\n const layerName = await findElementLayer(model, args.id);\n if (!layerName) {\n throw new CLIError(`Element ${args.id} not found`, ErrorCategory.NOT_FOUND, [\n 'Use \"model_search\" to find similar elements',\n ]);\n }\n\n // Build a reference registry from cross-layer references, then extend the\n // dependency graph with intra-layer relationships from relationships.yaml.\n const registry = new ReferenceRegistry();\n for (const layer of model.layers.values()) {\n for (const element of layer.listElements()) {\n registry.registerElement(element);\n }\n }\n\n const graph = registry.getDependencyGraph();\n for (const rel of model.relationships.getAll()) {\n if (!graph.hasNode(rel.source)) graph.addNode(rel.source);\n if (!graph.hasNode(rel.target)) graph.addNode(rel.target);\n if (!graph.hasEdge(rel.source, rel.target)) {\n graph.addEdge(rel.source, rel.target, { type: rel.predicate });\n }\n }\n\n const tracker = new DependencyTracker(graph, model);\n const direction = args.direction ?? \"both\";\n const maxDepth = args.depth ?? null;\n\n const result: {\n id: string;\n layer: string;\n direction: string;\n dependents?: { direct: string[]; transitive: string[] };\n dependencies?: { direct: string[]; transitive: string[] };\n } = { id: args.id, layer: layerName, direction };\n\n if (direction === \"up\" || direction === \"both\") {\n const direct = tracker.traceDependencies(args.id, TraceDirection.DOWN, 1);\n const transitiveAll = tracker.traceDependencies(args.id, TraceDirection.DOWN, maxDepth);\n result.dependents = {\n direct,\n transitive: transitiveAll.filter((d) => !direct.includes(d)),\n };\n }\n\n if (direction === \"down\" || direction === \"both\") {\n const direct = tracker.traceDependencies(args.id, TraceDirection.UP, 1);\n const transitiveAll = tracker.traceDependencies(args.id, TraceDirection.UP, maxDepth);\n result.dependencies = {\n direct,\n transitive: transitiveAll.filter((d) => !direct.includes(d)),\n };\n }\n\n return jsonResult(result);\n });\n}\n\nexport const modelTraceTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_trace\",\n description: \"Trace dependents and/or dependencies of an element across cross-layer references and relationships.\",\n inputSchema,\n handler: modelTraceHandler,\n};\n"],
|
|
5
|
+
"mappings": "AAIA,SAAS,SAAS;AAElB,SAAS,mBAAmB,sBAAsB;AAClD,SAAS,yBAAyB;AAClC,SAAS,wBAAwB;AACjC,SAAS,UAAU,qBAAqB;AACxC,SAAS,YAAY,WAAW,gBAAgB,eAAuC;AAEvF,MAAM,cAAc;EAClB,IAAI,EAAE,OAAM,EAAG,SAAS,8BAA8B;EACtD,WAAW,EACR,KAAK,CAAC,MAAM,QAAQ,MAAM,CAAC,EAC3B,SAAQ,EACR,SAAS,2HAA2H;EACvI,OAAO,EAAE,OAAM,EAAG,IAAG,EAAG,SAAQ,EAAG,SAAQ,EAAG,SAAS,0CAA0C;EACjG,UAAU;;AAKZ,eAAsB,kBAAkB,MAAoB;AAC1D,SAAO,QAAQ,YAAW;AACxB,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GAErC,YAAY,MAAM,iBAAiB,OAAO,KAAK,EAAE;AACvD,QAAI,CAAC;AACH,YAAM,IAAI,SAAS,WAAW,KAAK,EAAE,cAAc,cAAc,WAAW;QAC1E;OACD;AAKH,UAAM,WAAW,IAAI,kBAAiB;AACtC,eAAW,SAAS,MAAM,OAAO,OAAM;AACrC,iBAAW,WAAW,MAAM,aAAY;AACtC,iBAAS,gBAAgB,OAAO;AAIpC,UAAM,QAAQ,SAAS,mBAAkB;AACzC,eAAW,OAAO,MAAM,cAAc,OAAM;AAC1C,MAAK,MAAM,QAAQ,IAAI,MAAM,KAAG,MAAM,QAAQ,IAAI,MAAM,GACnD,MAAM,QAAQ,IAAI,MAAM,KAAG,MAAM,QAAQ,IAAI,MAAM,GACnD,MAAM,QAAQ,IAAI,QAAQ,IAAI,MAAM,KACvC,MAAM,QAAQ,IAAI,QAAQ,IAAI,QAAQ,EAAE,MAAM,IAAI,UAAS,CAAE;AAIjE,UAAM,UAAU,IAAI,kBAAkB,OAAO,KAAK,GAC5C,YAAY,KAAK,aAAa,QAC9B,WAAW,KAAK,SAAS,MAEzB,SAMF,EAAE,IAAI,KAAK,IAAI,OAAO,WAAW,UAAS;AAE9C,QAAI,cAAc,QAAQ,cAAc,QAAQ;AAC9C,YAAM,SAAS,QAAQ,kBAAkB,KAAK,IAAI,eAAe,MAAM,CAAC,GAClE,gBAAgB,QAAQ,kBAAkB,KAAK,IAAI,eAAe,MAAM,QAAQ;AACtF,aAAO,aAAa;QAClB;QACA,YAAY,cAAc,OAAO,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC;;IAE/D;AAEA,QAAI,cAAc,UAAU,cAAc,QAAQ;AAChD,YAAM,SAAS,QAAQ,kBAAkB,KAAK,IAAI,eAAe,IAAI,CAAC,GAChE,gBAAgB,QAAQ,kBAAkB,KAAK,IAAI,eAAe,IAAI,QAAQ;AACpF,aAAO,eAAe;QACpB;QACA,YAAY,cAAc,OAAO,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC;;IAE/D;AAEA,WAAO,WAAW,MAAM;EAC1B,CAAC;AACH;AAEO,MAAM,iBAAwD;EACnE,MAAM;EACN,aAAa;EACb;EACA,SAAS;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Element } from "../../core/element.js";
|
|
3
|
+
import { Layer } from "../../core/layer.js";
|
|
4
|
+
import { MutationHandler } from "../../core/mutation-handler.js";
|
|
5
|
+
import { getNodeTypesForLayer, isValidNodeType, normalizeNodeType } from "../../generated/node-types.js";
|
|
6
|
+
import { findElementLayer } from "../../utils/element-utils.js";
|
|
7
|
+
import { buildSourceReference, validateSourceReferenceOptions } from "../../utils/source-reference.js";
|
|
8
|
+
import { SchemaValidator } from "../../validators/schema-validator.js";
|
|
9
|
+
import { CLIError, ErrorCategory, findSimilar, formatValidOptions } from "../../utils/errors.js";
|
|
10
|
+
import { jsonResult, loadModel, rootPathSchema, runTool } from "./shared.js";
|
|
11
|
+
const inputSchema = {
|
|
12
|
+
id: z.string().describe("Element ID or path to update."),
|
|
13
|
+
name: z.string().optional(),
|
|
14
|
+
description: z.string().optional(),
|
|
15
|
+
type: z.string().optional().describe("New element type within the current layer."),
|
|
16
|
+
attributes: z.record(z.string(), z.unknown()).optional().describe("Replaces the element's attributes, validated against its spec schema."),
|
|
17
|
+
sourceFile: z.string().optional(),
|
|
18
|
+
sourceSymbol: z.string().optional(),
|
|
19
|
+
sourceProvenance: z.enum(["extracted", "manual", "inferred", "generated"]).optional(),
|
|
20
|
+
sourceRepoRemote: z.string().optional(),
|
|
21
|
+
sourceRepoCommit: z.string().optional().describe("Full 40-character Git commit SHA."),
|
|
22
|
+
clearSourceReference: z.boolean().optional().describe("Remove the element's source reference. Cannot be combined with other source options."),
|
|
23
|
+
rootPath: rootPathSchema
|
|
24
|
+
};
|
|
25
|
+
function validateUpdateSourceReferenceOptions(args) {
|
|
26
|
+
const hasSourceOptions = args.sourceFile || args.sourceSymbol || args.sourceProvenance || args.sourceRepoRemote || args.sourceRepoCommit;
|
|
27
|
+
if (args.clearSourceReference && hasSourceOptions)
|
|
28
|
+
throw new CLIError("Cannot use clearSourceReference with other source reference options", ErrorCategory.USER, [
|
|
29
|
+
"Specify either clearSourceReference or other source options, not both"
|
|
30
|
+
]);
|
|
31
|
+
hasSourceOptions && validateSourceReferenceOptions(args);
|
|
32
|
+
}
|
|
33
|
+
async function modelUpdateHandler(args) {
|
|
34
|
+
return runTool(async () => {
|
|
35
|
+
validateUpdateSourceReferenceOptions(args);
|
|
36
|
+
const model = await loadModel(args.rootPath), layerName = await findElementLayer(model, args.id);
|
|
37
|
+
if (!layerName)
|
|
38
|
+
throw new CLIError(`Element ${args.id} not found`, ErrorCategory.NOT_FOUND, [
|
|
39
|
+
'Use "model_search" to find similar elements'
|
|
40
|
+
]);
|
|
41
|
+
const layer = await model.getLayer(layerName), element = layer?.getElement(args.id);
|
|
42
|
+
if (!layer || !element)
|
|
43
|
+
throw new CLIError(`Element ${args.id} not found`, ErrorCategory.NOT_FOUND, [
|
|
44
|
+
'Use "model_search" to find similar elements'
|
|
45
|
+
]);
|
|
46
|
+
if (!(args.name || args.description !== void 0 || args.type || args.attributes || args.sourceFile || args.sourceSymbol || args.sourceProvenance || args.sourceRepoRemote || args.sourceRepoCommit || args.clearSourceReference))
|
|
47
|
+
return jsonResult({ status: "no-op", id: args.id, message: "No fields specified for update" });
|
|
48
|
+
const mutationHandler = new MutationHandler(model, args.id, layerName);
|
|
49
|
+
await mutationHandler.executeUpdate(element, async (elem, after) => {
|
|
50
|
+
let resolvedNewType;
|
|
51
|
+
if (args.type) {
|
|
52
|
+
if (!isValidNodeType(layerName, args.type)) {
|
|
53
|
+
const typeNames = getNodeTypesForLayer(layerName).map((t) => t.type).sort(), similar = findSimilar(args.type, typeNames, 3), suggestions = [`Valid types for ${layerName}: ${formatValidOptions(typeNames)}`];
|
|
54
|
+
throw similar.length > 0 && suggestions.unshift(`Did you mean: ${similar.join(" or ")}?`), new CLIError(`Invalid element type "${args.type}" for layer "${layerName}"`, ErrorCategory.USER, suggestions);
|
|
55
|
+
}
|
|
56
|
+
resolvedNewType = normalizeNodeType(layerName, args.type);
|
|
57
|
+
}
|
|
58
|
+
if (resolvedNewType || args.attributes) {
|
|
59
|
+
const candidateType = resolvedNewType ?? elem.type, tempElem = new Element({
|
|
60
|
+
...elem.toJSON(),
|
|
61
|
+
type: candidateType,
|
|
62
|
+
spec_node_id: `${layerName}.${candidateType}`,
|
|
63
|
+
attributes: args.attributes ?? elem.attributes
|
|
64
|
+
}), schemaValidator = new SchemaValidator(), tempLayer = new Layer(layerName);
|
|
65
|
+
tempLayer.addElement(tempElem);
|
|
66
|
+
const attrValidation = await schemaValidator.validateLayer(tempLayer);
|
|
67
|
+
if (!attrValidation.isValid()) {
|
|
68
|
+
const errorMessages = attrValidation.errors.map((e) => ` ${e.message}`).join(`
|
|
69
|
+
`);
|
|
70
|
+
throw new CLIError(`Updated attributes fail schema validation:
|
|
71
|
+
${errorMessages}`, ErrorCategory.USER, [
|
|
72
|
+
`Use the spec resource for "${candidateType}" to see the required attributes`
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
resolvedNewType && (elem.type = resolvedNewType, after.type = resolvedNewType, elem.spec_node_id = `${layerName}.${resolvedNewType}`, after.spec_node_id = `${layerName}.${resolvedNewType}`), args.name && (elem.name = args.name, after.name = args.name), args.description !== void 0 && (elem.description = args.description || void 0, after.description = args.description || void 0), args.attributes && (elem.attributes = args.attributes, after.attributes = args.attributes);
|
|
77
|
+
const hasSourceReferenceUpdate = args.sourceFile || args.sourceSymbol || args.sourceProvenance || args.sourceRepoRemote || args.sourceRepoCommit;
|
|
78
|
+
if (args.clearSourceReference)
|
|
79
|
+
elem.setSourceReference(void 0), after.sourceReference = void 0;
|
|
80
|
+
else if (hasSourceReferenceUpdate) {
|
|
81
|
+
const newRef = buildSourceReference(args);
|
|
82
|
+
newRef && (elem.setSourceReference(newRef), after.sourceReference = newRef);
|
|
83
|
+
}
|
|
84
|
+
layer.updateElement(elem);
|
|
85
|
+
});
|
|
86
|
+
const activeChangeset = await mutationHandler.getStagingManager().getActive(), staged = !!(activeChangeset && activeChangeset.status === "staged");
|
|
87
|
+
return jsonResult({
|
|
88
|
+
status: staged ? "staged" : "updated",
|
|
89
|
+
changeset: staged ? activeChangeset.name : void 0,
|
|
90
|
+
id: args.id,
|
|
91
|
+
layer: layerName
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const modelUpdateTool = {
|
|
96
|
+
name: "model_update",
|
|
97
|
+
description: "Update an existing element's name, description, type, attributes, or source reference.",
|
|
98
|
+
inputSchema,
|
|
99
|
+
handler: modelUpdateHandler
|
|
100
|
+
};
|
|
101
|
+
export {
|
|
102
|
+
modelUpdateHandler,
|
|
103
|
+
modelUpdateTool
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=model-update.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/model-update.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * model_update \u2014 update an existing element. Mirrors `dr update`, operating\n * through the shared MutationHandler.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { Element } from \"../../core/element.js\";\nimport { Layer } from \"../../core/layer.js\";\nimport { MutationHandler } from \"../../core/mutation-handler.js\";\nimport { getNodeTypesForLayer, isValidNodeType, normalizeNodeType } from \"../../generated/node-types.js\";\nimport { findElementLayer } from \"../../utils/element-utils.js\";\nimport { buildSourceReference, validateSourceReferenceOptions } from \"../../utils/source-reference.js\";\nimport { SchemaValidator } from \"../../validators/schema-validator.js\";\nimport { CLIError, ErrorCategory, findSimilar, formatValidOptions } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n id: z.string().describe(\"Element ID or path to update.\"),\n name: z.string().optional(),\n description: z.string().optional(),\n type: z.string().optional().describe(\"New element type within the current layer.\"),\n attributes: z.record(z.string(), z.unknown()).optional().describe(\"Replaces the element's attributes, validated against its spec schema.\"),\n sourceFile: z.string().optional(),\n sourceSymbol: z.string().optional(),\n sourceProvenance: z.enum([\"extracted\", \"manual\", \"inferred\", \"generated\"]).optional(),\n sourceRepoRemote: z.string().optional(),\n sourceRepoCommit: z.string().optional().describe(\"Full 40-character Git commit SHA.\"),\n clearSourceReference: z.boolean().optional().describe(\"Remove the element's source reference. Cannot be combined with other source options.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelUpdateArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nfunction validateUpdateSourceReferenceOptions(args: ModelUpdateArgs): void {\n const hasSourceOptions =\n args.sourceFile || args.sourceSymbol || args.sourceProvenance || args.sourceRepoRemote || args.sourceRepoCommit;\n\n if (args.clearSourceReference && hasSourceOptions) {\n throw new CLIError(\"Cannot use clearSourceReference with other source reference options\", ErrorCategory.USER, [\n \"Specify either clearSourceReference or other source options, not both\",\n ]);\n }\n\n if (hasSourceOptions) {\n validateSourceReferenceOptions(args);\n }\n}\n\nexport async function modelUpdateHandler(args: ModelUpdateArgs): Promise<CallToolResult> {\n return runTool(async () => {\n validateUpdateSourceReferenceOptions(args);\n\n const model = await loadModel(args.rootPath);\n\n const layerName = await findElementLayer(model, args.id);\n if (!layerName) {\n throw new CLIError(`Element ${args.id} not found`, ErrorCategory.NOT_FOUND, [\n 'Use \"model_search\" to find similar elements',\n ]);\n }\n\n const layer = await model.getLayer(layerName);\n const element = layer?.getElement(args.id);\n if (!layer || !element) {\n throw new CLIError(`Element ${args.id} not found`, ErrorCategory.NOT_FOUND, [\n 'Use \"model_search\" to find similar elements',\n ]);\n }\n\n const hasUpdates =\n args.name ||\n args.description !== undefined ||\n args.type ||\n args.attributes ||\n args.sourceFile ||\n args.sourceSymbol ||\n args.sourceProvenance ||\n args.sourceRepoRemote ||\n args.sourceRepoCommit ||\n args.clearSourceReference;\n\n if (!hasUpdates) {\n return jsonResult({ status: \"no-op\", id: args.id, message: \"No fields specified for update\" });\n }\n\n const mutationHandler = new MutationHandler(model, args.id, layerName);\n\n await mutationHandler.executeUpdate(element, async (elem, after) => {\n let resolvedNewType: string | undefined;\n if (args.type) {\n if (!isValidNodeType(layerName, args.type)) {\n const validNodeTypes = getNodeTypesForLayer(layerName);\n const typeNames = validNodeTypes.map((t) => t.type).sort();\n const similar = findSimilar(args.type!, typeNames, 3);\n const suggestions: string[] = [`Valid types for ${layerName}: ${formatValidOptions(typeNames)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Invalid element type \"${args.type}\" for layer \"${layerName}\"`, ErrorCategory.USER, suggestions);\n }\n resolvedNewType = normalizeNodeType(layerName, args.type);\n }\n\n if (resolvedNewType || args.attributes) {\n const candidateType = resolvedNewType ?? elem.type;\n const tempElem = new Element({\n ...elem.toJSON(),\n type: candidateType,\n spec_node_id: `${layerName}.${candidateType}`,\n attributes: args.attributes ?? elem.attributes,\n });\n const schemaValidator = new SchemaValidator();\n const tempLayer = new Layer(layerName);\n tempLayer.addElement(tempElem);\n const attrValidation = await schemaValidator.validateLayer(tempLayer);\n if (!attrValidation.isValid()) {\n const errorMessages = attrValidation.errors.map((e) => ` ${e.message}`).join(\"\\n\");\n throw new CLIError(`Updated attributes fail schema validation:\\n${errorMessages}`, ErrorCategory.USER, [\n `Use the spec resource for \"${candidateType}\" to see the required attributes`,\n ]);\n }\n }\n\n if (resolvedNewType) {\n elem.type = resolvedNewType;\n after.type = resolvedNewType;\n elem.spec_node_id = `${layerName}.${resolvedNewType}`;\n after.spec_node_id = `${layerName}.${resolvedNewType}`;\n }\n\n if (args.name) {\n elem.name = args.name;\n after.name = args.name;\n }\n\n if (args.description !== undefined) {\n elem.description = args.description || undefined;\n after.description = args.description || undefined;\n }\n\n if (args.attributes) {\n elem.attributes = args.attributes;\n after.attributes = args.attributes;\n }\n\n const hasSourceReferenceUpdate =\n args.sourceFile || args.sourceSymbol || args.sourceProvenance || args.sourceRepoRemote || args.sourceRepoCommit;\n\n if (args.clearSourceReference) {\n elem.setSourceReference(undefined);\n after.sourceReference = undefined;\n } else if (hasSourceReferenceUpdate) {\n const newRef = buildSourceReference(args);\n if (newRef) {\n elem.setSourceReference(newRef);\n after.sourceReference = newRef;\n }\n }\n\n layer.updateElement(elem);\n });\n\n const stagingManager = mutationHandler.getStagingManager();\n const activeChangeset = await stagingManager.getActive();\n const staged = !!(activeChangeset && activeChangeset.status === \"staged\");\n\n return jsonResult({\n status: staged ? \"staged\" : \"updated\",\n changeset: staged ? activeChangeset!.name : undefined,\n id: args.id,\n layer: layerName,\n });\n });\n}\n\nexport const modelUpdateTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_update\",\n description: \"Update an existing element's name, description, type, attributes, or source reference.\",\n inputSchema,\n handler: modelUpdateHandler,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getAllLayerIds, isValidLayer } from "../../generated/layer-registry.js";
|
|
3
|
+
import { CLIError, ErrorCategory, findSimilar, formatValidOptions } from "../../utils/errors.js";
|
|
4
|
+
import { ValidationFormatter } from "../../validators/validation-formatter.js";
|
|
5
|
+
import { Validator } from "../../validators/validator.js";
|
|
6
|
+
import { jsonResult, loadModel, rootPathSchema, runTool } from "./shared.js";
|
|
7
|
+
const inputSchema = {
|
|
8
|
+
layers: z.array(z.string()).optional().describe("Restrict validation to these layers. Omit to validate the whole model."),
|
|
9
|
+
strict: z.boolean().optional().describe("Also flag elements with no description as warnings."),
|
|
10
|
+
orphans: z.boolean().optional().describe("Return only the orphaned-elements report instead of running full validation."),
|
|
11
|
+
rootPath: rootPathSchema
|
|
12
|
+
};
|
|
13
|
+
async function modelValidateHandler(args) {
|
|
14
|
+
return runTool(async () => {
|
|
15
|
+
const model = await loadModel(args.rootPath), activeChangesetId = model.getActiveChangesetId();
|
|
16
|
+
let modelToValidate = activeChangesetId ? { ...await model.getVirtualProjectionEngine().projectModel(model, activeChangesetId), rootPath: model.rootPath } : model;
|
|
17
|
+
if (args.layers && args.layers.length > 0) {
|
|
18
|
+
const unknownLayers = args.layers.filter((name) => !isValidLayer(name));
|
|
19
|
+
if (unknownLayers.length > 0) {
|
|
20
|
+
const validLayers = getAllLayerIds(), suggestions = [`Use a valid layer name: ${formatValidOptions(validLayers)}`];
|
|
21
|
+
for (const unknown of unknownLayers) {
|
|
22
|
+
const similar = findSimilar(unknown, validLayers, 3);
|
|
23
|
+
similar.length > 0 && suggestions.unshift(`Did you mean "${similar.join(" or ")}" instead of "${unknown}"?`);
|
|
24
|
+
}
|
|
25
|
+
throw new CLIError(`Unknown layer(s): ${unknownLayers.join(", ")}`, ErrorCategory.USER, suggestions);
|
|
26
|
+
}
|
|
27
|
+
const requestedLayers = new Set(args.layers);
|
|
28
|
+
modelToValidate = {
|
|
29
|
+
...modelToValidate,
|
|
30
|
+
layers: new Map(Array.from(modelToValidate.layers.entries()).filter(([name]) => requestedLayers.has(name)))
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (args.orphans) {
|
|
34
|
+
const stats2 = ValidationFormatter.calculateStats(modelToValidate);
|
|
35
|
+
return jsonResult({
|
|
36
|
+
orphanCount: stats2.orphanedElements.length,
|
|
37
|
+
orphanedElements: stats2.orphanedElements
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const result = await new Validator().validateModel(modelToValidate), stats = ValidationFormatter.calculateStats(modelToValidate);
|
|
41
|
+
for (const orphanId of stats.orphanedElements)
|
|
42
|
+
result.addWarning({
|
|
43
|
+
message: `Element '${orphanId}' is orphaned (no cross-layer references or intra-layer relationships)`,
|
|
44
|
+
layer: orphanId.split(".")[0] ?? "",
|
|
45
|
+
elementId: orphanId,
|
|
46
|
+
category: "orphan",
|
|
47
|
+
fixSuggestion: "Add cross-layer references or relationships to connect this element to the rest of the model"
|
|
48
|
+
});
|
|
49
|
+
for (const [layerName, layer] of modelToValidate.layers)
|
|
50
|
+
for (const element of layer.listElements()) {
|
|
51
|
+
const elementId = element.path || element.id;
|
|
52
|
+
element.source_reference || result.addWarning({
|
|
53
|
+
message: `Element '${elementId}' has no source reference`,
|
|
54
|
+
layer: layerName,
|
|
55
|
+
elementId,
|
|
56
|
+
fixSuggestion: "Add a source_reference with provenance to link this element to its implementation"
|
|
57
|
+
}), args.strict && (!element.description || element.description.trim() === "") && result.addWarning({
|
|
58
|
+
message: `Element '${elementId}' has no description`,
|
|
59
|
+
layer: layerName,
|
|
60
|
+
elementId,
|
|
61
|
+
fixSuggestion: "Add a description to document what this element represents"
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const formatted = ValidationFormatter.toJSON(result, modelToValidate), valid = result.isValid() && !(args.strict && result.warnings.length > 0);
|
|
65
|
+
return jsonResult({ ...formatted, valid });
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const modelValidateTool = {
|
|
69
|
+
name: "model_validate",
|
|
70
|
+
description: "Run the full schema/naming/reference/semantic/relationship validation pipeline against the model.",
|
|
71
|
+
inputSchema,
|
|
72
|
+
handler: modelValidateHandler
|
|
73
|
+
};
|
|
74
|
+
export {
|
|
75
|
+
modelValidateHandler,
|
|
76
|
+
modelValidateTool
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=model-validate.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/model-validate.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * model_validate \u2014 run the 5-stage validation pipeline against the model.\n * Mirrors `dr validate`, reusing the shared Validator and ValidationFormatter.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Model } from \"../../core/model.js\";\nimport { getAllLayerIds, isValidLayer } from \"../../generated/layer-registry.js\";\nimport { CLIError, ErrorCategory, findSimilar, formatValidOptions } from \"../../utils/errors.js\";\nimport { ValidationFormatter } from \"../../validators/validation-formatter.js\";\nimport { Validator } from \"../../validators/validator.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n layers: z.array(z.string()).optional().describe(\"Restrict validation to these layers. Omit to validate the whole model.\"),\n strict: z.boolean().optional().describe(\"Also flag elements with no description as warnings.\"),\n orphans: z\n .boolean()\n .optional()\n .describe(\"Return only the orphaned-elements report instead of running full validation.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelValidateArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelValidateHandler(args: ModelValidateArgs): Promise<CallToolResult> {\n return runTool(async () => {\n const model = await loadModel(args.rootPath);\n\n // `Validator` is typed to accept `Model`, but a projected changeset is a\n // `ProjectedModel` (manifest/layers/relationships only, no `rootPath` or the\n // mutation methods `Model` exposes). The validation pipeline only reads\n // `rootPath` for telemetry (validator.ts), so it's carried over explicitly\n // rather than left undefined. This mirrors the identical cast in\n // `cli/src/commands/validate.ts`; a proper fix would give `Validator` a\n // narrower \"validatable model\" interface shared by both types.\n const activeChangesetId = model.getActiveChangesetId();\n let modelToValidate = (\n activeChangesetId\n ? { ...(await model.getVirtualProjectionEngine().projectModel(model, activeChangesetId)), rootPath: model.rootPath }\n : model\n ) as unknown as Model;\n\n // `loadModel()` returns the full cached model (all layers), so a `layers` scope\n // is applied here rather than at load time. Copies the layers Map onto a new\n // object instead of mutating `model.layers` directly, since that Map is the\n // shared cached instance other tool calls read from.\n if (args.layers && args.layers.length > 0) {\n const unknownLayers = args.layers.filter((name) => !isValidLayer(name));\n if (unknownLayers.length > 0) {\n const validLayers = getAllLayerIds();\n const suggestions: string[] = [`Use a valid layer name: ${formatValidOptions(validLayers)}`];\n for (const unknown of unknownLayers) {\n const similar = findSimilar(unknown, validLayers, 3);\n if (similar.length > 0) suggestions.unshift(`Did you mean \"${similar.join(\" or \")}\" instead of \"${unknown}\"?`);\n }\n throw new CLIError(`Unknown layer(s): ${unknownLayers.join(\", \")}`, ErrorCategory.USER, suggestions);\n }\n\n const requestedLayers = new Set(args.layers);\n modelToValidate = {\n ...modelToValidate,\n layers: new Map(\n Array.from(modelToValidate.layers.entries()).filter(([name]) => requestedLayers.has(name))\n ),\n } as unknown as Model;\n }\n\n if (args.orphans) {\n const stats = ValidationFormatter.calculateStats(modelToValidate);\n return jsonResult({\n orphanCount: stats.orphanedElements.length,\n orphanedElements: stats.orphanedElements,\n });\n }\n\n const validator = new Validator();\n const result = await validator.validateModel(modelToValidate);\n\n const stats = ValidationFormatter.calculateStats(modelToValidate);\n for (const orphanId of stats.orphanedElements) {\n result.addWarning({\n message: `Element '${orphanId}' is orphaned (no cross-layer references or intra-layer relationships)`,\n layer: orphanId.split(\".\")[0] ?? \"\",\n elementId: orphanId,\n category: \"orphan\",\n fixSuggestion: \"Add cross-layer references or relationships to connect this element to the rest of the model\",\n });\n }\n\n for (const [layerName, layer] of modelToValidate.layers) {\n for (const element of layer.listElements()) {\n const elementId = element.path || element.id;\n if (!element.source_reference) {\n result.addWarning({\n message: `Element '${elementId}' has no source reference`,\n layer: layerName,\n elementId,\n fixSuggestion: \"Add a source_reference with provenance to link this element to its implementation\",\n });\n }\n if (args.strict && (!element.description || element.description.trim() === \"\")) {\n result.addWarning({\n message: `Element '${elementId}' has no description`,\n layer: layerName,\n elementId,\n fixSuggestion: \"Add a description to document what this element represents\",\n });\n }\n }\n }\n\n const formatted = ValidationFormatter.toJSON(result, modelToValidate);\n const valid = result.isValid() && !(args.strict && result.warnings.length > 0);\n\n return jsonResult({ ...formatted, valid });\n });\n}\n\nexport const modelValidateTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_validate\",\n description: \"Run the full schema/naming/reference/semantic/relationship validation pipeline against the model.\",\n inputSchema,\n handler: modelValidateHandler,\n};\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,SAAS;AAGlB,SAAS,gBAAgB,oBAAoB;AAC7C,SAAS,UAAU,eAAe,aAAa,0BAA0B;AACzE,SAAS,2BAA2B;AACpC,SAAS,iBAAiB;AAC1B,SAAS,YAAY,WAAW,gBAAgB,eAAuC;AAEvF,MAAM,cAAc;EAClB,QAAQ,EAAE,MAAM,EAAE,OAAM,CAAE,EAAE,SAAQ,EAAG,SAAS,wEAAwE;EACxH,QAAQ,EAAE,QAAO,EAAG,SAAQ,EAAG,SAAS,qDAAqD;EAC7F,SAAS,EACN,QAAO,EACP,SAAQ,EACR,SAAS,8EAA8E;EAC1F,UAAU;;AAKZ,eAAsB,qBAAqB,MAAuB;AAChE,SAAO,QAAQ,YAAW;AACxB,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GASrC,oBAAoB,MAAM,qBAAoB;AACpD,QAAI,kBACF,oBACI,EAAE,GAAI,MAAM,MAAM,2BAA0B,EAAG,aAAa,OAAO,iBAAiB,GAAI,UAAU,MAAM,SAAQ,IAChH;AAON,QAAI,KAAK,UAAU,KAAK,OAAO,SAAS,GAAG;AACzC,YAAM,gBAAgB,KAAK,OAAO,OAAO,CAAC,SAAS,CAAC,aAAa,IAAI,CAAC;AACtE,UAAI,cAAc,SAAS,GAAG;AAC5B,cAAM,cAAc,eAAc,GAC5B,cAAwB,CAAC,2BAA2B,mBAAmB,WAAW,CAAC,EAAE;AAC3F,mBAAW,WAAW,eAAe;AACnC,gBAAM,UAAU,YAAY,SAAS,aAAa,CAAC;AACnD,UAAI,QAAQ,SAAS,KAAG,YAAY,QAAQ,iBAAiB,QAAQ,KAAK,MAAM,CAAC,iBAAiB,OAAO,IAAI;QAC/G;AACA,cAAM,IAAI,SAAS,qBAAqB,cAAc,KAAK,IAAI,CAAC,IAAI,cAAc,MAAM,WAAW;MACrG;AAEA,YAAM,kBAAkB,IAAI,IAAI,KAAK,MAAM;AAC3C,wBAAkB;QAChB,GAAG;QACH,QAAQ,IAAI,IACV,MAAM,KAAK,gBAAgB,OAAO,QAAO,CAAE,EAAE,OAAO,CAAC,CAAC,IAAI,MAAM,gBAAgB,IAAI,IAAI,CAAC,CAAC;;IAGhG;AAEA,QAAI,KAAK,SAAS;AAChB,YAAMA,SAAQ,oBAAoB,eAAe,eAAe;AAChE,aAAO,WAAW;QAChB,aAAaA,OAAM,iBAAiB;QACpC,kBAAkBA,OAAM;OACzB;IACH;AAGA,UAAM,SAAS,MADG,IAAI,UAAS,EACA,cAAc,eAAe,GAEtD,QAAQ,oBAAoB,eAAe,eAAe;AAChE,eAAW,YAAY,MAAM;AAC3B,aAAO,WAAW;QAChB,SAAS,YAAY,QAAQ;QAC7B,OAAO,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK;QACjC,WAAW;QACX,UAAU;QACV,eAAe;OAChB;AAGH,eAAW,CAAC,WAAW,KAAK,KAAK,gBAAgB;AAC/C,iBAAW,WAAW,MAAM,aAAY,GAAI;AAC1C,cAAM,YAAY,QAAQ,QAAQ,QAAQ;AAC1C,QAAK,QAAQ,oBACX,OAAO,WAAW;UAChB,SAAS,YAAY,SAAS;UAC9B,OAAO;UACP;UACA,eAAe;SAChB,GAEC,KAAK,WAAW,CAAC,QAAQ,eAAe,QAAQ,YAAY,KAAI,MAAO,OACzE,OAAO,WAAW;UAChB,SAAS,YAAY,SAAS;UAC9B,OAAO;UACP;UACA,eAAe;SAChB;MAEL;AAGF,UAAM,YAAY,oBAAoB,OAAO,QAAQ,eAAe,GAC9D,QAAQ,OAAO,QAAO,KAAM,EAAE,KAAK,UAAU,OAAO,SAAS,SAAS;AAE5E,WAAO,WAAW,EAAE,GAAG,WAAW,MAAK,CAAE;EAC3C,CAAC;AACH;AAEO,MAAM,oBAA2D;EACtE,MAAM;EACN,aAAa;EACb;EACA,SAAS;;",
|
|
6
|
+
"names": ["stats"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Model } from "../../core/model.js";
|
|
3
|
+
import { CLIError, ModelNotFoundError, getErrorMessage } from "../../utils/errors.js";
|
|
4
|
+
const rootPathSchema = z.string().optional().describe("Absolute path to the project root containing documentation-robotics/. Defaults to the MCP server's working directory."), modelCache = /* @__PURE__ */ new Map();
|
|
5
|
+
function modelCacheKey(rootPath) {
|
|
6
|
+
return rootPath ?? "";
|
|
7
|
+
}
|
|
8
|
+
function clearModelCache() {
|
|
9
|
+
modelCache.clear();
|
|
10
|
+
}
|
|
11
|
+
async function readModelFromDisk(rootPath) {
|
|
12
|
+
try {
|
|
13
|
+
return await Model.load(rootPath, { lazyLoad: !1 });
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (error instanceof CLIError)
|
|
16
|
+
throw error;
|
|
17
|
+
const message = getErrorMessage(error).toLowerCase();
|
|
18
|
+
throw message.includes("no dr project") || message.includes("model not found") || message.includes("no model found") ? new ModelNotFoundError(rootPath) : error;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function loadModel(rootPath) {
|
|
22
|
+
const key = modelCacheKey(rootPath), cached = modelCache.get(key);
|
|
23
|
+
if (cached)
|
|
24
|
+
return cached;
|
|
25
|
+
const promise = readModelFromDisk(rootPath);
|
|
26
|
+
return modelCache.set(key, promise), evictOnFailure(key, promise), promise;
|
|
27
|
+
}
|
|
28
|
+
async function reloadModel(rootPath) {
|
|
29
|
+
const key = modelCacheKey(rootPath), promise = readModelFromDisk(rootPath);
|
|
30
|
+
return modelCache.set(key, promise), evictOnFailure(key, promise), promise;
|
|
31
|
+
}
|
|
32
|
+
function evictOnFailure(key, promise) {
|
|
33
|
+
promise.catch(() => {
|
|
34
|
+
modelCache.get(key) === promise && modelCache.delete(key);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function jsonResult(data, options) {
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
40
|
+
...options?.isError ? { isError: !0 } : {}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function errorResult(error) {
|
|
44
|
+
if (error instanceof CLIError) {
|
|
45
|
+
const context = error.context;
|
|
46
|
+
return {
|
|
47
|
+
content: [
|
|
48
|
+
{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: JSON.stringify({
|
|
51
|
+
error: error.message,
|
|
52
|
+
category: errorCategoryName(error.exitCode),
|
|
53
|
+
suggestions: error.suggestions ?? [],
|
|
54
|
+
...context?.operation ? { operation: context.operation } : {},
|
|
55
|
+
...context?.relatedElements ? { relatedElements: context.relatedElements } : {},
|
|
56
|
+
...context?.partialProgress ? { partialProgress: context.partialProgress } : {}
|
|
57
|
+
}, null, 2)
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
isError: !0
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
content: [{ type: "text", text: JSON.stringify({ error: getErrorMessage(error) }, null, 2) }],
|
|
65
|
+
isError: !0
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function errorCategoryName(exitCode) {
|
|
69
|
+
switch (exitCode) {
|
|
70
|
+
case 1:
|
|
71
|
+
return "user";
|
|
72
|
+
case 2:
|
|
73
|
+
return "not_found";
|
|
74
|
+
case 3:
|
|
75
|
+
return "system";
|
|
76
|
+
case 4:
|
|
77
|
+
return "validation";
|
|
78
|
+
case 5:
|
|
79
|
+
return "breaking_change";
|
|
80
|
+
default:
|
|
81
|
+
return "unknown";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function runTool(fn) {
|
|
85
|
+
try {
|
|
86
|
+
return await fn();
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return logToolError(error), errorResult(error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function logToolError(error) {
|
|
92
|
+
error instanceof CLIError ? console.error(`[mcp] tool error: ${error.message}`) : error instanceof Error ? console.error(`[mcp] tool error: ${error.stack ?? error.message}`) : console.error(`[mcp] tool error: ${getErrorMessage(error)}`);
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
clearModelCache,
|
|
96
|
+
errorResult,
|
|
97
|
+
jsonResult,
|
|
98
|
+
loadModel,
|
|
99
|
+
reloadModel,
|
|
100
|
+
rootPathSchema,
|
|
101
|
+
runTool
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/shared.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared helpers for MCP model tool handlers.\n *\n * Centralizes model loading and the CLIError -> structured error content\n * translation so individual tool handlers stay focused on their own domain\n * logic.\n */\n\nimport { z, type ZodRawShape } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { Model } from \"../../core/model.js\";\nimport {\n CLIError,\n ModelNotFoundError,\n getErrorMessage,\n type ErrorContext,\n} from \"../../utils/errors.js\";\n\n/** Shared input field: lets a client point at a model outside the server's cwd. */\nexport const rootPathSchema = z\n .string()\n .optional()\n .describe(\n \"Absolute path to the project root containing documentation-robotics/. Defaults to the MCP server's working directory.\"\n );\n\nexport interface McpToolDefinition<Shape extends ZodRawShape = ZodRawShape> {\n name: string;\n description: string;\n inputSchema: Shape;\n // Method-shorthand (not an arrow-typed property) so tool definitions with\n // differently-shaped Args can share the heterogeneous MODEL_TOOLS array in\n // tool-registry.ts without a manual cast back to `any` at the storage site.\n handler(args: z.infer<z.ZodObject<Shape>>): Promise<CallToolResult>;\n}\n\n/**\n * Per-rootPath cache of the loaded architecture model, held for the lifetime of the\n * MCP server process: the Model is loaded once and reused across tool calls rather\n * than reread from disk on every invocation. Keyed by the raw `rootPath` argument\n * (`\"\"` for the server's default cwd), matching how MCP clients address a model\n * across calls.\n */\nconst modelCache = new Map<string, Promise<Model>>();\n\nfunction modelCacheKey(rootPath?: string): string {\n return rootPath ?? \"\";\n}\n\n/** Test-only escape hatch: clears the module-private model cache between test cases. */\nexport function clearModelCache(): void {\n modelCache.clear();\n}\n\n/** Reads the model fresh from disk, translating \"no model found\" into a CLIError consistently. */\nasync function readModelFromDisk(rootPath?: string): Promise<Model> {\n try {\n // Always a full, non-lazy load: the cached instance must be able to answer any\n // tool call regardless of which layers/options the first caller happened to need.\n return await Model.load(rootPath, { lazyLoad: false });\n } catch (error) {\n if (error instanceof CLIError) {\n throw error;\n }\n const message = getErrorMessage(error).toLowerCase();\n if (\n message.includes(\"no dr project\") ||\n message.includes(\"model not found\") ||\n message.includes(\"no model found\")\n ) {\n throw new ModelNotFoundError(rootPath);\n }\n throw error;\n }\n}\n\n/** Returns the cached model for this rootPath, loading it from disk on first use. */\nexport async function loadModel(rootPath?: string): Promise<Model> {\n const key = modelCacheKey(rootPath);\n const cached = modelCache.get(key);\n if (cached) {\n return cached;\n }\n\n const promise = readModelFromDisk(rootPath);\n modelCache.set(key, promise);\n evictOnFailure(key, promise);\n return promise;\n}\n\n/** Forces a fresh read from disk, replacing any cached instance for this rootPath. */\nexport async function reloadModel(rootPath?: string): Promise<Model> {\n const key = modelCacheKey(rootPath);\n const promise = readModelFromDisk(rootPath);\n modelCache.set(key, promise);\n evictOnFailure(key, promise);\n return promise;\n}\n\n/**\n * Don't let a failed load poison the cache for subsequent (possibly-fixed) calls.\n * Guarded by identity: if a newer promise has since replaced this one for `key`\n * (e.g. a concurrent reloadModel()), a stale rejection must not evict it.\n */\nfunction evictOnFailure(key: string, promise: Promise<Model>): void {\n promise.catch(() => {\n if (modelCache.get(key) === promise) {\n modelCache.delete(key);\n }\n });\n}\n\n/** Wraps structured data as the tool's JSON text content. */\nexport function jsonResult(data: unknown, options?: { isError?: boolean }): CallToolResult {\n return {\n content: [{ type: \"text\", text: JSON.stringify(data, null, 2) }],\n ...(options?.isError ? { isError: true } : {}),\n };\n}\n\n/** Converts a thrown error into a structured, non-throwing tool error result. */\nexport function errorResult(error: unknown): CallToolResult {\n if (error instanceof CLIError) {\n const context: ErrorContext | undefined = error.context;\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n error: error.message,\n category: errorCategoryName(error.exitCode),\n suggestions: error.suggestions ?? [],\n ...(context?.operation ? { operation: context.operation } : {}),\n ...(context?.relatedElements ? { relatedElements: context.relatedElements } : {}),\n ...(context?.partialProgress ? { partialProgress: context.partialProgress } : {}),\n },\n null,\n 2\n ),\n },\n ],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify({ error: getErrorMessage(error) }, null, 2) }],\n isError: true,\n };\n}\n\nfunction errorCategoryName(exitCode: number): string {\n switch (exitCode) {\n case 1:\n return \"user\";\n case 2:\n return \"not_found\";\n case 3:\n return \"system\";\n case 4:\n return \"validation\";\n case 5:\n return \"breaking_change\";\n default:\n return \"unknown\";\n }\n}\n\n/** Runs a tool handler body, catching any error into a structured tool result instead of throwing. */\nexport async function runTool(fn: () => Promise<CallToolResult>): Promise<CallToolResult> {\n try {\n return await fn();\n } catch (error) {\n logToolError(error);\n return errorResult(error);\n }\n}\n\n/**\n * Logs a tool failure to stderr unconditionally (independent of telemetry\n * settings, which are off by default) so server operators have visibility\n * into failures. Non-CLIError exceptions include their stack trace, since\n * that's otherwise discarded once errorResult() reduces them to a message.\n */\nfunction logToolError(error: unknown): void {\n if (error instanceof CLIError) {\n console.error(`[mcp] tool error: ${error.message}`);\n } else if (error instanceof Error) {\n console.error(`[mcp] tool error: ${error.stack ?? error.message}`);\n } else {\n console.error(`[mcp] tool error: ${getErrorMessage(error)}`);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -5,6 +5,7 @@ import { createAnchor } from "../utils/markdown-anchor.js";
|
|
|
5
5
|
import { escapeMarkdown, getLayerDescription, valueToMarkdown } from "../export/markdown-utils.js";
|
|
6
6
|
import { getLayerOrder, CANONICAL_LAYER_NAMES } from "../core/layers.js";
|
|
7
7
|
import { getValidRelationships } from "../generated/relationship-index.js";
|
|
8
|
+
import { getLayerReportFileName } from "./model-report-utils.js";
|
|
8
9
|
class ModelLayerReportGenerator {
|
|
9
10
|
modelVersion;
|
|
10
11
|
generatedAt;
|
|
@@ -22,6 +23,8 @@ class ModelLayerReportGenerator {
|
|
|
22
23
|
const lines = [];
|
|
23
24
|
return lines.push(`# ${formatLayerName(data.layerName)}
|
|
24
25
|
`), lines.push(`
|
|
26
|
+
`), lines.push(`[\u2190 Back to README](../README.md)
|
|
27
|
+
`), lines.push(`
|
|
25
28
|
`), lines.push(`${getLayerDescription(data.layerName)}
|
|
26
29
|
`), lines.push(`
|
|
27
30
|
`), lines.join("");
|
|
@@ -245,10 +248,9 @@ class ModelLayerReportGenerator {
|
|
|
245
248
|
* Create a markdown link to a layer report
|
|
246
249
|
*/
|
|
247
250
|
createLayerLink(layerName) {
|
|
248
|
-
|
|
249
|
-
if (layerNumber === -1)
|
|
251
|
+
if (getLayerOrder(layerName) === -1)
|
|
250
252
|
return layerName;
|
|
251
|
-
const filename = `./${
|
|
253
|
+
const filename = `./${getLayerReportFileName(layerName)}`;
|
|
252
254
|
return `[${formatLayerName(layerName)}](${filename})`;
|
|
253
255
|
}
|
|
254
256
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/reports/model-layer-report-generator.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Model Layer Report Generator\n *\n * Generates markdown documentation for a single architecture layer with:\n * - Mermaid intra-layer and inter-layer diagrams\n * - Relationship tables\n * - Element reference documentation\n * - Navigation and metadata\n *\n * Mirrors LayerReportGenerator from spec script but renders element instances\n * instead of type schemas.\n */\n\nimport type { ModelLayerReportData } from './model-report-data.js';\nimport type { Relationship } from '../core/relationships.js';\nimport { formatLayerName } from '../utils/layer-name-formatter.js';\nimport { formatMarkdownTable } from '../utils/markdown-table.js';\nimport { sanitizeMermaidId, escapeMermaidLabel } from '../utils/mermaid-utils.js';\nimport { createAnchor } from '../utils/markdown-anchor.js';\nimport { escapeMarkdown, getLayerDescription, valueToMarkdown } from '../export/markdown-utils.js';\nimport { getLayerOrder, CANONICAL_LAYER_NAMES } from '../core/layers.js';\nimport { getValidRelationships } from '../generated/relationship-index.js';\n\nexport class ModelLayerReportGenerator {\n constructor(private modelVersion: string, private generatedAt: string) {}\n\n /**\n * Generate complete layer report markdown\n */\n generate(data: ModelLayerReportData): string {\n const lines: string[] = [];\n\n // Document header\n lines.push(this.generateHeader(data));\n\n // Report Index (table of contents)\n lines.push(this.generateTableOfContents(data));\n\n // Layer Introduction + Statistics\n lines.push(this.generateLayerIntroduction(data));\n\n // Intra-Layer Relationships diagram\n lines.push(this.generateIntraLayerDiagram(data));\n\n // Inter-Layer Dependencies diagram\n lines.push(this.generateInterLayerDiagram(data));\n\n // Inter-Layer Relationships Table\n lines.push(this.generateInterLayerTable(data));\n\n // Element Reference section\n lines.push(this.generateElementReference(data));\n\n // Footer\n lines.push(this.generateFooter());\n\n return lines.join('');\n }\n\n private generateHeader(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push(`# ${formatLayerName(data.layerName)}\\n`);\n lines.push('\\n');\n lines.push(`${getLayerDescription(data.layerName)}\\n`);\n lines.push('\\n');\n return lines.join('');\n }\n\n private generateTableOfContents(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push('## Report Index\\n');\n lines.push('\\n');\n\n lines.push('- [Layer Introduction](#layer-introduction)\\n');\n lines.push('- [Intra-Layer Relationships](#intra-layer-relationships)\\n');\n lines.push('- [Inter-Layer Dependencies](#inter-layer-dependencies)\\n');\n\n if (data.interRelationships.length > 0) {\n lines.push('- [Inter-Layer Relationships Table](#inter-layer-relationships-table)\\n');\n }\n\n if (data.elements.length > 0) {\n lines.push('- [Element Reference](#element-reference)\\n');\n }\n\n lines.push('\\n');\n return lines.join('');\n }\n\n private generateLayerIntroduction(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push('## Layer Introduction\\n');\n lines.push('\\n');\n\n // Statistics table\n const headers = ['Metric', 'Count'];\n const rows = [\n ['Elements', String(data.statistics.elementCount)],\n ['Intra-Layer Relationships', String(data.statistics.intraRelationshipCount)],\n ['Inter-Layer Relationships', String(data.statistics.interRelationshipCount)],\n ['Inbound Relationships', String(data.statistics.inboundRelationshipCount)],\n ['Outbound Relationships', String(data.statistics.outboundRelationshipCount)],\n ];\n\n const table = formatMarkdownTable(headers, rows);\n lines.push(table);\n lines.push('\\n');\n\n // Upstream and downstream layers\n if (data.upstreamLayers.length > 0 || data.downstreamLayers.length > 0) {\n lines.push('**Cross-Layer References**:\\n');\n lines.push('\\n');\n\n if (data.upstreamLayers.length > 0) {\n const upstreamLinks = data.upstreamLayers\n .map((layerName) => this.createLayerLink(layerName))\n .join(', ');\n lines.push(`- **Upstream layers**: ${upstreamLinks}\\n`);\n }\n\n if (data.downstreamLayers.length > 0) {\n const downstreamLinks = data.downstreamLayers\n .map((layerName) => this.createLayerLink(layerName))\n .join(', ');\n lines.push(`- **Downstream layers**: ${downstreamLinks}\\n`);\n }\n\n lines.push('\\n');\n }\n\n return lines.join('');\n }\n\n private generateIntraLayerDiagram(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push('## Intra-Layer Relationships\\n');\n lines.push('\\n');\n\n // Empty layer handling\n if (data.elements.length === 0) {\n lines.push('No elements in this layer.\\n');\n lines.push('\\n');\n return lines.join('');\n }\n\n // Large layer fallback: For >30 elements, use summary table instead of Mermaid\n // to prevent rendering failures\n if (data.elements.length > 30) {\n lines.push('*This layer has >30 elements. Summary table shown instead of diagram.*\\n');\n lines.push('\\n');\n\n const headers = ['Element', 'Type', 'Relationships'];\n const rows: string[][] = [];\n\n for (const element of data.elements) {\n const relCount = data.intraRelationships.filter(\n (rel) => rel.source === element.path || rel.target === element.path\n ).length;\n\n rows.push([\n `\\`${escapeMarkdown(element.path)}\\``,\n `\\`${escapeMarkdown(element.type)}\\``,\n String(relCount),\n ]);\n }\n\n const table = formatMarkdownTable(headers, rows);\n lines.push(table);\n lines.push('\\n');\n\n return lines.join('');\n }\n\n // Generate mermaid diagram for layers with \u226430 elements\n lines.push('```mermaid\\n');\n lines.push('flowchart LR\\n');\n lines.push(` subgraph ${sanitizeMermaidId(data.layerName)}\\n`);\n\n // Add all elements as nodes (use escapeMermaidLabel for correct Mermaid escaping)\n for (const element of data.elements) {\n const nodeId = sanitizeMermaidId(element.path);\n const label = escapeMermaidLabel(element.name);\n lines.push(` ${nodeId}[\"${label}\"]\\n`);\n }\n\n // Add intra-layer relationships (sorted for deterministic output)\n const sortedRelationships = [...data.intraRelationships].sort((a, b) => {\n const aKey = `${a.source}-${a.predicate}-${a.target}`;\n const bKey = `${b.source}-${b.predicate}-${b.target}`;\n return aKey.localeCompare(bKey);\n });\n\n for (const rel of sortedRelationships) {\n const sourceId = sanitizeMermaidId(rel.source);\n const targetId = sanitizeMermaidId(rel.target);\n const predicate = escapeMermaidLabel(rel.predicate);\n lines.push(` ${sourceId} -->|${predicate}| ${targetId}\\n`);\n }\n\n lines.push(' end\\n');\n lines.push('```\\n');\n lines.push('\\n');\n\n return lines.join('');\n }\n\n private generateInterLayerDiagram(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push('## Inter-Layer Dependencies\\n');\n lines.push('\\n');\n\n // Empty layer handling\n if (data.elements.length === 0) {\n lines.push('No elements in this layer.\\n');\n lines.push('\\n');\n return lines.join('');\n }\n\n lines.push('```mermaid\\n');\n lines.push('flowchart TB\\n');\n lines.push(' classDef current fill:#f9f,stroke:#333,stroke-width:2px\\n');\n\n // Add all layers as nodes\n for (const layerName of CANONICAL_LAYER_NAMES) {\n const layerId = sanitizeMermaidId(layerName);\n const label = formatLayerName(layerName);\n lines.push(` ${layerId}[\"${label}\"]\\n`);\n }\n\n // Add layer-to-layer relationships for inter-layer dependencies\n const addedRelationships = new Set<string>();\n const layerRelationships: Array<{ sourceId: string; destId: string }> = [];\n\n for (const rel of data.interRelationships) {\n // Only include inter-layer relationships\n if (rel.layer !== rel.targetLayer && rel.targetLayer) {\n const key = `${rel.layer}-${rel.targetLayer}`;\n if (!addedRelationships.has(key)) {\n const sourceId = sanitizeMermaidId(rel.layer);\n const destId = sanitizeMermaidId(rel.targetLayer);\n layerRelationships.push({ sourceId, destId });\n addedRelationships.add(key);\n }\n }\n }\n\n // Sort and output relationships for deterministic ordering\n const sortedLayerRels = layerRelationships.sort((a, b) => {\n const aKey = `${a.sourceId}-${a.destId}`;\n const bKey = `${b.sourceId}-${b.destId}`;\n return aKey.localeCompare(bKey);\n });\n\n for (const { sourceId, destId } of sortedLayerRels) {\n lines.push(` ${sourceId} --> ${destId}\\n`);\n }\n\n // Highlight current layer\n const currentLayerId = sanitizeMermaidId(data.layerName);\n lines.push(` class ${currentLayerId} current\\n`);\n\n lines.push('```\\n');\n lines.push('\\n');\n\n return lines.join('');\n }\n\n private generateInterLayerTable(data: ModelLayerReportData): string {\n const lines: string[] = [];\n\n if (data.interRelationships.length === 0) {\n return '';\n }\n\n lines.push('## Inter-Layer Relationships Table\\n');\n lines.push('\\n');\n\n // Sort relationships for deterministic output\n const sortedRels = [...data.interRelationships].sort((a, b) => {\n const aKey = `${a.source}-${a.predicate}-${a.target}`;\n const bKey = `${b.source}-${b.predicate}-${b.target}`;\n return aKey.localeCompare(bKey);\n });\n\n const headers = ['Relationship ID', 'Source Node', 'Dest Node', 'Dest Layer', 'Predicate', 'Cardinality', 'Strength'];\n const rows: string[][] = [];\n\n for (const rel of sortedRels) {\n // Extract element types from paths (e.g., \"motivation.goal.customer-satisfaction\" -> \"motivation.goal\")\n const sourceType = this.extractElementType(rel.source);\n const targetType = this.extractElementType(rel.target);\n\n // Look up spec-level relationship properties\n const specs = getValidRelationships(sourceType, rel.predicate, targetType);\n const cardinality = specs.length > 0 ? specs[0].cardinality : 'unknown';\n const strength = specs.length > 0 ? specs[0].strength : 'unknown';\n\n // Use spec relationship ID when available, fall back to concatenated form\n const relationshipId = specs.length > 0 ? specs[0].id : `${rel.source}-${rel.predicate}-${rel.target}`;\n\n rows.push([\n `\\`${escapeMarkdown(relationshipId)}\\``,\n `\\`${escapeMarkdown(rel.source)}\\``,\n `\\`${escapeMarkdown(rel.target)}\\``,\n rel.targetLayer ? `\\`${escapeMarkdown(rel.targetLayer)}\\`` : '\u2014',\n `\\`${escapeMarkdown(rel.predicate)}\\``,\n cardinality,\n strength,\n ]);\n }\n\n const table = formatMarkdownTable(headers, rows);\n lines.push(table);\n lines.push('\\n');\n\n return lines.join('');\n }\n\n private generateElementReference(data: ModelLayerReportData): string {\n const lines: string[] = [];\n\n if (data.elements.length === 0) {\n return '';\n }\n\n lines.push('## Element Reference\\n');\n lines.push('\\n');\n\n for (const element of data.elements) {\n const anchor = createAnchor(element.name);\n lines.push(`### ${escapeMarkdown(element.name)} {#${anchor}}\\n`);\n lines.push('\\n');\n\n // ID and type\n lines.push(`**ID**: \\`${escapeMarkdown(element.path)}\\`\\n\\n`);\n lines.push(`**Type**: \\`${escapeMarkdown(element.type)}\\`\\n\\n`);\n\n // Description if available\n if (element.description) {\n lines.push(`${escapeMarkdown(element.description)}\\n\\n`);\n }\n\n // Attributes if available\n if (Object.keys(element.attributes).length > 0) {\n lines.push('#### Attributes\\n\\n');\n const attrHeaders = ['Name', 'Value'];\n const attrRows: string[][] = [];\n\n // Sort attributes for deterministic output\n const sortedAttrs = Object.entries(element.attributes).sort((a, b) =>\n a[0].localeCompare(b[0])\n );\n\n for (const [name, value] of sortedAttrs) {\n const valueStr = valueToMarkdown(value);\n attrRows.push([name, valueStr]);\n }\n\n const attrTable = formatMarkdownTable(attrHeaders, attrRows);\n lines.push(attrTable);\n lines.push('\\n');\n }\n\n // Relationships involving this element\n const elementRels = this.getElementRelationships(data, element.path);\n if (elementRels.length > 0) {\n lines.push('#### Relationships\\n\\n');\n const relHeaders = ['Type', 'Related Element', 'Predicate', 'Direction'];\n const relRows: string[][] = [];\n\n // Sort for deterministic output\n const sortedElementRels = [...elementRels].sort((a, b) => {\n const aKey = `${a.relType}-${a.rel.source}-${a.rel.predicate}-${a.rel.target}`;\n const bKey = `${b.relType}-${b.rel.source}-${b.rel.predicate}-${b.rel.target}`;\n return aKey.localeCompare(bKey);\n });\n\n for (const { rel, relType } of sortedElementRels) {\n const relatedElement = rel.source === element.path ? rel.target : rel.source;\n const direction = rel.source === element.path ? 'outbound' : 'inbound';\n\n relRows.push([\n relType,\n `\\`${escapeMarkdown(relatedElement)}\\``,\n `\\`${escapeMarkdown(rel.predicate)}\\``,\n direction,\n ]);\n }\n\n const relTable = formatMarkdownTable(relHeaders, relRows);\n lines.push(relTable);\n lines.push('\\n');\n }\n }\n\n return lines.join('');\n }\n\n private generateFooter(): string {\n const lines: string[] = [];\n lines.push('---\\n');\n lines.push('\\n');\n lines.push(`Generated: ${this.generatedAt} | Model Version: ${this.modelVersion}\\n`);\n return lines.join('');\n }\n\n /**\n * Create a markdown link to a layer report\n */\n private createLayerLink(layerName: string): string {\n const layerNumber = getLayerOrder(layerName);\n if (layerNumber === -1) {\n return layerName;\n }\n const filename = `./${String(layerNumber).padStart(2, '0')}-${layerName}-layer-report.md`;\n return `[${formatLayerName(layerName)}](${filename})`;\n }\n\n /**\n * Get relationships involving a specific element\n */\n private getElementRelationships(\n data: ModelLayerReportData,\n elementPath: string\n ): Array<{ rel: Relationship; relType: 'intra-layer' | 'inter-layer' }> {\n const rels: Array<{ rel: Relationship; relType: 'intra-layer' | 'inter-layer' }> = [];\n\n // Intra-layer relationships\n for (const rel of data.intraRelationships) {\n if (rel.source === elementPath || rel.target === elementPath) {\n rels.push({ rel, relType: 'intra-layer' });\n }\n }\n\n // Inter-layer relationships\n for (const rel of data.interRelationships) {\n if (rel.source === elementPath || rel.target === elementPath) {\n rels.push({ rel, relType: 'inter-layer' });\n }\n }\n\n return rels;\n }\n\n /**\n * Extract element type from element path in layer.type format\n * Example: \"motivation.goal.customer-satisfaction\" -> \"motivation.goal\"\n * This format matches the keys in RELATIONSHIPS_BY_SOURCE map.\n */\n private extractElementType(elementPath: string): string {\n const parts = elementPath.split('.');\n if (parts.length >= 2) {\n return parts.slice(0, 2).join('.');\n }\n return elementPath;\n }\n}\n"],
|
|
5
|
-
"mappings": "AAeA,SAAS,uBAAuB;AAChC,SAAS,2BAA2B;AACpC,SAAS,mBAAmB,0BAA0B;AACtD,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB,qBAAqB,uBAAuB;
|
|
4
|
+
"sourcesContent": ["/**\n * Model Layer Report Generator\n *\n * Generates markdown documentation for a single architecture layer with:\n * - Mermaid intra-layer and inter-layer diagrams\n * - Relationship tables\n * - Element reference documentation\n * - Navigation and metadata\n *\n * Mirrors LayerReportGenerator from spec script but renders element instances\n * instead of type schemas.\n */\n\nimport type { ModelLayerReportData } from './model-report-data.js';\nimport type { Relationship } from '../core/relationships.js';\nimport { formatLayerName } from '../utils/layer-name-formatter.js';\nimport { formatMarkdownTable } from '../utils/markdown-table.js';\nimport { sanitizeMermaidId, escapeMermaidLabel } from '../utils/mermaid-utils.js';\nimport { createAnchor } from '../utils/markdown-anchor.js';\nimport { escapeMarkdown, getLayerDescription, valueToMarkdown } from '../export/markdown-utils.js';\nimport type { CanonicalLayerName } from '../core/layers.js';\nimport { getLayerOrder, CANONICAL_LAYER_NAMES } from '../core/layers.js';\nimport { getValidRelationships } from '../generated/relationship-index.js';\nimport { getLayerReportFileName } from './model-report-utils.js';\n\nexport class ModelLayerReportGenerator {\n constructor(private modelVersion: string, private generatedAt: string) {}\n\n /**\n * Generate complete layer report markdown\n */\n generate(data: ModelLayerReportData): string {\n const lines: string[] = [];\n\n // Document header\n lines.push(this.generateHeader(data));\n\n // Report Index (table of contents)\n lines.push(this.generateTableOfContents(data));\n\n // Layer Introduction + Statistics\n lines.push(this.generateLayerIntroduction(data));\n\n // Intra-Layer Relationships diagram\n lines.push(this.generateIntraLayerDiagram(data));\n\n // Inter-Layer Dependencies diagram\n lines.push(this.generateInterLayerDiagram(data));\n\n // Inter-Layer Relationships Table\n lines.push(this.generateInterLayerTable(data));\n\n // Element Reference section\n lines.push(this.generateElementReference(data));\n\n // Footer\n lines.push(this.generateFooter());\n\n return lines.join('');\n }\n\n private generateHeader(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push(`# ${formatLayerName(data.layerName)}\\n`);\n lines.push('\\n');\n lines.push('[\u2190 Back to README](../README.md)\\n');\n lines.push('\\n');\n lines.push(`${getLayerDescription(data.layerName)}\\n`);\n lines.push('\\n');\n return lines.join('');\n }\n\n private generateTableOfContents(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push('## Report Index\\n');\n lines.push('\\n');\n\n lines.push('- [Layer Introduction](#layer-introduction)\\n');\n lines.push('- [Intra-Layer Relationships](#intra-layer-relationships)\\n');\n lines.push('- [Inter-Layer Dependencies](#inter-layer-dependencies)\\n');\n\n if (data.interRelationships.length > 0) {\n lines.push('- [Inter-Layer Relationships Table](#inter-layer-relationships-table)\\n');\n }\n\n if (data.elements.length > 0) {\n lines.push('- [Element Reference](#element-reference)\\n');\n }\n\n lines.push('\\n');\n return lines.join('');\n }\n\n private generateLayerIntroduction(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push('## Layer Introduction\\n');\n lines.push('\\n');\n\n // Statistics table\n const headers = ['Metric', 'Count'];\n const rows = [\n ['Elements', String(data.statistics.elementCount)],\n ['Intra-Layer Relationships', String(data.statistics.intraRelationshipCount)],\n ['Inter-Layer Relationships', String(data.statistics.interRelationshipCount)],\n ['Inbound Relationships', String(data.statistics.inboundRelationshipCount)],\n ['Outbound Relationships', String(data.statistics.outboundRelationshipCount)],\n ];\n\n const table = formatMarkdownTable(headers, rows);\n lines.push(table);\n lines.push('\\n');\n\n // Upstream and downstream layers\n if (data.upstreamLayers.length > 0 || data.downstreamLayers.length > 0) {\n lines.push('**Cross-Layer References**:\\n');\n lines.push('\\n');\n\n if (data.upstreamLayers.length > 0) {\n const upstreamLinks = data.upstreamLayers\n .map((layerName) => this.createLayerLink(layerName))\n .join(', ');\n lines.push(`- **Upstream layers**: ${upstreamLinks}\\n`);\n }\n\n if (data.downstreamLayers.length > 0) {\n const downstreamLinks = data.downstreamLayers\n .map((layerName) => this.createLayerLink(layerName))\n .join(', ');\n lines.push(`- **Downstream layers**: ${downstreamLinks}\\n`);\n }\n\n lines.push('\\n');\n }\n\n return lines.join('');\n }\n\n private generateIntraLayerDiagram(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push('## Intra-Layer Relationships\\n');\n lines.push('\\n');\n\n // Empty layer handling\n if (data.elements.length === 0) {\n lines.push('No elements in this layer.\\n');\n lines.push('\\n');\n return lines.join('');\n }\n\n // Large layer fallback: For >30 elements, use summary table instead of Mermaid\n // to prevent rendering failures\n if (data.elements.length > 30) {\n lines.push('*This layer has >30 elements. Summary table shown instead of diagram.*\\n');\n lines.push('\\n');\n\n const headers = ['Element', 'Type', 'Relationships'];\n const rows: string[][] = [];\n\n for (const element of data.elements) {\n const relCount = data.intraRelationships.filter(\n (rel) => rel.source === element.path || rel.target === element.path\n ).length;\n\n rows.push([\n `\\`${escapeMarkdown(element.path)}\\``,\n `\\`${escapeMarkdown(element.type)}\\``,\n String(relCount),\n ]);\n }\n\n const table = formatMarkdownTable(headers, rows);\n lines.push(table);\n lines.push('\\n');\n\n return lines.join('');\n }\n\n // Generate mermaid diagram for layers with \u226430 elements\n lines.push('```mermaid\\n');\n lines.push('flowchart LR\\n');\n lines.push(` subgraph ${sanitizeMermaidId(data.layerName)}\\n`);\n\n // Add all elements as nodes (use escapeMermaidLabel for correct Mermaid escaping)\n for (const element of data.elements) {\n const nodeId = sanitizeMermaidId(element.path);\n const label = escapeMermaidLabel(element.name);\n lines.push(` ${nodeId}[\"${label}\"]\\n`);\n }\n\n // Add intra-layer relationships (sorted for deterministic output)\n const sortedRelationships = [...data.intraRelationships].sort((a, b) => {\n const aKey = `${a.source}-${a.predicate}-${a.target}`;\n const bKey = `${b.source}-${b.predicate}-${b.target}`;\n return aKey.localeCompare(bKey);\n });\n\n for (const rel of sortedRelationships) {\n const sourceId = sanitizeMermaidId(rel.source);\n const targetId = sanitizeMermaidId(rel.target);\n const predicate = escapeMermaidLabel(rel.predicate);\n lines.push(` ${sourceId} -->|${predicate}| ${targetId}\\n`);\n }\n\n lines.push(' end\\n');\n lines.push('```\\n');\n lines.push('\\n');\n\n return lines.join('');\n }\n\n private generateInterLayerDiagram(data: ModelLayerReportData): string {\n const lines: string[] = [];\n lines.push('## Inter-Layer Dependencies\\n');\n lines.push('\\n');\n\n // Empty layer handling\n if (data.elements.length === 0) {\n lines.push('No elements in this layer.\\n');\n lines.push('\\n');\n return lines.join('');\n }\n\n lines.push('```mermaid\\n');\n lines.push('flowchart TB\\n');\n lines.push(' classDef current fill:#f9f,stroke:#333,stroke-width:2px\\n');\n\n // Add all layers as nodes\n for (const layerName of CANONICAL_LAYER_NAMES) {\n const layerId = sanitizeMermaidId(layerName);\n const label = formatLayerName(layerName);\n lines.push(` ${layerId}[\"${label}\"]\\n`);\n }\n\n // Add layer-to-layer relationships for inter-layer dependencies\n const addedRelationships = new Set<string>();\n const layerRelationships: Array<{ sourceId: string; destId: string }> = [];\n\n for (const rel of data.interRelationships) {\n // Only include inter-layer relationships\n if (rel.layer !== rel.targetLayer && rel.targetLayer) {\n const key = `${rel.layer}-${rel.targetLayer}`;\n if (!addedRelationships.has(key)) {\n const sourceId = sanitizeMermaidId(rel.layer);\n const destId = sanitizeMermaidId(rel.targetLayer);\n layerRelationships.push({ sourceId, destId });\n addedRelationships.add(key);\n }\n }\n }\n\n // Sort and output relationships for deterministic ordering\n const sortedLayerRels = layerRelationships.sort((a, b) => {\n const aKey = `${a.sourceId}-${a.destId}`;\n const bKey = `${b.sourceId}-${b.destId}`;\n return aKey.localeCompare(bKey);\n });\n\n for (const { sourceId, destId } of sortedLayerRels) {\n lines.push(` ${sourceId} --> ${destId}\\n`);\n }\n\n // Highlight current layer\n const currentLayerId = sanitizeMermaidId(data.layerName);\n lines.push(` class ${currentLayerId} current\\n`);\n\n lines.push('```\\n');\n lines.push('\\n');\n\n return lines.join('');\n }\n\n private generateInterLayerTable(data: ModelLayerReportData): string {\n const lines: string[] = [];\n\n if (data.interRelationships.length === 0) {\n return '';\n }\n\n lines.push('## Inter-Layer Relationships Table\\n');\n lines.push('\\n');\n\n // Sort relationships for deterministic output\n const sortedRels = [...data.interRelationships].sort((a, b) => {\n const aKey = `${a.source}-${a.predicate}-${a.target}`;\n const bKey = `${b.source}-${b.predicate}-${b.target}`;\n return aKey.localeCompare(bKey);\n });\n\n const headers = ['Relationship ID', 'Source Node', 'Dest Node', 'Dest Layer', 'Predicate', 'Cardinality', 'Strength'];\n const rows: string[][] = [];\n\n for (const rel of sortedRels) {\n // Extract element types from paths (e.g., \"motivation.goal.customer-satisfaction\" -> \"motivation.goal\")\n const sourceType = this.extractElementType(rel.source);\n const targetType = this.extractElementType(rel.target);\n\n // Look up spec-level relationship properties\n const specs = getValidRelationships(sourceType, rel.predicate, targetType);\n const cardinality = specs.length > 0 ? specs[0].cardinality : 'unknown';\n const strength = specs.length > 0 ? specs[0].strength : 'unknown';\n\n // Use spec relationship ID when available, fall back to concatenated form\n const relationshipId = specs.length > 0 ? specs[0].id : `${rel.source}-${rel.predicate}-${rel.target}`;\n\n rows.push([\n `\\`${escapeMarkdown(relationshipId)}\\``,\n `\\`${escapeMarkdown(rel.source)}\\``,\n `\\`${escapeMarkdown(rel.target)}\\``,\n rel.targetLayer ? `\\`${escapeMarkdown(rel.targetLayer)}\\`` : '\u2014',\n `\\`${escapeMarkdown(rel.predicate)}\\``,\n cardinality,\n strength,\n ]);\n }\n\n const table = formatMarkdownTable(headers, rows);\n lines.push(table);\n lines.push('\\n');\n\n return lines.join('');\n }\n\n private generateElementReference(data: ModelLayerReportData): string {\n const lines: string[] = [];\n\n if (data.elements.length === 0) {\n return '';\n }\n\n lines.push('## Element Reference\\n');\n lines.push('\\n');\n\n for (const element of data.elements) {\n const anchor = createAnchor(element.name);\n lines.push(`### ${escapeMarkdown(element.name)} {#${anchor}}\\n`);\n lines.push('\\n');\n\n // ID and type\n lines.push(`**ID**: \\`${escapeMarkdown(element.path)}\\`\\n\\n`);\n lines.push(`**Type**: \\`${escapeMarkdown(element.type)}\\`\\n\\n`);\n\n // Description if available\n if (element.description) {\n lines.push(`${escapeMarkdown(element.description)}\\n\\n`);\n }\n\n // Attributes if available\n if (Object.keys(element.attributes).length > 0) {\n lines.push('#### Attributes\\n\\n');\n const attrHeaders = ['Name', 'Value'];\n const attrRows: string[][] = [];\n\n // Sort attributes for deterministic output\n const sortedAttrs = Object.entries(element.attributes).sort((a, b) =>\n a[0].localeCompare(b[0])\n );\n\n for (const [name, value] of sortedAttrs) {\n const valueStr = valueToMarkdown(value);\n attrRows.push([name, valueStr]);\n }\n\n const attrTable = formatMarkdownTable(attrHeaders, attrRows);\n lines.push(attrTable);\n lines.push('\\n');\n }\n\n // Relationships involving this element\n const elementRels = this.getElementRelationships(data, element.path);\n if (elementRels.length > 0) {\n lines.push('#### Relationships\\n\\n');\n const relHeaders = ['Type', 'Related Element', 'Predicate', 'Direction'];\n const relRows: string[][] = [];\n\n // Sort for deterministic output\n const sortedElementRels = [...elementRels].sort((a, b) => {\n const aKey = `${a.relType}-${a.rel.source}-${a.rel.predicate}-${a.rel.target}`;\n const bKey = `${b.relType}-${b.rel.source}-${b.rel.predicate}-${b.rel.target}`;\n return aKey.localeCompare(bKey);\n });\n\n for (const { rel, relType } of sortedElementRels) {\n const relatedElement = rel.source === element.path ? rel.target : rel.source;\n const direction = rel.source === element.path ? 'outbound' : 'inbound';\n\n relRows.push([\n relType,\n `\\`${escapeMarkdown(relatedElement)}\\``,\n `\\`${escapeMarkdown(rel.predicate)}\\``,\n direction,\n ]);\n }\n\n const relTable = formatMarkdownTable(relHeaders, relRows);\n lines.push(relTable);\n lines.push('\\n');\n }\n }\n\n return lines.join('');\n }\n\n private generateFooter(): string {\n const lines: string[] = [];\n lines.push('---\\n');\n lines.push('\\n');\n lines.push(`Generated: ${this.generatedAt} | Model Version: ${this.modelVersion}\\n`);\n return lines.join('');\n }\n\n /**\n * Create a markdown link to a layer report\n */\n private createLayerLink(layerName: string): string {\n const layerNumber = getLayerOrder(layerName);\n if (layerNumber === -1) {\n return layerName;\n }\n const filename = `./${getLayerReportFileName(layerName as CanonicalLayerName)}`;\n return `[${formatLayerName(layerName)}](${filename})`;\n }\n\n /**\n * Get relationships involving a specific element\n */\n private getElementRelationships(\n data: ModelLayerReportData,\n elementPath: string\n ): Array<{ rel: Relationship; relType: 'intra-layer' | 'inter-layer' }> {\n const rels: Array<{ rel: Relationship; relType: 'intra-layer' | 'inter-layer' }> = [];\n\n // Intra-layer relationships\n for (const rel of data.intraRelationships) {\n if (rel.source === elementPath || rel.target === elementPath) {\n rels.push({ rel, relType: 'intra-layer' });\n }\n }\n\n // Inter-layer relationships\n for (const rel of data.interRelationships) {\n if (rel.source === elementPath || rel.target === elementPath) {\n rels.push({ rel, relType: 'inter-layer' });\n }\n }\n\n return rels;\n }\n\n /**\n * Extract element type from element path in layer.type format\n * Example: \"motivation.goal.customer-satisfaction\" -> \"motivation.goal\"\n * This format matches the keys in RELATIONSHIPS_BY_SOURCE map.\n */\n private extractElementType(elementPath: string): string {\n const parts = elementPath.split('.');\n if (parts.length >= 2) {\n return parts.slice(0, 2).join('.');\n }\n return elementPath;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|