@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
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,14 +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";
|
|
20
|
-
import { formatForClaudeCode, applyCopilotPermissions } from "../coding-agents/default-permissions.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";
|
|
21
24
|
import { getErrorMessage } from "../utils/errors.js";
|
|
22
|
-
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";
|
|
23
26
|
const JSONRPC_ERRORS = {
|
|
24
27
|
// Standard JSON-RPC errors
|
|
25
28
|
INVALID_PARAMS: -32602,
|
|
@@ -54,6 +57,8 @@ class VisualizationServer {
|
|
|
54
57
|
authEnabled = !0;
|
|
55
58
|
withDanger = !1;
|
|
56
59
|
// Danger mode disabled by default
|
|
60
|
+
withChangesets = !1;
|
|
61
|
+
// Changeset-only write mode disabled by default
|
|
57
62
|
viewerPath;
|
|
58
63
|
// Optional custom viewer path
|
|
59
64
|
activeChatProcesses = /* @__PURE__ */ new Map();
|
|
@@ -65,6 +70,12 @@ class VisualizationServer {
|
|
|
65
70
|
// Store initialization error for status endpoint
|
|
66
71
|
_testClaudeCmdOverride;
|
|
67
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();
|
|
68
79
|
/**
|
|
69
80
|
* Valid spec node IDs per layer
|
|
70
81
|
* Dynamically loaded from compiled spec (spec/dist/{layer}.json at module load time)
|
|
@@ -116,7 +127,7 @@ class VisualizationServer {
|
|
|
116
127
|
}), ids;
|
|
117
128
|
})();
|
|
118
129
|
constructor(model, options) {
|
|
119
|
-
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) => {
|
|
120
131
|
if (!this.authEnabled)
|
|
121
132
|
return next();
|
|
122
133
|
const authHeader = c.req.header("Authorization"), queryToken = c.req.query("token");
|
|
@@ -776,7 +787,8 @@ class VisualizationServer {
|
|
|
776
787
|
}
|
|
777
788
|
}
|
|
778
789
|
});
|
|
779
|
-
this.app.openapi(getChangesetsRoute, (c) => {
|
|
790
|
+
this.app.openapi(getChangesetsRoute, async (c) => {
|
|
791
|
+
await this.loadChangesetsFromDisk();
|
|
780
792
|
const changesets = {};
|
|
781
793
|
for (const [id, changeset] of this.changesets)
|
|
782
794
|
changesets[id] = {
|
|
@@ -819,8 +831,10 @@ class VisualizationServer {
|
|
|
819
831
|
}
|
|
820
832
|
}
|
|
821
833
|
});
|
|
822
|
-
this.app.openapi(getChangesetRoute, (c) => {
|
|
823
|
-
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);
|
|
824
838
|
return changeset ? c.json({
|
|
825
839
|
id: changeset.id,
|
|
826
840
|
name: changeset.name,
|
|
@@ -832,6 +846,51 @@ class VisualizationServer {
|
|
|
832
846
|
stats: changeset.stats,
|
|
833
847
|
changes: changeset.changes
|
|
834
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");
|
|
835
894
|
}), this.app.doc("/api-spec.yaml", {
|
|
836
895
|
openapi: "3.1.0",
|
|
837
896
|
info: {
|
|
@@ -1269,9 +1328,73 @@ class VisualizationServer {
|
|
|
1269
1328
|
/**
|
|
1270
1329
|
* Build command arguments for Claude Code launch
|
|
1271
1330
|
*/
|
|
1272
|
-
buildClaudeChatArgs() {
|
|
1273
|
-
const cmd = ["claude", "--agent", "dr-architect", "--print"];
|
|
1274
|
-
|
|
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;
|
|
1275
1398
|
}
|
|
1276
1399
|
/**
|
|
1277
1400
|
* Add permission flags to Copilot command based on withDanger setting
|
|
@@ -1288,13 +1411,20 @@ class VisualizationServer {
|
|
|
1288
1411
|
* Launch Claude Code CLI with dr-architect agent and stream responses
|
|
1289
1412
|
*/
|
|
1290
1413
|
async launchClaudeCodeChat(ws, conversationId, message, requestId) {
|
|
1414
|
+
let drMcp = null;
|
|
1291
1415
|
try {
|
|
1292
|
-
|
|
1293
|
-
|
|
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);
|
|
1294
1419
|
const proc = spawn(cmd[0], cmd.slice(1), {
|
|
1295
1420
|
cwd: this.model.rootPath,
|
|
1421
|
+
env: this.buildChatEnv(),
|
|
1296
1422
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1297
1423
|
});
|
|
1424
|
+
if (drMcp) {
|
|
1425
|
+
const cleanup = drMcp.cleanup;
|
|
1426
|
+
proc.once("exit", () => void cleanup()), proc.once("error", () => void cleanup());
|
|
1427
|
+
}
|
|
1298
1428
|
proc.on("error", (err) => {
|
|
1299
1429
|
const errorMsg = getErrorMessage(err);
|
|
1300
1430
|
console.error(`[Claude Code] Failed to spawn subprocess for conversation ${conversationId}: ${errorMsg}`), this.activeChatProcesses.delete(conversationId);
|
|
@@ -1428,6 +1558,7 @@ class VisualizationServer {
|
|
|
1428
1558
|
}
|
|
1429
1559
|
});
|
|
1430
1560
|
} catch (error) {
|
|
1561
|
+
drMcp?.cleanup();
|
|
1431
1562
|
const errorMsg = getErrorMessage(error);
|
|
1432
1563
|
ws.send(JSON.stringify({
|
|
1433
1564
|
jsonrpc: "2.0",
|
|
@@ -1561,19 +1692,7 @@ class VisualizationServer {
|
|
|
1561
1692
|
}), this.watcher.on("all", async (_event, path2) => {
|
|
1562
1693
|
process.env.VERBOSE && console.log(`[Watcher] File changed: ${path2}`);
|
|
1563
1694
|
try {
|
|
1564
|
-
|
|
1565
|
-
const modelData = await this.serializeModel(), message = JSON.stringify({
|
|
1566
|
-
type: "model.updated",
|
|
1567
|
-
data: modelData,
|
|
1568
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1569
|
-
});
|
|
1570
|
-
for (const client of this.clients)
|
|
1571
|
-
try {
|
|
1572
|
-
client.send(message);
|
|
1573
|
-
} catch (error) {
|
|
1574
|
-
const msg = getErrorMessage(error);
|
|
1575
|
-
console.warn(`[Watcher] Failed to send update: ${msg}`);
|
|
1576
|
-
}
|
|
1695
|
+
await this.reloadAndBroadcast();
|
|
1577
1696
|
} catch (error) {
|
|
1578
1697
|
const message = getErrorMessage(error);
|
|
1579
1698
|
console.error(`[Watcher] Failed to reload model: ${message}`);
|
|
@@ -2263,20 +2382,85 @@ class VisualizationServer {
|
|
|
2263
2382
|
}
|
|
2264
2383
|
}
|
|
2265
2384
|
/**
|
|
2266
|
-
*
|
|
2385
|
+
* Reload the model and changesets from disk and send the new model to every client.
|
|
2267
2386
|
*/
|
|
2268
|
-
async
|
|
2269
|
-
|
|
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)
|
|
2270
2395
|
try {
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
process.env.VERBOSE && console.log(`[Changesets] Loaded ${changesets.length} changeset(s) from disk`);
|
|
2276
|
-
} catch (err) {
|
|
2277
|
-
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}`);
|
|
2278
2400
|
}
|
|
2279
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
|
+
}
|
|
2280
2464
|
/**
|
|
2281
2465
|
* Start the server
|
|
2282
2466
|
*/
|