@documentation-robotics/cli 0.1.13 → 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 +74 -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/analyzers/verify-engine.js +22 -19
- package/dist/analyzers/verify-engine.js.map +2 -2
- 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 +112 -28
- package/dist/cli.js.map +3 -3
- package/dist/coding-agents/agents/claude-code.js +3 -1
- package/dist/coding-agents/agents/claude-code.js.map +2 -2
- package/dist/coding-agents/claude-code-client.js +2 -1
- package/dist/coding-agents/claude-code-client.js.map +2 -2
- package/dist/coding-agents/copilot-client.js +17 -12
- package/dist/coding-agents/copilot-client.js.map +2 -2
- package/dist/coding-agents/default-permissions.js +152 -0
- package/dist/coding-agents/default-permissions.js.map +7 -0
- package/dist/coding-agents/drbot-mcp.js +167 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +12 -7
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +134 -23
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/audit.js +6 -6
- package/dist/commands/audit.js.map +2 -2
- package/dist/commands/changeset-verify.js +55 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +261 -147
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/delete.js +52 -19
- package/dist/commands/delete.js.map +3 -3
- package/dist/commands/element.js +3 -2
- package/dist/commands/element.js.map +2 -2
- package/dist/commands/farm.js +773 -0
- package/dist/commands/farm.js.map +7 -0
- package/dist/commands/init.js +11 -1
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +122 -0
- package/dist/commands/mcp.js.map +7 -0
- package/dist/commands/relationship.js +251 -47
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +56 -24
- 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/validate.js +41 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +2 -2
- package/dist/commands/version.js.map +2 -2
- package/dist/commands/visualize.js +4 -3
- package/dist/commands/visualize.js.map +2 -2
- package/dist/config.js +83 -0
- package/dist/config.js.map +7 -0
- package/dist/core/annotation-store.js +138 -0
- package/dist/core/annotation-store.js.map +7 -0
- package/dist/core/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 +140 -0
- package/dist/core/farm-manifest.js.map +7 -0
- package/dist/core/farm-sync-engine.js +346 -0
- package/dist/core/farm-sync-engine.js.map +7 -0
- package/dist/core/farm-sync-state.js +167 -0
- package/dist/core/farm-sync-state.js.map +7 -0
- package/dist/core/manifest.js +6 -3
- package/dist/core/manifest.js.map +2 -2
- package/dist/core/migration-registry.js +84 -1
- 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 +257 -44
- package/dist/core/model.js.map +3 -3
- 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 +14 -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 +2209 -7727
- 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 +79 -0
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +52 -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 +111 -0
- package/dist/mcp/api-key-manager.js.map +7 -0
- package/dist/mcp/changeset-only.js +34 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/http-transport.js +176 -0
- package/dist/mcp/http-transport.js.map +7 -0
- package/dist/mcp/resource-registry.js +97 -0
- package/dist/mcp/resource-registry.js.map +7 -0
- package/dist/mcp/tool-registry.js +60 -0
- package/dist/mcp/tool-registry.js.map +7 -0
- package/dist/mcp/tools/annotation-create.js +39 -0
- package/dist/mcp/tools/annotation-create.js.map +7 -0
- package/dist/mcp/tools/annotation-delete.js +29 -0
- package/dist/mcp/tools/annotation-delete.js.map +7 -0
- package/dist/mcp/tools/annotation-get.js +29 -0
- package/dist/mcp/tools/annotation-get.js.map +7 -0
- package/dist/mcp/tools/annotation-list.js +24 -0
- package/dist/mcp/tools/annotation-list.js.map +7 -0
- package/dist/mcp/tools/annotation-reply.js +34 -0
- package/dist/mcp/tools/annotation-reply.js.map +7 -0
- package/dist/mcp/tools/annotation-shared.js +10 -0
- package/dist/mcp/tools/annotation-shared.js.map +7 -0
- package/dist/mcp/tools/annotation-update.js +39 -0
- package/dist/mcp/tools/annotation-update.js.map +7 -0
- package/dist/mcp/tools/changeset-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-list.js +33 -0
- package/dist/mcp/tools/changeset-list.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 +55 -0
- package/dist/mcp/tools/changeset-show.js.map +7 -0
- package/dist/mcp/tools/changeset-verify.js +43 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/chat-launch.js +50 -0
- package/dist/mcp/tools/chat-launch.js.map +7 -0
- package/dist/mcp/tools/chat-status.js +26 -0
- package/dist/mcp/tools/chat-status.js.map +7 -0
- package/dist/mcp/tools/index.js +65 -0
- package/dist/mcp/tools/index.js.map +7 -0
- package/dist/mcp/tools/model-add.js +107 -0
- package/dist/mcp/tools/model-add.js.map +7 -0
- package/dist/mcp/tools/model-delete.js +99 -0
- package/dist/mcp/tools/model-delete.js.map +7 -0
- package/dist/mcp/tools/model-export.js +72 -0
- package/dist/mcp/tools/model-export.js.map +7 -0
- package/dist/mcp/tools/model-info.js +51 -0
- package/dist/mcp/tools/model-info.js.map +7 -0
- package/dist/mcp/tools/model-list.js +53 -0
- package/dist/mcp/tools/model-list.js.map +7 -0
- package/dist/mcp/tools/model-reload.js +34 -0
- package/dist/mcp/tools/model-reload.js.map +7 -0
- package/dist/mcp/tools/model-search.js +102 -0
- package/dist/mcp/tools/model-search.js.map +7 -0
- package/dist/mcp/tools/model-show.js +68 -0
- package/dist/mcp/tools/model-show.js.map +7 -0
- package/dist/mcp/tools/model-stats.js +22 -0
- package/dist/mcp/tools/model-stats.js.map +7 -0
- package/dist/mcp/tools/model-trace.js +118 -0
- package/dist/mcp/tools/model-trace.js.map +7 -0
- package/dist/mcp/tools/model-update.js +121 -0
- package/dist/mcp/tools/model-update.js.map +7 -0
- package/dist/mcp/tools/model-validate.js +78 -0
- package/dist/mcp/tools/model-validate.js.map +7 -0
- package/dist/mcp/tools/relationship-tools.js +98 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/shared.js +126 -0
- package/dist/mcp/tools/shared.js.map +7 -0
- package/dist/mcp/tools/spec-type.js +90 -0
- package/dist/mcp/tools/spec-type.js.map +7 -0
- package/dist/reports/model-layer-report-generator.js +5 -3
- package/dist/reports/model-layer-report-generator.js.map +2 -2
- package/dist/reports/model-readme-generator.js +116 -0
- package/dist/reports/model-readme-generator.js.map +7 -0
- package/dist/reports/model-report-data.js +37 -1
- package/dist/reports/model-report-data.js.map +2 -2
- package/dist/reports/model-report-orchestrator.js +29 -6
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/reports/model-report-utils.js +9 -0
- package/dist/reports/model-report-utils.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +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 +745 -370
- package/dist/schemas/bundled/base.json +3 -220
- package/dist/schemas/bundled/business.json +452 -366
- package/dist/schemas/bundled/data-model.json +403 -383
- 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 +234 -31
- 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/config.js +2 -40
- package/dist/telemetry/config.js.map +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/types/index.js.map +2 -2
- package/dist/utils/ansi-suppressor.js +23 -0
- package/dist/utils/ansi-suppressor.js.map +7 -0
- package/dist/utils/attribute-patch.js +41 -0
- package/dist/utils/attribute-patch.js.map +7 -0
- package/dist/utils/color-utils.js +34 -0
- package/dist/utils/color-utils.js.map +7 -0
- package/dist/utils/element-reference-shape.js +15 -1
- package/dist/utils/element-reference-shape.js.map +3 -3
- package/dist/utils/error-hints.js +29 -0
- package/dist/utils/error-hints.js.map +7 -0
- package/dist/utils/errors.js +75 -10
- package/dist/utils/errors.js.map +2 -2
- package/dist/utils/globals.js +17 -1
- package/dist/utils/globals.js.map +2 -2
- package/dist/utils/project-paths.js +50 -3
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/reference-path-parser.js +49 -0
- package/dist/utils/reference-path-parser.js.map +7 -0
- package/dist/utils/source-reference.js +17 -10
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +10 -2
- package/dist/utils/spec-version.js.map +2 -2
- package/dist/validators/composed-reference-validator.js +240 -0
- package/dist/validators/composed-reference-validator.js.map +7 -0
- package/dist/validators/reference-validator.js +57 -13
- package/dist/validators/reference-validator.js.map +3 -3
- package/dist/validators/relationship-schema-validator.js +33 -5
- package/dist/validators/relationship-schema-validator.js.map +3 -3
- 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 +7 -3
- package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
- package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
package/dist/server/schemas.js
CHANGED
|
@@ -146,6 +146,13 @@ const SimpleWSMessageSchema = z.object({
|
|
|
146
146
|
}), ChangesetsListSchema = z.object({
|
|
147
147
|
version: z.string(),
|
|
148
148
|
changesets: z.record(z.string(), ChangesetMetadataSchema)
|
|
149
|
+
}), ChangesetActionResultSchema = z.object({
|
|
150
|
+
id: z.string(),
|
|
151
|
+
name: z.string(),
|
|
152
|
+
status: z.enum(["staged", "committed", "discarded"]),
|
|
153
|
+
committed: z.number().optional().describe("Changes applied to the model (commit only)"),
|
|
154
|
+
skipped: z.number().optional().describe("Changes skipped as already present (commit only)"),
|
|
155
|
+
failed: z.number().optional().describe("Changes that failed to apply (commit only)")
|
|
149
156
|
}), ChangesetDetailSchema = z.object({
|
|
150
157
|
id: z.string(),
|
|
151
158
|
name: z.string(),
|
|
@@ -177,6 +184,7 @@ export {
|
|
|
177
184
|
AnnotationSchema,
|
|
178
185
|
AnnotationUpdateSchema,
|
|
179
186
|
AnnotationsListSchema,
|
|
187
|
+
ChangesetActionResultSchema,
|
|
180
188
|
ChangesetDetailSchema,
|
|
181
189
|
ChangesetMetadataSchema,
|
|
182
190
|
ChangesetsListSchema,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/server/schemas.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from '@hono/zod-openapi';\nimport { CANONICAL_LAYER_NAMES } from '../core/layers.js';\n\n/**\n * Branded type for ElementId\n * Provides compile-time safety by distinguishing ElementId from plain strings\n * Use with parseElementId() to validate and brand a string at runtime\n *\n * This type is exported as a public API contract for external consumers who want\n * to use strong typing in their code. However, internal server.ts implementation\n * uses plain string keys in Maps and other internal structures for simplicity.\n *\n * USAGE PATTERNS:\n * - External/public APIs: Type function parameters with ElementId for contract clarity\n * - Internal state: Use plain strings in Maps/Sets for performance and simplicity\n * - Validation: Use parseElementId() to validate untrusted input\n * - Type guards: Use isElementId() for optional runtime type checking\n *\n * Example:\n * const brandedId = parseElementId(\"motivation.goal.customer-satisfaction\");\n * function processElement(id: ElementId) { ... } // Type-safe public API\n *\n * // Internal implementation can use plain strings:\n * private annotations: Map<string, Annotation> = new Map();\n */\nexport type ElementId = string & { readonly __brand: 'ElementId' };\n\n/**\n * Parse and validate a string as an ElementId\n * Returns a branded type for compile-time type safety\n */\nexport function parseElementId(input: string): ElementId {\n const result = ElementIdSchema.safeParse(input);\n if (!result.success) {\n const errorMessages = result.error.issues.map(issue => issue.message).join('; ');\n throw new Error(`Invalid element ID: ${errorMessages}`);\n }\n return result.data as ElementId;\n}\n\n/**\n * Type guard for ElementId\n * Use with function parameters for optional compile-time checking\n */\nexport function isElementId(value: unknown): value is ElementId {\n return typeof value === 'string' && ElementIdSchema.safeParse(value).success;\n}\n\n// WebSocket message schemas with runtime validation\nexport const SimpleWSMessageSchema = z.object({\n type: z.enum(['subscribe', 'annotate', 'ping']),\n topics: z.array(z.string()).optional(),\n annotation: z.object({\n elementId: z.string(),\n author: z.string(),\n text: z.string(),\n timestamp: z.string(),\n }).optional(),\n});\n\nexport const JSONRPCRequestSchema = z.object({\n jsonrpc: z.literal('2.0'),\n method: z.string(),\n params: z.unknown().optional(),\n id: z.union([z.string(), z.number()]).optional(),\n});\n\nexport const JSONRPCResponseSchema = z.object({\n jsonrpc: z.literal('2.0'),\n result: z.unknown().optional(),\n error: z.object({\n code: z.number(),\n message: z.string(),\n data: z.unknown().optional(),\n }).optional(),\n id: z.union([z.string(), z.number(), z.null()]),\n}).refine(\n (data) => (data.result !== undefined) !== (data.error !== undefined),\n {\n message: \"JSON-RPC 2.0 response must contain either 'result' or 'error', not both\",\n path: [\"response\"],\n }\n);\n\nexport const WSMessageSchema = z.union([\n SimpleWSMessageSchema,\n JSONRPCRequestSchema,\n JSONRPCResponseSchema,\n]);\n\n// Base schemas for common types\n// Enforces three-part element ID format: layer.type.name\n// - layer: canonical layer name (e.g., motivation, api, data-store)\n// - type: lowercase element type (e.g., goal, endpoint, entity)\n// - name: kebab-case element name (e.g., customer-satisfaction)\n//\n// Example valid IDs:\n// - motivation.goal.customer-satisfaction\n// - api.endpoint.create-order\n// - data-store.table.user-profile\n// - a.b.c (minimal single-character segments, valid for testing purposes)\n// - ux.a.test (two-character segments are valid)\nexport const ElementIdSchema = z.string()\n .min(1, 'Element ID is required')\n .regex(\n /^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$/,\n 'Invalid element ID format. Must be: layer.type.name (e.g., motivation.goal.customer-satisfaction)'\n );\n\nexport const TimestampSchema = z.string().datetime();\n\n/**\n * Tag validation schema.\n *\n * Format: lowercase alphanumeric with optional internal hyphens\n * Pattern: /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/\n *\n * Constraints:\n * - Cannot start or end with hyphens: Prevents URL slugification issues and confusion with CLI flags (e.g., --tag-name)\n * - Single character tags allowed (e.g., \"a\", \"1\") via the second alternation\n * - Matches common tag conventions (GitHub labels, NPM tags, etc.)\n *\n * Examples:\n * - \u2705 \"api-critical\"\n * - \u2705 \"high-priority\"\n * - \u2705 \"p0\"\n * - \u274C \"-api-critical\" (starts with hyphen)\n * - \u274C \"api-critical-\" (ends with hyphen)\n * - \u274C \"API-CRITICAL\" (uppercase not allowed)\n */\nexport const TagSchema = z.string()\n .min(1, 'Tag cannot be empty')\n .max(50, 'Tag too long')\n .regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/, 'Tag must contain only lowercase letters, digits, and hyphens');\n\n// Annotation schemas - for creating annotations\nexport const AnnotationCreateSchema = z.object({\n elementId: ElementIdSchema,\n author: z.string()\n .min(1, 'Author is required')\n .max(100, 'Author name too long')\n .optional()\n .default('Anonymous'),\n content: z.string()\n .min(1, 'Content is required')\n .max(5000, 'Content too long'),\n tags: z.array(TagSchema).optional().default([]),\n}).strict();\n\n// Annotation schemas - for updating annotations\nexport const AnnotationUpdateSchema = z.object({\n content: z.string()\n .min(1, 'Content is required')\n .max(5000, 'Content too long')\n .optional(),\n tags: z.array(TagSchema).optional(),\n resolved: z.boolean().optional(),\n}).strict().refine(\n (obj) => Object.keys(obj).some(key => obj[key as keyof typeof obj] !== undefined),\n 'At least one field must be provided for update'\n);\n\n// Annotation schemas - for creating replies\nexport const AnnotationReplyCreateSchema = z.object({\n author: z.string()\n .min(1, 'Author is required')\n .max(100, 'Author name too long'),\n content: z.string()\n .min(1, 'Content is required')\n .max(5000, 'Content too long'),\n}).strict();\n\n// Layer name schema - validates against canonical layer names\nexport const LayerNameSchema = z.enum(CANONICAL_LAYER_NAMES, {\n message: `Invalid layer name. Must be one of: ${CANONICAL_LAYER_NAMES.join(', ')}`\n});\n\n// ID schema - validates generic IDs for annotations, changesets, and other non-element identifiers\n// Accepts lowercase alphanumeric characters, hyphens, and underscores\n// Note: Different from ElementIdSchema which requires dot-separated format (layer.type.name)\n//\n// Lowercase-only constraint rationale:\n// - Provides case-insensitive ID lookups by normalizing to lowercase at validation time\n// - Prevents collisions (MyId vs myid cannot coexist in same namespace)\n// - System-generated IDs comply; externally-generated uppercase IDs will be rejected\n// - If external systems need uppercase support, IDs should be normalized before API transmission\n// - Consider implementing ID normalization in API middleware if integration with external systems is required\nexport const IdSchema = z.string()\n .min(1, 'ID is required')\n .regex(/^[a-z0-9_-]+$/, 'Invalid ID format. Must contain only lowercase alphanumeric characters, hyphens, and underscores');\n\n// Annotation filter schema - validates query parameters for GET /api/annotations\n// Currently only supports filtering by elementId\n// UNIMPLEMENTED FILTERS: author, tags, and resolved fields are defined here but filtering is not yet implemented.\n// See /workspace/cli/src/server/server.ts:650-651 for implementation details.\n// These fields are reserved for future extensibility and currently ignored by the handler.\nexport const AnnotationFilterSchema = z.object({\n elementId: ElementIdSchema.optional(),\n author: z.string().optional(),\n tags: z.string().optional(),\n resolved: z.enum(['true', 'false']).optional(),\n}).strict(); // Validate only declared fields\n\n// Response schemas for OpenAPI documentation\nexport const ErrorResponseSchema = z.object({\n error: z.string().describe('Error message'),\n});\n\nexport const HealthResponseSchema = z.object({\n status: z.string().describe('Server health status'),\n version: z.string().describe('API version'),\n});\n\nexport const AnnotationSchema = z.object({\n id: z.string().describe('Annotation ID'),\n elementId: ElementIdSchema.describe('Target element ID'),\n author: z.string().describe('Author name'),\n content: z.string().describe('Annotation content'),\n createdAt: z.string().describe('Creation timestamp'),\n updatedAt: z.string().optional().describe('Last update timestamp'),\n tags: z.array(z.string()).optional().describe('Annotation tags'),\n resolved: z.boolean().optional().describe('Resolution status'),\n replies: z.array(z.object({\n id: z.string(),\n author: z.string(),\n content: z.string(),\n createdAt: z.string(),\n })).optional().describe('Annotation replies'),\n});\n\nexport const AnnotationReplySchema = z.object({\n id: z.string().describe('Reply ID'),\n author: z.string().describe('Author name'),\n content: z.string().describe('Reply content'),\n createdAt: z.string().describe('Creation timestamp'),\n});\n\nexport const AnnotationsListSchema = z.object({\n annotations: z.array(AnnotationSchema).describe('List of annotations'),\n});\n\nexport const AnnotationRepliesSchema = z.object({\n replies: z.array(AnnotationReplySchema).describe('List of replies'),\n});\n\nexport const LayerResponseSchema = z.object({\n name: z.string().describe('Layer name'),\n elements: z.array(z.object({}).passthrough()).describe('Layer elements (each element is an object with id, name, type, and properties)'),\n elementCount: z.number().describe('Total element count'),\n});\n\nexport const GraphNodeSchema = z.object({\n id: z.string().describe('Element ID (UUID)'),\n spec_node_id: z.string().describe('Spec node type ID (e.g. motivation.goal)'),\n type: z.string().describe('Element type (e.g. goal, endpoint)'),\n layer_id: z.string().describe('Layer this element belongs to'),\n name: z.string().describe('Element display name'),\n description: z.string().optional().describe('Element description'),\n attributes: z.record(z.string(), z.unknown()).optional()\n .describe('Typed attribute bag per spec-node schema'),\n source_reference: z.object({\n provenance: z.enum(['extracted', 'manual', 'inferred', 'generated']),\n locations: z.array(z.object({\n file: z.string(),\n symbol: z.string().optional(),\n })),\n repository: z.object({\n url: z.string().optional(),\n commit: z.string().optional(),\n }).optional(),\n }).optional().describe('Source code provenance linking this element to its implementation'),\n metadata: z.object({\n created_at: z.string().optional(),\n updated_at: z.string().optional(),\n created_by: z.string().optional(),\n version: z.number().optional(),\n }).optional().describe('Element lifecycle metadata (timestamps, version)'),\n properties: z.record(z.string(), z.unknown()).optional()\n .describe('Legacy property bag (deprecated \u2014 prefer attributes)'),\n});\n\nexport const GraphLinkSchema = z.object({\n id: z.string().describe('Stable link ID derived from source, target, and type'),\n source: z.string().describe('Source element ID'),\n target: z.string().describe('Target element ID'),\n type: z.string().describe('Relationship predicate or reference type'),\n // Intra-layer links carry layer_id; cross-layer links carry source/target layer IDs\n layer_id: z.string().optional().describe('Layer ID for intra-layer relationships'),\n source_layer_id: z.string().optional().describe('Source layer ID for cross-layer references'),\n target_layer_id: z.string().optional().describe('Target layer ID for cross-layer references'),\n});\n\nexport const ModelResponseSchema = z.object({\n nodes: z.array(GraphNodeSchema).describe('All architecture elements across all layers'),\n links: z.array(GraphLinkSchema).describe('Intra-layer relationships and cross-layer references'),\n});\n\nexport const SpecResponseSchema = z.object({\n version: z.string().describe('Spec version'),\n type: z.string().describe('Response type'),\n description: z.string().describe('Response description'),\n source: z.string().describe('Schema source'),\n schemas: z.record(z.string(), z.unknown()).describe('JSON schema definitions (each schema is a JSON Schema object)'),\n schemaCount: z.number().describe('Number of schemas'),\n});\n\nexport const ChangesetMetadataSchema = z.object({\n name: z.string(),\n status: z.enum(['staged', 'committed', 'discarded'] as const),\n created: z.string(),\n changes_count: z.number(),\n});\n\nexport const ChangesetsListSchema = z.object({\n version: z.string(),\n changesets: z.record(z.string(), ChangesetMetadataSchema),\n});\n\nexport const ChangesetDetailSchema = z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().optional(),\n status: z.enum(['staged', 'committed', 'discarded'] as const),\n created: z.string(),\n modified: z.string(),\n baseSnapshot: z.string().optional(),\n stats: z.object({\n additions: z.number(),\n modifications: z.number(),\n deletions: z.number(),\n }),\n changes: z.array(z.object({\n type: z.enum(['add', 'update', 'delete'] as const),\n elementId: z.string(),\n layerName: z.string(),\n timestamp: z.string().optional(),\n before: z.unknown().optional().describe('Previous element state (for update/delete operations)'),\n after: z.unknown().optional().describe('New element state (for add/update operations)'),\n })),\n});\n\n// Type inference from input schemas\nexport type AnnotationCreate = z.infer<typeof AnnotationCreateSchema>;\nexport type AnnotationUpdate = z.infer<typeof AnnotationUpdateSchema>;\nexport type AnnotationReplyCreate = z.infer<typeof AnnotationReplyCreateSchema>;\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { z } from '@hono/zod-openapi';\nimport { CANONICAL_LAYER_NAMES } from '../core/layers.js';\n\n/**\n * Branded type for ElementId\n * Provides compile-time safety by distinguishing ElementId from plain strings\n * Use with parseElementId() to validate and brand a string at runtime\n *\n * This type is exported as a public API contract for external consumers who want\n * to use strong typing in their code. However, internal server.ts implementation\n * uses plain string keys in Maps and other internal structures for simplicity.\n *\n * USAGE PATTERNS:\n * - External/public APIs: Type function parameters with ElementId for contract clarity\n * - Internal state: Use plain strings in Maps/Sets for performance and simplicity\n * - Validation: Use parseElementId() to validate untrusted input\n * - Type guards: Use isElementId() for optional runtime type checking\n *\n * Example:\n * const brandedId = parseElementId(\"motivation.goal.customer-satisfaction\");\n * function processElement(id: ElementId) { ... } // Type-safe public API\n *\n * // Internal implementation can use plain strings:\n * private annotations: Map<string, Annotation> = new Map();\n */\nexport type ElementId = string & { readonly __brand: 'ElementId' };\n\n/**\n * Parse and validate a string as an ElementId\n * Returns a branded type for compile-time type safety\n */\nexport function parseElementId(input: string): ElementId {\n const result = ElementIdSchema.safeParse(input);\n if (!result.success) {\n const errorMessages = result.error.issues.map(issue => issue.message).join('; ');\n throw new Error(`Invalid element ID: ${errorMessages}`);\n }\n return result.data as ElementId;\n}\n\n/**\n * Type guard for ElementId\n * Use with function parameters for optional compile-time checking\n */\nexport function isElementId(value: unknown): value is ElementId {\n return typeof value === 'string' && ElementIdSchema.safeParse(value).success;\n}\n\n// WebSocket message schemas with runtime validation\nexport const SimpleWSMessageSchema = z.object({\n type: z.enum(['subscribe', 'annotate', 'ping']),\n topics: z.array(z.string()).optional(),\n annotation: z.object({\n elementId: z.string(),\n author: z.string(),\n text: z.string(),\n timestamp: z.string(),\n }).optional(),\n});\n\nexport const JSONRPCRequestSchema = z.object({\n jsonrpc: z.literal('2.0'),\n method: z.string(),\n params: z.unknown().optional(),\n id: z.union([z.string(), z.number()]).optional(),\n});\n\nexport const JSONRPCResponseSchema = z.object({\n jsonrpc: z.literal('2.0'),\n result: z.unknown().optional(),\n error: z.object({\n code: z.number(),\n message: z.string(),\n data: z.unknown().optional(),\n }).optional(),\n id: z.union([z.string(), z.number(), z.null()]),\n}).refine(\n (data) => (data.result !== undefined) !== (data.error !== undefined),\n {\n message: \"JSON-RPC 2.0 response must contain either 'result' or 'error', not both\",\n path: [\"response\"],\n }\n);\n\nexport const WSMessageSchema = z.union([\n SimpleWSMessageSchema,\n JSONRPCRequestSchema,\n JSONRPCResponseSchema,\n]);\n\n// Base schemas for common types\n// Enforces three-part element ID format: layer.type.name\n// - layer: canonical layer name (e.g., motivation, api, data-store)\n// - type: lowercase element type (e.g., goal, endpoint, entity)\n// - name: kebab-case element name (e.g., customer-satisfaction)\n//\n// Example valid IDs:\n// - motivation.goal.customer-satisfaction\n// - api.endpoint.create-order\n// - data-store.table.user-profile\n// - a.b.c (minimal single-character segments, valid for testing purposes)\n// - ux.a.test (two-character segments are valid)\nexport const ElementIdSchema = z.string()\n .min(1, 'Element ID is required')\n .regex(\n /^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$/,\n 'Invalid element ID format. Must be: layer.type.name (e.g., motivation.goal.customer-satisfaction)'\n );\n\nexport const TimestampSchema = z.string().datetime();\n\n/**\n * Tag validation schema.\n *\n * Format: lowercase alphanumeric with optional internal hyphens\n * Pattern: /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/\n *\n * Constraints:\n * - Cannot start or end with hyphens: Prevents URL slugification issues and confusion with CLI flags (e.g., --tag-name)\n * - Single character tags allowed (e.g., \"a\", \"1\") via the second alternation\n * - Matches common tag conventions (GitHub labels, NPM tags, etc.)\n *\n * Examples:\n * - \u2705 \"api-critical\"\n * - \u2705 \"high-priority\"\n * - \u2705 \"p0\"\n * - \u274C \"-api-critical\" (starts with hyphen)\n * - \u274C \"api-critical-\" (ends with hyphen)\n * - \u274C \"API-CRITICAL\" (uppercase not allowed)\n */\nexport const TagSchema = z.string()\n .min(1, 'Tag cannot be empty')\n .max(50, 'Tag too long')\n .regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/, 'Tag must contain only lowercase letters, digits, and hyphens');\n\n// Annotation schemas - for creating annotations\nexport const AnnotationCreateSchema = z.object({\n elementId: ElementIdSchema,\n author: z.string()\n .min(1, 'Author is required')\n .max(100, 'Author name too long')\n .optional()\n .default('Anonymous'),\n content: z.string()\n .min(1, 'Content is required')\n .max(5000, 'Content too long'),\n tags: z.array(TagSchema).optional().default([]),\n}).strict();\n\n// Annotation schemas - for updating annotations\nexport const AnnotationUpdateSchema = z.object({\n content: z.string()\n .min(1, 'Content is required')\n .max(5000, 'Content too long')\n .optional(),\n tags: z.array(TagSchema).optional(),\n resolved: z.boolean().optional(),\n}).strict().refine(\n (obj) => Object.keys(obj).some(key => obj[key as keyof typeof obj] !== undefined),\n 'At least one field must be provided for update'\n);\n\n// Annotation schemas - for creating replies\nexport const AnnotationReplyCreateSchema = z.object({\n author: z.string()\n .min(1, 'Author is required')\n .max(100, 'Author name too long'),\n content: z.string()\n .min(1, 'Content is required')\n .max(5000, 'Content too long'),\n}).strict();\n\n// Layer name schema - validates against canonical layer names\nexport const LayerNameSchema = z.enum(CANONICAL_LAYER_NAMES, {\n message: `Invalid layer name. Must be one of: ${CANONICAL_LAYER_NAMES.join(', ')}`\n});\n\n// ID schema - validates generic IDs for annotations, changesets, and other non-element identifiers\n// Accepts lowercase alphanumeric characters, hyphens, and underscores\n// Note: Different from ElementIdSchema which requires dot-separated format (layer.type.name)\n//\n// Lowercase-only constraint rationale:\n// - Provides case-insensitive ID lookups by normalizing to lowercase at validation time\n// - Prevents collisions (MyId vs myid cannot coexist in same namespace)\n// - System-generated IDs comply; externally-generated uppercase IDs will be rejected\n// - If external systems need uppercase support, IDs should be normalized before API transmission\n// - Consider implementing ID normalization in API middleware if integration with external systems is required\nexport const IdSchema = z.string()\n .min(1, 'ID is required')\n .regex(/^[a-z0-9_-]+$/, 'Invalid ID format. Must contain only lowercase alphanumeric characters, hyphens, and underscores');\n\n// Annotation filter schema - validates query parameters for GET /api/annotations\n// Currently only supports filtering by elementId\n// UNIMPLEMENTED FILTERS: author, tags, and resolved fields are defined here but filtering is not yet implemented.\n// See /workspace/cli/src/server/server.ts:650-651 for implementation details.\n// These fields are reserved for future extensibility and currently ignored by the handler.\nexport const AnnotationFilterSchema = z.object({\n elementId: ElementIdSchema.optional(),\n author: z.string().optional(),\n tags: z.string().optional(),\n resolved: z.enum(['true', 'false']).optional(),\n}).strict(); // Validate only declared fields\n\n// Response schemas for OpenAPI documentation\nexport const ErrorResponseSchema = z.object({\n error: z.string().describe('Error message'),\n});\n\nexport const HealthResponseSchema = z.object({\n status: z.string().describe('Server health status'),\n version: z.string().describe('API version'),\n});\n\nexport const AnnotationSchema = z.object({\n id: z.string().describe('Annotation ID'),\n elementId: ElementIdSchema.describe('Target element ID'),\n author: z.string().describe('Author name'),\n content: z.string().describe('Annotation content'),\n createdAt: z.string().describe('Creation timestamp'),\n updatedAt: z.string().optional().describe('Last update timestamp'),\n tags: z.array(z.string()).optional().describe('Annotation tags'),\n resolved: z.boolean().optional().describe('Resolution status'),\n replies: z.array(z.object({\n id: z.string(),\n author: z.string(),\n content: z.string(),\n createdAt: z.string(),\n })).optional().describe('Annotation replies'),\n});\n\nexport const AnnotationReplySchema = z.object({\n id: z.string().describe('Reply ID'),\n author: z.string().describe('Author name'),\n content: z.string().describe('Reply content'),\n createdAt: z.string().describe('Creation timestamp'),\n});\n\nexport const AnnotationsListSchema = z.object({\n annotations: z.array(AnnotationSchema).describe('List of annotations'),\n});\n\nexport const AnnotationRepliesSchema = z.object({\n replies: z.array(AnnotationReplySchema).describe('List of replies'),\n});\n\nexport const LayerResponseSchema = z.object({\n name: z.string().describe('Layer name'),\n elements: z.array(z.object({}).passthrough()).describe('Layer elements (each element is an object with id, name, type, and properties)'),\n elementCount: z.number().describe('Total element count'),\n});\n\nexport const GraphNodeSchema = z.object({\n id: z.string().describe('Element ID (UUID)'),\n spec_node_id: z.string().describe('Spec node type ID (e.g. motivation.goal)'),\n type: z.string().describe('Element type (e.g. goal, endpoint)'),\n layer_id: z.string().describe('Layer this element belongs to'),\n name: z.string().describe('Element display name'),\n description: z.string().optional().describe('Element description'),\n attributes: z.record(z.string(), z.unknown()).optional()\n .describe('Typed attribute bag per spec-node schema'),\n source_reference: z.object({\n provenance: z.enum(['extracted', 'manual', 'inferred', 'generated']),\n locations: z.array(z.object({\n file: z.string(),\n symbol: z.string().optional(),\n })),\n repository: z.object({\n url: z.string().optional(),\n commit: z.string().optional(),\n }).optional(),\n }).optional().describe('Source code provenance linking this element to its implementation'),\n metadata: z.object({\n created_at: z.string().optional(),\n updated_at: z.string().optional(),\n created_by: z.string().optional(),\n version: z.number().optional(),\n }).optional().describe('Element lifecycle metadata (timestamps, version)'),\n properties: z.record(z.string(), z.unknown()).optional()\n .describe('Legacy property bag (deprecated \u2014 prefer attributes)'),\n});\n\nexport const GraphLinkSchema = z.object({\n id: z.string().describe('Stable link ID derived from source, target, and type'),\n source: z.string().describe('Source element ID'),\n target: z.string().describe('Target element ID'),\n type: z.string().describe('Relationship predicate or reference type'),\n // Intra-layer links carry layer_id; cross-layer links carry source/target layer IDs\n layer_id: z.string().optional().describe('Layer ID for intra-layer relationships'),\n source_layer_id: z.string().optional().describe('Source layer ID for cross-layer references'),\n target_layer_id: z.string().optional().describe('Target layer ID for cross-layer references'),\n});\n\nexport const ModelResponseSchema = z.object({\n nodes: z.array(GraphNodeSchema).describe('All architecture elements across all layers'),\n links: z.array(GraphLinkSchema).describe('Intra-layer relationships and cross-layer references'),\n});\n\nexport const SpecResponseSchema = z.object({\n version: z.string().describe('Spec version'),\n type: z.string().describe('Response type'),\n description: z.string().describe('Response description'),\n source: z.string().describe('Schema source'),\n schemas: z.record(z.string(), z.unknown()).describe('JSON schema definitions (each schema is a JSON Schema object)'),\n schemaCount: z.number().describe('Number of schemas'),\n});\n\nexport const ChangesetMetadataSchema = z.object({\n name: z.string(),\n status: z.enum(['staged', 'committed', 'discarded'] as const),\n created: z.string(),\n changes_count: z.number(),\n});\n\nexport const ChangesetsListSchema = z.object({\n version: z.string(),\n changesets: z.record(z.string(), ChangesetMetadataSchema),\n});\n\nexport const ChangesetActionResultSchema = z.object({\n id: z.string(),\n name: z.string(),\n status: z.enum(['staged', 'committed', 'discarded'] as const),\n committed: z.number().optional().describe('Changes applied to the model (commit only)'),\n skipped: z.number().optional().describe('Changes skipped as already present (commit only)'),\n failed: z.number().optional().describe('Changes that failed to apply (commit only)'),\n});\n\nexport const ChangesetDetailSchema = z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().optional(),\n status: z.enum(['staged', 'committed', 'discarded'] as const),\n created: z.string(),\n modified: z.string(),\n baseSnapshot: z.string().optional(),\n stats: z.object({\n additions: z.number(),\n modifications: z.number(),\n deletions: z.number(),\n }),\n changes: z.array(z.object({\n type: z.enum(['add', 'update', 'delete'] as const),\n elementId: z.string(),\n layerName: z.string(),\n timestamp: z.string().optional(),\n before: z.unknown().optional().describe('Previous element state (for update/delete operations)'),\n after: z.unknown().optional().describe('New element state (for add/update operations)'),\n })),\n});\n\n// Type inference from input schemas\nexport type AnnotationCreate = z.infer<typeof AnnotationCreateSchema>;\nexport type AnnotationUpdate = z.infer<typeof AnnotationUpdateSchema>;\nexport type AnnotationReplyCreate = z.infer<typeof AnnotationReplyCreateSchema>;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/server/server.js
CHANGED
|
@@ -12,13 +12,17 @@ import path from "path";
|
|
|
12
12
|
const require2 = createRequire(import.meta.url);
|
|
13
13
|
import { Model } from "../core/model.js";
|
|
14
14
|
import { StagedChangesetStorage } from "../core/staged-changeset-storage.js";
|
|
15
|
+
import { StagingAreaManager } from "../core/staging-area.js";
|
|
15
16
|
import { CANONICAL_LAYER_NAMES } from "../core/layers.js";
|
|
16
17
|
import { telemetryMiddleware } from "./telemetry-middleware.js";
|
|
17
18
|
import { ClaudeCodeClient } from "../coding-agents/claude-code-client.js";
|
|
18
19
|
import { CopilotClient } from "../coding-agents/copilot-client.js";
|
|
19
20
|
import { detectAvailableClients, selectChatClient } from "../coding-agents/chat-utils.js";
|
|
21
|
+
import { formatForClaudeCode, formatForClaudeCodeWithChangesets, applyCopilotPermissions, CHANGESET_ONLY_ENV } from "../coding-agents/default-permissions.js";
|
|
22
|
+
import { DR_ARCHITECT_AGENT, checkInstalledAgentMcpTools, drBotMcpPrompt, drMcpAllowedTools, prepareDrMcpLaunch } from "../coding-agents/drbot-mcp.js";
|
|
23
|
+
import { ApiKeyManager } from "../mcp/api-key-manager.js";
|
|
20
24
|
import { getErrorMessage } from "../utils/errors.js";
|
|
21
|
-
import { AnnotationCreateSchema, AnnotationUpdateSchema, AnnotationReplyCreateSchema, LayerNameSchema, IdSchema, AnnotationFilterSchema, ErrorResponseSchema, HealthResponseSchema, AnnotationSchema, AnnotationReplySchema, AnnotationsListSchema, ChangesetsListSchema, ChangesetDetailSchema, ModelResponseSchema, LayerResponseSchema, SpecResponseSchema, AnnotationRepliesSchema, WSMessageSchema } from "./schemas.js";
|
|
25
|
+
import { AnnotationCreateSchema, AnnotationUpdateSchema, AnnotationReplyCreateSchema, LayerNameSchema, IdSchema, AnnotationFilterSchema, ErrorResponseSchema, HealthResponseSchema, AnnotationSchema, AnnotationReplySchema, AnnotationsListSchema, ChangesetsListSchema, ChangesetDetailSchema, ChangesetActionResultSchema, ModelResponseSchema, LayerResponseSchema, SpecResponseSchema, AnnotationRepliesSchema, WSMessageSchema } from "./schemas.js";
|
|
22
26
|
const JSONRPC_ERRORS = {
|
|
23
27
|
// Standard JSON-RPC errors
|
|
24
28
|
INVALID_PARAMS: -32602,
|
|
@@ -53,6 +57,8 @@ class VisualizationServer {
|
|
|
53
57
|
authEnabled = !0;
|
|
54
58
|
withDanger = !1;
|
|
55
59
|
// Danger mode disabled by default
|
|
60
|
+
withChangesets = !1;
|
|
61
|
+
// Changeset-only write mode disabled by default
|
|
56
62
|
viewerPath;
|
|
57
63
|
// Optional custom viewer path
|
|
58
64
|
activeChatProcesses = /* @__PURE__ */ new Map();
|
|
@@ -64,6 +70,12 @@ class VisualizationServer {
|
|
|
64
70
|
// Store initialization error for status endpoint
|
|
65
71
|
_testClaudeCmdOverride;
|
|
66
72
|
_testCopilotCmdOverride;
|
|
73
|
+
/** Test hook: prepare DrBot's MCP launch with these (fake key, scratch dirs) even under _testClaudeCmdOverride. */
|
|
74
|
+
_testDrMcpOptions;
|
|
75
|
+
/** Test hook: the claude arguments the last chat launch built, before any _testClaudeCmdOverride. */
|
|
76
|
+
_testLastClaudeChatArgs;
|
|
77
|
+
drMcpKey;
|
|
78
|
+
drBotWarnings = /* @__PURE__ */ new Set();
|
|
67
79
|
/**
|
|
68
80
|
* Valid spec node IDs per layer
|
|
69
81
|
* Dynamically loaded from compiled spec (spec/dist/{layer}.json at module load time)
|
|
@@ -115,7 +127,7 @@ class VisualizationServer {
|
|
|
115
127
|
}), ids;
|
|
116
128
|
})();
|
|
117
129
|
constructor(model, options) {
|
|
118
|
-
this.app = new OpenAPIHono(), this.model = model, this.loadWebSocketAdapter(), this.authEnabled = options?.authEnabled ?? process.env.DR_AUTH_ENABLED !== "false", this.authToken = options?.authToken || process.env.DR_AUTH_TOKEN || this.generateAuthToken(), this.withDanger = options?.withDanger || !1, this.viewerPath = options?.viewerPath || new URL("../viewer", import.meta.url).pathname, !this.authEnabled && options?.authToken && console.warn("[VisualizationServer] Warning: authToken provided but authEnabled is false. The token will be generated but not used for authentication. Set authEnabled: true to enable authentication."), this.app.use("/*", cors()), this.app.use("/*", telemetryMiddleware), this.app.use("/api/*", async (c, next) => {
|
|
130
|
+
this.app = new OpenAPIHono(), this.model = model, this.loadWebSocketAdapter(), this.authEnabled = options?.authEnabled ?? process.env.DR_AUTH_ENABLED !== "false", this.authToken = options?.authToken || process.env.DR_AUTH_TOKEN || this.generateAuthToken(), this.withDanger = options?.withDanger || !1, this.withChangesets = options?.withChangesets || !1, this.viewerPath = options?.viewerPath || new URL("../viewer", import.meta.url).pathname, !this.authEnabled && options?.authToken && console.warn("[VisualizationServer] Warning: authToken provided but authEnabled is false. The token will be generated but not used for authentication. Set authEnabled: true to enable authentication."), this.app.use("/*", cors()), this.app.use("/*", telemetryMiddleware), this.app.use("/api/*", async (c, next) => {
|
|
119
131
|
if (!this.authEnabled)
|
|
120
132
|
return next();
|
|
121
133
|
const authHeader = c.req.header("Authorization"), queryToken = c.req.query("token");
|
|
@@ -775,7 +787,8 @@ class VisualizationServer {
|
|
|
775
787
|
}
|
|
776
788
|
}
|
|
777
789
|
});
|
|
778
|
-
this.app.openapi(getChangesetsRoute, (c) => {
|
|
790
|
+
this.app.openapi(getChangesetsRoute, async (c) => {
|
|
791
|
+
await this.loadChangesetsFromDisk();
|
|
779
792
|
const changesets = {};
|
|
780
793
|
for (const [id, changeset] of this.changesets)
|
|
781
794
|
changesets[id] = {
|
|
@@ -818,8 +831,10 @@ class VisualizationServer {
|
|
|
818
831
|
}
|
|
819
832
|
}
|
|
820
833
|
});
|
|
821
|
-
this.app.openapi(getChangesetRoute, (c) => {
|
|
822
|
-
const { changesetId } = c.req.valid("param")
|
|
834
|
+
this.app.openapi(getChangesetRoute, async (c) => {
|
|
835
|
+
const { changesetId } = c.req.valid("param");
|
|
836
|
+
await this.loadChangesetsFromDisk();
|
|
837
|
+
const changeset = this.changesets.get(changesetId);
|
|
823
838
|
return changeset ? c.json({
|
|
824
839
|
id: changeset.id,
|
|
825
840
|
name: changeset.name,
|
|
@@ -831,6 +846,51 @@ class VisualizationServer {
|
|
|
831
846
|
stats: changeset.stats,
|
|
832
847
|
changes: changeset.changes
|
|
833
848
|
}) : c.json({ error: "Changeset not found" }, 404);
|
|
849
|
+
});
|
|
850
|
+
const changesetActionResponses = {
|
|
851
|
+
200: {
|
|
852
|
+
description: "Action completed",
|
|
853
|
+
content: { "application/json": { schema: ChangesetActionResultSchema } }
|
|
854
|
+
},
|
|
855
|
+
404: {
|
|
856
|
+
description: "Changeset not found",
|
|
857
|
+
content: { "application/json": { schema: ErrorResponseSchema } }
|
|
858
|
+
},
|
|
859
|
+
409: {
|
|
860
|
+
description: "Changeset is not staged, or the model drifted since it was created",
|
|
861
|
+
content: { "application/json": { schema: ErrorResponseSchema } }
|
|
862
|
+
},
|
|
863
|
+
422: {
|
|
864
|
+
description: "The changeset failed validation; nothing was applied",
|
|
865
|
+
content: { "application/json": { schema: ErrorResponseSchema } }
|
|
866
|
+
}
|
|
867
|
+
}, commitChangesetRoute = createRoute({
|
|
868
|
+
method: "post",
|
|
869
|
+
path: "/api/changesets/:changesetId/commit",
|
|
870
|
+
tags: ["Changesets"],
|
|
871
|
+
summary: "Commit changeset",
|
|
872
|
+
description: "Apply a staged changeset to the model (same as `dr changeset commit`): validates it, applies every change atomically, marks it committed, and deactivates it if it was active. Refused when the model changed since the changeset was created (use the CLI with --force).",
|
|
873
|
+
security: [{ bearerAuth: [] }],
|
|
874
|
+
request: { params: z.object({ changesetId: IdSchema }) },
|
|
875
|
+
responses: changesetActionResponses
|
|
876
|
+
});
|
|
877
|
+
this.app.openapi(commitChangesetRoute, async (c) => {
|
|
878
|
+
const { changesetId } = c.req.valid("param");
|
|
879
|
+
return this.runChangesetAction(c, changesetId, "commit");
|
|
880
|
+
});
|
|
881
|
+
const discardChangesetRoute = createRoute({
|
|
882
|
+
method: "post",
|
|
883
|
+
path: "/api/changesets/:changesetId/discard",
|
|
884
|
+
tags: ["Changesets"],
|
|
885
|
+
summary: "Discard changeset",
|
|
886
|
+
description: "Throw away a staged changeset's changes (same as `dr changeset discard`): clears them, marks it discarded, and deactivates it if it was active. The model is not touched.",
|
|
887
|
+
security: [{ bearerAuth: [] }],
|
|
888
|
+
request: { params: z.object({ changesetId: IdSchema }) },
|
|
889
|
+
responses: changesetActionResponses
|
|
890
|
+
});
|
|
891
|
+
this.app.openapi(discardChangesetRoute, async (c) => {
|
|
892
|
+
const { changesetId } = c.req.valid("param");
|
|
893
|
+
return this.runChangesetAction(c, changesetId, "discard");
|
|
834
894
|
}), this.app.doc("/api-spec.yaml", {
|
|
835
895
|
openapi: "3.1.0",
|
|
836
896
|
info: {
|
|
@@ -1265,17 +1325,106 @@ class VisualizationServer {
|
|
|
1265
1325
|
id: requestId
|
|
1266
1326
|
}));
|
|
1267
1327
|
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Build command arguments for Claude Code launch
|
|
1330
|
+
*/
|
|
1331
|
+
buildClaudeChatArgs(mcpConfigPath) {
|
|
1332
|
+
const cmd = ["claude", "--agent", "dr-architect", "--print"], mode = this.drBotMode(), mcpRules = mcpConfigPath ? drMcpAllowedTools(mode) : [];
|
|
1333
|
+
if (mode === "danger")
|
|
1334
|
+
cmd.push("--dangerously-skip-permissions");
|
|
1335
|
+
else {
|
|
1336
|
+
const bashRules = mode === "changesets" ? formatForClaudeCodeWithChangesets() : formatForClaudeCode();
|
|
1337
|
+
cmd.push("--allowedTools", [bashRules, ...mcpRules].join(","));
|
|
1338
|
+
}
|
|
1339
|
+
return mcpConfigPath && cmd.push("--mcp-config", mcpConfigPath, "--append-system-prompt", drBotMcpPrompt(mode)), cmd.push("--verbose", "--output-format", "stream-json"), cmd;
|
|
1340
|
+
}
|
|
1341
|
+
/** DrBot's permission mode; danger wins over changeset-only. */
|
|
1342
|
+
drBotMode() {
|
|
1343
|
+
return this.withDanger ? "danger" : this.withChangesets ? "changesets" : "read-safe";
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* Writes the MCP config that connects DrBot to `dr mcp` for this model. Returns null when it
|
|
1347
|
+
* can't (logged): DrBot then launches without MCP and uses its Bash rules.
|
|
1348
|
+
*/
|
|
1349
|
+
async prepareDrBotMcp() {
|
|
1350
|
+
const mode = this.drBotMode(), overrides = this._testDrMcpOptions ?? {};
|
|
1351
|
+
try {
|
|
1352
|
+
const check = await checkInstalledAgentMcpTools(this.model.rootPath, mode, overrides.homeDir);
|
|
1353
|
+
if (check && (this.warnDrBotOnce(check.noneVisible ? `[Claude Code] The installed ${DR_ARCHITECT_AGENT} agent (${check.path}) predates the dr MCP tools, so the chat can't use them and falls back to Bash dr commands. Run \`dr claude upgrade\` to update it.` : `[Claude Code] The installed ${DR_ARCHITECT_AGENT} agent (${check.path}) doesn't list ${check.missing.join(", ")}, so the chat can't use those dr MCP tools. Run \`dr claude upgrade\` to update it.`), check.noneVisible))
|
|
1354
|
+
return null;
|
|
1355
|
+
} catch (error) {
|
|
1356
|
+
this.warnDrBotOnce(`[Claude Code] Could not check the installed ${DR_ARCHITECT_AGENT} agent's tools (${getErrorMessage(error)}); connecting the dr MCP server anyway.`);
|
|
1357
|
+
}
|
|
1358
|
+
try {
|
|
1359
|
+
return await prepareDrMcpLaunch({
|
|
1360
|
+
rootPath: this.model.rootPath,
|
|
1361
|
+
changesetOnly: mode === "changesets",
|
|
1362
|
+
keyManager: { ensureKey: () => this.ensureDrMcpKey() },
|
|
1363
|
+
drCommand: overrides.drCommand,
|
|
1364
|
+
tempRoot: overrides.tempRoot
|
|
1365
|
+
});
|
|
1366
|
+
} catch (error) {
|
|
1367
|
+
return console.warn(`[Claude Code] dr MCP server unavailable for chat, falling back to Bash dr commands: ${getErrorMessage(error)}`), null;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* The installation's MCP API key. Concurrent chat launches share one in-flight ensureKey call,
|
|
1372
|
+
* so a first-time key is created once rather than raced and overwritten (which would leave an
|
|
1373
|
+
* earlier launch's MCP server holding a key that no longer matches). Once it settles the next
|
|
1374
|
+
* launch reads the key afresh, so a key rotated with `dr mcp --regenerate-key` is picked up.
|
|
1375
|
+
*/
|
|
1376
|
+
ensureDrMcpKey() {
|
|
1377
|
+
if (!this.drMcpKey) {
|
|
1378
|
+
const pending = (this._testDrMcpOptions?.keyManager ?? new ApiKeyManager()).ensureKey();
|
|
1379
|
+
this.drMcpKey = pending;
|
|
1380
|
+
const clear = () => {
|
|
1381
|
+
this.drMcpKey === pending && (this.drMcpKey = void 0);
|
|
1382
|
+
};
|
|
1383
|
+
pending.then(clear, clear);
|
|
1384
|
+
}
|
|
1385
|
+
return this.drMcpKey;
|
|
1386
|
+
}
|
|
1387
|
+
/** Logs a DrBot setup warning once per server rather than on every chat message. */
|
|
1388
|
+
warnDrBotOnce(message) {
|
|
1389
|
+
this.drBotWarnings.has(message) || (this.drBotWarnings.add(message), console.warn(message));
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Environment for chat agent processes. In changeset-only mode it sets
|
|
1393
|
+
* CHANGESET_ONLY_ENV, so any `dr` command the agent runs refuses to save the base
|
|
1394
|
+
* model and can only stage changes in an active changeset (core/changeset-only-guard.ts).
|
|
1395
|
+
*/
|
|
1396
|
+
buildChatEnv() {
|
|
1397
|
+
return this.withChangesets && !this.withDanger ? { ...process.env, [CHANGESET_ONLY_ENV]: "true" } : process.env;
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Add permission flags to Copilot command based on withDanger setting
|
|
1401
|
+
* Applies read-safe permissions when withDanger is false, with graceful degradation
|
|
1402
|
+
* if the installed Copilot CLI doesn't support granular permission flags.
|
|
1403
|
+
* @param cmd The command array to modify (will be mutated)
|
|
1404
|
+
* @param variant The Copilot variant for error messages (e.g., "gh copilot" or "copilot")
|
|
1405
|
+
*/
|
|
1406
|
+
addCopilotPermissionFlags(cmd, variant) {
|
|
1407
|
+
const copilotCommand = cmd[0] === "gh" ? "gh" : "copilot";
|
|
1408
|
+
applyCopilotPermissions(cmd, variant, copilotCommand, this.withDanger);
|
|
1409
|
+
}
|
|
1268
1410
|
/**
|
|
1269
1411
|
* Launch Claude Code CLI with dr-architect agent and stream responses
|
|
1270
1412
|
*/
|
|
1271
1413
|
async launchClaudeCodeChat(ws, conversationId, message, requestId) {
|
|
1414
|
+
let drMcp = null;
|
|
1272
1415
|
try {
|
|
1273
|
-
|
|
1274
|
-
|
|
1416
|
+
drMcp = this._testClaudeCmdOverride !== void 0 && this._testDrMcpOptions === void 0 ? null : await this.prepareDrBotMcp();
|
|
1417
|
+
const cmd = this.buildClaudeChatArgs(drMcp?.configPath);
|
|
1418
|
+
this._testLastClaudeChatArgs = [...cmd], this._testClaudeCmdOverride && cmd.splice(0, cmd.length, ...this._testClaudeCmdOverride);
|
|
1275
1419
|
const proc = spawn(cmd[0], cmd.slice(1), {
|
|
1276
1420
|
cwd: this.model.rootPath,
|
|
1421
|
+
env: this.buildChatEnv(),
|
|
1277
1422
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1278
1423
|
});
|
|
1424
|
+
if (drMcp) {
|
|
1425
|
+
const cleanup = drMcp.cleanup;
|
|
1426
|
+
proc.once("exit", () => void cleanup()), proc.once("error", () => void cleanup());
|
|
1427
|
+
}
|
|
1279
1428
|
proc.on("error", (err) => {
|
|
1280
1429
|
const errorMsg = getErrorMessage(err);
|
|
1281
1430
|
console.error(`[Claude Code] Failed to spawn subprocess for conversation ${conversationId}: ${errorMsg}`), this.activeChatProcesses.delete(conversationId);
|
|
@@ -1409,6 +1558,7 @@ class VisualizationServer {
|
|
|
1409
1558
|
}
|
|
1410
1559
|
});
|
|
1411
1560
|
} catch (error) {
|
|
1561
|
+
drMcp?.cleanup();
|
|
1412
1562
|
const errorMsg = getErrorMessage(error);
|
|
1413
1563
|
ws.send(JSON.stringify({
|
|
1414
1564
|
jsonrpc: "2.0",
|
|
@@ -1432,7 +1582,7 @@ class VisualizationServer {
|
|
|
1432
1582
|
const ghResult = spawnSync("gh", ["copilot", "--version"], {
|
|
1433
1583
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1434
1584
|
});
|
|
1435
|
-
ghResult.error ? console.warn(`[Copilot] 'gh copilot --version' probe failed to spawn: ${getErrorMessage(ghResult.error)}`) : ghResult.status !== 0 && process.env.VERBOSE && console.log(`[Copilot] 'gh copilot' unavailable (exit ${ghResult.status}), falling back to standalone 'copilot'`), ghResult.status === 0 ? (cmd = ["gh", "copilot", "explain"], this.
|
|
1585
|
+
ghResult.error ? console.warn(`[Copilot] 'gh copilot --version' probe failed to spawn: ${getErrorMessage(ghResult.error)}`) : ghResult.status !== 0 && process.env.VERBOSE && console.log(`[Copilot] 'gh copilot' unavailable (exit ${ghResult.status}), falling back to standalone 'copilot'`), ghResult.status === 0 ? (cmd = ["gh", "copilot", "explain"], this.addCopilotPermissionFlags(cmd, "gh copilot"), cmd.push(message)) : (cmd = ["copilot", "explain"], this.addCopilotPermissionFlags(cmd, "copilot"), cmd.push(message));
|
|
1436
1586
|
}
|
|
1437
1587
|
const proc = spawn(cmd[0], cmd.slice(1), {
|
|
1438
1588
|
cwd: this.model.rootPath,
|
|
@@ -1542,19 +1692,7 @@ class VisualizationServer {
|
|
|
1542
1692
|
}), this.watcher.on("all", async (_event, path2) => {
|
|
1543
1693
|
process.env.VERBOSE && console.log(`[Watcher] File changed: ${path2}`);
|
|
1544
1694
|
try {
|
|
1545
|
-
|
|
1546
|
-
const modelData = await this.serializeModel(), message = JSON.stringify({
|
|
1547
|
-
type: "model.updated",
|
|
1548
|
-
data: modelData,
|
|
1549
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1550
|
-
});
|
|
1551
|
-
for (const client of this.clients)
|
|
1552
|
-
try {
|
|
1553
|
-
client.send(message);
|
|
1554
|
-
} catch (error) {
|
|
1555
|
-
const msg = getErrorMessage(error);
|
|
1556
|
-
console.warn(`[Watcher] Failed to send update: ${msg}`);
|
|
1557
|
-
}
|
|
1695
|
+
await this.reloadAndBroadcast();
|
|
1558
1696
|
} catch (error) {
|
|
1559
1697
|
const message = getErrorMessage(error);
|
|
1560
1698
|
console.error(`[Watcher] Failed to reload model: ${message}`);
|
|
@@ -2244,20 +2382,85 @@ class VisualizationServer {
|
|
|
2244
2382
|
}
|
|
2245
2383
|
}
|
|
2246
2384
|
/**
|
|
2247
|
-
*
|
|
2385
|
+
* Reload the model and changesets from disk and send the new model to every client.
|
|
2248
2386
|
*/
|
|
2249
|
-
async
|
|
2250
|
-
|
|
2387
|
+
async reloadAndBroadcast() {
|
|
2388
|
+
this.model = await Model.load(this.model.rootPath, { lazyLoad: !1 }), await this.loadChangesetsFromDisk();
|
|
2389
|
+
const modelData = await this.serializeModel(), message = JSON.stringify({
|
|
2390
|
+
type: "model.updated",
|
|
2391
|
+
data: modelData,
|
|
2392
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2393
|
+
});
|
|
2394
|
+
for (const client of this.clients)
|
|
2251
2395
|
try {
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
process.env.VERBOSE && console.log(`[Changesets] Loaded ${changesets.length} changeset(s) from disk`);
|
|
2257
|
-
} catch (err) {
|
|
2258
|
-
console.warn(`[Changesets] Warning: Failed to load changesets from disk: ${err}`);
|
|
2396
|
+
client.send(message);
|
|
2397
|
+
} catch (error) {
|
|
2398
|
+
const msg = getErrorMessage(error);
|
|
2399
|
+
console.warn(`[Watcher] Failed to send update: ${msg}`);
|
|
2259
2400
|
}
|
|
2260
2401
|
}
|
|
2402
|
+
/**
|
|
2403
|
+
* Commit or discard a staged changeset for POST /api/changesets/:id/{commit,discard}.
|
|
2404
|
+
*
|
|
2405
|
+
* Works on a freshly loaded model rather than the server's in-memory copy, so a CLI
|
|
2406
|
+
* change since the last reload can't be overwritten. Afterwards the server reloads
|
|
2407
|
+
* (the watcher only sees model files, and a discard touches none) and broadcasts.
|
|
2408
|
+
*/
|
|
2409
|
+
async runChangesetAction(c, changesetId, action) {
|
|
2410
|
+
const model = await Model.load(this.model.rootPath, { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), changeset = await manager.load(changesetId);
|
|
2411
|
+
if (!changeset)
|
|
2412
|
+
return c.json({ error: "Changeset not found" }, 404);
|
|
2413
|
+
if (changeset.status !== "staged")
|
|
2414
|
+
return c.json({ error: `Changeset is already ${changeset.status}` }, 409);
|
|
2415
|
+
let result = {};
|
|
2416
|
+
try {
|
|
2417
|
+
if (action === "commit") {
|
|
2418
|
+
const commit = await manager.commit(model, changesetId, { validate: !0 });
|
|
2419
|
+
result = {
|
|
2420
|
+
committed: commit.committed,
|
|
2421
|
+
skipped: commit.skipped ?? 0,
|
|
2422
|
+
failed: commit.failed,
|
|
2423
|
+
preExistingErrors: commit.validation.preExistingErrors ?? 0
|
|
2424
|
+
};
|
|
2425
|
+
} else
|
|
2426
|
+
await manager.discard(changesetId);
|
|
2427
|
+
} catch (error) {
|
|
2428
|
+
const message = getErrorMessage(error);
|
|
2429
|
+
if (message.startsWith("Validation failed"))
|
|
2430
|
+
return c.json({ error: message }, 422);
|
|
2431
|
+
if (message.includes("drifted"))
|
|
2432
|
+
return c.json({ error: message }, 409);
|
|
2433
|
+
throw error;
|
|
2434
|
+
}
|
|
2435
|
+
await manager.getActiveId() === changesetId && await manager.clearActive();
|
|
2436
|
+
try {
|
|
2437
|
+
await this.reloadAndBroadcast();
|
|
2438
|
+
} catch (error) {
|
|
2439
|
+
console.error(`[Changesets] Reload after ${action} failed: ${getErrorMessage(error)}`);
|
|
2440
|
+
}
|
|
2441
|
+
const updated = this.changesets.get(changesetId) ?? await manager.load(changesetId);
|
|
2442
|
+
return c.json({
|
|
2443
|
+
id: changesetId,
|
|
2444
|
+
name: changeset.name,
|
|
2445
|
+
status: updated?.status ?? (action === "commit" ? "committed" : "discarded"),
|
|
2446
|
+
...result
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
/**
|
|
2450
|
+
* Load all changesets from disk into the in-memory map
|
|
2451
|
+
*/
|
|
2452
|
+
async loadChangesetsFromDisk() {
|
|
2453
|
+
this.changesetStorage ??= new StagedChangesetStorage(this.model.rootPath);
|
|
2454
|
+
try {
|
|
2455
|
+
const changesets = await this.changesetStorage.list();
|
|
2456
|
+
this.changesets.clear();
|
|
2457
|
+
for (const cs of changesets)
|
|
2458
|
+
this.changesets.set(cs.id, cs);
|
|
2459
|
+
process.env.VERBOSE && console.log(`[Changesets] Loaded ${changesets.length} changeset(s) from disk`);
|
|
2460
|
+
} catch (err) {
|
|
2461
|
+
console.warn(`[Changesets] Warning: Failed to load changesets from disk: ${err}`);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2261
2464
|
/**
|
|
2262
2465
|
* Start the server
|
|
2263
2466
|
*/
|