@documentation-robotics/cli 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -2
- package/dist/analysis/relationship-classifier.js +2 -9
- package/dist/analysis/relationship-classifier.js.map +2 -2
- package/dist/analyzers/call-graph-utils.js +2 -2
- package/dist/analyzers/call-graph-utils.js.map +2 -2
- package/dist/analyzers/cards/build.js +171 -0
- package/dist/analyzers/cards/build.js.map +7 -0
- package/dist/analyzers/cards/classify.js +42 -0
- package/dist/analyzers/cards/classify.js.map +7 -0
- package/dist/analyzers/cards/edge-index.js +44 -0
- package/dist/analyzers/cards/edge-index.js.map +7 -0
- package/dist/analyzers/cards/facts.js +46 -0
- package/dist/analyzers/cards/facts.js.map +7 -0
- package/dist/analyzers/cards/graph.js +42 -0
- package/dist/analyzers/cards/graph.js.map +7 -0
- package/dist/analyzers/cards/index.js +8 -0
- package/dist/analyzers/cards/index.js.map +7 -0
- package/dist/analyzers/cards/tier0.js +18 -0
- package/dist/analyzers/cards/tier0.js.map +7 -0
- package/dist/analyzers/cards/types.js +1 -0
- package/dist/analyzers/cards/types.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +195 -171
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +336 -0
- package/dist/analyzers/cbm-responses.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +45 -0
- package/dist/analyzers/edge-relationships.js.map +7 -0
- package/dist/analyzers/mapping-loader.js +9 -0
- package/dist/analyzers/mapping-loader.js.map +2 -2
- package/dist/analyzers/tier0-rules.js +153 -0
- package/dist/analyzers/tier0-rules.js.map +7 -0
- package/dist/analyzers/types.js.map +1 -1
- package/dist/audit/relationships/ai/prompts.js +10 -10
- package/dist/audit/relationships/ai/prompts.js.map +2 -2
- package/dist/audit/relationships/analysis/layer-templates.js +52 -52
- package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
- package/dist/cli.js +12 -2
- package/dist/cli.js.map +2 -2
- package/dist/coding-agents/default-permissions.js +31 -1
- package/dist/coding-agents/default-permissions.js.map +2 -2
- package/dist/coding-agents/drbot-mcp.js +167 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +3 -2
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +117 -14
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/changeset-verify.js +55 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +43 -22
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/delete.js +10 -4
- package/dist/commands/delete.js.map +2 -2
- package/dist/commands/farm.js +176 -60
- package/dist/commands/farm.js.map +2 -2
- package/dist/commands/mcp.js +19 -4
- package/dist/commands/mcp.js.map +2 -2
- package/dist/commands/relationship.js +207 -26
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/update.js +42 -23
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +99 -11
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/version.js +1 -1
- package/dist/commands/visualize.js +4 -3
- package/dist/commands/visualize.js.map +2 -2
- package/dist/core/catalog-migration.js +33 -0
- package/dist/core/catalog-migration.js.map +7 -0
- package/dist/core/changeset-analysis.js +421 -0
- package/dist/core/changeset-analysis.js.map +7 -0
- package/dist/core/changeset-base-index.js +153 -0
- package/dist/core/changeset-base-index.js.map +7 -0
- package/dist/core/changeset-brief-delta.js +102 -0
- package/dist/core/changeset-brief-delta.js.map +7 -0
- package/dist/core/changeset-graph.js +281 -0
- package/dist/core/changeset-graph.js.map +7 -0
- package/dist/core/changeset-only-guard.js +32 -0
- package/dist/core/changeset-only-guard.js.map +7 -0
- package/dist/core/changeset-summary.js +68 -0
- package/dist/core/changeset-summary.js.map +7 -0
- package/dist/core/changeset-validator.js +66 -20
- package/dist/core/changeset-validator.js.map +2 -2
- package/dist/core/changeset-verify.js +518 -0
- package/dist/core/changeset-verify.js.map +7 -0
- package/dist/core/changeset.js +56 -9
- package/dist/core/changeset.js.map +2 -2
- package/dist/core/element-type-migration.js +145 -0
- package/dist/core/element-type-migration.js.map +7 -0
- package/dist/core/farm-manifest.js +12 -6
- package/dist/core/farm-manifest.js.map +2 -2
- package/dist/core/farm-sync-engine.js +1 -1
- package/dist/core/farm-sync-engine.js.map +2 -2
- package/dist/core/farm-sync-state.js +10 -2
- package/dist/core/farm-sync-state.js.map +2 -2
- package/dist/core/migration-registry.js +75 -46
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/model-upgrade.js +102 -0
- package/dist/core/model-upgrade.js.map +7 -0
- package/dist/core/model.js +82 -30
- package/dist/core/model.js.map +2 -2
- package/dist/core/mutation-handler.js +71 -6
- package/dist/core/mutation-handler.js.map +2 -2
- package/dist/core/relationship-migration-table.js +6639 -0
- package/dist/core/relationship-migration-table.js.map +7 -0
- package/dist/core/relationship-migration.js +272 -0
- package/dist/core/relationship-migration.js.map +7 -0
- package/dist/core/relationship-prune.js +49 -0
- package/dist/core/relationship-prune.js.map +7 -0
- package/dist/core/relationship-staging.js +68 -0
- package/dist/core/relationship-staging.js.map +7 -0
- package/dist/core/relationships.js +26 -4
- package/dist/core/relationships.js.map +2 -2
- package/dist/core/report-data-model.js +7 -13
- package/dist/core/report-data-model.js.map +2 -2
- package/dist/core/staged-changeset-storage.js +64 -17
- package/dist/core/staged-changeset-storage.js.map +2 -2
- package/dist/core/staged-source-reference.js +28 -0
- package/dist/core/staged-source-reference.js.map +7 -0
- package/dist/core/staging-area.js +83 -18
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/virtual-projection.js +13 -5
- package/dist/core/virtual-projection.js.map +2 -2
- package/dist/export/archimate-exporter.js +1 -0
- package/dist/export/archimate-exporter.js.map +2 -2
- package/dist/generated/compiled-validators.js +2 -2
- package/dist/generated/compiled-validators.js.map +2 -2
- package/dist/generated/layer-registry.js +16 -16
- package/dist/generated/layer-registry.js.map +2 -2
- package/dist/generated/node-types.js +186 -168
- package/dist/generated/node-types.js.map +2 -2
- package/dist/generated/relationship-index.js +2236 -7790
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/agents/dr-architect.md +16 -3
- package/dist/integrations/claude_code/agents/dr-extractor.md +1 -1
- package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
- package/dist/integrations/claude_code/commands/dr-map.md +13 -0
- package/dist/integrations/claude_code/commands/dr-plan.md +40 -0
- package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
- package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
- package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
- package/dist/integrations/claude_code/docs/MCP_SERVER.md +26 -2
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +48 -1
- package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
- package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
- package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
- package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
- package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
- package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
- package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
- package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
- package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
- package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
- package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
- package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
- package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +92 -15
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +1 -1
- package/dist/integrations/github_copilot/agents/dr-architect.md +1 -1
- package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
- package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
- package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
- package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
- package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
- package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
- package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
- package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
- package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
- package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
- package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
- package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
- package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +222 -102
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/hash-utils.js.map +2 -2
- package/dist/mcp/api-key-manager.js +14 -1
- package/dist/mcp/api-key-manager.js.map +2 -2
- package/dist/mcp/changeset-only.js +34 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/tool-registry.js +19 -3
- package/dist/mcp/tool-registry.js.map +2 -2
- package/dist/mcp/tools/changeset-analysis-tools.js +78 -0
- package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +184 -0
- package/dist/mcp/tools/changeset-editing.js.map +7 -0
- package/dist/mcp/tools/changeset-lifecycle.js +83 -0
- package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
- package/dist/mcp/tools/changeset-shared.js +31 -0
- package/dist/mcp/tools/changeset-shared.js.map +7 -0
- package/dist/mcp/tools/changeset-show.js +17 -1
- package/dist/mcp/tools/changeset-show.js.map +2 -2
- package/dist/mcp/tools/changeset-verify.js +43 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/index.js +19 -1
- package/dist/mcp/tools/index.js.map +2 -2
- package/dist/mcp/tools/model-add.js +6 -5
- package/dist/mcp/tools/model-add.js.map +2 -2
- package/dist/mcp/tools/model-delete.js +2 -2
- package/dist/mcp/tools/model-delete.js.map +2 -2
- package/dist/mcp/tools/model-search.js +14 -0
- package/dist/mcp/tools/model-search.js.map +2 -2
- package/dist/mcp/tools/model-show.js +29 -2
- package/dist/mcp/tools/model-show.js.map +2 -2
- package/dist/mcp/tools/model-trace.js +93 -30
- package/dist/mcp/tools/model-trace.js.map +2 -2
- package/dist/mcp/tools/model-update.js +35 -19
- package/dist/mcp/tools/model-update.js.map +2 -2
- package/dist/mcp/tools/relationship-tools.js +98 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/shared.js +25 -2
- package/dist/mcp/tools/shared.js.map +2 -2
- package/dist/mcp/tools/spec-type.js +90 -0
- package/dist/mcp/tools/spec-type.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +1186 -68
- package/dist/schemas/bundled/analyzers/manifest.json +2 -2
- package/dist/schemas/bundled/api.json +1029 -1658
- package/dist/schemas/bundled/apm.json +499 -734
- package/dist/schemas/bundled/application.json +735 -371
- package/dist/schemas/bundled/base.json +3 -220
- package/dist/schemas/bundled/business.json +452 -366
- package/dist/schemas/bundled/data-model.json +395 -411
- package/dist/schemas/bundled/data-store.json +334 -558
- package/dist/schemas/bundled/manifest.json +18 -18
- package/dist/schemas/bundled/motivation.json +349 -368
- package/dist/schemas/bundled/navigation.json +415 -731
- package/dist/schemas/bundled/product.json +325 -159
- package/dist/schemas/bundled/security.json +864 -1232
- package/dist/schemas/bundled/technology.json +574 -703
- package/dist/schemas/bundled/testing.json +718 -1643
- package/dist/schemas/bundled/ux.json +739 -1352
- package/dist/server/schemas.js +8 -0
- package/dist/server/schemas.js.map +2 -2
- package/dist/server/server.js +218 -34
- package/dist/server/server.js.map +2 -2
- package/dist/server-entry.js +2 -1
- package/dist/server-entry.js.map +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/utils/ansi-suppressor.js +6 -8
- package/dist/utils/ansi-suppressor.js.map +2 -2
- package/dist/utils/attribute-patch.js +41 -0
- package/dist/utils/attribute-patch.js.map +7 -0
- package/dist/utils/error-hints.js +29 -0
- package/dist/utils/error-hints.js.map +7 -0
- package/dist/utils/errors.js +9 -3
- package/dist/utils/errors.js.map +2 -2
- package/dist/utils/project-paths.js +26 -1
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/source-reference.js +14 -12
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +2 -2
- package/dist/utils/spec-version.js.map +1 -1
- package/dist/validators/composed-reference-validator.js +5 -27
- package/dist/validators/composed-reference-validator.js.map +2 -2
- package/dist/validators/reference-validator.js +0 -7
- package/dist/validators/reference-validator.js.map +2 -2
- package/dist/validators/relationship-schema-validator.js +3 -3
- package/dist/validators/relationship-schema-validator.js.map +2 -2
- package/dist/validators/schema-validator.js +27 -9
- package/dist/validators/schema-validator.js.map +2 -2
- package/dist/validators/types.js.map +1 -1
- package/dist/viewer/README.md +6 -6
- package/dist/viewer/assets/main-CxzcuU_o.js +84 -0
- package/dist/viewer/assets/main-j-7ULYpm.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 +2 -1
- package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
- package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/changeset-lifecycle.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * changeset_create, changeset_activate, changeset_deactivate \u2014 open and switch the changeset\n * that model and relationship mutations stage into. Mirrors `dr changeset create|activate|deactivate`.\n *\n * Every one of these reloads the cached model afterwards: the model decides at load time whether\n * its layers are projected through an active changeset.\n *\n * Commit, apply and delete are deliberately not exposed over MCP: landing a change is the\n * human's step (viewer or CLI). Rename, unstage and (confirmed) discard are in\n * changeset-editing.ts. See docs/CHANGE_MODELING.md.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { StagingAreaManager } from \"../../core/staging-area.js\";\nimport { CLIError, ErrorCategory } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, reloadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\nimport { resolveChangeset } from \"./changeset-shared.js\";\n\n// ---------------------------------------------------------------------------\n// changeset_create\n// ---------------------------------------------------------------------------\n\nconst createInputSchema = {\n name: z.string().min(1).describe(\"Short name for the change, e.g. 'add-order-export'.\"),\n description: z\n .string()\n .optional()\n .describe(\"The change's intent: what it is for and what done looks like. Shown to the human reviewing it.\"),\n activate: z\n .boolean()\n .optional()\n .describe(\"Make it the active changeset so mutations stage into it (default true).\"),\n rootPath: rootPathSchema,\n};\n\nexport type ChangesetCreateArgs = z.infer<z.ZodObject<typeof createInputSchema>>;\n\nexport async function changesetCreateHandler(args: ChangesetCreateArgs): Promise<CallToolResult> {\n return runTool(async () => {\n const model = await loadModel(args.rootPath);\n const manager = new StagingAreaManager(model.rootPath, model);\n\n if (await manager.load(args.name)) {\n throw new CLIError(`Changeset '${args.name}' already exists`, ErrorCategory.USER, [\n `Use \"changeset_activate\" with \"${args.name}\" to continue it`,\n \"Or choose another name\",\n ]);\n }\n\n const changeset = await manager.create(args.name, args.description);\n const activate = args.activate ?? true;\n const previouslyActive = activate ? await manager.getActiveId() : null;\n if (activate) {\n await manager.setActive(changeset.id);\n await reloadModel(args.rootPath);\n }\n\n return jsonResult({\n id: changeset.id,\n name: changeset.name,\n ...(changeset.description ? { description: changeset.description } : {}),\n status: changeset.status,\n active: activate,\n ...(previouslyActive && previouslyActive !== changeset.id ? { deactivated: previouslyActive } : {}),\n });\n });\n}\n\nexport const changesetCreateTool: McpToolDefinition<typeof createInputSchema> = {\n name: \"changeset_create\",\n description:\n \"Start planning a change: create a changeset carrying the change's intent and (by default) activate it, \" +\n \"so model_add / model_update / model_delete / relationship_add / relationship_delete stage into it instead \" +\n \"of writing the model. The human commits it later; it is never committed over MCP.\",\n inputSchema: createInputSchema,\n handler: changesetCreateHandler,\n};\n\n// ---------------------------------------------------------------------------\n// changeset_activate\n// ---------------------------------------------------------------------------\n\nconst activateInputSchema = {\n changesetId: z.string().describe(\"Changeset ID or name.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ChangesetActivateArgs = z.infer<z.ZodObject<typeof activateInputSchema>>;\n\nexport async function changesetActivateHandler(args: ChangesetActivateArgs): Promise<CallToolResult> {\n return runTool(async () => {\n const model = await loadModel(args.rootPath);\n const manager = new StagingAreaManager(model.rootPath, model);\n const changeset = await resolveChangeset(manager, args.changesetId);\n\n if (changeset.status !== \"staged\") {\n throw new CLIError(\n `Changeset '${changeset.name}' is ${changeset.status} and cannot accept changes`,\n ErrorCategory.USER,\n ['Use \"changeset_create\" to start a new one']\n );\n }\n\n const previouslyActive = await manager.getActiveId();\n await manager.setActive(changeset.id);\n await reloadModel(args.rootPath);\n\n return jsonResult({\n id: changeset.id,\n name: changeset.name,\n active: true,\n changes: changeset.changes.length,\n ...(previouslyActive && previouslyActive !== changeset.id ? { deactivated: previouslyActive } : {}),\n });\n });\n}\n\nexport const changesetActivateTool: McpToolDefinition<typeof activateInputSchema> = {\n name: \"changeset_activate\",\n description: \"Make an existing staged changeset the active one, so mutations stage into it.\",\n inputSchema: activateInputSchema,\n handler: changesetActivateHandler,\n};\n\n// ---------------------------------------------------------------------------\n// changeset_deactivate\n// ---------------------------------------------------------------------------\n\nconst deactivateInputSchema = {\n rootPath: rootPathSchema,\n};\n\nexport type ChangesetDeactivateArgs = z.infer<z.ZodObject<typeof deactivateInputSchema>>;\n\nexport async function changesetDeactivateHandler(args: ChangesetDeactivateArgs): Promise<CallToolResult> {\n return runTool(async () => {\n const model = await loadModel(args.rootPath);\n const manager = new StagingAreaManager(model.rootPath, model);\n const activeId = await manager.getActiveId();\n if (activeId) {\n await manager.clearActive();\n await reloadModel(args.rootPath);\n }\n return jsonResult({ deactivated: activeId ?? null });\n });\n}\n\nexport const changesetDeactivateTool: McpToolDefinition<typeof deactivateInputSchema> = {\n name: \"changeset_deactivate\",\n description:\n \"Deactivate the active changeset. Its changes stay staged; afterwards mutations write the base model directly.\",\n inputSchema: deactivateInputSchema,\n handler: changesetDeactivateHandler,\n};\n"],
|
|
5
|
+
"mappings": "AAYA,SAAS,SAAS;AAElB,SAAS,0BAA0B;AACnC,SAAS,UAAU,qBAAqB;AACxC,SAAS,YAAY,WAAW,aAAa,gBAAgB,eAAuC;AACpG,SAAS,wBAAwB;AAMjC,MAAM,oBAAoB;EACxB,MAAM,EAAE,OAAM,EAAG,IAAI,CAAC,EAAE,SAAS,qDAAqD;EACtF,aAAa,EACV,OAAM,EACN,SAAQ,EACR,SAAS,gGAAgG;EAC5G,UAAU,EACP,QAAO,EACP,SAAQ,EACR,SAAS,yEAAyE;EACrF,UAAU;;AAKZ,eAAsB,uBAAuB,MAAyB;AACpE,SAAO,QAAQ,YAAW;AACxB,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GACrC,UAAU,IAAI,mBAAmB,MAAM,UAAU,KAAK;AAE5D,QAAI,MAAM,QAAQ,KAAK,KAAK,IAAI;AAC9B,YAAM,IAAI,SAAS,cAAc,KAAK,IAAI,oBAAoB,cAAc,MAAM;QAChF,kCAAkC,KAAK,IAAI;QAC3C;OACD;AAGH,UAAM,YAAY,MAAM,QAAQ,OAAO,KAAK,MAAM,KAAK,WAAW,GAC5D,WAAW,KAAK,YAAY,IAC5B,mBAAmB,WAAW,MAAM,QAAQ,YAAW,IAAK;AAClE,WAAI,aACF,MAAM,QAAQ,UAAU,UAAU,EAAE,GACpC,MAAM,YAAY,KAAK,QAAQ,IAG1B,WAAW;MAChB,IAAI,UAAU;MACd,MAAM,UAAU;MAChB,GAAI,UAAU,cAAc,EAAE,aAAa,UAAU,YAAW,IAAK,CAAA;MACrE,QAAQ,UAAU;MAClB,QAAQ;MACR,GAAI,oBAAoB,qBAAqB,UAAU,KAAK,EAAE,aAAa,iBAAgB,IAAK,CAAA;KACjG;EACH,CAAC;AACH;AAEO,MAAM,sBAAmE;EAC9E,MAAM;EACN,aACE;EAGF,aAAa;EACb,SAAS;GAOL,sBAAsB;EAC1B,aAAa,EAAE,OAAM,EAAG,SAAS,uBAAuB;EACxD,UAAU;;AAKZ,eAAsB,yBAAyB,MAA2B;AACxE,SAAO,QAAQ,YAAW;AACxB,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GACrC,UAAU,IAAI,mBAAmB,MAAM,UAAU,KAAK,GACtD,YAAY,MAAM,iBAAiB,SAAS,KAAK,WAAW;AAElE,QAAI,UAAU,WAAW;AACvB,YAAM,IAAI,SACR,cAAc,UAAU,IAAI,QAAQ,UAAU,MAAM,8BACpD,cAAc,MACd,CAAC,2CAA2C,CAAC;AAIjD,UAAM,mBAAmB,MAAM,QAAQ,YAAW;AAClD,iBAAM,QAAQ,UAAU,UAAU,EAAE,GACpC,MAAM,YAAY,KAAK,QAAQ,GAExB,WAAW;MAChB,IAAI,UAAU;MACd,MAAM,UAAU;MAChB,QAAQ;MACR,SAAS,UAAU,QAAQ;MAC3B,GAAI,oBAAoB,qBAAqB,UAAU,KAAK,EAAE,aAAa,iBAAgB,IAAK,CAAA;KACjG;EACH,CAAC;AACH;AAEO,MAAM,wBAAuE;EAClF,MAAM;EACN,aAAa;EACb,aAAa;EACb,SAAS;GAOL,wBAAwB;EAC5B,UAAU;;AAKZ,eAAsB,2BAA2B,MAA6B;AAC5E,SAAO,QAAQ,YAAW;AACxB,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GACrC,UAAU,IAAI,mBAAmB,MAAM,UAAU,KAAK,GACtD,WAAW,MAAM,QAAQ,YAAW;AAC1C,WAAI,aACF,MAAM,QAAQ,YAAW,GACzB,MAAM,YAAY,KAAK,QAAQ,IAE1B,WAAW,EAAE,aAAa,YAAY,KAAI,CAAE;EACrD,CAAC;AACH;AAEO,MAAM,0BAA2E;EACtF,MAAM;EACN,aACE;EACF,aAAa;EACb,SAAS;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ChangesetGraph } from "../../core/changeset-graph.js";
|
|
2
|
+
import { StagingAreaManager } from "../../core/staging-area.js";
|
|
3
|
+
import { CLIError, ErrorCategory } from "../../utils/errors.js";
|
|
4
|
+
async function resolveChangeset(manager, changesetId, parameter = "changesetId") {
|
|
5
|
+
const id = changesetId ?? await manager.getActiveId();
|
|
6
|
+
if (!id)
|
|
7
|
+
throw new CLIError("No changeset named and none is active", ErrorCategory.USER, [
|
|
8
|
+
`Pass "${parameter}", or use "changeset_create" / "changeset_activate" first`,
|
|
9
|
+
'Use "changeset_list" to see existing changesets'
|
|
10
|
+
]);
|
|
11
|
+
const changeset = await manager.load(id);
|
|
12
|
+
if (!changeset)
|
|
13
|
+
throw new CLIError(`Changeset ${id} not found`, ErrorCategory.NOT_FOUND, [
|
|
14
|
+
'Use "changeset_list" to see all available changesets'
|
|
15
|
+
]);
|
|
16
|
+
return changeset;
|
|
17
|
+
}
|
|
18
|
+
async function activeStagedChangeset(manager) {
|
|
19
|
+
const active = await manager.getActive();
|
|
20
|
+
return active && active.status === "staged" ? active : null;
|
|
21
|
+
}
|
|
22
|
+
async function loadChangesetGraph(model, changesetId) {
|
|
23
|
+
const manager = new StagingAreaManager(model.rootPath, model), changeset = await resolveChangeset(manager, changesetId), graph = await ChangesetGraph.build(model, changeset);
|
|
24
|
+
return { manager, changeset, graph };
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
activeStagedChangeset,
|
|
28
|
+
loadChangesetGraph,
|
|
29
|
+
resolveChangeset
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=changeset-shared.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/changeset-shared.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Helpers shared by the changeset-planning MCP tools.\n */\n\nimport type { Changeset } from \"../../core/changeset.js\";\nimport { ChangesetGraph } from \"../../core/changeset-graph.js\";\nimport type { Model } from \"../../core/model.js\";\nimport { StagingAreaManager } from \"../../core/staging-area.js\";\nimport { CLIError, ErrorCategory } from \"../../utils/errors.js\";\n\n/** Loads a changeset by id or name, or the active one when none is named. */\nexport async function resolveChangeset(\n manager: StagingAreaManager,\n changesetId?: string,\n /** The tool parameter that names the changeset, for the hint when none is named or active. */\n parameter = \"changesetId\"\n): Promise<Changeset> {\n const id = changesetId ?? (await manager.getActiveId());\n if (!id) {\n throw new CLIError(\"No changeset named and none is active\", ErrorCategory.USER, [\n `Pass \"${parameter}\", or use \"changeset_create\" / \"changeset_activate\" first`,\n 'Use \"changeset_list\" to see existing changesets',\n ]);\n }\n const changeset = await manager.load(id);\n if (!changeset) {\n throw new CLIError(`Changeset ${id} not found`, ErrorCategory.NOT_FOUND, [\n 'Use \"changeset_list\" to see all available changesets',\n ]);\n }\n return changeset;\n}\n\n/** The active changeset when it can still accept changes, else null. */\nexport async function activeStagedChangeset(manager: StagingAreaManager): Promise<Changeset | null> {\n const active = await manager.getActive();\n return active && active.status === \"staged\" ? active : null;\n}\n\n/** Builds the projected graph for a changeset (by id/name, or the active one). */\nexport async function loadChangesetGraph(\n model: Model,\n changesetId?: string\n): Promise<{ manager: StagingAreaManager; changeset: Changeset; graph: ChangesetGraph }> {\n const manager = new StagingAreaManager(model.rootPath, model);\n const changeset = await resolveChangeset(manager, changesetId);\n const graph = await ChangesetGraph.build(model, changeset);\n return { manager, changeset, graph };\n}\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,sBAAsB;AAE/B,SAAS,0BAA0B;AACnC,SAAS,UAAU,qBAAqB;AAGxC,eAAsB,iBACpB,SACA,aAEA,YAAY,eAAa;AAEzB,QAAM,KAAK,eAAgB,MAAM,QAAQ,YAAW;AACpD,MAAI,CAAC;AACH,UAAM,IAAI,SAAS,yCAAyC,cAAc,MAAM;MAC9E,SAAS,SAAS;MAClB;KACD;AAEH,QAAM,YAAY,MAAM,QAAQ,KAAK,EAAE;AACvC,MAAI,CAAC;AACH,UAAM,IAAI,SAAS,aAAa,EAAE,cAAc,cAAc,WAAW;MACvE;KACD;AAEH,SAAO;AACT;AAGA,eAAsB,sBAAsB,SAA2B;AACrE,QAAM,SAAS,MAAM,QAAQ,UAAS;AACtC,SAAO,UAAU,OAAO,WAAW,WAAW,SAAS;AACzD;AAGA,eAAsB,mBACpB,OACA,aAAoB;AAEpB,QAAM,UAAU,IAAI,mBAAmB,MAAM,UAAU,KAAK,GACtD,YAAY,MAAM,iBAAiB,SAAS,WAAW,GACvD,QAAQ,MAAM,eAAe,MAAM,OAAO,SAAS;AACzD,SAAO,EAAE,SAAS,WAAW,MAAK;AACpC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { StagingAreaManager } from "../../core/staging-area.js";
|
|
3
|
+
import { summarizeChangeset } from "../../core/changeset-summary.js";
|
|
3
4
|
import { CLIError, ErrorCategory } from "../../utils/errors.js";
|
|
4
5
|
import { jsonResult, loadModel, rootPathSchema, runTool } from "./shared.js";
|
|
5
6
|
const inputSchema = {
|
|
6
7
|
changesetId: z.string().describe("Changeset ID or name."),
|
|
8
|
+
detail: z.enum(["full", "summary"]).optional().describe('"full" (default): every change with its before/after snapshots. "summary": one entry per change (sequence, operation, element id and type or relationship source/predicate/target, and for updates the changed field names such as attributes.summary), plus totals per operation, without snapshots.'),
|
|
7
9
|
rootPath: rootPathSchema
|
|
8
10
|
};
|
|
9
11
|
async function changesetShowHandler(args) {
|
|
@@ -13,6 +15,20 @@ async function changesetShowHandler(args) {
|
|
|
13
15
|
throw new CLIError(`Changeset ${args.changesetId} not found`, ErrorCategory.NOT_FOUND, [
|
|
14
16
|
'Use "changeset_list" to see all available changesets'
|
|
15
17
|
]);
|
|
18
|
+
if (args.detail === "summary") {
|
|
19
|
+
const summary = summarizeChangeset(changeset.changes);
|
|
20
|
+
return jsonResult({
|
|
21
|
+
id: changeset.id,
|
|
22
|
+
name: changeset.name,
|
|
23
|
+
description: changeset.description,
|
|
24
|
+
status: changeset.status,
|
|
25
|
+
created: changeset.created,
|
|
26
|
+
modified: changeset.modified,
|
|
27
|
+
detail: "summary",
|
|
28
|
+
totals: summary.totals,
|
|
29
|
+
changes: summary.changes
|
|
30
|
+
});
|
|
31
|
+
}
|
|
16
32
|
return jsonResult({
|
|
17
33
|
id: changeset.id,
|
|
18
34
|
name: changeset.name,
|
|
@@ -28,7 +44,7 @@ async function changesetShowHandler(args) {
|
|
|
28
44
|
}
|
|
29
45
|
const changesetShowTool = {
|
|
30
46
|
name: "changeset_show",
|
|
31
|
-
description:
|
|
47
|
+
description: `Show a single changeset's detail including its description, stats, and list of changes. Pass detail: "summary" for one compact line per change (operation, element or relationship, changed fields) and totals per operation, without the before/after snapshots.`,
|
|
32
48
|
inputSchema,
|
|
33
49
|
handler: changesetShowHandler
|
|
34
50
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/mcp/tools/changeset-show.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * changeset_show \u2014 show a single changeset's full detail, including its list\n * of changes. Mirrors the REST `GET /api/changesets/:changesetId` endpoint\n * (see `ChangesetDetailSchema` in `cli/src/server/schemas.ts`).\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { StagingAreaManager } from \"../../core/staging-area.js\";\nimport { CLIError, ErrorCategory } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n changesetId: z.string().describe(\"Changeset ID or name.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ChangesetShowArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function changesetShowHandler(args: ChangesetShowArgs): Promise<CallToolResult> {\n return runTool(async () => {\n const model = await loadModel(args.rootPath);\n const manager = new StagingAreaManager(model.rootPath, model);\n const changeset = await manager.load(args.changesetId);\n\n if (!changeset) {\n throw new CLIError(`Changeset ${args.changesetId} not found`, ErrorCategory.NOT_FOUND, [\n 'Use \"changeset_list\" to see all available changesets',\n ]);\n }\n\n return jsonResult({\n id: changeset.id,\n name: changeset.name,\n description: changeset.description,\n status: changeset.status,\n created: changeset.created,\n modified: changeset.modified,\n baseSnapshot: changeset.baseSnapshot,\n stats: changeset.stats,\n changes: changeset.changes,\n });\n });\n}\n\nexport const changesetShowTool: McpToolDefinition<typeof inputSchema> = {\n name: \"changeset_show\",\n description
|
|
5
|
-
"mappings": "AAMA,SAAS,SAAS;AAElB,SAAS,0BAA0B;AACnC,SAAS,UAAU,qBAAqB;AACxC,SAAS,YAAY,WAAW,gBAAgB,eAAuC;AAEvF,MAAM,cAAc;EAClB,aAAa,EAAE,OAAM,EAAG,SAAS,uBAAuB;EACxD,UAAU;;AAKZ,eAAsB,qBAAqB,MAAuB;AAChE,SAAO,QAAQ,YAAW;AACxB,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GAErC,YAAY,MADF,IAAI,mBAAmB,MAAM,UAAU,KAAK,EAC5B,KAAK,KAAK,WAAW;AAErD,QAAI,CAAC;AACH,YAAM,IAAI,SAAS,aAAa,KAAK,WAAW,cAAc,cAAc,WAAW;QACrF;OACD;AAGH,WAAO,WAAW;MAChB,IAAI,UAAU;MACd,MAAM,UAAU;MAChB,aAAa,UAAU;MACvB,QAAQ,UAAU;MAClB,SAAS,UAAU;MACnB,UAAU,UAAU;MACpB,cAAc,UAAU;MACxB,OAAO,UAAU;MACjB,SAAS,UAAU;KACpB;EACH,CAAC;AACH;AAEO,MAAM,oBAA2D;EACtE,MAAM;EACN,
|
|
4
|
+
"sourcesContent": ["/**\n * changeset_show \u2014 show a single changeset's full detail, including its list\n * of changes. Mirrors the REST `GET /api/changesets/:changesetId` endpoint\n * (see `ChangesetDetailSchema` in `cli/src/server/schemas.ts`).\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { StagingAreaManager } from \"../../core/staging-area.js\";\nimport { summarizeChangeset } from \"../../core/changeset-summary.js\";\nimport { CLIError, ErrorCategory } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n changesetId: z.string().describe(\"Changeset ID or name.\"),\n detail: z\n .enum([\"full\", \"summary\"])\n .optional()\n .describe(\n '\"full\" (default): every change with its before/after snapshots. \"summary\": one entry per change ' +\n \"(sequence, operation, element id and type or relationship source/predicate/target, and for updates the \" +\n \"changed field names such as attributes.summary), plus totals per operation, without snapshots.\"\n ),\n rootPath: rootPathSchema,\n};\n\nexport type ChangesetShowArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function changesetShowHandler(args: ChangesetShowArgs): Promise<CallToolResult> {\n return runTool(async () => {\n const model = await loadModel(args.rootPath);\n const manager = new StagingAreaManager(model.rootPath, model);\n const changeset = await manager.load(args.changesetId);\n\n if (!changeset) {\n throw new CLIError(`Changeset ${args.changesetId} not found`, ErrorCategory.NOT_FOUND, [\n 'Use \"changeset_list\" to see all available changesets',\n ]);\n }\n\n if (args.detail === \"summary\") {\n const summary = summarizeChangeset(changeset.changes);\n return jsonResult({\n id: changeset.id,\n name: changeset.name,\n description: changeset.description,\n status: changeset.status,\n created: changeset.created,\n modified: changeset.modified,\n detail: \"summary\",\n totals: summary.totals,\n changes: summary.changes,\n });\n }\n\n return jsonResult({\n id: changeset.id,\n name: changeset.name,\n description: changeset.description,\n status: changeset.status,\n created: changeset.created,\n modified: changeset.modified,\n baseSnapshot: changeset.baseSnapshot,\n stats: changeset.stats,\n changes: changeset.changes,\n });\n });\n}\n\nexport const changesetShowTool: McpToolDefinition<typeof inputSchema> = {\n name: \"changeset_show\",\n description:\n \"Show a single changeset's detail including its description, stats, and list of changes. Pass \" +\n 'detail: \"summary\" for one compact line per change (operation, element or relationship, changed fields) ' +\n \"and totals per operation, without the before/after snapshots.\",\n inputSchema,\n handler: changesetShowHandler,\n};\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,SAAS;AAElB,SAAS,0BAA0B;AACnC,SAAS,0BAA0B;AACnC,SAAS,UAAU,qBAAqB;AACxC,SAAS,YAAY,WAAW,gBAAgB,eAAuC;AAEvF,MAAM,cAAc;EAClB,aAAa,EAAE,OAAM,EAAG,SAAS,uBAAuB;EACxD,QAAQ,EACL,KAAK,CAAC,QAAQ,SAAS,CAAC,EACxB,SAAQ,EACR,SACC,uSAEkG;EAEtG,UAAU;;AAKZ,eAAsB,qBAAqB,MAAuB;AAChE,SAAO,QAAQ,YAAW;AACxB,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GAErC,YAAY,MADF,IAAI,mBAAmB,MAAM,UAAU,KAAK,EAC5B,KAAK,KAAK,WAAW;AAErD,QAAI,CAAC;AACH,YAAM,IAAI,SAAS,aAAa,KAAK,WAAW,cAAc,cAAc,WAAW;QACrF;OACD;AAGH,QAAI,KAAK,WAAW,WAAW;AAC7B,YAAM,UAAU,mBAAmB,UAAU,OAAO;AACpD,aAAO,WAAW;QAChB,IAAI,UAAU;QACd,MAAM,UAAU;QAChB,aAAa,UAAU;QACvB,QAAQ,UAAU;QAClB,SAAS,UAAU;QACnB,UAAU,UAAU;QACpB,QAAQ;QACR,QAAQ,QAAQ;QAChB,SAAS,QAAQ;OAClB;IACH;AAEA,WAAO,WAAW;MAChB,IAAI,UAAU;MACd,MAAM,UAAU;MAChB,aAAa,UAAU;MACvB,QAAQ,UAAU;MAClB,SAAS,UAAU;MACnB,UAAU,UAAU;MACpB,cAAc,UAAU;MACxB,OAAO,UAAU;MACjB,SAAS,UAAU;KACpB;EACH,CAAC;AACH;AAEO,MAAM,oBAA2D;EACtE,MAAM;EACN,aACE;EAGF;EACA,SAAS;;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { verifyChangesetInModel } from "../../core/changeset-verify.js";
|
|
3
|
+
import { StagingAreaManager } from "../../core/staging-area.js";
|
|
4
|
+
import { CLIError, ErrorCategory } from "../../utils/errors.js";
|
|
5
|
+
import { jsonResult, reloadModel, rootPathSchema, runTool } from "./shared.js";
|
|
6
|
+
import { resolveChangeset } from "./changeset-shared.js";
|
|
7
|
+
const inputSchema = {
|
|
8
|
+
planned: z.string().optional().describe("The planned changeset, by ID or name. Defaults to the active changeset."),
|
|
9
|
+
against: z.object({
|
|
10
|
+
changesetId: z.string().optional().describe("An as-built changeset (by ID or name), e.g. one written by extraction or by hand."),
|
|
11
|
+
base: z.boolean().optional().describe("Compare with the base model, e.g. after the as-built changeset was committed on the branch.")
|
|
12
|
+
}).describe('What was built: {"changesetId": "..."} or {"base": true}.'),
|
|
13
|
+
matchBySource: z.boolean().optional().describe("Also match elements of the same layer and type that share a source file (default true)."),
|
|
14
|
+
rootPath: rootPathSchema
|
|
15
|
+
};
|
|
16
|
+
async function changesetVerifyHandler(args) {
|
|
17
|
+
return runTool(async () => {
|
|
18
|
+
if (args.against?.changesetId && args.against.base)
|
|
19
|
+
throw new CLIError('Pass either "against.changesetId" or "against.base", not both', ErrorCategory.USER);
|
|
20
|
+
if (!args.against?.changesetId && !args.against?.base)
|
|
21
|
+
throw new CLIError("Nothing to verify against", ErrorCategory.USER, [
|
|
22
|
+
'Pass "against": {"changesetId": "<as-built changeset>"} to compare with another changeset',
|
|
23
|
+
'Pass "against": {"base": true} to compare with the base model'
|
|
24
|
+
]);
|
|
25
|
+
const model = await reloadModel(args.rootPath), manager = new StagingAreaManager(model.rootPath, model), planned = await resolveChangeset(manager, args.planned, "planned"), asBuilt = args.against?.changesetId ? await resolveChangeset(manager, args.against.changesetId) : void 0;
|
|
26
|
+
return jsonResult(await verifyChangesetInModel(model, {
|
|
27
|
+
planned,
|
|
28
|
+
against: asBuilt ? { changeset: asBuilt } : { base: !0 },
|
|
29
|
+
matchBySource: args.matchBySource
|
|
30
|
+
}));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const changesetVerifyTool = {
|
|
34
|
+
name: "changeset_verify",
|
|
35
|
+
description: "Compare a planned changeset with what was built: another (as-built) changeset, or the base model. Elements match by id, then by layer + type + name ignoring case and separators, then by source file; relationships match through those element matches. Reports matched, missing (planned, not built), unplanned (built, not planned), divergent (matched but type, description or attributes differ, with the fields), and planned deletions that still exist, with a verdict. Fuzzy matches are marked probable with their reason; confirm them. Reads the model fresh from disk, so a commit made outside MCP is seen. Read-only.",
|
|
36
|
+
inputSchema,
|
|
37
|
+
handler: changesetVerifyHandler
|
|
38
|
+
};
|
|
39
|
+
export {
|
|
40
|
+
changesetVerifyHandler,
|
|
41
|
+
changesetVerifyTool
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=changeset-verify.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/tools/changeset-verify.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * changeset_verify \u2014 compare a planned changeset with what was built.\n * See `cli/src/core/changeset-verify.ts` and docs/CHANGE_MODELING.md.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { verifyChangesetInModel } from \"../../core/changeset-verify.js\";\nimport { StagingAreaManager } from \"../../core/staging-area.js\";\nimport { CLIError, ErrorCategory } from \"../../utils/errors.js\";\nimport { jsonResult, reloadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\nimport { resolveChangeset } from \"./changeset-shared.js\";\n\nconst inputSchema = {\n planned: z\n .string()\n .optional()\n .describe(\"The planned changeset, by ID or name. Defaults to the active changeset.\"),\n against: z\n .object({\n changesetId: z\n .string()\n .optional()\n .describe(\"An as-built changeset (by ID or name), e.g. one written by extraction or by hand.\"),\n base: z\n .boolean()\n .optional()\n .describe(\"Compare with the base model, e.g. after the as-built changeset was committed on the branch.\"),\n })\n .describe('What was built: {\"changesetId\": \"...\"} or {\"base\": true}.'),\n matchBySource: z\n .boolean()\n .optional()\n .describe(\"Also match elements of the same layer and type that share a source file (default true).\"),\n rootPath: rootPathSchema,\n};\n\nexport type ChangesetVerifyArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function changesetVerifyHandler(args: ChangesetVerifyArgs): Promise<CallToolResult> {\n return runTool(async () => {\n if (args.against?.changesetId && args.against.base) {\n throw new CLIError('Pass either \"against.changesetId\" or \"against.base\", not both', ErrorCategory.USER);\n }\n if (!args.against?.changesetId && !args.against?.base) {\n throw new CLIError(\"Nothing to verify against\", ErrorCategory.USER, [\n 'Pass \"against\": {\"changesetId\": \"<as-built changeset>\"} to compare with another changeset',\n 'Pass \"against\": {\"base\": true} to compare with the base model',\n ]);\n }\n // Always read the model fresh: the build is often committed outside MCP (`dr changeset commit` is\n // not exposed here), and a cached model would compare against the base as it was when the server\n // started. Verify is read-only and infrequent, so the reload is cheap insurance.\n const model = await reloadModel(args.rootPath);\n const manager = new StagingAreaManager(model.rootPath, model);\n const planned = await resolveChangeset(manager, args.planned, \"planned\");\n const asBuilt = args.against?.changesetId ? await resolveChangeset(manager, args.against.changesetId) : undefined;\n return jsonResult(\n await verifyChangesetInModel(model, {\n planned,\n against: asBuilt ? { changeset: asBuilt } : { base: true },\n matchBySource: args.matchBySource,\n })\n );\n });\n}\n\nexport const changesetVerifyTool: McpToolDefinition<typeof inputSchema> = {\n name: \"changeset_verify\",\n description:\n \"Compare a planned changeset with what was built: another (as-built) changeset, or the base model. Elements \" +\n \"match by id, then by layer + type + name ignoring case and separators, then by source file; relationships \" +\n \"match through those element matches. Reports matched, missing (planned, not built), unplanned (built, not \" +\n \"planned), divergent (matched but type, description or attributes differ, with the fields), and planned \" +\n \"deletions that still exist, with a verdict. Fuzzy matches are marked probable with their reason; confirm \" +\n \"them. Reads the model fresh from disk, so a commit made outside MCP is seen. Read-only.\",\n inputSchema,\n handler: changesetVerifyHandler,\n};\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,SAAS;AAElB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,UAAU,qBAAqB;AACxC,SAAS,YAAY,aAAa,gBAAgB,eAAuC;AACzF,SAAS,wBAAwB;AAEjC,MAAM,cAAc;EAClB,SAAS,EACN,OAAM,EACN,SAAQ,EACR,SAAS,yEAAyE;EACrF,SAAS,EACN,OAAO;IACN,aAAa,EACV,OAAM,EACN,SAAQ,EACR,SAAS,mFAAmF;IAC/F,MAAM,EACH,QAAO,EACP,SAAQ,EACR,SAAS,6FAA6F;GAC1G,EACA,SAAS,2DAA2D;EACvE,eAAe,EACZ,QAAO,EACP,SAAQ,EACR,SAAS,yFAAyF;EACrG,UAAU;;AAKZ,eAAsB,uBAAuB,MAAyB;AACpE,SAAO,QAAQ,YAAW;AACxB,QAAI,KAAK,SAAS,eAAe,KAAK,QAAQ;AAC5C,YAAM,IAAI,SAAS,iEAAiE,cAAc,IAAI;AAExG,QAAI,CAAC,KAAK,SAAS,eAAe,CAAC,KAAK,SAAS;AAC/C,YAAM,IAAI,SAAS,6BAA6B,cAAc,MAAM;QAClE;QACA;OACD;AAKH,UAAM,QAAQ,MAAM,YAAY,KAAK,QAAQ,GACvC,UAAU,IAAI,mBAAmB,MAAM,UAAU,KAAK,GACtD,UAAU,MAAM,iBAAiB,SAAS,KAAK,SAAS,SAAS,GACjE,UAAU,KAAK,SAAS,cAAc,MAAM,iBAAiB,SAAS,KAAK,QAAQ,WAAW,IAAI;AACxG,WAAO,WACL,MAAM,uBAAuB,OAAO;MAClC;MACA,SAAS,UAAU,EAAE,WAAW,QAAO,IAAK,EAAE,MAAM,GAAI;MACxD,eAAe,KAAK;KACrB,CAAC;EAEN,CAAC;AACH;AAEO,MAAM,sBAA6D;EACxE,MAAM;EACN,aACE;EAMF;EACA,SAAS;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/mcp/tools/index.js
CHANGED
|
@@ -18,8 +18,14 @@ import { modelExportTool } from "./model-export.js";
|
|
|
18
18
|
import { modelReloadTool } from "./model-reload.js";
|
|
19
19
|
import { changesetListTool } from "./changeset-list.js";
|
|
20
20
|
import { changesetShowTool } from "./changeset-show.js";
|
|
21
|
+
import { changesetCreateTool, changesetActivateTool, changesetDeactivateTool } from "./changeset-lifecycle.js";
|
|
22
|
+
import { changesetImpactTool, changesetBriefTool } from "./changeset-analysis-tools.js";
|
|
23
|
+
import { relationshipAddTool, relationshipDeleteTool } from "./relationship-tools.js";
|
|
24
|
+
import { specTypeTool } from "./spec-type.js";
|
|
21
25
|
import { chatStatusTool } from "./chat-status.js";
|
|
22
26
|
import { chatLaunchTool } from "./chat-launch.js";
|
|
27
|
+
import { changesetVerifyTool } from "./changeset-verify.js";
|
|
28
|
+
import { changesetUpdateTool, changesetUnstageTool, changesetDiscardTool } from "./changeset-editing.js";
|
|
23
29
|
export {
|
|
24
30
|
annotationCreateTool,
|
|
25
31
|
annotationDeleteTool,
|
|
@@ -27,8 +33,17 @@ export {
|
|
|
27
33
|
annotationListTool,
|
|
28
34
|
annotationReplyTool,
|
|
29
35
|
annotationUpdateTool,
|
|
36
|
+
changesetActivateTool,
|
|
37
|
+
changesetBriefTool,
|
|
38
|
+
changesetCreateTool,
|
|
39
|
+
changesetDeactivateTool,
|
|
40
|
+
changesetDiscardTool,
|
|
41
|
+
changesetImpactTool,
|
|
30
42
|
changesetListTool,
|
|
31
43
|
changesetShowTool,
|
|
44
|
+
changesetUnstageTool,
|
|
45
|
+
changesetUpdateTool,
|
|
46
|
+
changesetVerifyTool,
|
|
32
47
|
chatLaunchTool,
|
|
33
48
|
chatStatusTool,
|
|
34
49
|
modelAddTool,
|
|
@@ -42,6 +57,9 @@ export {
|
|
|
42
57
|
modelStatsTool,
|
|
43
58
|
modelTraceTool,
|
|
44
59
|
modelUpdateTool,
|
|
45
|
-
modelValidateTool
|
|
60
|
+
modelValidateTool,
|
|
61
|
+
relationshipAddTool,
|
|
62
|
+
relationshipDeleteTool,
|
|
63
|
+
specTypeTool
|
|
46
64
|
};
|
|
47
65
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/mcp/tools/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { annotationListTool } from \"./annotation-list.js\";\nexport { annotationGetTool } from \"./annotation-get.js\";\nexport { annotationCreateTool } from \"./annotation-create.js\";\nexport { annotationUpdateTool } from \"./annotation-update.js\";\nexport { annotationDeleteTool } from \"./annotation-delete.js\";\nexport { annotationReplyTool } from \"./annotation-reply.js\";\nexport { modelListTool } from \"./model-list.js\";\nexport { modelShowTool } from \"./model-show.js\";\nexport { modelSearchTool } from \"./model-search.js\";\nexport { modelStatsTool } from \"./model-stats.js\";\nexport { modelInfoTool } from \"./model-info.js\";\nexport { modelTraceTool } from \"./model-trace.js\";\nexport { modelAddTool } from \"./model-add.js\";\nexport { modelUpdateTool } from \"./model-update.js\";\nexport { modelDeleteTool } from \"./model-delete.js\";\nexport { modelValidateTool } from \"./model-validate.js\";\nexport { modelExportTool } from \"./model-export.js\";\nexport { modelReloadTool } from \"./model-reload.js\";\nexport { changesetListTool } from \"./changeset-list.js\";\nexport { changesetShowTool } from \"./changeset-show.js\";\nexport { chatStatusTool } from \"./chat-status.js\";\nexport { chatLaunchTool } from \"./chat-launch.js\";\nexport type { McpToolDefinition } from \"./shared.js\";\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,4BAA4B;AACrC,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;",
|
|
4
|
+
"sourcesContent": ["export { annotationListTool } from \"./annotation-list.js\";\nexport { annotationGetTool } from \"./annotation-get.js\";\nexport { annotationCreateTool } from \"./annotation-create.js\";\nexport { annotationUpdateTool } from \"./annotation-update.js\";\nexport { annotationDeleteTool } from \"./annotation-delete.js\";\nexport { annotationReplyTool } from \"./annotation-reply.js\";\nexport { modelListTool } from \"./model-list.js\";\nexport { modelShowTool } from \"./model-show.js\";\nexport { modelSearchTool } from \"./model-search.js\";\nexport { modelStatsTool } from \"./model-stats.js\";\nexport { modelInfoTool } from \"./model-info.js\";\nexport { modelTraceTool } from \"./model-trace.js\";\nexport { modelAddTool } from \"./model-add.js\";\nexport { modelUpdateTool } from \"./model-update.js\";\nexport { modelDeleteTool } from \"./model-delete.js\";\nexport { modelValidateTool } from \"./model-validate.js\";\nexport { modelExportTool } from \"./model-export.js\";\nexport { modelReloadTool } from \"./model-reload.js\";\nexport { changesetListTool } from \"./changeset-list.js\";\nexport { changesetShowTool } from \"./changeset-show.js\";\nexport { changesetCreateTool, changesetActivateTool, changesetDeactivateTool } from \"./changeset-lifecycle.js\";\nexport { changesetImpactTool, changesetBriefTool } from \"./changeset-analysis-tools.js\";\nexport { relationshipAddTool, relationshipDeleteTool } from \"./relationship-tools.js\";\nexport { specTypeTool } from \"./spec-type.js\";\nexport { chatStatusTool } from \"./chat-status.js\";\nexport { chatLaunchTool } from \"./chat-launch.js\";\nexport { changesetVerifyTool } from \"./changeset-verify.js\";\nexport type { McpToolDefinition } from \"./shared.js\";\nexport { changesetUpdateTool, changesetUnstageTool, changesetDiscardTool } from \"./changeset-editing.js\";\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,4BAA4B;AACrC,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAClC,SAAS,qBAAqB,uBAAuB,+BAA+B;AACpF,SAAS,qBAAqB,0BAA0B;AACxD,SAAS,qBAAqB,8BAA8B;AAC5D,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AAEpC,SAAS,qBAAqB,sBAAsB,4BAA4B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -6,9 +6,10 @@ import { getAllLayerIds, isValidLayer } from "../../generated/layer-registry.js"
|
|
|
6
6
|
import { getNodeTypesForLayer, isValidNodeType, normalizeNodeType } from "../../generated/node-types.js";
|
|
7
7
|
import { generateElementId, generateUUID } from "../../utils/id-generator.js";
|
|
8
8
|
import { buildSourceReference, validateSourceReferenceOptions } from "../../utils/source-reference.js";
|
|
9
|
+
import { schemaLookupHint } from "../../utils/error-hints.js";
|
|
9
10
|
import { SchemaValidator } from "../../validators/schema-validator.js";
|
|
10
11
|
import { CLIError, ErrorCategory, findSimilar, formatValidOptions } from "../../utils/errors.js";
|
|
11
|
-
import { jsonResult, loadModel, rootPathSchema, runTool } from "./shared.js";
|
|
12
|
+
import { jsonResult, loadModel, reloadModel, rootPathSchema, runTool } from "./shared.js";
|
|
12
13
|
const inputSchema = {
|
|
13
14
|
layer: z.string().describe("Canonical layer name (e.g. 'api', 'data-model')."),
|
|
14
15
|
type: z.string().describe("Element type within the layer (e.g. 'operation', 'entity')."),
|
|
@@ -37,8 +38,8 @@ async function modelAddHandler(args) {
|
|
|
37
38
|
throw new CLIError(`Cannot generate a valid element ID from name "${args.name}"`, ErrorCategory.USER, [
|
|
38
39
|
"Element names must contain at least one letter or digit"
|
|
39
40
|
]);
|
|
40
|
-
validateSourceReferenceOptions(args);
|
|
41
|
-
const model = await loadModel(args.rootPath);
|
|
41
|
+
validateSourceReferenceOptions(args, "mcp");
|
|
42
|
+
const model = await loadModel(args.rootPath), layerKnown = model.getLayerNames().includes(args.layer);
|
|
42
43
|
let layerObj = await model.getLayer(args.layer), isNewLayer = !1;
|
|
43
44
|
layerObj || (layerObj = new Layer(args.layer), isNewLayer = !0);
|
|
44
45
|
const now = (/* @__PURE__ */ new Date()).toISOString(), element = new Element({
|
|
@@ -67,7 +68,7 @@ async function modelAddHandler(args) {
|
|
|
67
68
|
`);
|
|
68
69
|
throw new CLIError(`Element ${elementPath} has invalid attributes:
|
|
69
70
|
${errorMessages}`, ErrorCategory.USER, [
|
|
70
|
-
|
|
71
|
+
schemaLookupHint("mcp", args.layer, resolvedType)
|
|
71
72
|
]);
|
|
72
73
|
}
|
|
73
74
|
}
|
|
@@ -83,7 +84,7 @@ ${errorMessages}`, ErrorCategory.USER, [
|
|
|
83
84
|
layerObj.addElement(elem);
|
|
84
85
|
});
|
|
85
86
|
const activeChangeset = await mutationHandler.getStagingManager().getActive(), staged = !!(activeChangeset && activeChangeset.status === "staged");
|
|
86
|
-
return jsonResult({
|
|
87
|
+
return staged && !layerKnown && await reloadModel(args.rootPath), jsonResult({
|
|
87
88
|
status: staged ? "staged" : "added",
|
|
88
89
|
changeset: staged ? activeChangeset.name : void 0,
|
|
89
90
|
id: elementPath,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/mcp/tools/model-add.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * model_add \u2014 add an element to a layer. Mirrors `dr add`, operating through\n * the shared MutationHandler so staging and base-model persistence stay\n * consistent with the CLI.\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 { getAllLayerIds, isValidLayer } from \"../../generated/layer-registry.js\";\nimport { getNodeTypesForLayer, isValidNodeType, normalizeNodeType } from \"../../generated/node-types.js\";\nimport { generateElementId, generateUUID } from \"../../utils/id-generator.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 layer: z.string().describe(\"Canonical layer name (e.g. 'api', 'data-model').\"),\n type: z.string().describe(\"Element type within the layer (e.g. 'operation', 'entity').\"),\n name: z.string().describe(\"Human-readable element name; used to derive the element ID.\"),\n description: z.string().optional(),\n attributes: z.record(z.string(), z.unknown()).optional().describe(\"Type-specific attributes, validated against the element's spec schema.\"),\n sourceFile: z.string().optional().describe(\"Source file path relative to the repository root.\"),\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 rootPath: rootPathSchema,\n};\n\nexport type ModelAddArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelAddHandler(args: ModelAddArgs): Promise<CallToolResult> {\n return runTool(async () => {\n if (!isValidLayer(args.layer)) {\n const validLayers = getAllLayerIds();\n const similar = findSimilar(args.layer, validLayers, 3);\n const suggestions: string[] = [`Use a valid layer name: ${formatValidOptions(validLayers)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Unknown layer \"${args.layer}\"`, ErrorCategory.USER, suggestions);\n }\n\n if (!isValidNodeType(args.layer, args.type)) {\n const validNodeTypes = getNodeTypesForLayer(args.layer);\n const typeNames = validNodeTypes.map((t) => t.type).sort();\n const similar = findSimilar(args.type, typeNames, 3);\n const suggestions: string[] = [`Valid types for ${args.layer}: ${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 \"${args.layer}\"`, ErrorCategory.USER, suggestions);\n }\n\n const resolvedType = normalizeNodeType(args.layer, args.type);\n const elementPath = generateElementId(args.layer, resolvedType, args.name);\n const elementUUID = generateUUID();\n\n const slugPart = elementPath.split(\".\")[2];\n if (!slugPart) {\n throw new CLIError(`Cannot generate a valid element ID from name \"${args.name}\"`, ErrorCategory.USER, [\n \"Element names must contain at least one letter or digit\",\n ]);\n }\n\n validateSourceReferenceOptions(args);\n\n const model = await loadModel(args.rootPath);\n\n let layerObj = await model.getLayer(args.layer);\n let isNewLayer = false;\n if (!layerObj) {\n layerObj = new Layer(args.layer);\n isNewLayer = true;\n }\n\n const now = new Date().toISOString();\n const element = new Element({\n id: elementUUID,\n path: elementPath,\n spec_node_id: `${args.layer}.${resolvedType}`,\n layer_id: args.layer,\n type: resolvedType,\n name: args.name,\n description: args.description,\n attributes: args.attributes ?? {},\n metadata: {\n created_at: now,\n updated_at: now,\n version: 1,\n },\n layer: args.layer,\n });\n\n const sourceRef = buildSourceReference(args);\n if (sourceRef) {\n element.setSourceReference(sourceRef);\n }\n\n {\n const schemaValidator = new SchemaValidator();\n const tempLayer = new Layer(args.layer);\n tempLayer.addElement(element);\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(`Element ${elementPath} has invalid attributes:\\n${errorMessages}`, ErrorCategory.USER, [\n
|
|
5
|
-
"mappings": "AAMA,SAAS,SAAS;AAElB,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,SAAS,gBAAgB,oBAAoB;AAC7C,SAAS,sBAAsB,iBAAiB,yBAAyB;AACzE,SAAS,mBAAmB,oBAAoB;AAChD,SAAS,sBAAsB,sCAAsC;AACrE,SAAS,uBAAuB;AAChC,SAAS,UAAU,eAAe,aAAa,0BAA0B;AACzE,SAAS,YAAY,WAAW,gBAAgB,eAAuC;
|
|
4
|
+
"sourcesContent": ["/**\n * model_add \u2014 add an element to a layer. Mirrors `dr add`, operating through\n * the shared MutationHandler so staging and base-model persistence stay\n * consistent with the CLI.\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 { getAllLayerIds, isValidLayer } from \"../../generated/layer-registry.js\";\nimport { getNodeTypesForLayer, isValidNodeType, normalizeNodeType } from \"../../generated/node-types.js\";\nimport { generateElementId, generateUUID } from \"../../utils/id-generator.js\";\nimport { buildSourceReference, validateSourceReferenceOptions } from \"../../utils/source-reference.js\";\nimport { schemaLookupHint } from \"../../utils/error-hints.js\";\nimport { SchemaValidator } from \"../../validators/schema-validator.js\";\nimport { CLIError, ErrorCategory, findSimilar, formatValidOptions } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, reloadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n layer: z.string().describe(\"Canonical layer name (e.g. 'api', 'data-model').\"),\n type: z.string().describe(\"Element type within the layer (e.g. 'operation', 'entity').\"),\n name: z.string().describe(\"Human-readable element name; used to derive the element ID.\"),\n description: z.string().optional(),\n attributes: z.record(z.string(), z.unknown()).optional().describe(\"Type-specific attributes, validated against the element's spec schema.\"),\n sourceFile: z.string().optional().describe(\"Source file path relative to the repository root.\"),\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 rootPath: rootPathSchema,\n};\n\nexport type ModelAddArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelAddHandler(args: ModelAddArgs): Promise<CallToolResult> {\n return runTool(async () => {\n if (!isValidLayer(args.layer)) {\n const validLayers = getAllLayerIds();\n const similar = findSimilar(args.layer, validLayers, 3);\n const suggestions: string[] = [`Use a valid layer name: ${formatValidOptions(validLayers)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Unknown layer \"${args.layer}\"`, ErrorCategory.USER, suggestions);\n }\n\n if (!isValidNodeType(args.layer, args.type)) {\n const validNodeTypes = getNodeTypesForLayer(args.layer);\n const typeNames = validNodeTypes.map((t) => t.type).sort();\n const similar = findSimilar(args.type, typeNames, 3);\n const suggestions: string[] = [`Valid types for ${args.layer}: ${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 \"${args.layer}\"`, ErrorCategory.USER, suggestions);\n }\n\n const resolvedType = normalizeNodeType(args.layer, args.type);\n const elementPath = generateElementId(args.layer, resolvedType, args.name);\n const elementUUID = generateUUID();\n\n const slugPart = elementPath.split(\".\")[2];\n if (!slugPart) {\n throw new CLIError(`Cannot generate a valid element ID from name \"${args.name}\"`, ErrorCategory.USER, [\n \"Element names must contain at least one letter or digit\",\n ]);\n }\n\n validateSourceReferenceOptions(args, \"mcp\");\n\n const model = await loadModel(args.rootPath);\n\n // Inside a changeset getLayer() projects even a layer the model has no elements in, so ask the\n // model's layer list whether this layer is new to it.\n const layerKnown = model.getLayerNames().includes(args.layer);\n let layerObj = await model.getLayer(args.layer);\n let isNewLayer = false;\n if (!layerObj) {\n layerObj = new Layer(args.layer);\n isNewLayer = true;\n }\n\n const now = new Date().toISOString();\n const element = new Element({\n id: elementUUID,\n path: elementPath,\n spec_node_id: `${args.layer}.${resolvedType}`,\n layer_id: args.layer,\n type: resolvedType,\n name: args.name,\n description: args.description,\n attributes: args.attributes ?? {},\n metadata: {\n created_at: now,\n updated_at: now,\n version: 1,\n },\n layer: args.layer,\n });\n\n const sourceRef = buildSourceReference(args);\n if (sourceRef) {\n element.setSourceReference(sourceRef);\n }\n\n {\n const schemaValidator = new SchemaValidator();\n const tempLayer = new Layer(args.layer);\n tempLayer.addElement(element);\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(`Element ${elementPath} has invalid attributes:\\n${errorMessages}`, ErrorCategory.USER, [\n schemaLookupHint(\"mcp\", args.layer, resolvedType),\n ]);\n }\n }\n\n if (layerObj.getElement(elementPath)) {\n throw new CLIError(`Element ${elementPath} already exists in ${args.layer} layer`, ErrorCategory.USER, [\n `Use \"model_show\" to view the existing element`,\n `Use \"model_update\" to modify it`,\n `Use \"model_delete\" to remove it first if you want to recreate it`,\n ]);\n }\n\n if (isNewLayer) {\n model.addLayer(layerObj);\n }\n\n const mutationHandler = new MutationHandler(model, elementPath, args.layer);\n await mutationHandler.executeAdd(element, (elem) => {\n layerObj!.addElement(elem);\n });\n\n const stagingManager = mutationHandler.getStagingManager();\n const activeChangeset = await stagingManager.getActive();\n const staged = !!(activeChangeset && activeChangeset.status === \"staged\");\n if (staged && !layerKnown) {\n // The cached model did not list this layer: reread it so every later tool call\n // (relationship_add, model_show, model_update, ...) sees the layer and the element.\n await reloadModel(args.rootPath);\n }\n\n return jsonResult({\n status: staged ? \"staged\" : \"added\",\n changeset: staged ? activeChangeset!.name : undefined,\n id: elementPath,\n layer: args.layer,\n type: resolvedType,\n name: args.name,\n });\n });\n}\n\nexport const modelAddTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_add\",\n description: \"Add a new element to a layer, validated against its spec schema.\",\n inputSchema,\n handler: modelAddHandler,\n};\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,SAAS;AAElB,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,SAAS,gBAAgB,oBAAoB;AAC7C,SAAS,sBAAsB,iBAAiB,yBAAyB;AACzE,SAAS,mBAAmB,oBAAoB;AAChD,SAAS,sBAAsB,sCAAsC;AACrE,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,UAAU,eAAe,aAAa,0BAA0B;AACzE,SAAS,YAAY,WAAW,aAAa,gBAAgB,eAAuC;AAEpG,MAAM,cAAc;EAClB,OAAO,EAAE,OAAM,EAAG,SAAS,kDAAkD;EAC7E,MAAM,EAAE,OAAM,EAAG,SAAS,6DAA6D;EACvF,MAAM,EAAE,OAAM,EAAG,SAAS,6DAA6D;EACvF,aAAa,EAAE,OAAM,EAAG,SAAQ;EAChC,YAAY,EAAE,OAAO,EAAE,OAAM,GAAI,EAAE,QAAO,CAAE,EAAE,SAAQ,EAAG,SAAS,wEAAwE;EAC1I,YAAY,EAAE,OAAM,EAAG,SAAQ,EAAG,SAAS,mDAAmD;EAC9F,cAAc,EAAE,OAAM,EAAG,SAAQ;EACjC,kBAAkB,EAAE,KAAK,CAAC,aAAa,UAAU,YAAY,WAAW,CAAC,EAAE,SAAQ;EACnF,kBAAkB,EAAE,OAAM,EAAG,SAAQ;EACrC,kBAAkB,EAAE,OAAM,EAAG,SAAQ,EAAG,SAAS,mCAAmC;EACpF,UAAU;;AAKZ,eAAsB,gBAAgB,MAAkB;AACtD,SAAO,QAAQ,YAAW;AACxB,QAAI,CAAC,aAAa,KAAK,KAAK,GAAG;AAC7B,YAAM,cAAc,eAAc,GAC5B,UAAU,YAAY,KAAK,OAAO,aAAa,CAAC,GAChD,cAAwB,CAAC,2BAA2B,mBAAmB,WAAW,CAAC,EAAE;AAC3F,YAAI,QAAQ,SAAS,KAAG,YAAY,QAAQ,iBAAiB,QAAQ,KAAK,MAAM,CAAC,GAAG,GAC9E,IAAI,SAAS,kBAAkB,KAAK,KAAK,KAAK,cAAc,MAAM,WAAW;IACrF;AAEA,QAAI,CAAC,gBAAgB,KAAK,OAAO,KAAK,IAAI,GAAG;AAE3C,YAAM,YADiB,qBAAqB,KAAK,KAAK,EACrB,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAI,GAClD,UAAU,YAAY,KAAK,MAAM,WAAW,CAAC,GAC7C,cAAwB,CAAC,mBAAmB,KAAK,KAAK,KAAK,mBAAmB,SAAS,CAAC,EAAE;AAChG,YAAI,QAAQ,SAAS,KAAG,YAAY,QAAQ,iBAAiB,QAAQ,KAAK,MAAM,CAAC,GAAG,GAC9E,IAAI,SAAS,yBAAyB,KAAK,IAAI,gBAAgB,KAAK,KAAK,KAAK,cAAc,MAAM,WAAW;IACrH;AAEA,UAAM,eAAe,kBAAkB,KAAK,OAAO,KAAK,IAAI,GACtD,cAAc,kBAAkB,KAAK,OAAO,cAAc,KAAK,IAAI,GACnE,cAAc,aAAY;AAGhC,QAAI,CADa,YAAY,MAAM,GAAG,EAAE,CAAC;AAEvC,YAAM,IAAI,SAAS,iDAAiD,KAAK,IAAI,KAAK,cAAc,MAAM;QACpG;OACD;AAGH,mCAA+B,MAAM,KAAK;AAE1C,UAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,GAIrC,aAAa,MAAM,cAAa,EAAG,SAAS,KAAK,KAAK;AAC5D,QAAI,WAAW,MAAM,MAAM,SAAS,KAAK,KAAK,GAC1C,aAAa;AACjB,IAAK,aACH,WAAW,IAAI,MAAM,KAAK,KAAK,GAC/B,aAAa;AAGf,UAAM,OAAM,oBAAI,KAAI,GAAG,YAAW,GAC5B,UAAU,IAAI,QAAQ;MAC1B,IAAI;MACJ,MAAM;MACN,cAAc,GAAG,KAAK,KAAK,IAAI,YAAY;MAC3C,UAAU,KAAK;MACf,MAAM;MACN,MAAM,KAAK;MACX,aAAa,KAAK;MAClB,YAAY,KAAK,cAAc,CAAA;MAC/B,UAAU;QACR,YAAY;QACZ,YAAY;QACZ,SAAS;;MAEX,OAAO,KAAK;KACb,GAEK,YAAY,qBAAqB,IAAI;AAC3C,IAAI,aACF,QAAQ,mBAAmB,SAAS;AAGtC;AACE,YAAM,kBAAkB,IAAI,gBAAe,GACrC,YAAY,IAAI,MAAM,KAAK,KAAK;AACtC,gBAAU,WAAW,OAAO;AAC5B,YAAM,iBAAiB,MAAM,gBAAgB,cAAc,SAAS;AACpE,UAAI,CAAC,eAAe,QAAO,GAAI;AAC7B,cAAM,gBAAgB,eAAe,OAAO,IAAI,CAAC,MAAM,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK;CAAI;AAClF,cAAM,IAAI,SAAS,WAAW,WAAW;EAA6B,aAAa,IAAI,cAAc,MAAM;UACzG,iBAAiB,OAAO,KAAK,OAAO,YAAY;SACjD;MACH;IACF;AAEA,QAAI,SAAS,WAAW,WAAW;AACjC,YAAM,IAAI,SAAS,WAAW,WAAW,sBAAsB,KAAK,KAAK,UAAU,cAAc,MAAM;QACrG;QACA;QACA;OACD;AAGH,IAAI,cACF,MAAM,SAAS,QAAQ;AAGzB,UAAM,kBAAkB,IAAI,gBAAgB,OAAO,aAAa,KAAK,KAAK;AAC1E,UAAM,gBAAgB,WAAW,SAAS,CAAC,SAAQ;AACjD,eAAU,WAAW,IAAI;IAC3B,CAAC;AAGD,UAAM,kBAAkB,MADD,gBAAgB,kBAAiB,EACX,UAAS,GAChD,SAAS,CAAC,EAAE,mBAAmB,gBAAgB,WAAW;AAChE,WAAI,UAAU,CAAC,cAGb,MAAM,YAAY,KAAK,QAAQ,GAG1B,WAAW;MAChB,QAAQ,SAAS,WAAW;MAC5B,WAAW,SAAS,gBAAiB,OAAO;MAC5C,IAAI;MACJ,OAAO,KAAK;MACZ,MAAM;MACN,MAAM,KAAK;KACZ;EACH,CAAC;AACH;AAEO,MAAM,eAAsD;EACjE,MAAM;EACN,aAAa;EACb;EACA,SAAS;;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,7 +4,7 @@ import { MutationHandler } from "../../core/mutation-handler.js";
|
|
|
4
4
|
import { ReferenceRegistry } from "../../core/reference-registry.js";
|
|
5
5
|
import { findElementLayer } from "../../utils/element-utils.js";
|
|
6
6
|
import { CLIError, ErrorCategory, getErrorMessage } from "../../utils/errors.js";
|
|
7
|
-
import { jsonResult, loadModel, rootPathSchema, runTool } from "./shared.js";
|
|
7
|
+
import { jsonResult, loadModel, reloadModel, rootPathSchema, runTool } from "./shared.js";
|
|
8
8
|
const inputSchema = {
|
|
9
9
|
id: z.string().describe("Element ID or path to delete."),
|
|
10
10
|
cascade: z.boolean().optional().describe("Also delete elements that depend on this one."),
|
|
@@ -76,7 +76,7 @@ async function modelDeleteHandler(args) {
|
|
|
76
76
|
const mutationHandler = new MutationHandler(model, args.id, layerName);
|
|
77
77
|
await mutationHandler.executeDelete(element);
|
|
78
78
|
const activeChangeset = await mutationHandler.getStagingManager().getActive(), staged = !!(activeChangeset && activeChangeset.status === "staged");
|
|
79
|
-
return jsonResult({
|
|
79
|
+
return staged && await reloadModel(args.rootPath), jsonResult({
|
|
80
80
|
status: staged ? "staged" : "deleted",
|
|
81
81
|
changeset: staged ? activeChangeset.name : void 0,
|
|
82
82
|
id: args.id,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/mcp/tools/model-delete.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * model_delete \u2014 delete an element (optionally cascading to dependents).\n * Mirrors `dr delete`, but since an MCP session has no interactive confirmation\n * channel, the caller must pass `force` or `cascade` explicitly when dependents\n * exist rather than being prompted; operates through the shared MutationHandler.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { DependencyTracker, TraceDirection } from \"../../core/dependency-tracker.js\";\nimport { MutationHandler } from \"../../core/mutation-handler.js\";\nimport { ReferenceRegistry } from \"../../core/reference-registry.js\";\nimport { findElementLayer } from \"../../utils/element-utils.js\";\nimport { CLIError, ErrorCategory, getErrorMessage } 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 delete.\"),\n cascade: z.boolean().optional().describe(\"Also delete elements that depend on this one.\"),\n force: z.boolean().optional().describe(\"Skip the dependency check and delete only this element, even if others depend on it.\"),\n dryRun: z.boolean().optional().describe(\"Preview what would be deleted without making changes.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelDeleteArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelDeleteHandler(args: ModelDeleteArgs): 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 const layer = (await model.getLayer(layerName))!;\n const element = layer.getElement(args.id);\n if (!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 // Cascade is scoped to cross-layer references only, matching `dr delete`. This is\n // narrower than \"model_trace\", which also follows intra-layer relationships.yaml\n // edges \u2014 a dependent found by model_trace may not be included in a cascade delete.\n const registry = new ReferenceRegistry();\n for (const l of model.layers.values()) {\n for (const el of l.listElements()) {\n registry.registerElement(el);\n }\n }\n const tracker = new DependencyTracker(registry, model);\n const dependents = tracker.traceDependencies(args.id, TraceDirection.DOWN, null);\n\n if (dependents.length > 0 && !args.cascade && !args.force) {\n throw new CLIError(\"Element has dependencies\", ErrorCategory.USER, [\n \"Use cascade=true to remove all dependent elements\",\n \"Use dryRun=true with cascade=true to preview what would be deleted\",\n \"Or use force=true to remove only this element (dependencies will reference a non-existent element)\",\n ]);\n }\n\n const elementsToRemove = args.cascade ? [args.id, ...dependents] : [args.id];\n\n if (args.dryRun) {\n return jsonResult({\n status: \"dry-run\",\n id: args.id,\n layer: layerName,\n elementsToRemove,\n });\n }\n\n let deletedCount = 0;\n const skippedDependents: string[] = [];\n const cascadeDeleted: string[] = [];\n if (args.cascade && dependents.length > 0) {\n for (const depId of [...dependents].reverse()) {\n const depLayerName = await findElementLayer(model, depId);\n if (!depLayerName) {\n console.error(`[mcp] model_delete: cascade dependent \"${depId}\" not found, skipping`);\n skippedDependents.push(depId);\n continue;\n }\n\n const depLayer = (await model.getLayer(depLayerName))!;\n const depElement = depLayer.getElement(depId);\n if (!depElement) {\n console.error(`[mcp] model_delete: cascade dependent \"${depId}\" not found, skipping`);\n skippedDependents.push(depId);\n continue;\n }\n\n const depHandler = new MutationHandler(model, depId, depLayerName);\n try {\n await depHandler.executeDelete(depElement);\n } catch (error) {\n throw new CLIError(\n `Failed to delete dependent element \"${depId}\": ${getErrorMessage(error)}`,\n ErrorCategory.SYSTEM,\n [\n `${cascadeDeleted.length} dependent element(s) were deleted before the error`,\n 'Use \"model_validate\" to check the model for broken references',\n `\"${args.id}\" was not deleted \u2014 you can retry the operation once dependents are resolved`,\n ],\n {\n operation: \"model_delete (cascade)\",\n relatedElements: cascadeDeleted,\n partialProgress: { completed: cascadeDeleted.length, total: dependents.length },\n }\n );\n }\n cascadeDeleted.push(depId);\n deletedCount++;\n }\n }\n\n const mutationHandler = new MutationHandler(model, args.id, layerName);\n await mutationHandler.executeDelete(element);\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\" : \"deleted\",\n changeset: staged ? activeChangeset!.name : undefined,\n id: args.id,\n layer: layerName,\n cascadedDeletes: deletedCount,\n ...(skippedDependents.length > 0 ? { skippedDependents } : {}),\n });\n });\n}\n\nexport const modelDeleteTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_delete\",\n description: \"Delete an element, optionally cascading to elements that depend on it.\",\n inputSchema,\n handler: modelDeleteHandler,\n};\n"],
|
|
5
|
-
"mappings": "AAOA,SAAS,SAAS;AAElB,SAAS,mBAAmB,sBAAsB;AAClD,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,wBAAwB;AACjC,SAAS,UAAU,eAAe,uBAAuB;AACzD,SAAS,YAAY,WAAW,gBAAgB,eAAuC;
|
|
4
|
+
"sourcesContent": ["/**\n * model_delete \u2014 delete an element (optionally cascading to dependents).\n * Mirrors `dr delete`, but since an MCP session has no interactive confirmation\n * channel, the caller must pass `force` or `cascade` explicitly when dependents\n * exist rather than being prompted; operates through the shared MutationHandler.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { DependencyTracker, TraceDirection } from \"../../core/dependency-tracker.js\";\nimport { MutationHandler } from \"../../core/mutation-handler.js\";\nimport { ReferenceRegistry } from \"../../core/reference-registry.js\";\nimport { findElementLayer } from \"../../utils/element-utils.js\";\nimport { CLIError, ErrorCategory, getErrorMessage } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, reloadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n id: z.string().describe(\"Element ID or path to delete.\"),\n cascade: z.boolean().optional().describe(\"Also delete elements that depend on this one.\"),\n force: z.boolean().optional().describe(\"Skip the dependency check and delete only this element, even if others depend on it.\"),\n dryRun: z.boolean().optional().describe(\"Preview what would be deleted without making changes.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelDeleteArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelDeleteHandler(args: ModelDeleteArgs): 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 const layer = (await model.getLayer(layerName))!;\n const element = layer.getElement(args.id);\n if (!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 // Cascade is scoped to cross-layer references only, matching `dr delete`. This is\n // narrower than \"model_trace\", which also follows intra-layer relationships.yaml\n // edges \u2014 a dependent found by model_trace may not be included in a cascade delete.\n const registry = new ReferenceRegistry();\n for (const l of model.layers.values()) {\n for (const el of l.listElements()) {\n registry.registerElement(el);\n }\n }\n const tracker = new DependencyTracker(registry, model);\n const dependents = tracker.traceDependencies(args.id, TraceDirection.DOWN, null);\n\n if (dependents.length > 0 && !args.cascade && !args.force) {\n throw new CLIError(\"Element has dependencies\", ErrorCategory.USER, [\n \"Use cascade=true to remove all dependent elements\",\n \"Use dryRun=true with cascade=true to preview what would be deleted\",\n \"Or use force=true to remove only this element (dependencies will reference a non-existent element)\",\n ]);\n }\n\n const elementsToRemove = args.cascade ? [args.id, ...dependents] : [args.id];\n\n if (args.dryRun) {\n return jsonResult({\n status: \"dry-run\",\n id: args.id,\n layer: layerName,\n elementsToRemove,\n });\n }\n\n let deletedCount = 0;\n const skippedDependents: string[] = [];\n const cascadeDeleted: string[] = [];\n if (args.cascade && dependents.length > 0) {\n for (const depId of [...dependents].reverse()) {\n const depLayerName = await findElementLayer(model, depId);\n if (!depLayerName) {\n console.error(`[mcp] model_delete: cascade dependent \"${depId}\" not found, skipping`);\n skippedDependents.push(depId);\n continue;\n }\n\n const depLayer = (await model.getLayer(depLayerName))!;\n const depElement = depLayer.getElement(depId);\n if (!depElement) {\n console.error(`[mcp] model_delete: cascade dependent \"${depId}\" not found, skipping`);\n skippedDependents.push(depId);\n continue;\n }\n\n const depHandler = new MutationHandler(model, depId, depLayerName);\n try {\n await depHandler.executeDelete(depElement);\n } catch (error) {\n throw new CLIError(\n `Failed to delete dependent element \"${depId}\": ${getErrorMessage(error)}`,\n ErrorCategory.SYSTEM,\n [\n `${cascadeDeleted.length} dependent element(s) were deleted before the error`,\n 'Use \"model_validate\" to check the model for broken references',\n `\"${args.id}\" was not deleted \u2014 you can retry the operation once dependents are resolved`,\n ],\n {\n operation: \"model_delete (cascade)\",\n relatedElements: cascadeDeleted,\n partialProgress: { completed: cascadeDeleted.length, total: dependents.length },\n }\n );\n }\n cascadeDeleted.push(depId);\n deletedCount++;\n }\n }\n\n const mutationHandler = new MutationHandler(model, args.id, layerName);\n await mutationHandler.executeDelete(element);\n\n const stagingManager = mutationHandler.getStagingManager();\n const activeChangeset = await stagingManager.getActive();\n const staged = !!(activeChangeset && activeChangeset.status === \"staged\");\n // The cached model's merged relationships still hold the rows the delete just staged for\n // removal; reload so later reads (model_validate, model_export) see the plan.\n if (staged) await reloadModel(args.rootPath);\n\n return jsonResult({\n status: staged ? \"staged\" : \"deleted\",\n changeset: staged ? activeChangeset!.name : undefined,\n id: args.id,\n layer: layerName,\n cascadedDeletes: deletedCount,\n ...(skippedDependents.length > 0 ? { skippedDependents } : {}),\n });\n });\n}\n\nexport const modelDeleteTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_delete\",\n description: \"Delete an element, optionally cascading to elements that depend on it.\",\n inputSchema,\n handler: modelDeleteHandler,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { ChangesetGraph } from "../../core/changeset-graph.js";
|
|
3
|
+
import { StagingAreaManager } from "../../core/staging-area.js";
|
|
4
|
+
import { activeStagedChangeset } from "./changeset-shared.js";
|
|
2
5
|
import { getAllLayerIds, isValidLayer } from "../../generated/layer-registry.js";
|
|
3
6
|
import { NODE_TYPES } from "../../generated/node-types.js";
|
|
4
7
|
import { CLIError, ErrorCategory, findSimilar, formatValidOptions } from "../../utils/errors.js";
|
|
@@ -67,6 +70,17 @@ async function modelSearchHandler(args) {
|
|
|
67
70
|
});
|
|
68
71
|
}
|
|
69
72
|
}
|
|
73
|
+
const active = await activeStagedChangeset(new StagingAreaManager(model.rootPath, model));
|
|
74
|
+
if (active) {
|
|
75
|
+
const graph = await ChangesetGraph.build(model, active);
|
|
76
|
+
return jsonResult({
|
|
77
|
+
query: args.query ?? "",
|
|
78
|
+
sourceFile: args.sourceFile,
|
|
79
|
+
changeset: { id: active.id, name: active.name },
|
|
80
|
+
count: results.length,
|
|
81
|
+
results: results.map((r) => ({ ...r, changeStatus: graph.getElement(r.id)?.status ?? "unchanged" }))
|
|
82
|
+
});
|
|
83
|
+
}
|
|
70
84
|
return jsonResult({
|
|
71
85
|
query: args.query ?? "",
|
|
72
86
|
sourceFile: args.sourceFile,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/mcp/tools/model-search.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * model_search \u2014 search for elements across the model by name/ID substring or\n * source file reference. Mirrors `dr search`.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Element } from \"../../core/element.js\";\nimport { getAllLayerIds, isValidLayer } from \"../../generated/layer-registry.js\";\nimport { NODE_TYPES } from \"../../generated/node-types.js\";\nimport { CLIError, ErrorCategory, findSimilar, formatValidOptions } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n query: z\n .string()\n .optional()\n .describe(\"Text to match against element ID and name (case-insensitive substring). Ignored when sourceFile is set.\"),\n layer: z.string().optional().describe(\"Restrict search to a single layer.\"),\n type: z.string().optional().describe(\"Restrict search to a single element type.\"),\n sourceFile: z.string().optional().describe(\"Find elements whose source_reference points at this file path.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelSearchArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nfunction normalizePath(filePath: string): string {\n return filePath.replace(/^\\.\\//, \"\").replace(/\\\\/g, \"/\");\n}\n\nfunction matchesSourceFile(element: Element, sourceFilePath: string): boolean {\n const sourceRef = element.getSourceReference();\n if (!sourceRef) return false;\n\n const normalizedQuery = normalizePath(sourceFilePath);\n return (sourceRef.locations ?? []).some((loc) => normalizePath(loc.file) === normalizedQuery);\n}\n\nexport async function modelSearchHandler(args: ModelSearchArgs): Promise<CallToolResult> {\n return runTool(async () => {\n if (!args.query && !args.sourceFile && !args.layer && !args.type) {\n throw new CLIError(\n \"At least one of query, sourceFile, layer, or type must be provided\",\n ErrorCategory.USER,\n ['Use \"model_list\" to list all elements without filtering']\n );\n }\n\n if (args.layer && !isValidLayer(args.layer)) {\n const validLayers = getAllLayerIds();\n const similar = findSimilar(args.layer, validLayers, 3);\n const suggestions: string[] = [`Use a valid layer name: ${formatValidOptions(validLayers)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Unknown layer \"${args.layer}\"`, ErrorCategory.USER, suggestions);\n }\n\n if (args.type) {\n const candidateTypes = args.layer\n ? Array.from(NODE_TYPES.values()).filter((t) => t.layer === args.layer)\n : Array.from(NODE_TYPES.values());\n const isKnownType = candidateTypes.some((t) => t.type === args.type);\n if (!isKnownType) {\n const validTypeNames = Array.from(new Set(candidateTypes.map((t) => t.type))).sort();\n const similar = findSimilar(args.type, validTypeNames, 3);\n const suggestions: string[] = [\n args.layer\n ? `Valid types for ${args.layer}: ${formatValidOptions(validTypeNames)}`\n : `Valid types: ${formatValidOptions(validTypeNames)}`,\n ];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(\n `Unknown element type \"${args.type}\"${args.layer ? ` for layer \"${args.layer}\"` : \"\"}`,\n ErrorCategory.USER,\n suggestions\n );\n }\n }\n\n const model = await loadModel(args.rootPath);\n const isSourceFileSearch = !!args.sourceFile;\n const queryLower = (args.query ?? \"\").toLowerCase();\n\n const results: Array<{\n layer: string;\n id: string;\n type: string;\n name: string;\n description?: string;\n sourceFile?: string;\n sourceSymbol?: string;\n }> = [];\n\n for (const layerName of model.getLayerNames()) {\n if (args.layer && layerName !== args.layer) continue;\n\n const layerObj = await model.getLayer(layerName);\n if (!layerObj) continue;\n\n for (const element of layerObj.listElements()) {\n if (args.type && element.type !== args.type) continue;\n\n if (isSourceFileSearch) {\n if (!matchesSourceFile(element, args.sourceFile!)) continue;\n } else {\n const displayId = element.path || element.id;\n const idMatch = displayId.toLowerCase().includes(queryLower);\n const nameMatch = element.name.toLowerCase().includes(queryLower);\n if (!idMatch && !nameMatch) continue;\n }\n\n let sourceFile: string | undefined;\n let sourceSymbol: string | undefined;\n const sourceRef = element.getSourceReference();\n if (sourceRef?.locations && sourceRef.locations.length > 0) {\n sourceFile = sourceRef.locations[0].file;\n sourceSymbol = sourceRef.locations[0].symbol;\n }\n\n results.push({\n layer: layerName,\n id: element.path || element.id,\n type: element.type,\n name: element.name,\n description: element.description,\n sourceFile,\n sourceSymbol,\n });\n }\n }\n\n return jsonResult({\n query: args.query ?? \"\",\n sourceFile: args.sourceFile,\n count: results.length,\n results,\n });\n });\n}\n\nexport const modelSearchTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_search\",\n description: \"Search for elements across the model by name/ID substring or by source file reference.\",\n inputSchema,\n handler: modelSearchHandler,\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * model_search \u2014 search for elements across the model by name/ID substring or\n * source file reference. Mirrors `dr search`.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Element } from \"../../core/element.js\";\nimport { ChangesetGraph } from \"../../core/changeset-graph.js\";\nimport { StagingAreaManager } from \"../../core/staging-area.js\";\nimport { activeStagedChangeset } from \"./changeset-shared.js\";\nimport { getAllLayerIds, isValidLayer } from \"../../generated/layer-registry.js\";\nimport { NODE_TYPES } from \"../../generated/node-types.js\";\nimport { CLIError, ErrorCategory, findSimilar, formatValidOptions } from \"../../utils/errors.js\";\nimport { jsonResult, loadModel, rootPathSchema, runTool, type McpToolDefinition } from \"./shared.js\";\n\nconst inputSchema = {\n query: z\n .string()\n .optional()\n .describe(\"Text to match against element ID and name (case-insensitive substring). Ignored when sourceFile is set.\"),\n layer: z.string().optional().describe(\"Restrict search to a single layer.\"),\n type: z.string().optional().describe(\"Restrict search to a single element type.\"),\n sourceFile: z.string().optional().describe(\"Find elements whose source_reference points at this file path.\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelSearchArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nfunction normalizePath(filePath: string): string {\n return filePath.replace(/^\\.\\//, \"\").replace(/\\\\/g, \"/\");\n}\n\nfunction matchesSourceFile(element: Element, sourceFilePath: string): boolean {\n const sourceRef = element.getSourceReference();\n if (!sourceRef) return false;\n\n const normalizedQuery = normalizePath(sourceFilePath);\n return (sourceRef.locations ?? []).some((loc) => normalizePath(loc.file) === normalizedQuery);\n}\n\nexport async function modelSearchHandler(args: ModelSearchArgs): Promise<CallToolResult> {\n return runTool(async () => {\n if (!args.query && !args.sourceFile && !args.layer && !args.type) {\n throw new CLIError(\n \"At least one of query, sourceFile, layer, or type must be provided\",\n ErrorCategory.USER,\n ['Use \"model_list\" to list all elements without filtering']\n );\n }\n\n if (args.layer && !isValidLayer(args.layer)) {\n const validLayers = getAllLayerIds();\n const similar = findSimilar(args.layer, validLayers, 3);\n const suggestions: string[] = [`Use a valid layer name: ${formatValidOptions(validLayers)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Unknown layer \"${args.layer}\"`, ErrorCategory.USER, suggestions);\n }\n\n if (args.type) {\n const candidateTypes = args.layer\n ? Array.from(NODE_TYPES.values()).filter((t) => t.layer === args.layer)\n : Array.from(NODE_TYPES.values());\n const isKnownType = candidateTypes.some((t) => t.type === args.type);\n if (!isKnownType) {\n const validTypeNames = Array.from(new Set(candidateTypes.map((t) => t.type))).sort();\n const similar = findSimilar(args.type, validTypeNames, 3);\n const suggestions: string[] = [\n args.layer\n ? `Valid types for ${args.layer}: ${formatValidOptions(validTypeNames)}`\n : `Valid types: ${formatValidOptions(validTypeNames)}`,\n ];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(\n `Unknown element type \"${args.type}\"${args.layer ? ` for layer \"${args.layer}\"` : \"\"}`,\n ErrorCategory.USER,\n suggestions\n );\n }\n }\n\n const model = await loadModel(args.rootPath);\n const isSourceFileSearch = !!args.sourceFile;\n const queryLower = (args.query ?? \"\").toLowerCase();\n\n const results: Array<{\n layer: string;\n id: string;\n type: string;\n name: string;\n description?: string;\n sourceFile?: string;\n sourceSymbol?: string;\n }> = [];\n\n for (const layerName of model.getLayerNames()) {\n if (args.layer && layerName !== args.layer) continue;\n\n const layerObj = await model.getLayer(layerName);\n if (!layerObj) continue;\n\n for (const element of layerObj.listElements()) {\n if (args.type && element.type !== args.type) continue;\n\n if (isSourceFileSearch) {\n if (!matchesSourceFile(element, args.sourceFile!)) continue;\n } else {\n const displayId = element.path || element.id;\n const idMatch = displayId.toLowerCase().includes(queryLower);\n const nameMatch = element.name.toLowerCase().includes(queryLower);\n if (!idMatch && !nameMatch) continue;\n }\n\n let sourceFile: string | undefined;\n let sourceSymbol: string | undefined;\n const sourceRef = element.getSourceReference();\n if (sourceRef?.locations && sourceRef.locations.length > 0) {\n sourceFile = sourceRef.locations[0].file;\n sourceSymbol = sourceRef.locations[0].symbol;\n }\n\n results.push({\n layer: layerName,\n id: element.path || element.id,\n type: element.type,\n name: element.name,\n description: element.description,\n sourceFile,\n sourceSymbol,\n });\n }\n }\n\n // Inside an active changeset, say which results the changeset adds or updates.\n const active = await activeStagedChangeset(new StagingAreaManager(model.rootPath, model));\n if (active) {\n const graph = await ChangesetGraph.build(model, active);\n return jsonResult({\n query: args.query ?? \"\",\n sourceFile: args.sourceFile,\n changeset: { id: active.id, name: active.name },\n count: results.length,\n results: results.map((r) => ({ ...r, changeStatus: graph.getElement(r.id)?.status ?? \"unchanged\" })),\n });\n }\n\n return jsonResult({\n query: args.query ?? \"\",\n sourceFile: args.sourceFile,\n count: results.length,\n results,\n });\n });\n}\n\nexport const modelSearchTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_search\",\n description: \"Search for elements across the model by name/ID substring or by source file reference.\",\n inputSchema,\n handler: modelSearchHandler,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { ChangesetGraph } from "../../core/changeset-graph.js";
|
|
3
|
+
import { StagingAreaManager } from "../../core/staging-area.js";
|
|
2
4
|
import { findElementLayer } from "../../utils/element-utils.js";
|
|
5
|
+
import { activeStagedChangeset } from "./changeset-shared.js";
|
|
3
6
|
import { CLIError, ErrorCategory } from "../../utils/errors.js";
|
|
4
7
|
import { jsonResult, loadModel, rootPathSchema, runTool } from "./shared.js";
|
|
5
8
|
const inputSchema = {
|
|
@@ -20,7 +23,31 @@ async function modelShowHandler(args) {
|
|
|
20
23
|
'Use "model_search" to find similar elements',
|
|
21
24
|
'Use "model_list" to list all elements in a layer'
|
|
22
25
|
]);
|
|
23
|
-
const elementId = element.path || element.id,
|
|
26
|
+
const elementId = element.path || element.id, active = await activeStagedChangeset(new StagingAreaManager(model.rootPath, model));
|
|
27
|
+
if (active) {
|
|
28
|
+
const graph = await ChangesetGraph.build(model, active), graphElement = graph.getElement(elementId), neighbors = graph.neighbors(elementId, { includeDeleted: !0 }), row = (n) => {
|
|
29
|
+
const rel = n.relationship;
|
|
30
|
+
return {
|
|
31
|
+
source: rel.source,
|
|
32
|
+
predicate: rel.predicate,
|
|
33
|
+
target: rel.target,
|
|
34
|
+
layer: rel.layer,
|
|
35
|
+
...rel.targetLayer ? { targetLayer: rel.targetLayer } : {},
|
|
36
|
+
...rel.properties ? { properties: rel.properties } : {},
|
|
37
|
+
status: rel.status
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
return jsonResult({
|
|
41
|
+
layer: layerName,
|
|
42
|
+
element: element.toJSON(),
|
|
43
|
+
changeset: { id: active.id, name: active.name, elementStatus: graphElement?.status ?? "unchanged" },
|
|
44
|
+
relationships: {
|
|
45
|
+
outgoing: neighbors.filter((n) => n.direction === "out").map(row),
|
|
46
|
+
incoming: neighbors.filter((n) => n.direction === "in").map(row)
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const { outgoing, incoming } = model.relationships.getForElement(elementId);
|
|
24
51
|
return jsonResult({
|
|
25
52
|
layer: layerName,
|
|
26
53
|
element: element.toJSON(),
|
|
@@ -30,7 +57,7 @@ async function modelShowHandler(args) {
|
|
|
30
57
|
}
|
|
31
58
|
const modelShowTool = {
|
|
32
59
|
name: "model_show",
|
|
33
|
-
description: "Show a single element's full details, attributes, and relationships.",
|
|
60
|
+
description: "Show a single element's full details, attributes, and relationships. Inside an active changeset the relationships include staged ones, each with a status (added, deleted, unchanged).",
|
|
34
61
|
inputSchema,
|
|
35
62
|
handler: modelShowHandler
|
|
36
63
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/mcp/tools/model-show.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * model_show \u2014 show a single element with its relationships. Mirrors `dr show`.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.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 (e.g. 'api.operation.create-order').\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelShowArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelShowHandler(args: ModelShowArgs): 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 'Use \"model_list\" to list all elements in a layer',\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 'Use \"model_list\" to list all elements in a layer',\n ]);\n }\n\n const elementId = element.path || element.id;\n const { outgoing, incoming } = model.relationships.getForElement(elementId);\n\n return jsonResult({\n layer: layerName,\n element: element.toJSON(),\n relationships: { outgoing, incoming },\n });\n });\n}\n\nexport const modelShowTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_show\",\n description
|
|
5
|
-
"mappings": "AAIA,SAAS,SAAS;AAElB,SAAS,wBAAwB;AACjC,SAAS,UAAU,qBAAqB;AACxC,SAAS,YAAY,WAAW,gBAAgB,eAAuC;AAEvF,MAAM,cAAc;EAClB,IAAI,EAAE,OAAM,EAAG,SAAS,yDAAyD;EACjF,UAAU;;AAKZ,eAAsB,iBAAiB,MAAmB;AACxD,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;QACA;OACD;AAGH,UAAM,QAAQ,MAAM,MAAM,SAAS,SAAS,GACtC,UAAU,OAAO,WAAW,KAAK,EAAE;AACzC,QAAI,CAAC,SAAS,CAAC;AACb,YAAM,IAAI,SAAS,WAAW,KAAK,EAAE,cAAc,cAAc,WAAW;QAC1E;QACA;OACD;AAGH,UAAM,YAAY,QAAQ,QAAQ,QAAQ,
|
|
4
|
+
"sourcesContent": ["/**\n * model_show \u2014 show a single element with its relationships. Mirrors `dr show`.\n */\n\nimport { z } from \"zod\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { ChangesetGraph } from \"../../core/changeset-graph.js\";\nimport { StagingAreaManager } from \"../../core/staging-area.js\";\nimport { findElementLayer } from \"../../utils/element-utils.js\";\nimport { activeStagedChangeset } from \"./changeset-shared.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 (e.g. 'api.operation.create-order').\"),\n rootPath: rootPathSchema,\n};\n\nexport type ModelShowArgs = z.infer<z.ZodObject<typeof inputSchema>>;\n\nexport async function modelShowHandler(args: ModelShowArgs): 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 'Use \"model_list\" to list all elements in a layer',\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 'Use \"model_list\" to list all elements in a layer',\n ]);\n }\n\n const elementId = element.path || element.id;\n\n // Inside an active changeset, show the element's relationships as the changeset leaves them:\n // staged additions included, staged removals marked, each with its change status.\n const active = await activeStagedChangeset(new StagingAreaManager(model.rootPath, model));\n if (active) {\n const graph = await ChangesetGraph.build(model, active);\n const graphElement = graph.getElement(elementId);\n const neighbors = graph.neighbors(elementId, { includeDeleted: true });\n const row = (n: (typeof neighbors)[number]) => {\n const rel = n.relationship;\n return {\n source: rel.source,\n predicate: rel.predicate,\n target: rel.target,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n ...(rel.properties ? { properties: rel.properties } : {}),\n status: rel.status,\n };\n };\n return jsonResult({\n layer: layerName,\n element: element.toJSON(),\n changeset: { id: active.id, name: active.name, elementStatus: graphElement?.status ?? \"unchanged\" },\n relationships: {\n outgoing: neighbors.filter((n) => n.direction === \"out\").map(row),\n incoming: neighbors.filter((n) => n.direction === \"in\").map(row),\n },\n });\n }\n\n const { outgoing, incoming } = model.relationships.getForElement(elementId);\n\n return jsonResult({\n layer: layerName,\n element: element.toJSON(),\n relationships: { outgoing, incoming },\n });\n });\n}\n\nexport const modelShowTool: McpToolDefinition<typeof inputSchema> = {\n name: \"model_show\",\n description:\n \"Show a single element's full details, attributes, and relationships. Inside an active changeset the \" +\n \"relationships include staged ones, each with a status (added, deleted, unchanged).\",\n inputSchema,\n handler: modelShowHandler,\n};\n"],
|
|
5
|
+
"mappings": "AAIA,SAAS,SAAS;AAElB,SAAS,sBAAsB;AAC/B,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,6BAA6B;AACtC,SAAS,UAAU,qBAAqB;AACxC,SAAS,YAAY,WAAW,gBAAgB,eAAuC;AAEvF,MAAM,cAAc;EAClB,IAAI,EAAE,OAAM,EAAG,SAAS,yDAAyD;EACjF,UAAU;;AAKZ,eAAsB,iBAAiB,MAAmB;AACxD,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;QACA;OACD;AAGH,UAAM,QAAQ,MAAM,MAAM,SAAS,SAAS,GACtC,UAAU,OAAO,WAAW,KAAK,EAAE;AACzC,QAAI,CAAC,SAAS,CAAC;AACb,YAAM,IAAI,SAAS,WAAW,KAAK,EAAE,cAAc,cAAc,WAAW;QAC1E;QACA;OACD;AAGH,UAAM,YAAY,QAAQ,QAAQ,QAAQ,IAIpC,SAAS,MAAM,sBAAsB,IAAI,mBAAmB,MAAM,UAAU,KAAK,CAAC;AACxF,QAAI,QAAQ;AACV,YAAM,QAAQ,MAAM,eAAe,MAAM,OAAO,MAAM,GAChD,eAAe,MAAM,WAAW,SAAS,GACzC,YAAY,MAAM,UAAU,WAAW,EAAE,gBAAgB,GAAI,CAAE,GAC/D,MAAM,CAAC,MAAiC;AAC5C,cAAM,MAAM,EAAE;AACd,eAAO;UACL,QAAQ,IAAI;UACZ,WAAW,IAAI;UACf,QAAQ,IAAI;UACZ,OAAO,IAAI;UACX,GAAI,IAAI,cAAc,EAAE,aAAa,IAAI,YAAW,IAAK,CAAA;UACzD,GAAI,IAAI,aAAa,EAAE,YAAY,IAAI,WAAU,IAAK,CAAA;UACtD,QAAQ,IAAI;;MAEhB;AACA,aAAO,WAAW;QAChB,OAAO;QACP,SAAS,QAAQ,OAAM;QACvB,WAAW,EAAE,IAAI,OAAO,IAAI,MAAM,OAAO,MAAM,eAAe,cAAc,UAAU,YAAW;QACjG,eAAe;UACb,UAAU,UAAU,OAAO,CAAC,MAAM,EAAE,cAAc,KAAK,EAAE,IAAI,GAAG;UAChE,UAAU,UAAU,OAAO,CAAC,MAAM,EAAE,cAAc,IAAI,EAAE,IAAI,GAAG;;OAElE;IACH;AAEA,UAAM,EAAE,UAAU,SAAQ,IAAK,MAAM,cAAc,cAAc,SAAS;AAE1E,WAAO,WAAW;MAChB,OAAO;MACP,SAAS,QAAQ,OAAM;MACvB,eAAe,EAAE,UAAU,SAAQ;KACpC;EACH,CAAC;AACH;AAEO,MAAM,gBAAuD;EAClE,MAAM;EACN,aACE;EAEF;EACA,SAAS;;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|