@documentation-robotics/cli 0.2.0 → 0.4.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 +46 -16
- package/dist/analysis/relationship-classifier.js +2 -9
- package/dist/analysis/relationship-classifier.js.map +2 -2
- package/dist/analyzers/active-analyzer.js +62 -0
- package/dist/analyzers/active-analyzer.js.map +7 -0
- 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 +191 -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/extract.js +138 -0
- package/dist/analyzers/cards/extract.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/routes.js +96 -0
- package/dist/analyzers/cards/routes.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 +270 -174
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +342 -0
- package/dist/analyzers/cbm-responses.js.map +7 -0
- package/dist/analyzers/code-changes.js +159 -0
- package/dist/analyzers/code-changes.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +49 -0
- package/dist/analyzers/edge-relationships.js.map +7 -0
- package/dist/analyzers/extraction-plan.js +541 -0
- package/dist/analyzers/extraction-plan.js.map +7 -0
- package/dist/analyzers/index-job.js +229 -0
- package/dist/analyzers/index-job.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 +23 -11
- 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 +269 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +7 -4
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +143 -40
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/changeset-verify.js +63 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +80 -29
- 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/init.js +9 -26
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +40 -21
- package/dist/commands/mcp.js.map +3 -3
- package/dist/commands/relationship.js +208 -37
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +3 -3
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +52 -32
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +99 -103
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/validate.js +19 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +1 -1
- package/dist/commands/visualize.js +34 -15
- package/dist/commands/visualize.js.map +2 -2
- package/dist/core/annotation-store.js +15 -5
- package/dist/core/annotation-store.js.map +2 -2
- package/dist/core/catalog-migration.js +34 -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 +160 -0
- package/dist/core/changeset-base-index.js.map +7 -0
- package/dist/core/changeset-brief-compact.js +256 -0
- package/dist/core/changeset-brief-compact.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 +848 -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/extraction-observability.js +161 -0
- package/dist/core/extraction-observability.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 +88 -47
- 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/project-init.js +53 -0
- package/dist/core/project-init.js.map +7 -0
- 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 +161 -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 +145 -18
- 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 +166 -24
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/upgrade-plan.js +117 -0
- package/dist/core/upgrade-plan.js.map +7 -0
- 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 +2468 -7913
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/.claude-plugin/plugin.json +24 -0
- package/dist/integrations/claude_code/agents/dr-architect.md +30 -3
- package/dist/integrations/claude_code/agents/dr-extractor.md +8 -2
- package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
- package/dist/integrations/claude_code/commands/dr-changeset.md +2 -1
- package/dist/integrations/claude_code/commands/dr-map.md +20 -1
- package/dist/integrations/claude_code/commands/dr-plan.md +66 -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 +47 -26
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +68 -2
- package/dist/integrations/claude_code/plugin-agents/dr-advisor.md +255 -0
- package/dist/integrations/claude_code/plugin-agents/dr-architect.md +306 -0
- 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 +95 -15
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +178 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +8 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +6 -1
- package/dist/integrations/github_copilot/agents/dr-architect.md +3 -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 +225 -102
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +177 -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 +45 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/project-root.js +85 -0
- package/dist/mcp/project-root.js.map +7 -0
- package/dist/mcp/server-instructions.js +27 -0
- package/dist/mcp/server-instructions.js.map +7 -0
- package/dist/mcp/strict-schema.js +52 -0
- package/dist/mcp/strict-schema.js.map +7 -0
- package/dist/mcp/tool-registry.js +55 -5
- package/dist/mcp/tool-registry.js.map +2 -2
- package/dist/mcp/tools/changeset-analysis-tools.js +98 -0
- package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
- package/dist/mcp/tools/changeset-commit.js +224 -0
- package/dist/mcp/tools/changeset-commit.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +260 -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 +49 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/codebase-extract.js +836 -0
- package/dist/mcp/tools/codebase-extract.js.map +7 -0
- package/dist/mcp/tools/codebase-index.js +125 -0
- package/dist/mcp/tools/codebase-index.js.map +7 -0
- package/dist/mcp/tools/codebase-shared.js +265 -0
- package/dist/mcp/tools/codebase-shared.js.map +7 -0
- package/dist/mcp/tools/codebase-verify.js +48 -0
- package/dist/mcp/tools/codebase-verify.js.map +7 -0
- package/dist/mcp/tools/index.js +34 -1
- package/dist/mcp/tools/index.js.map +2 -2
- package/dist/mcp/tools/model-add.js +191 -74
- 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 +46 -26
- package/dist/mcp/tools/model-update.js.map +2 -2
- package/dist/mcp/tools/model-validate.js +46 -4
- package/dist/mcp/tools/model-validate.js.map +2 -2
- package/dist/mcp/tools/project-status-collectors.js +381 -0
- package/dist/mcp/tools/project-status-collectors.js.map +7 -0
- package/dist/mcp/tools/project-status.js +237 -0
- package/dist/mcp/tools/project-status.js.map +7 -0
- package/dist/mcp/tools/project-tools.js +505 -0
- package/dist/mcp/tools/project-tools.js.map +7 -0
- package/dist/mcp/tools/relationship-tools.js +167 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/review-open.js +210 -0
- package/dist/mcp/tools/review-open.js.map +7 -0
- package/dist/mcp/tools/shared.js +35 -4
- 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/reports/model-report-orchestrator.js +31 -2
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/schemas/bundled/analyzers/cbm.json +1200 -70
- 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 +865 -1646
- 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 +686 -231
- package/dist/server/server.js.map +3 -3
- package/dist/server/viewer-registry.js +264 -0
- package/dist/server/viewer-registry.js.map +7 -0
- 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/id-generator.js +5 -2
- package/dist/utils/id-generator.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 +64 -31
- 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/model-warnings.js +28 -0
- package/dist/validators/model-warnings.js.map +7 -0
- 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-CUOQGGRA.css +1 -0
- package/dist/viewer/assets/main-DvH3gYrI.js +84 -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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/commands/farm.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Farm Commands - Manage model farms and project registration\n */\n\nimport ansis from \"ansis\";\nimport { Command } from \"commander\";\nimport path from \"path\";\nimport { rm } from \"fs/promises\";\nimport { FarmManifest } from \"../core/farm-manifest.js\";\nimport { findFarmRoot } from \"../utils/project-paths.js\";\nimport { fileExists } from \"../utils/file-io.js\";\nimport { execSync, execFileSync } from \"child_process\";\nimport * as prompts from \"@clack/prompts\";\nimport { getErrorMessage, handleSuccess, handleInfo } from \"../utils/errors.js\";\nimport { isJson } from \"../utils/globals.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { Model } from \"../core/model.js\";\nimport { ComposedReferenceValidator } from \"../validators/composed-reference-validator.js\";\nimport { ValidationFormatter } from \"../validators/validation-formatter.js\";\nimport { FarmSyncEngine } from \"../core/farm-sync-engine.js\";\n\ninterface FarmSyncResultEntry {\n project: string;\n status: \"success\" | \"error\" | \"partial\";\n change_count?: number;\n changeset_id?: string;\n files_changed?: { added: string[]; modified: string[]; deleted: string[] };\n ambiguities?: number;\n commits_before?: string;\n commits_after?: string;\n auto_committed?: boolean;\n committed_changes?: number;\n commit_error?: string;\n message?: string;\n}\n\n/**\n * Check if a directory is a git repository.\n * Returns true if git rev-parse succeeds, false if the directory is not a git repo\n * or if unexpected errors occur (which are logged in DEBUG mode only).\n * Does not re-throw errors; unexpected git errors are logged diagnostically but do not\n * prevent the operation from proceeding.\n */\nfunction isGitRepository(cwd: string): boolean {\n try {\n execSync(\"git rev-parse --git-dir\", { cwd, stdio: \"pipe\" });\n return true;\n } catch (error) {\n const errorMsg = getErrorMessage(error);\n\n // Only return false for the \"not a git repository\" case\n // Pattern: \"fatal: not a git repository\" (case insensitive check for safety)\n if (errorMsg.toLowerCase().includes(\"not a git repository\")) {\n return false;\n }\n\n // For unexpected errors (missing git binary, permission denied, etc), log diagnostically\n // but return false to preserve existing behavior of not blocking operations\n if (process.env.DEBUG) {\n console.warn(`Warning: Unexpected error checking git repository at ${cwd}: ${errorMsg}`);\n }\n return false;\n }\n}\n\n/**\n * Initialize a new farm\n */\nexport async function farmInitCommand(options: {\n name?: string;\n description?: string;\n format?: string;\n platformView?: boolean;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.init\") : null;\n\n try {\n const farmPath = process.cwd();\n const farmYamlPath = path.join(farmPath, \"farm.yaml\");\n\n // Check if farm.yaml already exists\n const useJson = options.format === \"json\" || isJson();\n if (await fileExists(farmYamlPath)) {\n const message = \"Farm already initialized in this directory\";\n if (useJson) {\n console.log(JSON.stringify({ status: \"error\", code: 1, message }));\n } else {\n console.error(ansis.red(`Error: ${message}`));\n }\n if (span) endSpan(span);\n process.exit(1);\n }\n\n // Get farm name\n let farmName = options.name;\n if (!farmName) {\n const isInteractive = process.stdin.isTTY;\n if (isInteractive) {\n const result = await prompts.text({\n message: \"Farm name\",\n placeholder: \"My Architecture Farm\",\n });\n\n if (typeof result === \"string\") {\n farmName = result;\n }\n }\n }\n\n if (!farmName) {\n farmName = \"Architecture Farm\";\n }\n\n // Create manifest with platform_view support if requested\n const manifest = FarmManifest.create(farmName, {\n platform_view: options.platformView || false,\n });\n await manifest.save(farmYamlPath);\n\n // Initialize farm-level git repository\n try {\n execSync(\"git init\", { cwd: farmPath, stdio: useJson ? \"pipe\" : \"inherit\" });\n execSync(\"git config user.email 'dr-farm@localhost'\", {\n cwd: farmPath,\n stdio: \"pipe\",\n });\n execSync(\"git config user.name 'DR Farm'\", {\n cwd: farmPath,\n stdio: \"pipe\",\n });\n\n // Add farm.yaml and commit\n execSync(\"git add farm.yaml\", { cwd: farmPath, stdio: \"pipe\" });\n execSync(\"git commit -m 'Initialize farm manifest'\", {\n cwd: farmPath,\n stdio: useJson ? \"pipe\" : \"inherit\",\n });\n } catch (gitError) {\n throw new Error(\n `Failed to initialize farm git repository: ${getErrorMessage(gitError)}`\n );\n }\n\n if (useJson) {\n console.log(JSON.stringify({ status: \"ok\", farmPath, farmName, platform_view: options.platformView || false }));\n } else {\n const platformViewNote = options.platformView ? \" (platform-view enabled)\" : \"\";\n handleSuccess(\n `Farm initialized: ${ansis.bold(farmName)}${platformViewNote}\\n Location: ${farmPath}`\n );\n }\n\n if (span) endSpan(span);\n } catch (error) {\n const useJsonError = options.format === \"json\" || isJson();\n if (useJsonError) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 1,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(1);\n }\n}\n\n/**\n * Add a project to the farm\n */\nexport async function farmAddCommand(\n name: string,\n options: {\n remote?: string;\n codebase?: string;\n format?: string;\n }\n): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.add\", { \"project.name\": name }) : null;\n const useJson = options.format === \"json\" || isJson();\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory. Run 'dr farm init' first.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n // Check if project already exists\n if (manifest.getProject(name)) {\n throw new Error(`Project '${name}' already exists in this farm`);\n }\n\n // Determine codebase path\n let codebasePath = options.codebase || name;\n\n // Clone if remote URL provided\n if (options.remote) {\n const codebaseFullPath = path.join(farmRoot, codebasePath);\n if (await fileExists(codebaseFullPath)) {\n throw new Error(`Codebase directory '${codebasePath}' already exists`);\n }\n\n if (!useJson) {\n handleInfo(`Cloning ${options.remote} to ${codebasePath}...`);\n }\n\n try {\n execFileSync(\"git\", [\"clone\", options.remote, codebaseFullPath], {\n stdio: useJson ? \"pipe\" : \"inherit\",\n });\n } catch (error) {\n throw new Error(`Failed to clone repository: ${getErrorMessage(error)}`);\n }\n }\n\n // Create and scaffold model folder\n const modelFolder = `${name}-model`;\n const modelFullPath = path.join(farmRoot, modelFolder);\n\n if (!(await fileExists(modelFullPath))) {\n // Initialize model with manifest and layer structure\n await Model.init(\n modelFullPath,\n {\n name: name,\n version: \"0.1.0\",\n description: undefined,\n author: undefined,\n specVersion: (await import(\"../utils/spec-version.js\")).getCliBundledSpecVersion(),\n created: new Date().toISOString(),\n },\n { lazyLoad: false }\n );\n\n if (!useJson) {\n handleInfo(`Created and initialized model folder: ${modelFolder}`);\n }\n }\n\n // Add project to manifest\n manifest.addProject(name, {\n name,\n source: codebasePath,\n model: modelFolder,\n remote: options.remote,\n });\n\n await manifest.save(farmYamlPath);\n\n // Commit farm.yaml changes to farm-level git repository if git is available\n // Check for git repo first\n const gitRepoExists = isGitRepository(farmRoot);\n\n // If git repo exists, proceed with commit (handle commit errors independently)\n if (gitRepoExists) {\n try {\n execSync(\"git add farm.yaml\", { cwd: farmRoot, stdio: \"pipe\" });\n execFileSync(\"git\", [\"commit\", \"-m\", `Add project: ${name}`], {\n cwd: farmRoot,\n stdio: useJson ? \"pipe\" : \"inherit\",\n });\n } catch (commitError) {\n const errorMsg = getErrorMessage(commitError);\n // If nothing to commit, that's fine\n if (!errorMsg.includes(\"nothing to commit\")) {\n throw new Error(`Failed to commit farm changes: ${errorMsg}`);\n }\n }\n }\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"ok\",\n project: name,\n source: codebasePath,\n model: modelFolder,\n })\n );\n } else {\n handleSuccess(\n `Project added to farm: ${ansis.bold(name)}\\n Codebase: ${codebasePath}\\n Model: ${modelFolder}`\n );\n }\n\n if (span) endSpan(span);\n } catch (error) {\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 1,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(1);\n }\n}\n\n/**\n * Remove a project from the farm\n */\nexport async function farmRemoveCommand(\n name: string,\n options: {\n deleteModel?: boolean;\n format?: string;\n }\n): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.remove\", { \"project.name\": name }) : null;\n const useJson = options.format === \"json\" || isJson();\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n // Check if project exists\n const project = manifest.getProject(name);\n if (!project) {\n throw new Error(`Project '${name}' not found in farm`);\n }\n\n // Remove model folder if requested\n if (options.deleteModel) {\n const modelFullPath = path.resolve(path.join(farmRoot, project.model));\n const farmRootResolved = path.resolve(farmRoot);\n\n // Validate that the resolved path is strictly within the farm root to prevent path traversal\n if (!modelFullPath.startsWith(farmRootResolved + path.sep)) {\n throw new Error(\n `Invalid model path: would escape farm root. Path: ${project.model}`\n );\n }\n\n if (await fileExists(modelFullPath)) {\n try {\n await rm(modelFullPath, { recursive: true, force: false });\n if (!useJson) {\n handleInfo(`Deleted model folder: ${project.model}`);\n }\n } catch (error) {\n throw new Error(`Failed to delete model folder: ${getErrorMessage(error)}`);\n }\n }\n }\n\n // Remove project from manifest\n manifest.removeProject(name);\n await manifest.save(farmYamlPath);\n\n // Commit farm.yaml changes to farm-level git repository if git is available\n // Check for git repo first\n const gitRepoExists = isGitRepository(farmRoot);\n\n // If git repo exists, proceed with commit (handle commit errors independently)\n if (gitRepoExists) {\n try {\n execSync(\"git add farm.yaml\", { cwd: farmRoot, stdio: \"pipe\" });\n execFileSync(\"git\", [\"commit\", \"-m\", `Remove project: ${name}`], {\n cwd: farmRoot,\n stdio: useJson ? \"pipe\" : \"inherit\",\n });\n } catch (commitError) {\n const errorMsg = getErrorMessage(commitError);\n // If nothing to commit, that's fine\n if (!errorMsg.includes(\"nothing to commit\")) {\n throw new Error(`Failed to commit farm changes: ${errorMsg}`);\n }\n }\n }\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"ok\",\n project: name,\n modelDeleted: options.deleteModel ?? false,\n })\n );\n } else {\n handleSuccess(`Project removed from farm: ${ansis.bold(name)}`);\n }\n\n if (span) endSpan(span);\n } catch (error) {\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 1,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(1);\n }\n}\n\n/**\n * Show farm status\n */\nexport async function farmStatusCommand(options: {\n format?: string;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.status\") : null;\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n const projects = manifest.getAllProjects();\n const engine = new FarmSyncEngine(farmRoot);\n\n // Compute pending changes using lightweight commit comparison\n const projectsWithStatus = await Promise.all(\n projects.map(async (p) => {\n try {\n const syncStatePath = path.join(farmRoot, p.model, \".farm-sync.yaml\");\n const syncState = await (await import(\"../core/farm-sync-state.js\")).FarmSyncState.loadOrCreate(\n syncStatePath,\n p.name\n );\n\n // Use lightweight commit comparison instead of full diff\n const currentCommit = await engine.getCurrentCommit(p.source);\n const lastSyncCommit = syncState.lastSyncCommit;\n const hasPendingChanges = !!(lastSyncCommit && lastSyncCommit !== currentCommit);\n\n return {\n name: p.name,\n source: p.source,\n model: p.model,\n remote: p.remote,\n last_sync_commit: lastSyncCommit,\n current_commit: currentCommit,\n has_pending_changes: hasPendingChanges,\n };\n } catch (error) {\n // If sync state doesn't exist yet, that's expected - treat as no sync yet\n // For unexpected errors (YAML parse, git permission, etc), always log them\n const errorMsg = getErrorMessage(error);\n if (\n !errorMsg.includes(\"not found\") &&\n !errorMsg.includes(\"does not exist\") &&\n !errorMsg.includes(\"ENOENT\")\n ) {\n // Unexpected error - always log it to surface issues to users\n console.error(`Warning: Error reading sync state for ${p.name}: ${errorMsg}`);\n }\n return {\n name: p.name,\n source: p.source,\n model: p.model,\n remote: p.remote,\n last_sync_commit: undefined,\n current_commit: undefined,\n has_pending_changes: false,\n };\n }\n })\n );\n\n const useJson = options.format === \"json\" || isJson();\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"ok\",\n farm: {\n name: manifest.name,\n path: farmRoot,\n created: manifest.created,\n modified: manifest.modified,\n platform_view: manifest.platform_view,\n },\n projects: projectsWithStatus,\n project_count: projects.length,\n })\n );\n } else {\n console.log(ansis.bold(`Farm: ${manifest.name}`));\n console.log(`Location: ${farmRoot}`);\n if (manifest.platform_view) {\n console.log(`Platform-View: ${ansis.green(\"enabled\")}`);\n }\n console.log(`Projects: ${projects.length}\\n`);\n\n if (projects.length === 0) {\n console.log(ansis.dim(\"No projects registered yet.\"));\n } else {\n projectsWithStatus.forEach((project) => {\n console.log(` ${ansis.cyan(project.name)}`);\n console.log(` Codebase: ${project.source}`);\n console.log(` Model: ${project.model}`);\n if (project.remote) {\n console.log(` Remote: ${project.remote}`);\n }\n if (project.has_pending_changes) {\n console.log(` Status: ${ansis.yellow(\"\u26A0 Pending changes\")}`);\n } else if (project.last_sync_commit) {\n console.log(` Status: ${ansis.green(\"\u2713 Up to date\")}`);\n } else {\n console.log(` Status: ${ansis.dim(\"Not synced yet\")}`);\n }\n });\n }\n }\n\n if (span) endSpan(span);\n } catch (error) {\n const useJsonError = options.format === \"json\" || isJson();\n if (useJsonError) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n}\n\n/**\n * Validate a farm project or all projects using composed scope\n */\nexport async function farmValidateCommand(options: {\n project?: string;\n verbose?: boolean;\n quiet?: boolean;\n output?: string;\n format?: string;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.validate\") : null;\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory. Run 'dr farm init' first.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const farmManifest = await FarmManifest.load(farmYamlPath);\n const useJson = options.format === \"json\" || isJson();\n\n // Determine which projects to validate\n let projectsToValidate = farmManifest.getAllProjects();\n let isPlatformViewValidation = false;\n\n if (options.project) {\n const project = farmManifest.getProject(options.project);\n if (!project) {\n throw new Error(`Project '${options.project}' not found in farm`);\n }\n projectsToValidate = [project];\n\n // Check if this is a platform-view project validation\n if (farmManifest.isPlatformViewEnabled() && options.project === \"platform-view\") {\n isPlatformViewValidation = true;\n } else if (options.project === \"platform-view\" && !farmManifest.isPlatformViewEnabled()) {\n // Warn if platform-view project is being validated but platform-view is not enabled\n if (!useJson && !options.quiet) {\n handleInfo(\n `Note: Validating platform-view project, but platform-view is not enabled on this farm`\n );\n }\n }\n }\n\n if (projectsToValidate.length === 0) {\n throw new Error(\"No projects found in farm\");\n }\n\n // Create composed validator from farm\n // This automatically resolves model-path overrides for all projects in the farm\n const composedValidator = await ComposedReferenceValidator.fromFarm(farmRoot);\n if (useJson) {\n console.log(JSON.stringify({ status: \"validating\", projects: projectsToValidate.length, platform_view: isPlatformViewValidation }));\n } else if (!options.quiet) {\n if (options.project) {\n const platformViewNote = isPlatformViewValidation ? \" (platform-view aggregation)\" : \"\";\n handleInfo(`Validating project '${options.project}'${platformViewNote} with farm-aware references...`);\n } else {\n handleInfo(`Validating ${projectsToValidate.length} farm project(s) with farm-aware references...`);\n }\n }\n\n const allResults = [];\n const reportData = [];\n\n // Validate each project\n for (const project of projectsToValidate) {\n const modelPath = path.join(farmRoot, project.model);\n\n // Check if model folder exists\n if (!(await fileExists(modelPath))) {\n const error = `Model folder not found for project '${project.name}' at ${modelPath}`;\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n project: project.name,\n message: error,\n })\n );\n } else {\n console.error(ansis.red(`Error: ${error}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n\n // Load the model using the safer startPath parameter\n // For detached models, check if manifest.yaml exists directly in the model folder.\n // If so, pass it directly to Model.load().\n let drModelPath = modelPath;\n const manifestPath = path.join(modelPath, \"manifest.yaml\");\n if (await fileExists(manifestPath)) {\n // Point directly to the manifest.yaml file\n drModelPath = manifestPath;\n }\n\n const model = await Model.load(drModelPath);\n\n let platformViewInfo: {\n declared_models: string[];\n missing_models: string[];\n } | undefined;\n\n // For platform-view projects, validate that all declared external models are resolvable\n if (isPlatformViewValidation) {\n const declaredModels = model.manifest.models || {};\n const declaredModelNames = Object.keys(declaredModels);\n\n platformViewInfo = {\n declared_models: declaredModelNames,\n missing_models: [],\n };\n\n if (declaredModelNames.length === 0) {\n if (!useJson && !options.quiet) {\n handleInfo(\n ` Platform-view project has no declared external models`\n );\n }\n } else {\n if (!useJson && !options.quiet) {\n handleInfo(\n ` Platform-view is declaring external models: ${declaredModelNames.join(\", \")}`\n );\n }\n\n // Verify all declared models are available in the farm\n const missingModels: string[] = [];\n for (const declaredModelName of declaredModelNames) {\n const farmProject = farmManifest.getProject(declaredModelName);\n if (!farmProject) {\n missingModels.push(declaredModelName);\n }\n }\n\n platformViewInfo.missing_models = missingModels;\n\n if (missingModels.length > 0) {\n if (!useJson) {\n console.error(\n ansis.yellow(\n ` \u26A0 Warning: The following declared external models are not registered in the farm: ${missingModels.join(\", \")}`\n )\n );\n }\n }\n }\n }\n\n // Validate using composed reference validator\n const result = await composedValidator.validateModel(model);\n\n allResults.push({ project: project.name, result });\n\n // Format and display validation output\n const formatted = ValidationFormatter.format(result, model, {\n verbose: options.verbose,\n quiet: options.quiet,\n });\n\n // Collect report data for output file\n const reportItem: any = {\n project: project.name,\n valid: result.isValid(),\n errors: result.errors.map((e) => ({\n message: e.message,\n layer: e.layer,\n elementId: e.elementId,\n location: e.location,\n })),\n warnings: result.warnings.map((w) => ({\n message: w.message,\n layer: w.layer,\n elementId: w.elementId,\n location: w.location,\n })),\n formatted,\n };\n\n if (platformViewInfo) {\n reportItem.platform_view_info = platformViewInfo;\n }\n\n reportData.push(reportItem);\n\n if (!options.quiet) {\n console.log(ansis.bold(`\\nProject: ${project.name}`));\n console.log(formatted);\n }\n\n if (!result.isValid()) {\n if (options.project) {\n // Single project validation failed\n throw new Error(`Validation failed for project '${project.name}'`);\n }\n // Multi-project validation: track but continue\n }\n }\n\n // Check if all validations passed\n const allValid = allResults.every((r) => r.result.isValid());\n\n // Write output file if requested\n if (options.output) {\n const outputExt = path.extname(options.output).toLowerCase();\n\n if (outputExt === \".json\") {\n // Write JSON report\n const jsonReport = {\n timestamp: new Date().toISOString(),\n farm_root: farmRoot,\n all_valid: allValid,\n projects: reportData.map((r) => {\n const projectData: any = {\n project: r.project,\n valid: r.valid,\n errors: r.errors,\n warnings: r.warnings,\n };\n if (r.platform_view_info) {\n projectData.platform_view_info = r.platform_view_info;\n }\n return projectData;\n }),\n };\n await (await import(\"fs/promises\")).writeFile(\n options.output,\n JSON.stringify(jsonReport, null, 2),\n \"utf-8\"\n );\n } else if (outputExt === \".md\") {\n // Write Markdown report\n let mdContent = `# Farm Validation Report\\n\\n`;\n mdContent += `**Date**: ${new Date().toISOString()}\\n`;\n mdContent += `**Farm Root**: ${farmRoot}\\n`;\n mdContent += `**Overall Status**: ${allValid ? \"\u2705 Valid\" : \"\u274C Invalid\"}\\n\\n`;\n\n mdContent += `## Projects\\n\\n`;\n for (const r of reportData) {\n mdContent += `### ${r.project}\\n\\n`;\n mdContent += `**Status**: ${r.valid ? \"\u2705 Valid\" : \"\u274C Invalid\"}\\n\\n`;\n\n if (r.errors.length > 0) {\n mdContent += `#### Errors (${r.errors.length})\\n\\n`;\n for (const err of r.errors) {\n mdContent += `- ${err.message}\\n`;\n }\n mdContent += \"\\n\";\n }\n\n if (r.warnings.length > 0) {\n mdContent += `#### Warnings (${r.warnings.length})\\n\\n`;\n for (const warn of r.warnings) {\n mdContent += `- ${warn.message}\\n`;\n }\n mdContent += \"\\n\";\n }\n }\n\n await (await import(\"fs/promises\")).writeFile(options.output, mdContent, \"utf-8\");\n } else {\n throw new Error(`Unsupported output format: ${outputExt}. Use .json or .md`);\n }\n\n if (!options.quiet) {\n handleInfo(`Report written to ${options.output}`);\n }\n }\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"ok\",\n projects: allResults.map((r) => ({\n name: r.project,\n valid: r.result.isValid(),\n errors: r.result.errors.length,\n warnings: r.result.warnings.length,\n })),\n all_valid: allValid,\n output: options.output ? path.resolve(options.output) : undefined,\n })\n );\n }\n\n if (!allValid) {\n if (span) endSpan(span);\n process.exit(1);\n }\n\n if (!options.quiet) {\n handleSuccess(\n options.project\n ? `Project '${options.project}' validated successfully`\n : `All farm projects validated successfully`\n );\n }\n\n if (span) endSpan(span);\n } catch (error) {\n const useJson = options.format === \"json\" || isJson();\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n}\n\n/**\n * Pull latest changes from remote for farm projects\n */\nexport async function farmPullCommand(options: {\n project?: string;\n verbose?: boolean;\n format?: string;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.pull\") : null;\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory. Run 'dr farm init' first.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n // Determine which projects to pull\n let projectsToPull = manifest.getAllProjects();\n if (options.project) {\n const project = manifest.getProject(options.project);\n if (!project) {\n throw new Error(`Project '${options.project}' not found in farm`);\n }\n projectsToPull = [project];\n }\n\n if (projectsToPull.length === 0) {\n throw new Error(\"No projects found in farm\");\n }\n\n const useJson = options.format === \"json\" || isJson();\n if (!useJson && !options.verbose) {\n handleInfo(`Pulling ${projectsToPull.length} project(s)...`);\n }\n\n // Create sync engine (model not needed for pull-only operations)\n const engine = new FarmSyncEngine(farmRoot);\n\n const results = [];\n\n // Pull each project\n for (const project of projectsToPull) {\n try {\n const commit = await engine.pullCodebase(project.source);\n\n results.push({\n project: project.name,\n status: \"success\",\n commit,\n });\n\n if (options.verbose && !useJson) {\n handleInfo(` \u2713 ${project.name}: ${commit.substring(0, 8)}`);\n }\n } catch (error) {\n results.push({\n project: project.name,\n status: \"error\",\n message: getErrorMessage(error),\n });\n\n if (!useJson) {\n console.error(ansis.red(` \u2717 ${project.name}: ${getErrorMessage(error)}`));\n }\n }\n }\n\n const allSucceeded = results.every((r) => r.status === \"success\");\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: allSucceeded ? \"ok\" : \"partial\",\n code: allSucceeded ? 0 : 1,\n projects: results,\n pulled: results.filter((r) => r.status === \"success\").length,\n failed: results.filter((r) => r.status === \"error\").length,\n })\n );\n } else if (allSucceeded) {\n handleSuccess(`Pulled ${projectsToPull.length} project(s) successfully`);\n } else {\n console.error(ansis.red(`Pull failed for some projects`));\n }\n\n if (span) endSpan(span);\n if (!allSucceeded) {\n process.exit(1);\n }\n } catch (error) {\n const useJson = options.format === \"json\" || isJson();\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n}\n\n/**\n * Sync farm projects with their models\n */\nexport async function farmSyncCommand(options: {\n project?: string;\n verbose?: boolean;\n dryRun?: boolean;\n force?: boolean;\n output?: string;\n format?: string;\n autoCommit?: boolean;\n concurrency?: string;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.sync\") : null;\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory. Run 'dr farm init' first.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n // Determine which projects to sync\n let projectsToSync = manifest.getAllProjects();\n if (options.project) {\n const project = manifest.getProject(options.project);\n if (!project) {\n throw new Error(`Project '${options.project}' not found in farm`);\n }\n projectsToSync = [project];\n }\n\n if (projectsToSync.length === 0) {\n throw new Error(\"No projects found in farm\");\n }\n\n // Parse concurrency level\n const concurrency = options.concurrency ? Math.max(1, parseInt(options.concurrency, 10)) : 1;\n if (isNaN(concurrency)) {\n throw new Error(\"Concurrency must be a positive number\");\n }\n\n // Reject incompatible option combination: --auto-commit with --concurrency > 1\n if (options.autoCommit && concurrency > 1) {\n throw new Error(\n \"Cannot use --auto-commit with --concurrency > 1: concurrent git operations would cause race conditions. \" +\n \"Use --concurrency 1 for auto-commit, or remove --auto-commit for parallel processing.\"\n );\n }\n\n const useJson = options.format === \"json\" || isJson();\n if (!useJson && !options.verbose) {\n handleInfo(`Syncing ${projectsToSync.length} project(s) (concurrency: ${concurrency})...`);\n }\n\n const allResults: FarmSyncResultEntry[] = [];\n\n // Process projects with concurrency control\n const processSyncProject = async (project: typeof projectsToSync[0]) => {\n try {\n const modelPath = path.join(farmRoot, project.model);\n\n if (!(await fileExists(modelPath))) {\n throw new Error(`Model folder not found for project '${project.name}' at ${modelPath}`);\n }\n\n // Load model using detached model layout\n let drModelPath = modelPath;\n const manifestPath = path.join(modelPath, \"manifest.yaml\");\n if (await fileExists(manifestPath)) {\n drModelPath = manifestPath;\n }\n\n try {\n const model = await Model.load(drModelPath);\n const engine = new FarmSyncEngine(farmRoot, model);\n\n const result = await engine.syncProject(project, {\n verbose: options.verbose,\n dryRun: options.dryRun,\n force: options.force,\n });\n\n const resultEntry: FarmSyncResultEntry = {\n project: project.name,\n status: result.status === \"failed\" ? \"error\" : result.status,\n change_count: result.changeCount,\n changeset_id: result.changesetId,\n files_changed: result.filesChanged,\n ambiguities: result.ambiguities.length,\n commits_before: result.commitsBefore,\n commits_after: result.commitsAfter,\n };\n\n // Auto-commit if requested and changes were staged\n if (options.autoCommit && result.changesetId && result.changeCount > 0 && !options.dryRun) {\n try {\n const projectModelPath = path.join(farmRoot, project.model);\n const stagingManager = new (await import(\"../core/staging-area.js\")).StagingAreaManager(\n projectModelPath,\n model\n );\n const commitResult = await stagingManager.commit(model, result.changesetId);\n resultEntry.auto_committed = true;\n resultEntry.committed_changes = commitResult.committed;\n\n // Commit changes to the farm-level git repository if git is available\n // Scope git add to the project's model folder to avoid staging unrelated changes\n // Check for git repo first\n const gitRepoExists = isGitRepository(farmRoot);\n\n // If git repo exists, proceed with commit (handle commit errors independently)\n if (gitRepoExists) {\n try {\n execFileSync(\"git\", [\"add\", project.model], { cwd: farmRoot, stdio: \"pipe\" });\n execFileSync(\n \"git\",\n [\"commit\", \"-m\", `Sync: ${result.changesetId} - ${commitResult.committed} change(s)`],\n { cwd: farmRoot, stdio: \"pipe\" }\n );\n } catch (gitCommitError) {\n // If there's nothing to commit (no changes), that's fine\n if (!getErrorMessage(gitCommitError).includes(\"nothing to commit\")) {\n throw gitCommitError;\n }\n }\n }\n\n if (options.verbose && !useJson) {\n handleInfo(` Auto-committed: ${commitResult.committed} change(s)`);\n }\n } catch (commitError) {\n resultEntry.auto_committed = false;\n resultEntry.commit_error = getErrorMessage(commitError);\n resultEntry.status = \"error\";\n if (!useJson) {\n handleInfo(` Auto-commit failed: ${getErrorMessage(commitError)}`);\n }\n }\n }\n\n allResults.push(resultEntry);\n\n if (options.verbose && !useJson) {\n handleInfo(`\\nProject: ${project.name}`);\n const statusEmoji = result.status === \"success\" ? \"\u2713\" : result.status === \"partial\" ? \"\u26A0\" : \"\u2717\";\n const statusText = result.status === \"success\" ? \"Success\" : result.status === \"partial\" ? \"Partial\" : \"Failed\";\n handleInfo(` Status: ${statusEmoji} ${statusText}`);\n handleInfo(` Commits: ${result.commitsBefore}...${result.commitsAfter}`);\n handleInfo(\n ` Files changed: +${result.filesChanged.added.length} ~${result.filesChanged.modified.length} -${result.filesChanged.deleted.length}`\n );\n handleInfo(` Staged changes: ${result.changeCount}`);\n if (result.changesetId) {\n handleInfo(` Changeset: ${result.changesetId}`);\n }\n if (result.ambiguities.length > 0) {\n handleInfo(` Ambiguities: ${result.ambiguities.length} (flagged for review)`);\n }\n for (const note of result.notes) {\n console.log(` ${note}`);\n }\n }\n } catch (error) {\n allResults.push({\n project: project.name,\n status: \"error\",\n message: getErrorMessage(error),\n });\n\n if (!useJson) {\n console.error(ansis.red(`\u2717 ${project.name}: ${getErrorMessage(error)}`));\n }\n }\n } catch (error) {\n allResults.push({\n project: project.name,\n status: \"error\",\n message: getErrorMessage(error),\n });\n\n if (!useJson) {\n console.error(ansis.red(`\u2717 ${project.name}: ${getErrorMessage(error)}`));\n }\n }\n };\n\n // Process with concurrency control\n if (concurrency === 1) {\n // Sequential processing\n for (const project of projectsToSync) {\n await processSyncProject(project);\n }\n } else {\n // Parallel processing with limited concurrency\n const queue = [...projectsToSync];\n const active: Promise<void>[] = [];\n\n while (queue.length > 0 || active.length > 0) {\n while (active.length < concurrency && queue.length > 0) {\n const project = queue.shift()!;\n const promise = processSyncProject(project);\n const wrapped = promise.then(() => {\n const idx = active.indexOf(wrapped);\n if (idx !== -1) {\n active.splice(idx, 1);\n }\n });\n active.push(wrapped);\n }\n\n if (active.length > 0) {\n await Promise.race(active);\n }\n }\n }\n\n const allSucceeded = allResults.every((r) => r.status === \"success\" || r.status === \"partial\");\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: allSucceeded ? \"ok\" : \"error\",\n code: allSucceeded ? 0 : 1,\n projects: allResults,\n synced: allResults.filter((r) => r.status === \"success\").length,\n failed: allResults.filter((r) => r.status === \"error\").length,\n auto_committed: options.autoCommit,\n })\n );\n } else {\n const synced = allResults.filter((r) => r.status === \"success\").length;\n if (allSucceeded) {\n handleSuccess(`Synced ${synced}/${projectsToSync.length} project(s)`);\n }\n }\n\n // Write output file if requested\n if (options.output) {\n const { writeFile } = await import(\"../utils/file-io.js\");\n const outputExt = path.extname(options.output).toLowerCase();\n\n if (outputExt === \".json\") {\n await writeFile(\n options.output,\n JSON.stringify(\n {\n timestamp: new Date().toISOString(),\n farm_root: farmRoot,\n projects: allResults,\n },\n null,\n 2\n )\n );\n }\n }\n\n if (span) endSpan(span);\n if (!allSucceeded) {\n process.exit(1);\n }\n } catch (error) {\n const useJson = options.format === \"json\" || isJson();\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n}\n\n/**\n * Register farm commands with the CLI\n */\nexport function farmCommands(program: Command): void {\n const farmGroup = program.command(\"farm\").description(\"Manage model farms\");\n\n farmGroup\n .command(\"init\")\n .description(\"Initialize a new farm\")\n .option(\"--name <name>\", \"Farm name\")\n .option(\"--platform-view\", \"Enable platform-view support for cross-model aggregation\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm init\n $ dr farm init --name \"My Architecture Farm\"\n $ dr farm init --platform-view\n $ dr farm init --format json\n\nNotes:\n When using --platform-view, create a project named exactly \"platform-view\" to serve as\n the aggregation hub. When validating this project with 'dr farm validate --project platform-view',\n the CLI will automatically resolve cross-model references from all farm projects.`\n )\n .action(async (options) => {\n await farmInitCommand(options);\n });\n\n farmGroup\n .command(\"add <name>\")\n .description(\"Add a project to the farm\")\n .option(\"--remote <url>\", \"Git remote URL to clone\")\n .option(\"--codebase <path>\", \"Path to codebase folder (defaults to project name)\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm add my-service\n $ dr farm add my-service --remote https://github.com/org/my-service.git\n $ dr farm add my-service --codebase ./services/my-service\n $ dr farm add my-service --format json`\n )\n .action(async (name, options) => {\n await farmAddCommand(name, options);\n });\n\n farmGroup\n .command(\"remove <name>\")\n .description(\"Remove a project from the farm\")\n .option(\"--delete-model\", \"Also delete the model folder\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm remove my-service\n $ dr farm remove my-service --delete-model\n $ dr farm remove my-service --format json`\n )\n .action(async (name, options) => {\n await farmRemoveCommand(name, options);\n });\n\n farmGroup\n .command(\"status\")\n .description(\"Show farm status and registered projects\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm status\n $ dr farm status --format json`\n )\n .action(async (options) => {\n await farmStatusCommand(options);\n });\n\n farmGroup\n .command(\"validate\")\n .description(\"Validate farm projects using composed scope (cross-model references)\")\n .option(\"--project <name>\", \"Validate only a specific project (default: all)\")\n .option(\"--verbose\", \"Show verbose validation output\")\n .option(\"--quiet\", \"Suppress success messages\")\n .option(\"--output <path>\", \"Export validation report to file (JSON/Markdown)\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm validate\n $ dr farm validate --project my-service\n $ dr farm validate --verbose\n $ dr farm validate --format json\n $ dr farm validate --output report.json\n\nNotes:\n For platform-view aggregation: Use 'dr farm validate --project platform-view' to validate\n a platform-view project. The project name must be exactly 'platform-view' and the farm\n must have platform-view enabled (set during 'dr farm init --platform-view').`\n )\n .action(async (options) => {\n await farmValidateCommand(options);\n });\n\n farmGroup\n .command(\"pull\")\n .description(\"Pull latest changes from remote for farm projects\")\n .option(\"--project <name>\", \"Pull only a specific project (default: all)\")\n .option(\"--verbose\", \"Show verbose output\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm pull\n $ dr farm pull --project my-service\n $ dr farm pull --verbose\n $ dr farm pull --format json`\n )\n .action(async (options) => {\n await farmPullCommand(options);\n });\n\n farmGroup\n .command(\"sync\")\n .description(\"Sync farm projects with their models (generates staged changesets)\")\n .option(\"--project <name>\", \"Sync only a specific project (default: all)\")\n .option(\"--verbose\", \"Show verbose output\")\n .option(\"--dry-run\", \"Preview without creating changesets\")\n .option(\"--force\", \"Proceed despite ambiguous file-to-element mappings\")\n .option(\"--output <path>\", \"Export sync report to file (JSON)\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .option(\"--auto-commit\", \"Automatically commit changes (bypasses staged review)\")\n .option(\"--concurrency <n>\", \"Process multiple projects in parallel (default: 1)\", \"1\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm sync\n $ dr farm sync --project my-service\n $ dr farm sync --verbose --output sync-report.json\n $ dr farm sync --dry-run\n $ dr farm sync --format json --auto-commit\n $ dr farm sync --concurrency 4\n\nAutomation (cron/CI):\n $ dr farm sync --format json --auto-commit --output sync-report.json\n $ dr farm sync --format json --concurrency 4 --output sync-report.json\n\nNote: --auto-commit and --concurrency > 1 cannot be used together (race condition risk).\nUse --concurrency 1 (default) with --auto-commit for automated syncs.`\n )\n .action(async (options) => {\n await farmSyncCommand(options);\n });\n\n farmGroup.showSuggestionAfterError();\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Farm Commands - Manage model farms and project registration\n */\n\nimport ansis from \"ansis\";\nimport { Command } from \"commander\";\nimport path from \"path\";\nimport { rm } from \"fs/promises\";\nimport { FarmManifest } from \"../core/farm-manifest.js\";\nimport { findFarmRoot, resolveModelDirectory } from \"../utils/project-paths.js\";\nimport { fileExists } from \"../utils/file-io.js\";\nimport { execSync, execFileSync } from \"child_process\";\nimport * as prompts from \"@clack/prompts\";\nimport { getErrorMessage, handleSuccess, handleInfo, handleWarning } from \"../utils/errors.js\";\nimport { isJson } from \"../utils/globals.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { Model } from \"../core/model.js\";\nimport { ComposedReferenceValidator } from \"../validators/composed-reference-validator.js\";\nimport { ValidationFormatter } from \"../validators/validation-formatter.js\";\nimport { FarmSyncEngine } from \"../core/farm-sync-engine.js\";\nimport { FarmSyncState, FarmSyncStateNotFoundError } from \"../core/farm-sync-state.js\";\n\ninterface FarmSyncResultEntry {\n project: string;\n status: \"success\" | \"error\" | \"partial\";\n change_count?: number;\n changeset_id?: string;\n files_changed?: { added: string[]; modified: string[]; deleted: string[] };\n ambiguities?: number;\n commits_before?: string;\n commits_after?: string;\n auto_committed?: boolean;\n committed_changes?: number;\n commit_error?: string;\n /** Whether the model changes were committed to the farm-level git repository */\n git_committed?: boolean;\n /** Set when the farm git repository could not be checked; changes were saved but not committed */\n git_warning?: string;\n message?: string;\n}\n\ninterface ProjectStatus {\n name: string;\n source: string;\n model: string;\n remote?: string;\n last_sync_commit: string | undefined;\n current_commit: string | undefined;\n has_pending_changes: boolean | undefined;\n /** Set when .farm-sync.yaml exists but could not be read (corrupt YAML, permissions, ...) */\n sync_state_error?: string;\n /** Set when the project's codebase directory is missing or its HEAD cannot be read */\n codebase_error?: string;\n}\n\n/**\n * Result of checking whether a directory is a git repository.\n * - `isRepo: true` \u2014 git rev-parse succeeded; auto-commits can proceed.\n * - `isRepo: false, error: undefined` \u2014 git reported \"not a git repository\"; auto-commits are\n * skipped silently (the farm was never put under version control).\n * - `isRepo: false, error: string` \u2014 git could not answer (binary missing, permission denied,\n * ...). Callers must surface `error` so a change that was saved but not committed is visible.\n */\ninterface GitRepositoryCheck {\n isRepo: boolean;\n error?: string;\n}\n\n/**\n * Check if a directory is a git repository, distinguishing \"not a repository\" from\n * unexpected failures of the git command itself.\n */\nfunction checkGitRepository(cwd: string): GitRepositoryCheck {\n try {\n execSync(\"git rev-parse --git-dir\", { cwd, stdio: \"pipe\" });\n return { isRepo: true };\n } catch (error) {\n const errorMsg = getErrorMessage(error);\n\n // Pattern: \"fatal: not a git repository\" (case insensitive check for safety)\n if (errorMsg.toLowerCase().includes(\"not a git repository\")) {\n return { isRepo: false };\n }\n\n // Missing git binary, permission denied, corrupt .git, ... \u2014 the caller decides\n // how to report it; the change itself has already been saved to disk.\n return { isRepo: false, error: errorMsg.trim() };\n }\n}\n\n/**\n * Build the user-facing warning for a change that was saved to disk but could not be\n * committed because the farm git repository could not be checked.\n */\nfunction uncommittedChangeWarning(what: string, farmRoot: string, gitError: string): string {\n return `${what} was saved but not committed: could not check git repository at ${farmRoot}: ${gitError}`;\n}\n\n/**\n * Resolve the top-level directory of the git repository containing `cwd`, or null when\n * `cwd` is not inside one (or git cannot answer).\n */\nfunction gitTopLevel(cwd: string): string | null {\n try {\n return execSync(\"git rev-parse --show-toplevel\", { cwd, stdio: \"pipe\", encoding: \"utf-8\" }).trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * True when `target` is tracked by the same git repository as `farmRoot`, i.e. a\n * `git add` of it from the farm root can succeed. A model outside the farm root, or inside\n * a nested checkout with its own `.git`, belongs to another repository.\n */\nfunction isInSameGitRepository(farmRoot: string, target: string): boolean {\n const farmTop = gitTopLevel(farmRoot);\n return farmTop !== null && farmTop === gitTopLevel(target);\n}\n\n/**\n * How `dr farm add` settled on a model folder for a project.\n */\ninterface ModelRegistration {\n /** Model path as recorded in farm.yaml: relative to the farm root, and allowed to leave it */\n modelFolder: string;\n /** Absolute path of the registered model directory */\n modelFullPath: string;\n /** True when an existing model was registered instead of scaffolding one */\n adopted: boolean;\n /** Set when --new-model ignored a model that lives in the codebase */\n ignoredModelPath?: string;\n /** User-facing warning attached to the registration (also carried in JSON output) */\n warning?: string;\n}\n\n/**\n * A path relative to the farm root, using forward slashes so farm.yaml stays portable.\n * Returns \".\" for the farm root itself.\n */\nfunction farmRelativePath(farmRoot: string, target: string): string {\n const rel = path.relative(farmRoot, target);\n return rel === \"\" ? \".\" : rel.split(path.sep).join(\"/\");\n}\n\n/**\n * True when `target` is `parent` itself or lies strictly inside it (lexical check on\n * resolved paths; symlinks are not followed).\n */\nfunction isWithinPath(target: string, parent: string): boolean {\n return target === parent || target.startsWith(parent + path.sep);\n}\n\n/**\n * Decide which model folder a newly added project should use.\n *\n * Lookup order, mirroring `ComposedReferenceValidator`'s external model resolution:\n * `{codebase}/documentation-robotics/model`, `{codebase}/model`, then the codebase path\n * itself. A codebase that already carries a model is adopted in place unless\n * `forceNewModel` asks for the old scaffold-a-duplicate behaviour; `explicitModel` skips\n * detection and registers that path (resolved with the same lookup order).\n */\nasync function resolveProjectModel(\n name: string,\n input: {\n farmRoot: string;\n codebaseFullPath: string;\n explicitModel?: string;\n forceNewModel: boolean;\n }\n): Promise<ModelRegistration> {\n const { farmRoot, codebaseFullPath, explicitModel, forceNewModel } = input;\n\n if (explicitModel) {\n const explicitFullPath = path.resolve(farmRoot, explicitModel);\n const resolved = await resolveModelDirectory(explicitFullPath, { requireManifest: true });\n if (!resolved) {\n throw new Error(\n `No model found at '${explicitModel}': expected manifest.yaml in ${explicitFullPath}, ` +\n `${path.join(explicitFullPath, \"model\")} or ${path.join(explicitFullPath, \"documentation-robotics\", \"model\")}. ` +\n `Omit --model to scaffold a new model at ${name}-model.`\n );\n }\n return {\n modelFolder: farmRelativePath(farmRoot, resolved.modelDir),\n modelFullPath: resolved.modelDir,\n adopted: true,\n };\n }\n\n // A codebase that self-hosts its model (documentation-robotics/model/manifest.yaml) is\n // adopted rather than shadowed by an empty duplicate (#962). The farm root itself is\n // never a candidate: a farm is not a model.\n const detected =\n codebaseFullPath === farmRoot\n ? null\n : await resolveModelDirectory(codebaseFullPath, { requireManifest: true });\n\n if (detected && !forceNewModel) {\n return {\n modelFolder: farmRelativePath(farmRoot, detected.modelDir),\n modelFullPath: detected.modelDir,\n adopted: true,\n };\n }\n\n // Scaffold (or reuse) <farm>/<name>-model\n const modelFolder = `${name}-model`;\n const modelFullPath = path.resolve(path.join(farmRoot, modelFolder));\n\n // Validate path traversal for model folder\n if (!modelFullPath.startsWith(farmRoot + path.sep)) {\n throw new Error(`Invalid model path: would escape farm root. Path: ${modelFolder}`);\n }\n\n return {\n modelFolder,\n modelFullPath,\n adopted: false,\n ...(detected ? { ignoredModelPath: farmRelativePath(farmRoot, detected.modelDir) } : {}),\n };\n}\n\n/**\n * Initialize a new farm\n */\nexport async function farmInitCommand(options: {\n name?: string;\n description?: string;\n format?: string;\n platformView?: boolean;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.init\") : null;\n\n try {\n const farmPath = process.cwd();\n const farmYamlPath = path.join(farmPath, \"farm.yaml\");\n\n // Check if farm.yaml already exists\n const useJson = options.format === \"json\" || isJson();\n if (await fileExists(farmYamlPath)) {\n const message = \"Farm already initialized in this directory\";\n if (useJson) {\n console.log(JSON.stringify({ status: \"error\", code: 1, message }));\n } else {\n console.error(ansis.red(`Error: ${message}`));\n }\n if (span) endSpan(span);\n process.exit(1);\n }\n\n // Get farm name\n let farmName = options.name;\n if (!farmName) {\n const isInteractive = process.stdin.isTTY;\n if (isInteractive) {\n const result = await prompts.text({\n message: \"Farm name\",\n placeholder: \"My Architecture Farm\",\n });\n\n if (typeof result === \"string\") {\n farmName = result;\n }\n }\n }\n\n if (!farmName) {\n farmName = \"Architecture Farm\";\n }\n\n // Create manifest with platform_view support if requested\n const manifest = FarmManifest.create(farmName, {\n platform_view: options.platformView || false,\n });\n await manifest.save(farmYamlPath);\n\n // Initialize farm-level git repository\n try {\n execSync(\"git init\", { cwd: farmPath, stdio: useJson ? \"pipe\" : \"inherit\" });\n execSync(\"git config user.email 'dr-farm@localhost'\", {\n cwd: farmPath,\n stdio: \"pipe\",\n });\n execSync(\"git config user.name 'DR Farm'\", {\n cwd: farmPath,\n stdio: \"pipe\",\n });\n\n // Add farm.yaml and commit\n execSync(\"git add farm.yaml\", { cwd: farmPath, stdio: \"pipe\" });\n execSync(\"git commit -m 'Initialize farm manifest'\", {\n cwd: farmPath,\n stdio: useJson ? \"pipe\" : \"inherit\",\n });\n } catch (gitError) {\n throw new Error(\n `Failed to initialize farm git repository: ${getErrorMessage(gitError)}`\n );\n }\n\n if (useJson) {\n console.log(JSON.stringify({ status: \"ok\", farmPath, farmName, platform_view: options.platformView || false }));\n } else {\n const platformViewNote = options.platformView ? \" (platform-view enabled)\" : \"\";\n handleSuccess(\n `Farm initialized: ${ansis.bold(farmName)}${platformViewNote}\\n Location: ${farmPath}`\n );\n }\n\n if (span) endSpan(span);\n } catch (error) {\n const useJsonError = options.format === \"json\" || isJson();\n if (useJsonError) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 1,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(1);\n }\n}\n\n/**\n * Add a project to the farm\n */\nexport async function farmAddCommand(\n name: string,\n options: {\n remote?: string;\n codebase?: string;\n model?: string;\n newModel?: boolean;\n format?: string;\n }\n): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.add\", { \"project.name\": name }) : null;\n const useJson = options.format === \"json\" || isJson();\n\n try {\n if (options.model && options.newModel) {\n throw new Error(\n \"--model and --new-model cannot be combined: --model registers an existing model, --new-model scaffolds a fresh one\"\n );\n }\n\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory. Run 'dr farm init' first.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n // Check if project already exists\n if (manifest.getProject(name)) {\n throw new Error(`Project '${name}' already exists in this farm`);\n }\n\n // Determine codebase path\n let codebasePath = options.codebase || name;\n\n const codebaseFullPath = path.resolve(path.join(farmRoot, codebasePath));\n const farmRootResolved = path.resolve(farmRoot);\n\n // Clone if remote URL provided\n if (options.remote) {\n // Validate path traversal: `git clone` writes to codebaseFullPath, so it must resolve\n // within farmRoot. Without --remote nothing is written to the codebase path (it is only\n // recorded in farm.yaml), so a sibling checkout such as `--codebase ../my-service` is\n // allowed and resolved later by FarmSyncEngine.\n if (!codebaseFullPath.startsWith(farmRootResolved + path.sep)) {\n throw new Error(\n `Invalid codebase path: would escape farm root. Path: ${codebasePath}`\n );\n }\n\n if (await fileExists(codebaseFullPath)) {\n throw new Error(`Codebase directory '${codebasePath}' already exists`);\n }\n\n if (!useJson) {\n handleInfo(`Cloning ${options.remote} to ${codebasePath}...`);\n }\n\n try {\n execFileSync(\"git\", [\"clone\", options.remote, codebaseFullPath], {\n stdio: useJson ? \"pipe\" : \"inherit\",\n });\n } catch (error) {\n throw new Error(`Failed to clone repository: ${getErrorMessage(error)}`);\n }\n }\n\n // Decide which model the project uses: an explicit --model path, the codebase's own\n // self-hosted model (adopted in place), or a fresh scaffold at <name>-model.\n const registration = await resolveProjectModel(name, {\n farmRoot: farmRootResolved,\n codebaseFullPath,\n explicitModel: options.model,\n forceNewModel: options.newModel ?? false,\n });\n const modelFolder = registration.modelFolder;\n\n if (registration.ignoredModelPath) {\n const ignoredWarning = `Codebase '${codebasePath}' already has a model at ${registration.ignoredModelPath}; ignoring it and scaffolding a new model at ${modelFolder} (--new-model)`;\n registration.warning = ignoredWarning;\n if (!useJson) {\n handleWarning(ignoredWarning);\n }\n }\n\n if (registration.adopted) {\n if (!useJson) {\n handleInfo(`Using existing model at ${registration.modelFullPath}; nothing was created`);\n }\n } else if (!(await fileExists(registration.modelFullPath))) {\n // Initialize model with manifest and layer structure\n await Model.init(\n registration.modelFullPath,\n {\n name: name,\n version: \"0.1.0\",\n description: undefined,\n author: undefined,\n specVersion: (await import(\"../utils/spec-version.js\")).getCliBundledSpecVersion(),\n created: new Date().toISOString(),\n },\n { lazyLoad: false }\n );\n\n if (!useJson) {\n handleInfo(`Created and initialized model folder: ${modelFolder}`);\n }\n }\n\n // Add project to manifest\n manifest.addProject(name, {\n name,\n source: codebasePath,\n model: modelFolder,\n remote: options.remote,\n });\n\n await manifest.save(farmYamlPath);\n\n // Commit farm.yaml changes to farm-level git repository if git is available\n const gitCheck = checkGitRepository(farmRoot);\n let gitCommitted = false;\n let gitWarning: string | undefined;\n\n if (gitCheck.error) {\n gitWarning = uncommittedChangeWarning(\"farm.yaml\", farmRoot, gitCheck.error);\n if (!useJson) {\n handleWarning(gitWarning);\n }\n } else if (gitCheck.isRepo) {\n // Proceed with commit (handle commit errors independently)\n try {\n execSync(\"git add farm.yaml\", { cwd: farmRoot, stdio: \"pipe\" });\n execFileSync(\"git\", [\"commit\", \"-m\", `Add project: ${name}`], {\n cwd: farmRoot,\n stdio: useJson ? \"pipe\" : \"inherit\",\n });\n gitCommitted = true;\n } catch (commitError) {\n const errorMsg = getErrorMessage(commitError);\n // If nothing to commit, that's fine\n if (!errorMsg.includes(\"nothing to commit\")) {\n throw new Error(`Failed to commit farm changes: ${errorMsg}`);\n }\n }\n }\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"ok\",\n project: name,\n source: codebasePath,\n model: modelFolder,\n model_path: registration.modelFullPath,\n model_adopted: registration.adopted,\n ...(registration.ignoredModelPath ? { ignored_model: registration.ignoredModelPath } : {}),\n ...(registration.warning ? { warning: registration.warning } : {}),\n git_committed: gitCommitted,\n ...(gitWarning ? { git_warning: gitWarning } : {}),\n })\n );\n } else {\n const modelNote = registration.adopted ? \" (existing model, adopted in place)\" : \"\";\n handleSuccess(\n `Project added to farm: ${ansis.bold(name)}\\n Codebase: ${codebasePath}\\n Model: ${modelFolder}${modelNote}`\n );\n }\n\n if (span) endSpan(span);\n } catch (error) {\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 1,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(1);\n }\n}\n\n/**\n * Remove a project from the farm\n */\nexport async function farmRemoveCommand(\n name: string,\n options: {\n deleteModel?: boolean;\n format?: string;\n }\n): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.remove\", { \"project.name\": name }) : null;\n const useJson = options.format === \"json\" || isJson();\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n // Check if project exists\n const project = manifest.getProject(name);\n if (!project) {\n throw new Error(`Project '${name}' not found in farm`);\n }\n\n // Remove model folder if requested. Only a model the farm scaffolded for itself is\n // deleted: one adopted from the codebase (inside the project's source tree) or lying\n // outside the farm root is left untouched and the project is merely deregistered.\n let modelDeleted = false;\n let modelKeptReason: string | undefined;\n if (options.deleteModel) {\n const modelFullPath = path.resolve(path.join(farmRoot, project.model));\n const farmRootResolved = path.resolve(farmRoot);\n const codebaseFullPath = path.resolve(path.join(farmRoot, project.source));\n\n if (!modelFullPath.startsWith(farmRootResolved + path.sep)) {\n // Traversal guard: never delete anything outside the farm root\n modelKeptReason = `model '${project.model}' lies outside the farm root and is not managed by the farm`;\n } else if (isWithinPath(modelFullPath, codebaseFullPath)) {\n modelKeptReason = `model '${project.model}' is the codebase's own model (inside '${project.source}')`;\n }\n\n if (modelKeptReason) {\n if (!useJson) {\n handleWarning(`Model folder not deleted: ${modelKeptReason}. Remove it by hand if that is what you want.`);\n }\n } else if (await fileExists(modelFullPath)) {\n try {\n await rm(modelFullPath, { recursive: true, force: false });\n modelDeleted = true;\n if (!useJson) {\n handleInfo(`Deleted model folder: ${project.model}`);\n }\n } catch (error) {\n throw new Error(`Failed to delete model folder: ${getErrorMessage(error)}`);\n }\n }\n }\n\n // Remove project from manifest\n manifest.removeProject(name);\n await manifest.save(farmYamlPath);\n\n // Commit farm.yaml changes to farm-level git repository if git is available\n const gitCheck = checkGitRepository(farmRoot);\n let gitCommitted = false;\n let gitWarning: string | undefined;\n\n if (gitCheck.error) {\n gitWarning = uncommittedChangeWarning(\"farm.yaml\", farmRoot, gitCheck.error);\n if (!useJson) {\n handleWarning(gitWarning);\n }\n } else if (gitCheck.isRepo) {\n // Proceed with commit (handle commit errors independently)\n try {\n execSync(\"git add farm.yaml\", { cwd: farmRoot, stdio: \"pipe\" });\n execFileSync(\"git\", [\"commit\", \"-m\", `Remove project: ${name}`], {\n cwd: farmRoot,\n stdio: useJson ? \"pipe\" : \"inherit\",\n });\n gitCommitted = true;\n } catch (commitError) {\n const errorMsg = getErrorMessage(commitError);\n // If nothing to commit, that's fine\n if (!errorMsg.includes(\"nothing to commit\")) {\n throw new Error(`Failed to commit farm changes: ${errorMsg}`);\n }\n }\n }\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"ok\",\n project: name,\n model: project.model,\n modelDeleted,\n ...(modelKeptReason ? { model_kept_reason: modelKeptReason } : {}),\n git_committed: gitCommitted,\n ...(gitWarning ? { git_warning: gitWarning } : {}),\n })\n );\n } else {\n handleSuccess(`Project removed from farm: ${ansis.bold(name)}`);\n }\n\n if (span) endSpan(span);\n } catch (error) {\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 1,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(1);\n }\n}\n\n/**\n * Show farm status\n */\nexport async function farmStatusCommand(options: {\n format?: string;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.status\") : null;\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n const projects = manifest.getAllProjects();\n const engine = new FarmSyncEngine(farmRoot);\n\n const useJson = options.format === \"json\" || isJson();\n\n // Compute pending changes using lightweight commit comparison\n const projectsWithStatus = await Promise.all(\n projects.map(async (p) => {\n const result: ProjectStatus = {\n name: p.name,\n source: p.source,\n model: p.model,\n remote: p.remote,\n last_sync_commit: undefined,\n current_commit: undefined,\n has_pending_changes: undefined,\n };\n\n // Step 1: sync state. A missing .farm-sync.yaml means the project has never been\n // synced (loadOrCreate returns an empty state); anything else is a real error.\n let lastSyncCommit: string | undefined;\n try {\n const syncStatePath = path.join(farmRoot, p.model, \".farm-sync.yaml\");\n const syncState = await FarmSyncState.loadOrCreate(syncStatePath, p.name);\n lastSyncCommit = syncState.lastSyncCommit;\n result.last_sync_commit = lastSyncCommit;\n } catch (error) {\n if (error instanceof FarmSyncStateNotFoundError) {\n // Not synced yet (defensive: loadOrCreate does not normally throw this)\n result.has_pending_changes = false;\n return result;\n }\n // Corrupt YAML, permission denied, ... \u2014 report it on the project\n result.sync_state_error = getErrorMessage(error);\n if (!useJson) {\n handleWarning(`${p.name}: could not read sync state: ${result.sync_state_error}`);\n }\n return result;\n }\n\n // Step 2: codebase HEAD. A missing codebase directory is an error on the project,\n // never \"not synced yet\".\n try {\n const currentCommit = await engine.getCurrentCommit(p.source);\n result.current_commit = currentCommit;\n result.has_pending_changes = !!(lastSyncCommit && lastSyncCommit !== currentCommit);\n } catch (error) {\n result.codebase_error = getErrorMessage(error);\n if (!useJson) {\n handleWarning(`${p.name}: ${result.codebase_error}`);\n }\n }\n\n return result;\n })\n );\n\n const projectsWithErrors = projectsWithStatus.filter(\n (p) => p.sync_state_error !== undefined || p.codebase_error !== undefined\n );\n const allHealthy = projectsWithErrors.length === 0;\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: allHealthy ? \"ok\" : \"error\",\n code: allHealthy ? 0 : 1,\n farm: {\n name: manifest.name,\n path: farmRoot,\n created: manifest.created,\n modified: manifest.modified,\n platform_view: manifest.platform_view,\n },\n projects: projectsWithStatus,\n project_count: projects.length,\n })\n );\n } else {\n console.log(ansis.bold(`Farm: ${manifest.name}`));\n console.log(`Location: ${farmRoot}`);\n if (manifest.platform_view) {\n console.log(`Platform-View: ${ansis.green(\"enabled\")}`);\n }\n console.log(`Projects: ${projects.length}\\n`);\n\n if (projects.length === 0) {\n console.log(ansis.dim(\"No projects registered yet.\"));\n } else {\n projectsWithStatus.forEach((project) => {\n console.log(` ${ansis.cyan(project.name)}`);\n console.log(` Codebase: ${project.source}`);\n console.log(` Model: ${project.model}`);\n if (project.remote) {\n console.log(` Remote: ${project.remote}`);\n }\n if (project.sync_state_error) {\n console.log(` Status: ${ansis.red(\"\u2717 Sync state corrupted\")}`);\n console.log(` Error: ${project.sync_state_error}`);\n } else if (project.codebase_error) {\n console.log(` Status: ${ansis.red(\"\u2717 Codebase unavailable\")}`);\n console.log(` Error: ${project.codebase_error}`);\n } else if (project.has_pending_changes) {\n console.log(` Status: ${ansis.yellow(\"\u26A0 Pending changes\")}`);\n } else if (project.last_sync_commit) {\n console.log(` Status: ${ansis.green(\"\u2713 Up to date\")}`);\n } else {\n console.log(` Status: ${ansis.dim(\"Not synced yet\")}`);\n }\n });\n }\n\n if (!allHealthy) {\n console.error(\n ansis.red(`\\n${projectsWithErrors.length} project(s) could not be checked (see errors above)`)\n );\n }\n }\n\n if (span) endSpan(span);\n if (!allHealthy) {\n process.exit(1);\n }\n } catch (error) {\n const useJsonError = options.format === \"json\" || isJson();\n if (useJsonError) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n}\n\n/**\n * Validate a farm project or all projects using composed scope\n */\nexport async function farmValidateCommand(options: {\n project?: string;\n verbose?: boolean;\n quiet?: boolean;\n output?: string;\n format?: string;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.validate\") : null;\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory. Run 'dr farm init' first.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const farmManifest = await FarmManifest.load(farmYamlPath);\n const useJson = options.format === \"json\" || isJson();\n\n // Determine which projects to validate\n let projectsToValidate = farmManifest.getAllProjects();\n let isPlatformViewValidation = false;\n\n if (options.project) {\n const project = farmManifest.getProject(options.project);\n if (!project) {\n throw new Error(`Project '${options.project}' not found in farm`);\n }\n projectsToValidate = [project];\n\n // Check if this is a platform-view project validation\n if (farmManifest.isPlatformViewEnabled() && options.project === \"platform-view\") {\n isPlatformViewValidation = true;\n } else if (options.project === \"platform-view\" && !farmManifest.isPlatformViewEnabled()) {\n // Warn if platform-view project is being validated but platform-view is not enabled\n if (!useJson && !options.quiet) {\n handleInfo(\n `Note: Validating platform-view project, but platform-view is not enabled on this farm`\n );\n }\n }\n }\n\n if (projectsToValidate.length === 0) {\n throw new Error(\"No projects found in farm\");\n }\n\n // Create composed validator from farm\n // This automatically resolves model-path overrides for all projects in the farm\n const composedValidator = await ComposedReferenceValidator.fromFarm(farmRoot);\n if (useJson) {\n console.log(JSON.stringify({ status: \"validating\", projects: projectsToValidate.length, platform_view: isPlatformViewValidation }));\n } else if (!options.quiet) {\n if (options.project) {\n const platformViewNote = isPlatformViewValidation ? \" (platform-view aggregation)\" : \"\";\n handleInfo(`Validating project '${options.project}'${platformViewNote} with farm-aware references...`);\n } else {\n handleInfo(`Validating ${projectsToValidate.length} farm project(s) with farm-aware references...`);\n }\n }\n\n const allResults = [];\n const reportData = [];\n\n // Validate each project\n for (const project of projectsToValidate) {\n const modelPath = path.join(farmRoot, project.model);\n\n // Check if model folder exists\n if (!(await fileExists(modelPath))) {\n const error = `Model folder not found for project '${project.name}' at ${modelPath}`;\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n project: project.name,\n message: error,\n })\n );\n } else {\n console.error(ansis.red(`Error: ${error}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n\n // Load the model using the safer startPath parameter\n // For detached models, check if manifest.yaml exists directly in the model folder.\n // If so, pass it directly to Model.load().\n let drModelPath = modelPath;\n const manifestPath = path.join(modelPath, \"manifest.yaml\");\n if (await fileExists(manifestPath)) {\n // Point directly to the manifest.yaml file\n drModelPath = manifestPath;\n }\n\n const model = await Model.load(drModelPath);\n\n let platformViewInfo: {\n declared_models: string[];\n missing_models: string[];\n } | undefined;\n\n // For platform-view projects, validate that all declared external models are resolvable\n if (isPlatformViewValidation) {\n const declaredModels = model.manifest.models || {};\n const declaredModelNames = Object.keys(declaredModels);\n\n platformViewInfo = {\n declared_models: declaredModelNames,\n missing_models: [],\n };\n\n if (declaredModelNames.length === 0) {\n if (!useJson && !options.quiet) {\n handleInfo(\n ` Platform-view project has no declared external models`\n );\n }\n } else {\n if (!useJson && !options.quiet) {\n handleInfo(\n ` Platform-view is declaring external models: ${declaredModelNames.join(\", \")}`\n );\n }\n\n // Verify all declared models are available in the farm\n const missingModels: string[] = [];\n for (const declaredModelName of declaredModelNames) {\n const farmProject = farmManifest.getProject(declaredModelName);\n if (!farmProject) {\n missingModels.push(declaredModelName);\n }\n }\n\n platformViewInfo.missing_models = missingModels;\n\n if (missingModels.length > 0) {\n if (!useJson) {\n console.error(\n ansis.yellow(\n ` \u26A0 Warning: The following declared external models are not registered in the farm: ${missingModels.join(\", \")}`\n )\n );\n }\n }\n }\n }\n\n // Validate using composed reference validator\n const result = await composedValidator.validateModel(model);\n\n allResults.push({ project: project.name, result });\n\n // Format and display validation output\n const formatted = ValidationFormatter.format(result, model, {\n verbose: options.verbose,\n quiet: options.quiet,\n });\n\n // Collect report data for output file\n const reportItem: any = {\n project: project.name,\n valid: result.isValid(),\n errors: result.errors.map((e) => ({\n message: e.message,\n layer: e.layer,\n elementId: e.elementId,\n location: e.location,\n })),\n warnings: result.warnings.map((w) => ({\n message: w.message,\n layer: w.layer,\n elementId: w.elementId,\n location: w.location,\n })),\n formatted,\n };\n\n if (platformViewInfo) {\n reportItem.platform_view_info = platformViewInfo;\n }\n\n reportData.push(reportItem);\n\n if (!options.quiet) {\n console.log(ansis.bold(`\\nProject: ${project.name}`));\n console.log(formatted);\n }\n\n if (!result.isValid()) {\n if (options.project) {\n // Single project validation failed\n throw new Error(`Validation failed for project '${project.name}'`);\n }\n // Multi-project validation: track but continue\n }\n }\n\n // Check if all validations passed\n const allValid = allResults.every((r) => r.result.isValid());\n\n // Write output file if requested\n if (options.output) {\n const outputExt = path.extname(options.output).toLowerCase();\n\n if (outputExt === \".json\") {\n // Write JSON report\n const jsonReport = {\n timestamp: new Date().toISOString(),\n farm_root: farmRoot,\n all_valid: allValid,\n projects: reportData.map((r) => {\n const projectData: any = {\n project: r.project,\n valid: r.valid,\n errors: r.errors,\n warnings: r.warnings,\n };\n if (r.platform_view_info) {\n projectData.platform_view_info = r.platform_view_info;\n }\n return projectData;\n }),\n };\n await (await import(\"fs/promises\")).writeFile(\n options.output,\n JSON.stringify(jsonReport, null, 2),\n \"utf-8\"\n );\n } else if (outputExt === \".md\") {\n // Write Markdown report\n let mdContent = `# Farm Validation Report\\n\\n`;\n mdContent += `**Date**: ${new Date().toISOString()}\\n`;\n mdContent += `**Farm Root**: ${farmRoot}\\n`;\n mdContent += `**Overall Status**: ${allValid ? \"\u2705 Valid\" : \"\u274C Invalid\"}\\n\\n`;\n\n mdContent += `## Projects\\n\\n`;\n for (const r of reportData) {\n mdContent += `### ${r.project}\\n\\n`;\n mdContent += `**Status**: ${r.valid ? \"\u2705 Valid\" : \"\u274C Invalid\"}\\n\\n`;\n\n if (r.errors.length > 0) {\n mdContent += `#### Errors (${r.errors.length})\\n\\n`;\n for (const err of r.errors) {\n mdContent += `- ${err.message}\\n`;\n }\n mdContent += \"\\n\";\n }\n\n if (r.warnings.length > 0) {\n mdContent += `#### Warnings (${r.warnings.length})\\n\\n`;\n for (const warn of r.warnings) {\n mdContent += `- ${warn.message}\\n`;\n }\n mdContent += \"\\n\";\n }\n }\n\n await (await import(\"fs/promises\")).writeFile(options.output, mdContent, \"utf-8\");\n } else {\n throw new Error(`Unsupported output format: ${outputExt}. Use .json or .md`);\n }\n\n if (!options.quiet) {\n handleInfo(`Report written to ${options.output}`);\n }\n }\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"ok\",\n projects: allResults.map((r) => ({\n name: r.project,\n valid: r.result.isValid(),\n errors: r.result.errors.length,\n warnings: r.result.warnings.length,\n })),\n all_valid: allValid,\n output: options.output ? path.resolve(options.output) : undefined,\n })\n );\n }\n\n if (!allValid) {\n if (span) endSpan(span);\n process.exit(1);\n }\n\n if (!options.quiet) {\n handleSuccess(\n options.project\n ? `Project '${options.project}' validated successfully`\n : `All farm projects validated successfully`\n );\n }\n\n if (span) endSpan(span);\n } catch (error) {\n const useJson = options.format === \"json\" || isJson();\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n}\n\n/**\n * Pull latest changes from remote for farm projects\n */\nexport async function farmPullCommand(options: {\n project?: string;\n verbose?: boolean;\n format?: string;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.pull\") : null;\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory. Run 'dr farm init' first.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n // Determine which projects to pull\n let projectsToPull = manifest.getAllProjects();\n if (options.project) {\n const project = manifest.getProject(options.project);\n if (!project) {\n throw new Error(`Project '${options.project}' not found in farm`);\n }\n projectsToPull = [project];\n }\n\n if (projectsToPull.length === 0) {\n throw new Error(\"No projects found in farm\");\n }\n\n const useJson = options.format === \"json\" || isJson();\n if (!useJson && !options.verbose) {\n handleInfo(`Pulling ${projectsToPull.length} project(s)...`);\n }\n\n // Create sync engine (model not needed for pull-only operations)\n const engine = new FarmSyncEngine(farmRoot);\n\n const results = [];\n\n // Pull each project\n for (const project of projectsToPull) {\n try {\n const commit = await engine.pullCodebase(project.source);\n\n results.push({\n project: project.name,\n status: \"success\",\n commit,\n });\n\n if (options.verbose && !useJson) {\n handleInfo(` \u2713 ${project.name}: ${commit.substring(0, 8)}`);\n }\n } catch (error) {\n results.push({\n project: project.name,\n status: \"error\",\n message: getErrorMessage(error),\n });\n\n if (!useJson) {\n console.error(ansis.red(` \u2717 ${project.name}: ${getErrorMessage(error)}`));\n }\n }\n }\n\n const allSucceeded = results.every((r) => r.status === \"success\");\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: allSucceeded ? \"ok\" : \"partial\",\n code: allSucceeded ? 0 : 1,\n projects: results,\n pulled: results.filter((r) => r.status === \"success\").length,\n failed: results.filter((r) => r.status === \"error\").length,\n })\n );\n } else if (allSucceeded) {\n handleSuccess(`Pulled ${projectsToPull.length} project(s) successfully`);\n } else {\n console.error(ansis.red(`Pull failed for some projects`));\n }\n\n if (span) endSpan(span);\n if (!allSucceeded) {\n process.exit(1);\n }\n } catch (error) {\n const useJson = options.format === \"json\" || isJson();\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n}\n\n/**\n * Sync farm projects with their models\n */\nexport async function farmSyncCommand(options: {\n project?: string;\n verbose?: boolean;\n dryRun?: boolean;\n force?: boolean;\n output?: string;\n format?: string;\n autoCommit?: boolean;\n concurrency?: string;\n}): Promise<void> {\n const span = isTelemetryEnabled ? startSpan(\"farm.sync\") : null;\n\n try {\n // Find farm root\n const farmRoot = await findFarmRoot();\n if (!farmRoot) {\n throw new Error(\"Not in a farm directory. Run 'dr farm init' first.\");\n }\n\n const farmYamlPath = path.join(farmRoot, \"farm.yaml\");\n const manifest = await FarmManifest.load(farmYamlPath);\n\n // Determine which projects to sync\n let projectsToSync = manifest.getAllProjects();\n if (options.project) {\n const project = manifest.getProject(options.project);\n if (!project) {\n throw new Error(`Project '${options.project}' not found in farm`);\n }\n projectsToSync = [project];\n }\n\n if (projectsToSync.length === 0) {\n throw new Error(\"No projects found in farm\");\n }\n\n // Parse concurrency level\n const concurrency = options.concurrency ? Math.max(1, parseInt(options.concurrency, 10)) : 1;\n if (isNaN(concurrency)) {\n throw new Error(\"Concurrency must be a positive number\");\n }\n\n // Reject incompatible option combination: --auto-commit with --concurrency > 1\n if (options.autoCommit && concurrency > 1) {\n throw new Error(\n \"Cannot use --auto-commit with --concurrency > 1: concurrent git operations would cause race conditions. \" +\n \"Use --concurrency 1 for auto-commit, or remove --auto-commit for parallel processing.\"\n );\n }\n\n // Validate the report path before any project is synced so an unsupported extension\n // fails fast instead of silently writing nothing after the work is done\n if (options.output) {\n const outputExt = path.extname(options.output).toLowerCase();\n if (outputExt !== \".json\") {\n throw new Error(`Unsupported output format: ${outputExt || \"(no extension)\"}. Use .json`);\n }\n }\n\n const useJson = options.format === \"json\" || isJson();\n if (!useJson && !options.verbose) {\n handleInfo(`Syncing ${projectsToSync.length} project(s) (concurrency: ${concurrency})...`);\n }\n\n const allResults: FarmSyncResultEntry[] = [];\n\n // Process projects with concurrency control\n const processSyncProject = async (project: typeof projectsToSync[0]) => {\n try {\n const modelPath = path.join(farmRoot, project.model);\n\n if (!(await fileExists(modelPath))) {\n throw new Error(`Model folder not found for project '${project.name}' at ${modelPath}`);\n }\n\n // Load model using detached model layout\n let drModelPath = modelPath;\n const manifestPath = path.join(modelPath, \"manifest.yaml\");\n if (await fileExists(manifestPath)) {\n drModelPath = manifestPath;\n }\n\n try {\n const model = await Model.load(drModelPath);\n const engine = new FarmSyncEngine(farmRoot, model);\n\n const result = await engine.syncProject(project, {\n verbose: options.verbose,\n dryRun: options.dryRun,\n force: options.force,\n });\n\n const resultEntry: FarmSyncResultEntry = {\n project: project.name,\n status: result.status === \"failed\" ? \"error\" : result.status,\n change_count: result.changeCount,\n changeset_id: result.changesetId,\n files_changed: result.filesChanged,\n ambiguities: result.ambiguities.length,\n commits_before: result.commitsBefore,\n commits_after: result.commitsAfter,\n };\n\n // Auto-commit if requested and changes were staged\n if (options.autoCommit && result.changesetId && result.changeCount > 0 && !options.dryRun) {\n try {\n // The staging area lives under the model's project root (which, for a model\n // adopted from a codebase, is the codebase itself rather than farm.yaml's `model`)\n const stagingManager = new (await import(\"../core/staging-area.js\")).StagingAreaManager(\n model.rootPath,\n model\n );\n const commitResult = await stagingManager.commit(model, result.changesetId);\n resultEntry.auto_committed = true;\n resultEntry.committed_changes = commitResult.committed;\n\n // Commit changes to the farm-level git repository if git is available\n // Scope git add to the project's model folder to avoid staging unrelated changes\n const gitCheck = checkGitRepository(farmRoot);\n\n if (gitCheck.error) {\n // The model changes are on disk; say so rather than silently skipping the commit\n resultEntry.git_committed = false;\n resultEntry.git_warning = uncommittedChangeWarning(\n `Model '${project.model}'`,\n farmRoot,\n gitCheck.error\n );\n if (!useJson) {\n handleWarning(`${project.name}: ${resultEntry.git_warning}`);\n }\n } else if (gitCheck.isRepo && !isInSameGitRepository(farmRoot, modelPath)) {\n // An adopted model outside the farm's repository (a sibling checkout, or a\n // nested clone with its own .git) cannot be committed from the farm root.\n // The changes are on disk in the model's own repository; say so.\n resultEntry.git_committed = false;\n resultEntry.git_warning =\n `Model '${project.model}' is outside the farm git repository at ${farmRoot}: ` +\n `the synced changes were saved but not committed. Commit them in the model's own repository.`;\n if (!useJson) {\n handleWarning(`${project.name}: ${resultEntry.git_warning}`);\n }\n } else if (gitCheck.isRepo) {\n // Proceed with commit (handle commit errors independently)\n try {\n execFileSync(\"git\", [\"add\", project.model], { cwd: farmRoot, stdio: \"pipe\" });\n execFileSync(\n \"git\",\n [\"commit\", \"-m\", `Sync: ${result.changesetId} - ${commitResult.committed} change(s)`],\n { cwd: farmRoot, stdio: \"pipe\" }\n );\n resultEntry.git_committed = true;\n } catch (gitCommitError) {\n // If there's nothing to commit (no changes), that's fine\n if (!getErrorMessage(gitCommitError).includes(\"nothing to commit\")) {\n throw gitCommitError;\n }\n resultEntry.git_committed = true;\n }\n } else {\n resultEntry.git_committed = false;\n }\n\n if (options.verbose && !useJson) {\n handleInfo(` Auto-committed: ${commitResult.committed} change(s)`);\n }\n } catch (commitError) {\n resultEntry.auto_committed = false;\n resultEntry.commit_error = getErrorMessage(commitError);\n resultEntry.status = \"error\";\n if (!useJson) {\n handleWarning(`${project.name}: auto-commit failed: ${getErrorMessage(commitError)}`);\n }\n }\n }\n\n allResults.push(resultEntry);\n\n if (options.verbose && !useJson) {\n handleInfo(`\\nProject: ${project.name}`);\n const statusEmoji = result.status === \"success\" ? \"\u2713\" : result.status === \"partial\" ? \"\u26A0\" : \"\u2717\";\n const statusText = result.status === \"success\" ? \"Success\" : result.status === \"partial\" ? \"Partial\" : \"Failed\";\n handleInfo(` Status: ${statusEmoji} ${statusText}`);\n handleInfo(` Commits: ${result.commitsBefore}...${result.commitsAfter}`);\n handleInfo(\n ` Files changed: +${result.filesChanged.added.length} ~${result.filesChanged.modified.length} -${result.filesChanged.deleted.length}`\n );\n handleInfo(` Staged changes: ${result.changeCount}`);\n if (result.changesetId) {\n handleInfo(` Changeset: ${result.changesetId}`);\n }\n if (result.ambiguities.length > 0) {\n handleInfo(` Ambiguities: ${result.ambiguities.length} (flagged for review)`);\n }\n for (const note of result.notes) {\n console.log(` ${note}`);\n }\n }\n } catch (error) {\n allResults.push({\n project: project.name,\n status: \"error\",\n message: getErrorMessage(error),\n });\n\n if (!useJson) {\n console.error(ansis.red(`\u2717 ${project.name}: ${getErrorMessage(error)}`));\n }\n }\n } catch (error) {\n allResults.push({\n project: project.name,\n status: \"error\",\n message: getErrorMessage(error),\n });\n\n if (!useJson) {\n console.error(ansis.red(`\u2717 ${project.name}: ${getErrorMessage(error)}`));\n }\n }\n };\n\n // Process with concurrency control\n if (concurrency === 1) {\n // Sequential processing\n for (const project of projectsToSync) {\n await processSyncProject(project);\n }\n } else {\n // Parallel processing with limited concurrency\n const queue = [...projectsToSync];\n const active: Promise<void>[] = [];\n\n while (queue.length > 0 || active.length > 0) {\n while (active.length < concurrency && queue.length > 0) {\n const project = queue.shift()!;\n const promise = processSyncProject(project);\n const wrapped = promise.then(() => {\n const idx = active.indexOf(wrapped);\n if (idx !== -1) {\n active.splice(idx, 1);\n }\n });\n active.push(wrapped);\n }\n\n if (active.length > 0) {\n await Promise.race(active);\n }\n }\n }\n\n const allSucceeded = allResults.every((r) => r.status === \"success\" || r.status === \"partial\");\n\n if (useJson) {\n console.log(\n JSON.stringify({\n status: allSucceeded ? \"ok\" : \"error\",\n code: allSucceeded ? 0 : 1,\n projects: allResults,\n synced: allResults.filter((r) => r.status === \"success\").length,\n failed: allResults.filter((r) => r.status === \"error\").length,\n auto_committed: options.autoCommit,\n })\n );\n } else {\n const synced = allResults.filter((r) => r.status === \"success\").length;\n if (allSucceeded) {\n handleSuccess(`Synced ${synced}/${projectsToSync.length} project(s)`);\n }\n }\n\n // Write output file if requested (extension validated above; only .json is supported)\n if (options.output) {\n const { writeFile } = await import(\"../utils/file-io.js\");\n await writeFile(\n options.output,\n JSON.stringify(\n {\n timestamp: new Date().toISOString(),\n farm_root: farmRoot,\n projects: allResults,\n },\n null,\n 2\n )\n );\n if (!useJson) {\n handleInfo(`Report written to ${options.output}`);\n }\n }\n\n if (span) endSpan(span);\n if (!allSucceeded) {\n process.exit(1);\n }\n } catch (error) {\n const useJson = options.format === \"json\" || isJson();\n if (useJson) {\n console.log(\n JSON.stringify({\n status: \"error\",\n code: 2,\n message: getErrorMessage(error),\n })\n );\n } else {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n }\n if (span) endSpan(span);\n process.exit(2);\n }\n}\n\n/**\n * Register farm commands with the CLI\n */\nexport function farmCommands(program: Command): void {\n const farmGroup = program.command(\"farm\").description(\"Manage model farms\");\n\n farmGroup\n .command(\"init\")\n .description(\"Initialize a new farm\")\n .option(\"--name <name>\", \"Farm name\")\n .option(\"--platform-view\", \"Enable platform-view support for cross-model aggregation\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm init\n $ dr farm init --name \"My Architecture Farm\"\n $ dr farm init --platform-view\n $ dr farm init --format json\n\nNotes:\n When using --platform-view, create a project named exactly \"platform-view\" to serve as\n the aggregation hub. When validating this project with 'dr farm validate --project platform-view',\n the CLI will automatically resolve cross-model references from all farm projects.`\n )\n .action(async (options) => {\n await farmInitCommand(options);\n });\n\n farmGroup\n .command(\"add <name>\")\n .description(\"Add a project to the farm\")\n .option(\"--remote <url>\", \"Git remote URL to clone\")\n .option(\n \"--codebase <path>\",\n \"Path to codebase folder, relative to the farm root (defaults to project name; may point outside the farm root unless --remote is used)\"\n )\n .option(\n \"--model <path>\",\n \"Register an existing model at this path (relative to the farm root) instead of detecting or scaffolding one\"\n )\n .option(\n \"--new-model\",\n \"Always scaffold a fresh <name>-model, even when the codebase already carries a model\"\n )\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm add my-service\n $ dr farm add my-service --remote https://github.com/org/my-service.git\n $ dr farm add my-service --codebase ./services/my-service\n $ dr farm add my-service --codebase ../my-service # sibling checkout outside the farm root\n $ dr farm add my-service --codebase ../my-service --new-model\n $ dr farm add my-service --model ../shared-models/my-service\n $ dr farm add my-service --format json\n\nModel detection:\n If the codebase already holds a model (documentation-robotics/model/manifest.yaml, model/manifest.yaml\n or manifest.yaml at the codebase path itself), that model is adopted in place and nothing is\n created; farm.yaml records its path (which may lie outside the farm root). Use --new-model to\n scaffold a separate <name>-model regardless, or --model to point at a model explicitly.`\n )\n .action(async (name, options) => {\n await farmAddCommand(name, options);\n });\n\n farmGroup\n .command(\"remove <name>\")\n .description(\"Remove a project from the farm\")\n .option(\"--delete-model\", \"Also delete the model folder\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm remove my-service\n $ dr farm remove my-service --delete-model\n $ dr farm remove my-service --format json`\n )\n .action(async (name, options) => {\n await farmRemoveCommand(name, options);\n });\n\n farmGroup\n .command(\"status\")\n .description(\"Show farm status and registered projects\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm status\n $ dr farm status --format json`\n )\n .action(async (options) => {\n await farmStatusCommand(options);\n });\n\n farmGroup\n .command(\"validate\")\n .description(\"Validate farm projects using composed scope (cross-model references)\")\n .option(\"--project <name>\", \"Validate only a specific project (default: all)\")\n .option(\"--verbose\", \"Show verbose validation output\")\n .option(\"--quiet\", \"Suppress success messages\")\n .option(\"--output <path>\", \"Export validation report to file (JSON/Markdown)\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm validate\n $ dr farm validate --project my-service\n $ dr farm validate --verbose\n $ dr farm validate --format json\n $ dr farm validate --output report.json\n\nNotes:\n For platform-view aggregation: Use 'dr farm validate --project platform-view' to validate\n a platform-view project. The project name must be exactly 'platform-view' and the farm\n must have platform-view enabled (set during 'dr farm init --platform-view').`\n )\n .action(async (options) => {\n await farmValidateCommand(options);\n });\n\n farmGroup\n .command(\"pull\")\n .description(\"Pull latest changes from remote for farm projects\")\n .option(\"--project <name>\", \"Pull only a specific project (default: all)\")\n .option(\"--verbose\", \"Show verbose output\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm pull\n $ dr farm pull --project my-service\n $ dr farm pull --verbose\n $ dr farm pull --format json`\n )\n .action(async (options) => {\n await farmPullCommand(options);\n });\n\n farmGroup\n .command(\"sync\")\n .description(\"Sync farm projects with their models (generates staged changesets)\")\n .option(\"--project <name>\", \"Sync only a specific project (default: all)\")\n .option(\"--verbose\", \"Show verbose output\")\n .option(\"--dry-run\", \"Preview without creating changesets\")\n .option(\"--force\", \"Proceed despite ambiguous file-to-element mappings\")\n .option(\"--output <path>\", \"Export sync report to file (.json only)\")\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .option(\"--auto-commit\", \"Automatically commit changes (bypasses staged review)\")\n .option(\"--concurrency <n>\", \"Process multiple projects in parallel (default: 1)\", \"1\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr farm sync\n $ dr farm sync --project my-service\n $ dr farm sync --verbose --output sync-report.json\n $ dr farm sync --dry-run\n $ dr farm sync --format json --auto-commit\n $ dr farm sync --concurrency 4\n\nAutomation (cron/CI):\n $ dr farm sync --format json --auto-commit --output sync-report.json\n $ dr farm sync --format json --concurrency 4 --output sync-report.json\n\nNote: --auto-commit and --concurrency > 1 cannot be used together (race condition risk).\nUse --concurrency 1 (default) with --auto-commit for automated syncs.`\n )\n .action(async (options) => {\n await farmSyncCommand(options);\n });\n\n farmGroup.showSuggestionAfterError();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { intro, text, outro } from "@clack/prompts";
|
|
2
2
|
import ansis from "ansis";
|
|
3
|
-
import {
|
|
4
|
-
import { fileExists } from "../utils/file-io.js";
|
|
5
|
-
import { logVerbose, logDebug } from "../utils/globals.js";
|
|
6
|
-
import { installSpecReference } from "../utils/spec-installer.js";
|
|
3
|
+
import { hasModel, initProject } from "../core/project-init.js";
|
|
7
4
|
import { getCliBundledSpecVersion } from "../utils/spec-version.js";
|
|
8
5
|
import { isTelemetryEnabled, startSpan, endSpan } from "../telemetry/index.js";
|
|
9
6
|
import { getErrorMessage } from "../utils/errors.js";
|
|
10
|
-
import { regenerateLayerReports } from "./reports.js";
|
|
11
7
|
async function initCommand(options) {
|
|
12
8
|
intro(ansis.bold(ansis.blue("\u2699\uFE0F Initialize Documentation Robotics Model")));
|
|
13
9
|
const span = isTelemetryEnabled ? startSpan("model.init", {
|
|
@@ -16,8 +12,8 @@ async function initCommand(options) {
|
|
|
16
12
|
"init.hasAuthor": !!options.author
|
|
17
13
|
}) : null;
|
|
18
14
|
try {
|
|
19
|
-
const rootPath = process.cwd()
|
|
20
|
-
await
|
|
15
|
+
const rootPath = process.cwd();
|
|
16
|
+
await hasModel(rootPath) && (console.error(ansis.red("Error: Model already initialized in this directory")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Model already exists" }), endSpan(span), process.exit(1));
|
|
21
17
|
const isInteractive = process.stdin.isTTY;
|
|
22
18
|
isTelemetryEnabled && span && span.setAttribute("cli.interactive", isInteractive);
|
|
23
19
|
const skipPrompts = !!options.name, name = options.name || (isInteractive ? await text({
|
|
@@ -32,28 +28,15 @@ async function initCommand(options) {
|
|
|
32
28
|
message: "Author (optional):",
|
|
33
29
|
defaultValue: ""
|
|
34
30
|
}) : "");
|
|
35
|
-
isTelemetryEnabled && span && (span.setAttribute("model.name", name), span.setAttribute("model.specVersion", getCliBundledSpecVersion()))
|
|
36
|
-
const
|
|
31
|
+
isTelemetryEnabled && span && (span.setAttribute("model.name", name), span.setAttribute("model.specVersion", getCliBundledSpecVersion()));
|
|
32
|
+
const result = await initProject(rootPath, {
|
|
37
33
|
name,
|
|
38
|
-
version: "0.1.0",
|
|
39
34
|
description: description || void 0,
|
|
40
|
-
author: author || void 0
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}, { lazyLoad: !1 });
|
|
44
|
-
logVerbose(`Model saved with:
|
|
45
|
-
- Version: 0.1.0
|
|
46
|
-
- Spec Version: ${getCliBundledSpecVersion()}
|
|
47
|
-
- Location: ${rootPath}/documentation-robotics/model`), logDebug("Installing spec reference (.dr/ folder)..."), await installSpecReference(rootPath, !1), logVerbose("Spec reference installed"), logDebug("Generating reports and README...");
|
|
48
|
-
try {
|
|
49
|
-
await regenerateLayerReports(rootPath), logVerbose("Reports and README generated");
|
|
50
|
-
} catch (reportError) {
|
|
51
|
-
const reportMessage = getErrorMessage(reportError);
|
|
52
|
-
console.warn(ansis.yellow(`\u26A0 Warning: Failed to generate reports and README: ${reportMessage}
|
|
35
|
+
author: author || void 0
|
|
36
|
+
});
|
|
37
|
+
result.reportError !== void 0 && console.warn(ansis.yellow(`\u26A0 Warning: Failed to generate reports and README: ${result.reportError}
|
|
53
38
|
Model initialized successfully. To regenerate reports later, run:
|
|
54
|
-
dr reports regenerate`)),
|
|
55
|
-
}
|
|
56
|
-
isTelemetryEnabled && span && (span.setAttribute("model.path", rootPath), span.setStatus({ code: 0 })), outro(ansis.green(`\u2713 Model initialized: ${ansis.bold(model.manifest.name)}`));
|
|
39
|
+
dr reports regenerate`)), isTelemetryEnabled && span && (span.setAttribute("model.path", rootPath), span.setStatus({ code: 0 })), outro(ansis.green(`\u2713 Model initialized: ${ansis.bold(result.name)}`));
|
|
57
40
|
} catch (error) {
|
|
58
41
|
isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
|
|
59
42
|
code: 2,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/commands/init.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Initialize a new Documentation Robotics model\n */\n\nimport { intro, text, outro } from \"@clack/prompts\";\nimport ansis from \"ansis\";\nimport {
|
|
5
|
-
"mappings": "AAIA,SAAS,OAAO,MAAM,aAAa;AACnC,OAAO,WAAW;AAClB,SAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * Initialize a new Documentation Robotics model\n */\n\nimport { intro, text, outro } from \"@clack/prompts\";\nimport ansis from \"ansis\";\nimport { hasModel, initProject } from \"../core/project-init.js\";\nimport { getCliBundledSpecVersion } from \"../utils/spec-version.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\nexport interface InitOptions {\n name?: string;\n author?: string;\n description?: string;\n verbose?: boolean;\n debug?: boolean;\n}\n\nexport async function initCommand(options: InitOptions): Promise<void> {\n intro(ansis.bold(ansis.blue(\"\u2699\uFE0F Initialize Documentation Robotics Model\")));\n\n const span = isTelemetryEnabled\n ? startSpan(\"model.init\", {\n \"init.hasName\": !!options.name,\n \"init.hasDescription\": !!options.description,\n \"init.hasAuthor\": !!options.author,\n })\n : null;\n\n try {\n const rootPath = process.cwd();\n // Check if model already exists\n if (await hasModel(rootPath)) {\n console.error(ansis.red(\"Error: Model already initialized in this directory\"));\n if (isTelemetryEnabled && span) {\n (span as any).setStatus({ code: 2, message: \"Model already exists\" });\n }\n endSpan(span);\n process.exit(1);\n }\n\n // Gather model metadata\n // Check if stdin is a TTY to determine if we should prompt\n const isInteractive = process.stdin.isTTY;\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"cli.interactive\", isInteractive);\n }\n\n // If name is provided, skip all prompts\n const skipPrompts = !!options.name;\n\n const name =\n options.name ||\n (isInteractive\n ? await text({\n message: \"Model name:\",\n validate: (value) => (value.length === 0 ? \"Name is required\" : undefined),\n })\n : (() => {\n console.error(ansis.red(\"Error: Model name is required (use --name option)\"));\n if (isTelemetryEnabled && span) {\n (span as any).setStatus({ code: 2, message: \"Model name required\" });\n }\n endSpan(span);\n process.exit(1);\n })());\n\n const description =\n options.description ||\n (skipPrompts\n ? \"\"\n : isInteractive\n ? await text({\n message: \"Description (optional):\",\n defaultValue: \"\",\n })\n : \"\");\n\n const author =\n options.author ||\n (skipPrompts\n ? \"\"\n : isInteractive\n ? await text({\n message: \"Author (optional):\",\n defaultValue: \"\",\n })\n : \"\");\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"model.name\", name as string);\n (span as any).setAttribute(\"model.specVersion\", getCliBundledSpecVersion());\n }\n\n // Create the model, spec reference and reports (shared with the project_init MCP tool)\n const result = await initProject(rootPath, {\n name: name as string,\n description: (description as string) || undefined,\n author: (author as string) || undefined,\n });\n\n if (result.reportError !== undefined) {\n console.warn(\n ansis.yellow(\n `\u26A0 Warning: Failed to generate reports and README: ${result.reportError}\\n` +\n ` Model initialized successfully. To regenerate reports later, run:\\n` +\n ` dr reports regenerate`\n )\n );\n }\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"model.path\", rootPath);\n (span as any).setStatus({ code: 0 });\n }\n\n outro(ansis.green(`\u2713 Model initialized: ${ansis.bold(result.name)}`));\n } catch (error) {\n if (isTelemetryEnabled && span) {\n (span as any).recordException(error as Error);\n (span as any).setStatus({\n code: 2,\n message: getErrorMessage(error),\n });\n }\n const message = getErrorMessage(error);\n console.error(ansis.red(`Error: ${message}`));\n endSpan(span);\n process.exit(1);\n } finally {\n endSpan(span);\n }\n}\n"],
|
|
5
|
+
"mappings": "AAIA,SAAS,OAAO,MAAM,aAAa;AACnC,OAAO,WAAW;AAClB,SAAS,UAAU,mBAAmB;AACtC,SAAS,gCAAgC;AACzC,SAAS,oBAAoB,WAAW,eAAe;AACvD,SAAS,uBAAuB;AAUhC,eAAsB,YAAY,SAAoB;AACpD,QAAM,MAAM,KAAK,MAAM,KAAK,uDAA6C,CAAC,CAAC;AAE3E,QAAM,OAAO,qBACT,UAAU,cAAc;IACtB,gBAAgB,CAAC,CAAC,QAAQ;IAC1B,uBAAuB,CAAC,CAAC,QAAQ;IACjC,kBAAkB,CAAC,CAAC,QAAQ;GAC7B,IACD;AAEJ,MAAI;AACF,UAAM,WAAW,QAAQ,IAAG;AAE5B,IAAI,MAAM,SAAS,QAAQ,MACzB,QAAQ,MAAM,MAAM,IAAI,oDAAoD,CAAC,GACzE,sBAAsB,QACvB,KAAa,UAAU,EAAE,MAAM,GAAG,SAAS,uBAAsB,CAAE,GAEtE,QAAQ,IAAI,GACZ,QAAQ,KAAK,CAAC;AAKhB,UAAM,gBAAgB,QAAQ,MAAM;AAEpC,IAAI,sBAAsB,QACvB,KAAa,aAAa,mBAAmB,aAAa;AAI7D,UAAM,cAAc,CAAC,CAAC,QAAQ,MAExB,OACJ,QAAQ,SACP,gBACG,MAAM,KAAK;MACT,SAAS;MACT,UAAU,CAAC,UAAW,MAAM,WAAW,IAAI,qBAAqB;KACjE,KACA,MAAK;AACJ,cAAQ,MAAM,MAAM,IAAI,mDAAmD,CAAC,GACxE,sBAAsB,QACvB,KAAa,UAAU,EAAE,MAAM,GAAG,SAAS,sBAAqB,CAAE,GAErE,QAAQ,IAAI,GACZ,QAAQ,KAAK,CAAC;IAChB,GAAE,IAEF,cACJ,QAAQ,gBACP,cACG,KACA,gBACE,MAAM,KAAK;MACT,SAAS;MACT,cAAc;KACf,IACD,KAEF,SACJ,QAAQ,WACP,cACG,KACA,gBACE,MAAM,KAAK;MACT,SAAS;MACT,cAAc;KACf,IACD;AAER,IAAI,sBAAsB,SACvB,KAAa,aAAa,cAAc,IAAc,GACtD,KAAa,aAAa,qBAAqB,yBAAwB,CAAE;AAI5E,UAAM,SAAS,MAAM,YAAY,UAAU;MACzC;MACA,aAAc,eAA0B;MACxC,QAAS,UAAqB;KAC/B;AAED,IAAI,OAAO,gBAAgB,UACzB,QAAQ,KACN,MAAM,OACJ,0DAAqD,OAAO,WAAW;;wBAE9C,CAC1B,GAID,sBAAsB,SACvB,KAAa,aAAa,cAAc,QAAQ,GAChD,KAAa,UAAU,EAAE,MAAM,EAAC,CAAE,IAGrC,MAAM,MAAM,MAAM,6BAAwB,MAAM,KAAK,OAAO,IAAI,CAAC,EAAE,CAAC;EACtE,SAAS,OAAO;AACd,IAAI,sBAAsB,SACvB,KAAa,gBAAgB,KAAc,GAC3C,KAAa,UAAU;MACtB,MAAM;MACN,SAAS,gBAAgB,KAAK;KAC/B;AAEH,UAAM,UAAU,gBAAgB,KAAK;AACrC,YAAQ,MAAM,MAAM,IAAI,UAAU,OAAO,EAAE,CAAC,GAC5C,QAAQ,IAAI,GACZ,QAAQ,KAAK,CAAC;EAChB;AACE,YAAQ,IAAI;EACd;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { isCancel, text } from "@clack/prompts";
|
|
2
|
+
import { RootsListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
2
3
|
import { ApiKeyManager } from "../mcp/api-key-manager.js";
|
|
4
|
+
import { followClientRoots, markEnvProjectRoot } from "../mcp/project-root.js";
|
|
3
5
|
import { McpResourceRegistry } from "../mcp/resource-registry.js";
|
|
6
|
+
import { SERVER_INSTRUCTIONS } from "../mcp/server-instructions.js";
|
|
4
7
|
import { McpToolRegistry } from "../mcp/tool-registry.js";
|
|
5
|
-
import { loadModel } from "../mcp/tools/shared.js";
|
|
8
|
+
import { clearModelCache, loadModel } from "../mcp/tools/shared.js";
|
|
6
9
|
import { startActiveSpan } from "../telemetry/index.js";
|
|
7
10
|
import { CLIError, getErrorMessage } from "../utils/errors.js";
|
|
8
11
|
import { getCliVersion } from "../utils/spec-version.js";
|
|
@@ -15,35 +18,55 @@ const cliVersion = getCliVersion(), promptForKeyPath = async (defaultPath) => {
|
|
|
15
18
|
return isCancel(result) || typeof result != "string" || result.trim().length === 0 ? defaultPath : result.trim();
|
|
16
19
|
};
|
|
17
20
|
async function createConfiguredServer() {
|
|
18
|
-
const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js"), server = new McpServer({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
new McpToolRegistry().registerAll(server), await new McpResourceRegistry().registerAll(server);
|
|
21
|
+
const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js"), server = new McpServer({ name: "documentation-robotics", version: cliVersion }, { instructions: SERVER_INSTRUCTIONS });
|
|
22
|
+
return new McpToolRegistry().registerAll(server), await new McpResourceRegistry().registerAll(server), server;
|
|
23
|
+
}
|
|
24
|
+
async function warmModel() {
|
|
23
25
|
try {
|
|
24
26
|
await loadModel();
|
|
25
27
|
} catch (error) {
|
|
26
28
|
process.stderr.write(`[mcp] model warmup skipped: ${getErrorMessage(error)}
|
|
27
29
|
`);
|
|
28
30
|
}
|
|
29
|
-
|
|
31
|
+
}
|
|
32
|
+
function serveClientRoots(server) {
|
|
33
|
+
const inner = server.server, follow = () => followClientRoots(() => inner.listRoots(), { onChange: () => clearModelCache() }).then(warmModel);
|
|
34
|
+
inner.setNotificationHandler(RootsListChangedNotificationSchema, async () => {
|
|
35
|
+
await follow();
|
|
36
|
+
}), inner.oninitialized = () => {
|
|
37
|
+
inner.getClientCapabilities()?.roots ? follow() : warmModel();
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function serveFromRootPathEnv(env = process.env) {
|
|
41
|
+
const rootPath = env.DR_MCP_ROOT_PATH;
|
|
42
|
+
if (!rootPath)
|
|
43
|
+
return !1;
|
|
44
|
+
try {
|
|
45
|
+
process.chdir(rootPath);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return process.stderr.write(`[mcp] DR_MCP_ROOT_PATH=${rootPath} is not usable (${getErrorMessage(error)}); serving from ${process.cwd()}
|
|
48
|
+
`), !1;
|
|
49
|
+
}
|
|
50
|
+
return markEnvProjectRoot(process.cwd()), !0;
|
|
30
51
|
}
|
|
31
52
|
async function mcpCommand(options = {}) {
|
|
32
53
|
const keyManager = new ApiKeyManager();
|
|
33
54
|
try {
|
|
34
55
|
if (options.regenerateKey) {
|
|
35
56
|
await startActiveSpan("mcp.key.rotate", async (span) => {
|
|
36
|
-
const
|
|
37
|
-
span.setAttribute("mcp.key.path",
|
|
38
|
-
`), process.stderr.write(`MCP API key: ${
|
|
57
|
+
const isInteractive = process.stdin.isTTY === !0, { key, path } = await keyManager.rotate(isInteractive ? promptForKeyPath : void 0);
|
|
58
|
+
span.setAttribute("mcp.key.path", path), process.stderr.write(`Generated new MCP API key, stored at ${path}
|
|
59
|
+
`), process.stderr.write(`MCP API key: ${key}
|
|
39
60
|
`);
|
|
40
61
|
});
|
|
41
62
|
return;
|
|
42
63
|
}
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
`
|
|
64
|
+
const servesEnvRoot = serveFromRootPathEnv();
|
|
65
|
+
if (options.transport === "http") {
|
|
66
|
+
const isInteractive = process.stdin.isTTY === !0, { key, path, isNew } = await keyManager.ensureKey(isInteractive ? promptForKeyPath : void 0);
|
|
67
|
+
isNew && process.stderr.write(`Generated new MCP API key, stored at ${path}
|
|
68
|
+
`), /^(1|true|yes|on)$/i.test(process.env.DR_MCP_QUIET_KEY ?? "") || process.stderr.write(`MCP API key: ${key}
|
|
69
|
+
`), await warmModel();
|
|
47
70
|
const { createMcpHttpApp, startHttpServer, closeHttpServer } = await import("../mcp/http-transport.js"), host = options.host || "127.0.0.1", port = options.port || 3100;
|
|
48
71
|
let httpApp;
|
|
49
72
|
const httpServer = await startActiveSpan("mcp.server.start", async (span) => {
|
|
@@ -77,14 +100,9 @@ Shutting down HTTP server...
|
|
|
77
100
|
};
|
|
78
101
|
process.on("SIGINT", shutdown), process.on("SIGTERM", shutdown), await keepAlive;
|
|
79
102
|
} else {
|
|
80
|
-
if (!keyManager.validate(process.env.DR_MCP_API_KEY, key))
|
|
81
|
-
throw process.stderr.write(`Error: DR_MCP_API_KEY environment variable is missing or does not match the stored API key.
|
|
82
|
-
`), process.stderr.write(`Set DR_MCP_API_KEY to the key above when configuring the MCP client, e.g.:
|
|
83
|
-
`), process.stderr.write(` { "command": "dr", "args": ["mcp"], "env": { "DR_MCP_API_KEY": "<key>" } }
|
|
84
|
-
`), new CLIError("MCP authentication failed: invalid or missing DR_MCP_API_KEY", 1);
|
|
85
103
|
const transport = await startActiveSpan("mcp.server.start", async (span) => {
|
|
86
104
|
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js"), server = await createConfiguredServer();
|
|
87
|
-
span.setAttribute("mcp.server.name", "documentation-robotics"), span.setAttribute("mcp.server.version", cliVersion), span.setAttribute("mcp.server.transport", "stdio");
|
|
105
|
+
servesEnvRoot ? await warmModel() : serveClientRoots(server), span.setAttribute("mcp.server.name", "documentation-robotics"), span.setAttribute("mcp.server.version", cliVersion), span.setAttribute("mcp.server.transport", "stdio");
|
|
88
106
|
const serverTransport = new StdioServerTransport();
|
|
89
107
|
return await server.connect(serverTransport), serverTransport;
|
|
90
108
|
});
|
|
@@ -102,6 +120,7 @@ Shutting down HTTP server...
|
|
|
102
120
|
}
|
|
103
121
|
}
|
|
104
122
|
export {
|
|
105
|
-
mcpCommand
|
|
123
|
+
mcpCommand,
|
|
124
|
+
serveFromRootPathEnv
|
|
106
125
|
};
|
|
107
126
|
//# sourceMappingURL=mcp.js.map
|