@documentation-robotics/cli 0.1.13 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -2
- package/dist/analysis/relationship-classifier.js +2 -9
- package/dist/analysis/relationship-classifier.js.map +2 -2
- package/dist/analyzers/call-graph-utils.js +2 -2
- package/dist/analyzers/call-graph-utils.js.map +2 -2
- package/dist/analyzers/cards/build.js +171 -0
- package/dist/analyzers/cards/build.js.map +7 -0
- package/dist/analyzers/cards/classify.js +42 -0
- package/dist/analyzers/cards/classify.js.map +7 -0
- package/dist/analyzers/cards/edge-index.js +44 -0
- package/dist/analyzers/cards/edge-index.js.map +7 -0
- package/dist/analyzers/cards/facts.js +46 -0
- package/dist/analyzers/cards/facts.js.map +7 -0
- package/dist/analyzers/cards/graph.js +42 -0
- package/dist/analyzers/cards/graph.js.map +7 -0
- package/dist/analyzers/cards/index.js +8 -0
- package/dist/analyzers/cards/index.js.map +7 -0
- package/dist/analyzers/cards/tier0.js +18 -0
- package/dist/analyzers/cards/tier0.js.map +7 -0
- package/dist/analyzers/cards/types.js +1 -0
- package/dist/analyzers/cards/types.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +195 -171
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +336 -0
- package/dist/analyzers/cbm-responses.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +45 -0
- package/dist/analyzers/edge-relationships.js.map +7 -0
- package/dist/analyzers/mapping-loader.js +9 -0
- package/dist/analyzers/mapping-loader.js.map +2 -2
- package/dist/analyzers/tier0-rules.js +153 -0
- package/dist/analyzers/tier0-rules.js.map +7 -0
- package/dist/analyzers/types.js.map +1 -1
- package/dist/analyzers/verify-engine.js +22 -19
- package/dist/analyzers/verify-engine.js.map +2 -2
- package/dist/audit/relationships/ai/prompts.js +10 -10
- package/dist/audit/relationships/ai/prompts.js.map +2 -2
- package/dist/audit/relationships/analysis/layer-templates.js +52 -52
- package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
- package/dist/cli.js +112 -28
- package/dist/cli.js.map +3 -3
- package/dist/coding-agents/agents/claude-code.js +3 -1
- package/dist/coding-agents/agents/claude-code.js.map +2 -2
- package/dist/coding-agents/claude-code-client.js +2 -1
- package/dist/coding-agents/claude-code-client.js.map +2 -2
- package/dist/coding-agents/copilot-client.js +17 -12
- package/dist/coding-agents/copilot-client.js.map +2 -2
- package/dist/coding-agents/default-permissions.js +152 -0
- package/dist/coding-agents/default-permissions.js.map +7 -0
- package/dist/coding-agents/drbot-mcp.js +167 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +12 -7
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +134 -23
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/audit.js +6 -6
- package/dist/commands/audit.js.map +2 -2
- package/dist/commands/changeset-verify.js +55 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +261 -147
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/delete.js +52 -19
- package/dist/commands/delete.js.map +3 -3
- package/dist/commands/element.js +3 -2
- package/dist/commands/element.js.map +2 -2
- package/dist/commands/farm.js +773 -0
- package/dist/commands/farm.js.map +7 -0
- package/dist/commands/init.js +11 -1
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +122 -0
- package/dist/commands/mcp.js.map +7 -0
- package/dist/commands/relationship.js +251 -47
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +56 -24
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +99 -11
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/validate.js +41 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +2 -2
- package/dist/commands/version.js.map +2 -2
- package/dist/commands/visualize.js +4 -3
- package/dist/commands/visualize.js.map +2 -2
- package/dist/config.js +83 -0
- package/dist/config.js.map +7 -0
- package/dist/core/annotation-store.js +138 -0
- package/dist/core/annotation-store.js.map +7 -0
- package/dist/core/catalog-migration.js +33 -0
- package/dist/core/catalog-migration.js.map +7 -0
- package/dist/core/changeset-analysis.js +421 -0
- package/dist/core/changeset-analysis.js.map +7 -0
- package/dist/core/changeset-base-index.js +153 -0
- package/dist/core/changeset-base-index.js.map +7 -0
- package/dist/core/changeset-brief-delta.js +102 -0
- package/dist/core/changeset-brief-delta.js.map +7 -0
- package/dist/core/changeset-graph.js +281 -0
- package/dist/core/changeset-graph.js.map +7 -0
- package/dist/core/changeset-only-guard.js +32 -0
- package/dist/core/changeset-only-guard.js.map +7 -0
- package/dist/core/changeset-summary.js +68 -0
- package/dist/core/changeset-summary.js.map +7 -0
- package/dist/core/changeset-validator.js +66 -20
- package/dist/core/changeset-validator.js.map +2 -2
- package/dist/core/changeset-verify.js +518 -0
- package/dist/core/changeset-verify.js.map +7 -0
- package/dist/core/changeset.js +56 -9
- package/dist/core/changeset.js.map +2 -2
- package/dist/core/element-type-migration.js +145 -0
- package/dist/core/element-type-migration.js.map +7 -0
- package/dist/core/farm-manifest.js +140 -0
- package/dist/core/farm-manifest.js.map +7 -0
- package/dist/core/farm-sync-engine.js +346 -0
- package/dist/core/farm-sync-engine.js.map +7 -0
- package/dist/core/farm-sync-state.js +167 -0
- package/dist/core/farm-sync-state.js.map +7 -0
- package/dist/core/manifest.js +6 -3
- package/dist/core/manifest.js.map +2 -2
- package/dist/core/migration-registry.js +84 -1
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/model-upgrade.js +102 -0
- package/dist/core/model-upgrade.js.map +7 -0
- package/dist/core/model.js +257 -44
- package/dist/core/model.js.map +3 -3
- package/dist/core/mutation-handler.js +71 -6
- package/dist/core/mutation-handler.js.map +2 -2
- package/dist/core/relationship-migration-table.js +6639 -0
- package/dist/core/relationship-migration-table.js.map +7 -0
- package/dist/core/relationship-migration.js +272 -0
- package/dist/core/relationship-migration.js.map +7 -0
- package/dist/core/relationship-prune.js +49 -0
- package/dist/core/relationship-prune.js.map +7 -0
- package/dist/core/relationship-staging.js +68 -0
- package/dist/core/relationship-staging.js.map +7 -0
- package/dist/core/relationships.js +26 -4
- package/dist/core/relationships.js.map +2 -2
- package/dist/core/report-data-model.js +7 -13
- package/dist/core/report-data-model.js.map +2 -2
- package/dist/core/staged-changeset-storage.js +64 -17
- package/dist/core/staged-changeset-storage.js.map +2 -2
- package/dist/core/staged-source-reference.js +28 -0
- package/dist/core/staged-source-reference.js.map +7 -0
- package/dist/core/staging-area.js +83 -18
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/virtual-projection.js +14 -5
- package/dist/core/virtual-projection.js.map +2 -2
- package/dist/export/archimate-exporter.js +1 -0
- package/dist/export/archimate-exporter.js.map +2 -2
- package/dist/generated/compiled-validators.js +2 -2
- package/dist/generated/compiled-validators.js.map +2 -2
- package/dist/generated/layer-registry.js +16 -16
- package/dist/generated/layer-registry.js.map +2 -2
- package/dist/generated/node-types.js +186 -168
- package/dist/generated/node-types.js.map +2 -2
- package/dist/generated/relationship-index.js +2209 -7727
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/agents/dr-architect.md +16 -3
- package/dist/integrations/claude_code/agents/dr-extractor.md +1 -1
- package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
- package/dist/integrations/claude_code/commands/dr-map.md +13 -0
- package/dist/integrations/claude_code/commands/dr-plan.md +40 -0
- package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
- package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
- package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
- package/dist/integrations/claude_code/docs/MCP_SERVER.md +79 -0
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +52 -1
- package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
- package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
- package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
- package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
- package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
- package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
- package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
- package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
- package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
- package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
- package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
- package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
- package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +92 -15
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +1 -1
- package/dist/integrations/github_copilot/agents/dr-architect.md +1 -1
- package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
- package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
- package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
- package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
- package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
- package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
- package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
- package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
- package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
- package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
- package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
- package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
- package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +222 -102
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/hash-utils.js.map +2 -2
- package/dist/mcp/api-key-manager.js +111 -0
- package/dist/mcp/api-key-manager.js.map +7 -0
- package/dist/mcp/changeset-only.js +34 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/http-transport.js +176 -0
- package/dist/mcp/http-transport.js.map +7 -0
- package/dist/mcp/resource-registry.js +97 -0
- package/dist/mcp/resource-registry.js.map +7 -0
- package/dist/mcp/tool-registry.js +60 -0
- package/dist/mcp/tool-registry.js.map +7 -0
- package/dist/mcp/tools/annotation-create.js +39 -0
- package/dist/mcp/tools/annotation-create.js.map +7 -0
- package/dist/mcp/tools/annotation-delete.js +29 -0
- package/dist/mcp/tools/annotation-delete.js.map +7 -0
- package/dist/mcp/tools/annotation-get.js +29 -0
- package/dist/mcp/tools/annotation-get.js.map +7 -0
- package/dist/mcp/tools/annotation-list.js +24 -0
- package/dist/mcp/tools/annotation-list.js.map +7 -0
- package/dist/mcp/tools/annotation-reply.js +34 -0
- package/dist/mcp/tools/annotation-reply.js.map +7 -0
- package/dist/mcp/tools/annotation-shared.js +10 -0
- package/dist/mcp/tools/annotation-shared.js.map +7 -0
- package/dist/mcp/tools/annotation-update.js +39 -0
- package/dist/mcp/tools/annotation-update.js.map +7 -0
- package/dist/mcp/tools/changeset-analysis-tools.js +78 -0
- package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +184 -0
- package/dist/mcp/tools/changeset-editing.js.map +7 -0
- package/dist/mcp/tools/changeset-lifecycle.js +83 -0
- package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
- package/dist/mcp/tools/changeset-list.js +33 -0
- package/dist/mcp/tools/changeset-list.js.map +7 -0
- package/dist/mcp/tools/changeset-shared.js +31 -0
- package/dist/mcp/tools/changeset-shared.js.map +7 -0
- package/dist/mcp/tools/changeset-show.js +55 -0
- package/dist/mcp/tools/changeset-show.js.map +7 -0
- package/dist/mcp/tools/changeset-verify.js +43 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/chat-launch.js +50 -0
- package/dist/mcp/tools/chat-launch.js.map +7 -0
- package/dist/mcp/tools/chat-status.js +26 -0
- package/dist/mcp/tools/chat-status.js.map +7 -0
- package/dist/mcp/tools/index.js +65 -0
- package/dist/mcp/tools/index.js.map +7 -0
- package/dist/mcp/tools/model-add.js +107 -0
- package/dist/mcp/tools/model-add.js.map +7 -0
- package/dist/mcp/tools/model-delete.js +99 -0
- package/dist/mcp/tools/model-delete.js.map +7 -0
- package/dist/mcp/tools/model-export.js +72 -0
- package/dist/mcp/tools/model-export.js.map +7 -0
- package/dist/mcp/tools/model-info.js +51 -0
- package/dist/mcp/tools/model-info.js.map +7 -0
- package/dist/mcp/tools/model-list.js +53 -0
- package/dist/mcp/tools/model-list.js.map +7 -0
- package/dist/mcp/tools/model-reload.js +34 -0
- package/dist/mcp/tools/model-reload.js.map +7 -0
- package/dist/mcp/tools/model-search.js +102 -0
- package/dist/mcp/tools/model-search.js.map +7 -0
- package/dist/mcp/tools/model-show.js +68 -0
- package/dist/mcp/tools/model-show.js.map +7 -0
- package/dist/mcp/tools/model-stats.js +22 -0
- package/dist/mcp/tools/model-stats.js.map +7 -0
- package/dist/mcp/tools/model-trace.js +118 -0
- package/dist/mcp/tools/model-trace.js.map +7 -0
- package/dist/mcp/tools/model-update.js +121 -0
- package/dist/mcp/tools/model-update.js.map +7 -0
- package/dist/mcp/tools/model-validate.js +78 -0
- package/dist/mcp/tools/model-validate.js.map +7 -0
- package/dist/mcp/tools/relationship-tools.js +98 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/shared.js +126 -0
- package/dist/mcp/tools/shared.js.map +7 -0
- package/dist/mcp/tools/spec-type.js +90 -0
- package/dist/mcp/tools/spec-type.js.map +7 -0
- package/dist/reports/model-layer-report-generator.js +5 -3
- package/dist/reports/model-layer-report-generator.js.map +2 -2
- package/dist/reports/model-readme-generator.js +116 -0
- package/dist/reports/model-readme-generator.js.map +7 -0
- package/dist/reports/model-report-data.js +37 -1
- package/dist/reports/model-report-data.js.map +2 -2
- package/dist/reports/model-report-orchestrator.js +29 -6
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/reports/model-report-utils.js +9 -0
- package/dist/reports/model-report-utils.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +1186 -68
- package/dist/schemas/bundled/analyzers/manifest.json +2 -2
- package/dist/schemas/bundled/api.json +1029 -1658
- package/dist/schemas/bundled/apm.json +499 -734
- package/dist/schemas/bundled/application.json +745 -370
- package/dist/schemas/bundled/base.json +3 -220
- package/dist/schemas/bundled/business.json +452 -366
- package/dist/schemas/bundled/data-model.json +403 -383
- package/dist/schemas/bundled/data-store.json +334 -558
- package/dist/schemas/bundled/manifest.json +18 -18
- package/dist/schemas/bundled/motivation.json +349 -368
- package/dist/schemas/bundled/navigation.json +415 -731
- package/dist/schemas/bundled/product.json +325 -159
- package/dist/schemas/bundled/security.json +864 -1232
- package/dist/schemas/bundled/technology.json +574 -703
- package/dist/schemas/bundled/testing.json +718 -1643
- package/dist/schemas/bundled/ux.json +739 -1352
- package/dist/server/schemas.js +8 -0
- package/dist/server/schemas.js.map +2 -2
- package/dist/server/server.js +234 -31
- package/dist/server/server.js.map +2 -2
- package/dist/server-entry.js +2 -1
- package/dist/server-entry.js.map +2 -2
- package/dist/telemetry/config.js +2 -40
- package/dist/telemetry/config.js.map +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/types/index.js.map +2 -2
- package/dist/utils/ansi-suppressor.js +23 -0
- package/dist/utils/ansi-suppressor.js.map +7 -0
- package/dist/utils/attribute-patch.js +41 -0
- package/dist/utils/attribute-patch.js.map +7 -0
- package/dist/utils/color-utils.js +34 -0
- package/dist/utils/color-utils.js.map +7 -0
- package/dist/utils/element-reference-shape.js +15 -1
- package/dist/utils/element-reference-shape.js.map +3 -3
- package/dist/utils/error-hints.js +29 -0
- package/dist/utils/error-hints.js.map +7 -0
- package/dist/utils/errors.js +75 -10
- package/dist/utils/errors.js.map +2 -2
- package/dist/utils/globals.js +17 -1
- package/dist/utils/globals.js.map +2 -2
- package/dist/utils/project-paths.js +50 -3
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/reference-path-parser.js +49 -0
- package/dist/utils/reference-path-parser.js.map +7 -0
- package/dist/utils/source-reference.js +17 -10
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +10 -2
- package/dist/utils/spec-version.js.map +2 -2
- package/dist/validators/composed-reference-validator.js +240 -0
- package/dist/validators/composed-reference-validator.js.map +7 -0
- package/dist/validators/reference-validator.js +57 -13
- package/dist/validators/reference-validator.js.map +3 -3
- package/dist/validators/relationship-schema-validator.js +33 -5
- package/dist/validators/relationship-schema-validator.js.map +3 -3
- package/dist/validators/schema-validator.js +27 -9
- package/dist/validators/schema-validator.js.map +2 -2
- package/dist/validators/types.js.map +1 -1
- package/dist/viewer/README.md +6 -6
- package/dist/viewer/assets/main-CxzcuU_o.js +84 -0
- package/dist/viewer/assets/main-j-7ULYpm.css +1 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/manifest.json +10 -10
- package/dist/viewer/version.json +1 -1
- package/package.json +7 -3
- package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
- package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
package/dist/server-entry.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Model } from "./core/model.js";
|
|
2
2
|
import { VisualizationServer } from "./server/server.js";
|
|
3
3
|
import { getErrorMessage } from "./utils/errors.js";
|
|
4
|
-
const port = parseInt(process.env.DR_VISUALIZE_PORT || "8080", 10), projectPath = process.env.DR_PROJECT_PATH || process.cwd(), authEnabled = process.env.DR_AUTH_ENABLED !== "false", authToken = process.env.DR_AUTH_TOKEN && process.env.DR_AUTH_TOKEN.length > 0 ? process.env.DR_AUTH_TOKEN : void 0, withDanger = process.env.DR_WITH_DANGER === "true", viewerPath = process.env.DR_VIEWER_PATH, isTelemetryEnabled = !1;
|
|
4
|
+
const port = parseInt(process.env.DR_VISUALIZE_PORT || "8080", 10), projectPath = process.env.DR_PROJECT_PATH || process.cwd(), authEnabled = process.env.DR_AUTH_ENABLED !== "false", authToken = process.env.DR_AUTH_TOKEN && process.env.DR_AUTH_TOKEN.length > 0 ? process.env.DR_AUTH_TOKEN : void 0, withDanger = process.env.DR_WITH_DANGER === "true", withChangesets = process.env.DR_WITH_CHANGESETS === "true", viewerPath = process.env.DR_VIEWER_PATH, isTelemetryEnabled = !1;
|
|
5
5
|
let serverInstance = null, isShuttingDown = !1;
|
|
6
6
|
async function main() {
|
|
7
7
|
try {
|
|
@@ -23,6 +23,7 @@ async function main() {
|
|
|
23
23
|
authEnabled,
|
|
24
24
|
authToken,
|
|
25
25
|
withDanger,
|
|
26
|
+
withChangesets,
|
|
26
27
|
viewerPath
|
|
27
28
|
});
|
|
28
29
|
serverInstance = server, await server.start(port), authEnabled && console.log(`TOKEN:${server.getAuthToken()}`), setupShutdownHandlers();
|
package/dist/server-entry.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/server-entry.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Visualization Server Entry Point\n * This is spawned as a subprocess by `dr visualize` (see cli/src/commands/visualize.ts),\n * using whichever runtime (Node.js or Bun) is already running the parent CLI process.\n * It receives configuration via environment variables and starts the server.\n */\n\nimport { Model } from \"./core/model.js\";\nimport { VisualizationServer } from \"./server/server.js\";\nimport { getErrorMessage } from \"./utils/errors.js\";\n\n// Get configuration from environment variables\nconst port = parseInt(process.env.DR_VISUALIZE_PORT || \"8080\", 10);\nconst projectPath = process.env.DR_PROJECT_PATH || process.cwd();\nconst authEnabled = process.env.DR_AUTH_ENABLED !== \"false\";\n// Only pass authToken if it's a non-empty string, otherwise let server generate one\nconst authToken =\n process.env.DR_AUTH_TOKEN && process.env.DR_AUTH_TOKEN.length > 0\n ? process.env.DR_AUTH_TOKEN\n : undefined;\nconst withDanger = process.env.DR_WITH_DANGER === \"true\";\nconst viewerPath = process.env.DR_VIEWER_PATH;\n\n// Conditional telemetry import based on compile-time flag\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\nlet serverInstance: VisualizationServer | null = null;\nlet isShuttingDown = false;\n\nasync function main() {\n try {\n // CRITICAL: Initialize telemetry SDK in subprocess\n // Without this, no spans will be created or exported even though TELEMETRY_ENABLED=true\n if (isTelemetryEnabled) {\n try {\n const { initTelemetry } = await import(\"./telemetry/index.js\");\n await initTelemetry();\n\n // Load and display actual OTLP configuration\n const { loadOTLPConfig } = await import(\"./telemetry/config.js\");\n const otlpConfig = await loadOTLPConfig();\n\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.log(`[Telemetry] SDK initialized in server subprocess`);\n console.log(`[Telemetry] OTLP traces endpoint: ${otlpConfig.endpoint}`);\n console.log(`[Telemetry] OTLP logs endpoint: ${otlpConfig.logsEndpoint}`);\n console.log(`[Telemetry] Service name: ${otlpConfig.serviceName}`);\n\n // Runtime detection and compatibility info\n const isBun = typeof (globalThis as any).Bun !== \"undefined\";\n if (isBun) {\n console.log(`[Telemetry] Runtime: Bun (using fetch-based OTLP exporter)`);\n } else {\n console.log(`[Telemetry] Runtime: Node.js (using http-based OTLP exporter)`);\n }\n }\n } catch (error) {\n // Log telemetry initialization errors but don't fail the server\n console.error(\"[Telemetry] Failed to initialize telemetry:\", error);\n console.error(\"[Telemetry] Server will continue without telemetry\");\n }\n } else if (process.env.DEBUG || process.env.VERBOSE) {\n console.log(`[Telemetry] TELEMETRY_ENABLED is false - telemetry disabled`);\n }\n\n // Load model with full content\n const model = await Model.load(projectPath, { lazyLoad: false });\n\n // Create and start server\n const server = new VisualizationServer(model, {\n authEnabled,\n authToken,\n withDanger,\n viewerPath,\n });\n serverInstance = server; // Store for signal handlers\n await server.start(port);\n\n // Output token for parent process to read\n if (authEnabled) {\n console.log(`TOKEN:${server.getAuthToken()}`);\n }\n\n // Setup graceful shutdown handlers\n setupShutdownHandlers();\n } catch (error) {\n const message = getErrorMessage(error);\n console.error(`Error: ${message}`);\n if (error instanceof Error) {\n console.error(`Stack: ${error.stack}`);\n }\n await gracefulShutdown(1);\n }\n}\n\n/**\n * Gracefully shutdown the server and flush telemetry\n */\nasync function gracefulShutdown(exitCode: number = 0): Promise<void> {\n if (isShuttingDown) {\n return; // Prevent multiple shutdown attempts\n }\n isShuttingDown = true;\n\n try {\n // Stop the visualization server\n if (serverInstance) {\n serverInstance.stop();\n serverInstance = null;\n }\n\n // Flush telemetry spans before exit\n if (isTelemetryEnabled) {\n console.log(\"[Telemetry] Shutting down telemetry and flushing spans...\");\n const { shutdownTelemetry } = await import(\"./telemetry/index.js\");\n await shutdownTelemetry();\n console.log(\"[Telemetry] Telemetry shutdown complete\");\n } else {\n if (process.env.DEBUG) {\n console.log(\"[Telemetry] Telemetry is disabled (TELEMETRY_ENABLED=false at build time)\");\n }\n }\n } catch (error) {\n // Don't block shutdown on errors\n if (process.env.DEBUG) {\n console.error(\"Error during shutdown:\", error);\n }\n } finally {\n process.exit(exitCode);\n }\n}\n\n/**\n * Setup handlers for graceful shutdown on signals\n */\nfunction setupShutdownHandlers(): void {\n // Handle Ctrl-C (SIGINT)\n process.on(\"SIGINT\", async () => {\n console.log(\"\\n[SIGINT] Shutting down visualization server...\");\n await gracefulShutdown(0);\n });\n\n // Handle termination signal (SIGTERM)\n process.on(\"SIGTERM\", async () => {\n console.log(\"\\n[SIGTERM] Shutting down visualization server...\");\n await gracefulShutdown(0);\n });\n\n // Handle uncaught exceptions\n process.on(\"uncaughtException\", async (error) => {\n console.error(\"Uncaught exception:\", error);\n await gracefulShutdown(1);\n });\n\n // Handle unhandled promise rejections\n process.on(\"unhandledRejection\", async (reason) => {\n console.error(\"Unhandled rejection:\", reason);\n await gracefulShutdown(1);\n });\n}\n\nmain();\n"],
|
|
5
|
-
"mappings": "AAOA,SAAS,aAAa;AACtB,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAGhC,MAAM,OAAO,SAAS,QAAQ,IAAI,qBAAqB,QAAQ,EAAE,GAC3D,cAAc,QAAQ,IAAI,mBAAmB,QAAQ,IAAG,GACxD,cAAc,QAAQ,IAAI,oBAAoB,SAE9C,YACJ,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,cAAc,SAAS,IAC5D,QAAQ,IAAI,gBACZ,QACA,aAAa,QAAQ,IAAI,mBAAmB,QAC5C,aAAa,QAAQ,IAAI,gBAIzB,qBAAgE;AAEtE,IAAI,iBAA6C,MAC7C,iBAAiB;AAErB,eAAe,OAAI;AACjB,MAAI;AAGF,QAAI;AACF,UAAI;AACF,cAAM,EAAE,cAAa,IAAK,MAAM,OAAO,sBAAsB;AAC7D,cAAM,cAAa;AAGnB,cAAM,EAAE,eAAc,IAAK,MAAM,OAAO,uBAAuB,GACzD,aAAa,MAAM,eAAc;AAEvC,YAAI,QAAQ,IAAI,SAAS,QAAQ,IAAI,SAAS;AAC5C,kBAAQ,IAAI,kDAAkD,GAC9D,QAAQ,IAAI,qCAAqC,WAAW,QAAQ,EAAE,GACtE,QAAQ,IAAI,mCAAmC,WAAW,YAAY,EAAE,GACxE,QAAQ,IAAI,6BAA6B,WAAW,WAAW,EAAE;AAGjE,gBAAM,QAAQ,OAAQ,WAAmB,MAAQ;AACjD,UACE,QAAQ,IADN,QACU,+DAEA,+DAF4D;QAI5E;MACF,SAAS,OAAO;AAEd,gBAAQ,MAAM,+CAA+C,KAAK,GAClE,QAAQ,MAAM,oDAAoD;MACpE;QACK,EAAI,QAAQ,IAAI,SAAS,QAAQ,IAAI,YAC1C,QAAQ,IAAI,6DAA6D;AAI3E,UAAM,QAAQ,MAAM,MAAM,KAAK,aAAa,EAAE,UAAU,GAAK,CAAE,GAGzD,SAAS,IAAI,oBAAoB,OAAO;MAC5C;MACA;MACA;MACA;KACD;AACD,qBAAiB,QACjB,MAAM,OAAO,MAAM,IAAI,GAGnB,eACF,QAAQ,IAAI,SAAS,OAAO,aAAY,CAAE,EAAE,GAI9C,sBAAqB;EACvB,SAAS,OAAO;AACd,UAAM,UAAU,gBAAgB,KAAK;AACrC,YAAQ,MAAM,UAAU,OAAO,EAAE,GAC7B,iBAAiB,SACnB,QAAQ,MAAM,UAAU,MAAM,KAAK,EAAE,GAEvC,MAAM,iBAAiB,CAAC;EAC1B;AACF;AAKA,eAAe,iBAAiB,WAAmB,GAAC;AAClD,MAAI,iBAGJ;qBAAiB;AAEjB,QAAI;AAQF,UANI,mBACF,eAAe,KAAI,GACnB,iBAAiB,OAIf,oBAAoB;AACtB,gBAAQ,IAAI,2DAA2D;AACvE,cAAM,EAAE,kBAAiB,IAAK,MAAM,OAAO,sBAAsB;AACjE,cAAM,kBAAiB,GACvB,QAAQ,IAAI,yCAAyC;MACvD;AACE,QAAI,QAAQ,IAAI,SACd,QAAQ,IAAI,2EAA2E;IAG7F,SAAS,OAAO;AAEd,MAAI,QAAQ,IAAI,SACd,QAAQ,MAAM,0BAA0B,KAAK;IAEjD;AACE,cAAQ,KAAK,QAAQ;IACvB;;AACF;AAKA,SAAS,wBAAqB;AAE5B,UAAQ,GAAG,UAAU,YAAW;AAC9B,YAAQ,IAAI;+CAAkD,GAC9D,MAAM,iBAAiB,CAAC;EAC1B,CAAC,GAGD,QAAQ,GAAG,WAAW,YAAW;AAC/B,YAAQ,IAAI;gDAAmD,GAC/D,MAAM,iBAAiB,CAAC;EAC1B,CAAC,GAGD,QAAQ,GAAG,qBAAqB,OAAO,UAAS;AAC9C,YAAQ,MAAM,uBAAuB,KAAK,GAC1C,MAAM,iBAAiB,CAAC;EAC1B,CAAC,GAGD,QAAQ,GAAG,sBAAsB,OAAO,WAAU;AAChD,YAAQ,MAAM,wBAAwB,MAAM,GAC5C,MAAM,iBAAiB,CAAC;EAC1B,CAAC;AACH;AAEA,KAAI;",
|
|
4
|
+
"sourcesContent": ["/**\n * Visualization Server Entry Point\n * This is spawned as a subprocess by `dr visualize` (see cli/src/commands/visualize.ts),\n * using whichever runtime (Node.js or Bun) is already running the parent CLI process.\n * It receives configuration via environment variables and starts the server.\n */\n\nimport { Model } from \"./core/model.js\";\nimport { VisualizationServer } from \"./server/server.js\";\nimport { getErrorMessage } from \"./utils/errors.js\";\n\n// Get configuration from environment variables\nconst port = parseInt(process.env.DR_VISUALIZE_PORT || \"8080\", 10);\nconst projectPath = process.env.DR_PROJECT_PATH || process.cwd();\nconst authEnabled = process.env.DR_AUTH_ENABLED !== \"false\";\n// Only pass authToken if it's a non-empty string, otherwise let server generate one\nconst authToken =\n process.env.DR_AUTH_TOKEN && process.env.DR_AUTH_TOKEN.length > 0\n ? process.env.DR_AUTH_TOKEN\n : undefined;\nconst withDanger = process.env.DR_WITH_DANGER === \"true\";\nconst withChangesets = process.env.DR_WITH_CHANGESETS === \"true\";\nconst viewerPath = process.env.DR_VIEWER_PATH;\n\n// Conditional telemetry import based on compile-time flag\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\nlet serverInstance: VisualizationServer | null = null;\nlet isShuttingDown = false;\n\nasync function main() {\n try {\n // CRITICAL: Initialize telemetry SDK in subprocess\n // Without this, no spans will be created or exported even though TELEMETRY_ENABLED=true\n if (isTelemetryEnabled) {\n try {\n const { initTelemetry } = await import(\"./telemetry/index.js\");\n await initTelemetry();\n\n // Load and display actual OTLP configuration\n const { loadOTLPConfig } = await import(\"./telemetry/config.js\");\n const otlpConfig = await loadOTLPConfig();\n\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.log(`[Telemetry] SDK initialized in server subprocess`);\n console.log(`[Telemetry] OTLP traces endpoint: ${otlpConfig.endpoint}`);\n console.log(`[Telemetry] OTLP logs endpoint: ${otlpConfig.logsEndpoint}`);\n console.log(`[Telemetry] Service name: ${otlpConfig.serviceName}`);\n\n // Runtime detection and compatibility info\n const isBun = typeof (globalThis as any).Bun !== \"undefined\";\n if (isBun) {\n console.log(`[Telemetry] Runtime: Bun (using fetch-based OTLP exporter)`);\n } else {\n console.log(`[Telemetry] Runtime: Node.js (using http-based OTLP exporter)`);\n }\n }\n } catch (error) {\n // Log telemetry initialization errors but don't fail the server\n console.error(\"[Telemetry] Failed to initialize telemetry:\", error);\n console.error(\"[Telemetry] Server will continue without telemetry\");\n }\n } else if (process.env.DEBUG || process.env.VERBOSE) {\n console.log(`[Telemetry] TELEMETRY_ENABLED is false - telemetry disabled`);\n }\n\n // Load model with full content\n const model = await Model.load(projectPath, { lazyLoad: false });\n\n // Create and start server\n const server = new VisualizationServer(model, {\n authEnabled,\n authToken,\n withDanger,\n withChangesets,\n viewerPath,\n });\n serverInstance = server; // Store for signal handlers\n await server.start(port);\n\n // Output token for parent process to read\n if (authEnabled) {\n console.log(`TOKEN:${server.getAuthToken()}`);\n }\n\n // Setup graceful shutdown handlers\n setupShutdownHandlers();\n } catch (error) {\n const message = getErrorMessage(error);\n console.error(`Error: ${message}`);\n if (error instanceof Error) {\n console.error(`Stack: ${error.stack}`);\n }\n await gracefulShutdown(1);\n }\n}\n\n/**\n * Gracefully shutdown the server and flush telemetry\n */\nasync function gracefulShutdown(exitCode: number = 0): Promise<void> {\n if (isShuttingDown) {\n return; // Prevent multiple shutdown attempts\n }\n isShuttingDown = true;\n\n try {\n // Stop the visualization server\n if (serverInstance) {\n serverInstance.stop();\n serverInstance = null;\n }\n\n // Flush telemetry spans before exit\n if (isTelemetryEnabled) {\n console.log(\"[Telemetry] Shutting down telemetry and flushing spans...\");\n const { shutdownTelemetry } = await import(\"./telemetry/index.js\");\n await shutdownTelemetry();\n console.log(\"[Telemetry] Telemetry shutdown complete\");\n } else {\n if (process.env.DEBUG) {\n console.log(\"[Telemetry] Telemetry is disabled (TELEMETRY_ENABLED=false at build time)\");\n }\n }\n } catch (error) {\n // Don't block shutdown on errors\n if (process.env.DEBUG) {\n console.error(\"Error during shutdown:\", error);\n }\n } finally {\n process.exit(exitCode);\n }\n}\n\n/**\n * Setup handlers for graceful shutdown on signals\n */\nfunction setupShutdownHandlers(): void {\n // Handle Ctrl-C (SIGINT)\n process.on(\"SIGINT\", async () => {\n console.log(\"\\n[SIGINT] Shutting down visualization server...\");\n await gracefulShutdown(0);\n });\n\n // Handle termination signal (SIGTERM)\n process.on(\"SIGTERM\", async () => {\n console.log(\"\\n[SIGTERM] Shutting down visualization server...\");\n await gracefulShutdown(0);\n });\n\n // Handle uncaught exceptions\n process.on(\"uncaughtException\", async (error) => {\n console.error(\"Uncaught exception:\", error);\n await gracefulShutdown(1);\n });\n\n // Handle unhandled promise rejections\n process.on(\"unhandledRejection\", async (reason) => {\n console.error(\"Unhandled rejection:\", reason);\n await gracefulShutdown(1);\n });\n}\n\nmain();\n"],
|
|
5
|
+
"mappings": "AAOA,SAAS,aAAa;AACtB,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAGhC,MAAM,OAAO,SAAS,QAAQ,IAAI,qBAAqB,QAAQ,EAAE,GAC3D,cAAc,QAAQ,IAAI,mBAAmB,QAAQ,IAAG,GACxD,cAAc,QAAQ,IAAI,oBAAoB,SAE9C,YACJ,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,cAAc,SAAS,IAC5D,QAAQ,IAAI,gBACZ,QACA,aAAa,QAAQ,IAAI,mBAAmB,QAC5C,iBAAiB,QAAQ,IAAI,uBAAuB,QACpD,aAAa,QAAQ,IAAI,gBAIzB,qBAAgE;AAEtE,IAAI,iBAA6C,MAC7C,iBAAiB;AAErB,eAAe,OAAI;AACjB,MAAI;AAGF,QAAI;AACF,UAAI;AACF,cAAM,EAAE,cAAa,IAAK,MAAM,OAAO,sBAAsB;AAC7D,cAAM,cAAa;AAGnB,cAAM,EAAE,eAAc,IAAK,MAAM,OAAO,uBAAuB,GACzD,aAAa,MAAM,eAAc;AAEvC,YAAI,QAAQ,IAAI,SAAS,QAAQ,IAAI,SAAS;AAC5C,kBAAQ,IAAI,kDAAkD,GAC9D,QAAQ,IAAI,qCAAqC,WAAW,QAAQ,EAAE,GACtE,QAAQ,IAAI,mCAAmC,WAAW,YAAY,EAAE,GACxE,QAAQ,IAAI,6BAA6B,WAAW,WAAW,EAAE;AAGjE,gBAAM,QAAQ,OAAQ,WAAmB,MAAQ;AACjD,UACE,QAAQ,IADN,QACU,+DAEA,+DAF4D;QAI5E;MACF,SAAS,OAAO;AAEd,gBAAQ,MAAM,+CAA+C,KAAK,GAClE,QAAQ,MAAM,oDAAoD;MACpE;QACK,EAAI,QAAQ,IAAI,SAAS,QAAQ,IAAI,YAC1C,QAAQ,IAAI,6DAA6D;AAI3E,UAAM,QAAQ,MAAM,MAAM,KAAK,aAAa,EAAE,UAAU,GAAK,CAAE,GAGzD,SAAS,IAAI,oBAAoB,OAAO;MAC5C;MACA;MACA;MACA;MACA;KACD;AACD,qBAAiB,QACjB,MAAM,OAAO,MAAM,IAAI,GAGnB,eACF,QAAQ,IAAI,SAAS,OAAO,aAAY,CAAE,EAAE,GAI9C,sBAAqB;EACvB,SAAS,OAAO;AACd,UAAM,UAAU,gBAAgB,KAAK;AACrC,YAAQ,MAAM,UAAU,OAAO,EAAE,GAC7B,iBAAiB,SACnB,QAAQ,MAAM,UAAU,MAAM,KAAK,EAAE,GAEvC,MAAM,iBAAiB,CAAC;EAC1B;AACF;AAKA,eAAe,iBAAiB,WAAmB,GAAC;AAClD,MAAI,iBAGJ;qBAAiB;AAEjB,QAAI;AAQF,UANI,mBACF,eAAe,KAAI,GACnB,iBAAiB,OAIf,oBAAoB;AACtB,gBAAQ,IAAI,2DAA2D;AACvE,cAAM,EAAE,kBAAiB,IAAK,MAAM,OAAO,sBAAsB;AACjE,cAAM,kBAAiB,GACvB,QAAQ,IAAI,yCAAyC;MACvD;AACE,QAAI,QAAQ,IAAI,SACd,QAAQ,IAAI,2EAA2E;IAG7F,SAAS,OAAO;AAEd,MAAI,QAAQ,IAAI,SACd,QAAQ,MAAM,0BAA0B,KAAK;IAEjD;AACE,cAAQ,KAAK,QAAQ;IACvB;;AACF;AAKA,SAAS,wBAAqB;AAE5B,UAAQ,GAAG,UAAU,YAAW;AAC9B,YAAQ,IAAI;+CAAkD,GAC9D,MAAM,iBAAiB,CAAC;EAC1B,CAAC,GAGD,QAAQ,GAAG,WAAW,YAAW;AAC/B,YAAQ,IAAI;gDAAmD,GAC/D,MAAM,iBAAiB,CAAC;EAC1B,CAAC,GAGD,QAAQ,GAAG,qBAAqB,OAAO,UAAS;AAC9C,YAAQ,MAAM,uBAAuB,KAAK,GAC1C,MAAM,iBAAiB,CAAC;EAC1B,CAAC,GAGD,QAAQ,GAAG,sBAAsB,OAAO,WAAU;AAChD,YAAQ,MAAM,wBAAwB,MAAM,GAC5C,MAAM,iBAAiB,CAAC;EAC1B,CAAC;AACH;AAEA,KAAI;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/telemetry/config.js
CHANGED
|
@@ -1,49 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
4
|
-
import { parse } from "yaml";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
const CONFIG_FILENAME = ".dr-config.yaml";
|
|
1
|
+
import { loadDRConfig } from "../config.js";
|
|
7
2
|
async function loadOTLPConfig() {
|
|
8
3
|
const defaults = {
|
|
9
4
|
endpoint: "http://localhost:4318/v1/traces",
|
|
10
5
|
logsEndpoint: "http://localhost:4318/v1/logs",
|
|
11
6
|
serviceName: "dr-cli",
|
|
12
7
|
isExplicitlyConfigured: !1
|
|
13
|
-
}
|
|
14
|
-
let fileConfig = {};
|
|
15
|
-
const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), CONFIG_FILENAME);
|
|
16
|
-
if (existsSync(configPath))
|
|
17
|
-
try {
|
|
18
|
-
const content = await readFile(configPath, "utf-8");
|
|
19
|
-
fileConfig = parse(content);
|
|
20
|
-
} catch (error) {
|
|
21
|
-
if (error instanceof Error) {
|
|
22
|
-
const errorMsg = error.message;
|
|
23
|
-
errorMsg.includes("EACCES") || errorMsg.includes("permission denied") ? (process.stderr.write(`Error: Cannot read config file ${configPath} - permission denied
|
|
24
|
-
`), process.stderr.write(`Suggestions:
|
|
25
|
-
`), process.stderr.write(` \u2022 Check file permissions with: ls -l ${configPath}
|
|
26
|
-
`), process.stderr.write(` \u2022 Ensure you have read access to the file
|
|
27
|
-
`), process.stderr.write(` \u2022 Try: chmod 644 ${configPath}
|
|
28
|
-
`)) : errorMsg.includes("YAMLException") || error.name === "YAMLException" || errorMsg.includes("bad indentation") || errorMsg.includes("unexpected") ? (process.stderr.write(`Error: Invalid YAML syntax in ${configPath}
|
|
29
|
-
`), process.stderr.write(`Details: ${errorMsg}
|
|
30
|
-
`), process.stderr.write(`Suggestions:
|
|
31
|
-
`), process.stderr.write(` \u2022 Validate your YAML syntax at https://www.yamllint.com/
|
|
32
|
-
`), process.stderr.write(` \u2022 Check for proper indentation (use spaces, not tabs)
|
|
33
|
-
`), process.stderr.write(` \u2022 Verify colons have spaces after them
|
|
34
|
-
`)) : (process.stderr.write(`Error: Failed to load config file ${configPath}
|
|
35
|
-
`), process.stderr.write(`Details: ${errorMsg}
|
|
36
|
-
`), process.stderr.write(`Suggestions:
|
|
37
|
-
`), process.stderr.write(` \u2022 Verify the file is valid UTF-8 encoded text
|
|
38
|
-
`), process.stderr.write(` \u2022 Check if the file system is accessible
|
|
39
|
-
`), process.stderr.write(` \u2022 Try recreating the file if it may be corrupted
|
|
40
|
-
`)), process.stderr.write(`Using default OTLP configuration due to config file error
|
|
41
|
-
`);
|
|
42
|
-
} else
|
|
43
|
-
process.stderr.write(`Warning: Failed to parse ${configPath}, using defaults
|
|
44
|
-
`);
|
|
45
|
-
}
|
|
46
|
-
const otlp = fileConfig?.telemetry?.otlp, getEnvVar = (value) => value !== void 0 && value.trim().length > 0 ? value : void 0, getValidUrl = (url, fieldName = "URL") => {
|
|
8
|
+
}, otlp = (await loadDRConfig())?.telemetry?.otlp, getEnvVar = (value) => value !== void 0 && value.trim().length > 0 ? value : void 0, getValidUrl = (url, fieldName = "URL") => {
|
|
47
9
|
if (!url)
|
|
48
10
|
return;
|
|
49
11
|
const trimmed = url.trim();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/telemetry/config.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * OTLP Configuration Loader\n *\n * Loads and merges OTLP configuration from multiple sources with the following precedence:\n * 1. DR-specific env vars: DR_OTLP_ENDPOINT, DR_OTLP_LOGS_ENDPOINT, DR_OTLP_SERVICE_NAME (highest)\n * 2. ~/.dr-config.yaml file configuration\n * 3. Standard OTEL env vars: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,\n * OTEL_SERVICE_NAME \u2014 treated as a low-priority fallback so that ambient OTEL env vars set\n * by a parent process (e.g. Claude Code) do not silently override the DR config file.\n * 4. Hard-coded defaults (lowest priority)\n *\n * Why DR-specific env vars are highest: the standard OTEL_* vars are commonly set in developer\n * environments by other OTEL-instrumented tools (IDEs, shell profiles, CI). When dr runs as a\n * subprocess it inherits those vars and would silently misdirect spans. DR_OTLP_* vars are\n * unambiguously for dr and always win.\n *\n * Configuration file format (~/.dr-config.yaml):\n * ```yaml\n * telemetry:\n * otlp:\n * endpoint: 'http://localhost:4318/v1/traces'\n * logs_endpoint: 'http://localhost:4318/v1/logs'\n * service_name: 'dr-cli'\n * ```\n */\n\nimport {
|
|
5
|
-
"mappings": "AA0BA,SAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * OTLP Configuration Loader\n *\n * Loads and merges OTLP configuration from multiple sources with the following precedence:\n * 1. DR-specific env vars: DR_OTLP_ENDPOINT, DR_OTLP_LOGS_ENDPOINT, DR_OTLP_SERVICE_NAME (highest)\n * 2. ~/.dr-config.yaml file configuration\n * 3. Standard OTEL env vars: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,\n * OTEL_SERVICE_NAME \u2014 treated as a low-priority fallback so that ambient OTEL env vars set\n * by a parent process (e.g. Claude Code) do not silently override the DR config file.\n * 4. Hard-coded defaults (lowest priority)\n *\n * Why DR-specific env vars are highest: the standard OTEL_* vars are commonly set in developer\n * environments by other OTEL-instrumented tools (IDEs, shell profiles, CI). When dr runs as a\n * subprocess it inherits those vars and would silently misdirect spans. DR_OTLP_* vars are\n * unambiguously for dr and always win.\n *\n * Configuration file format (~/.dr-config.yaml):\n * ```yaml\n * telemetry:\n * otlp:\n * endpoint: 'http://localhost:4318/v1/traces'\n * logs_endpoint: 'http://localhost:4318/v1/logs'\n * service_name: 'dr-cli'\n * ```\n */\n\nimport { loadDRConfig } from \"../config.js\";\n\n/**\n * Resolved OTLP configuration with all required fields\n */\nexport interface OTLPConfig {\n endpoint: string;\n logsEndpoint: string;\n serviceName: string;\n /** True only when an endpoint was explicitly set via env var or config file. */\n isExplicitlyConfigured: boolean;\n}\n\n/**\n * Load OTLP configuration from multiple sources.\n *\n * Configuration precedence (each field resolved independently):\n * 1. Environment variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, OTEL_SERVICE_NAME)\n * 2. File configuration (~/.dr-config.yaml)\n * 3. Hard-coded defaults\n *\n * All endpoint URLs are validated. Invalid URLs are treated as not set and fall back to next priority.\n *\n * @returns Resolved OTLP configuration with all required fields\n *\n * @example\n * ```typescript\n * const config = await loadOTLPConfig();\n * console.log(config.endpoint); // 'http://localhost:4318/v1/traces' (or from env/file)\n * ```\n */\nexport async function loadOTLPConfig(): Promise<OTLPConfig> {\n // Hard-coded defaults (Priority 3)\n const defaults: OTLPConfig = {\n endpoint: \"http://localhost:4318/v1/traces\",\n logsEndpoint: \"http://localhost:4318/v1/logs\",\n serviceName: \"dr-cli\",\n isExplicitlyConfigured: false,\n };\n\n // Load file configuration (Priority 2) via the shared DR config loader.\n // Malformed/unreadable config files are reported to stderr there and\n // resolve to an empty object here, matching prior loadOTLPConfig() behavior.\n const fileConfig = await loadDRConfig();\n const otlp = fileConfig?.telemetry?.otlp;\n\n // Helper to check if env var is effectively set (not empty after trim)\n const getEnvVar = (value: string | undefined) => {\n return value !== undefined && value.trim().length > 0 ? value : undefined;\n };\n\n // Helper to validate URL and return if valid, undefined if invalid\n const getValidUrl = (url: string | undefined, fieldName: string = \"URL\") => {\n if (!url) return undefined;\n const trimmed = url.trim();\n if (trimmed.length === 0) return undefined;\n\n try {\n const parsedUrl = new URL(trimmed);\n\n // Only accept http and https protocols\n if (parsedUrl.protocol !== \"http:\" && parsedUrl.protocol !== \"https:\") {\n const protocolMsg =\n parsedUrl.protocol === \"\" || parsedUrl.protocol === \":\"\n ? \"URL must include http:// or https:// scheme\"\n : `Invalid protocol \"${parsedUrl.protocol}\" (expected http or https)`;\n process.stderr.write(`Error: ${protocolMsg} in ${fieldName}\\n`);\n process.stderr.write(` Provided: ${trimmed}\\n`);\n process.stderr.write(` Expected: URL must start with http:// or https://\\n`);\n process.stderr.write(` Using fallback configuration for this field\\n`);\n return undefined;\n }\n\n return trimmed;\n } catch (error) {\n process.stderr.write(`Error: Invalid URL in ${fieldName}: \"${trimmed}\"\\n`);\n if (error instanceof Error) {\n process.stderr.write(` Reason: ${error.message}\\n`);\n }\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(\" \u2022 Ensure URL starts with http:// or https://\\n\");\n process.stderr.write(\" \u2022 Check for typos in hostname\\n\");\n process.stderr.write(\" \u2022 Verify port number if specified (e.g., :4318)\\n\");\n process.stderr.write(\" \u2022 Example: http://localhost:4318/v1/traces\\n\");\n process.stderr.write(` Using fallback configuration for this field\\n`);\n return undefined;\n }\n };\n\n // Resolve each field using the 4-level precedence chain:\n // 1. DR-specific env vars (unambiguously for dr, never set by other tools)\n // 2. ~/.dr-config.yaml (explicit user config for dr)\n // 3. Standard OTEL env vars (low-priority fallback; may be set by parent processes)\n // 4. Hard-coded defaults\n //\n // Standard OTEL env vars are intentionally below the config file. When dr runs as a\n // subprocess of another OTEL-instrumented tool (e.g. Claude Code), it inherits those\n // env vars and would otherwise silently redirect spans to the wrong collector.\n const explicitEndpoint =\n getValidUrl(getEnvVar(process.env.DR_OTLP_ENDPOINT), \"DR_OTLP_ENDPOINT\") ??\n getValidUrl(otlp?.endpoint, \"telemetry.otlp.endpoint\") ??\n getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_ENDPOINT), \"OTEL_EXPORTER_OTLP_ENDPOINT\");\n\n const explicitLogsEndpoint =\n getValidUrl(getEnvVar(process.env.DR_OTLP_LOGS_ENDPOINT), \"DR_OTLP_LOGS_ENDPOINT\") ??\n getValidUrl(otlp?.logs_endpoint, \"telemetry.otlp.logs_endpoint\") ??\n getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT), \"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT\");\n\n return {\n endpoint: explicitEndpoint ?? defaults.endpoint,\n logsEndpoint: explicitLogsEndpoint ?? defaults.logsEndpoint,\n serviceName:\n getEnvVar(process.env.DR_OTLP_SERVICE_NAME) ??\n otlp?.service_name ??\n getEnvVar(process.env.OTEL_SERVICE_NAME) ??\n defaults.serviceName,\n // True only when at least one endpoint was explicitly provided. Without this,\n // TELEMETRY_ENABLED=true (build-time) would try to connect to localhost:4318\n // even when no collector is running, causing a hang at shutdown.\n isExplicitlyConfigured: !!(explicitEndpoint || explicitLogsEndpoint),\n };\n}\n"],
|
|
5
|
+
"mappings": "AA0BA,SAAS,oBAAoB;AA+B7B,eAAsB,iBAAc;AAElC,QAAM,WAAuB;IAC3B,UAAU;IACV,cAAc;IACd,aAAa;IACb,wBAAwB;KAOpB,QADa,MAAM,aAAY,IACZ,WAAW,MAG9B,YAAY,CAAC,UACV,UAAU,UAAa,MAAM,KAAI,EAAG,SAAS,IAAI,QAAQ,QAI5D,cAAc,CAAC,KAAyB,YAAoB,UAAS;AACzE,QAAI,CAAC;AAAK;AACV,UAAM,UAAU,IAAI,KAAI;AACxB,QAAI,QAAQ,WAAW;AAEvB,UAAI;AACF,cAAM,YAAY,IAAI,IAAI,OAAO;AAGjC,YAAI,UAAU,aAAa,WAAW,UAAU,aAAa,UAAU;AACrE,gBAAM,cACJ,UAAU,aAAa,MAAM,UAAU,aAAa,MAChD,gDACA,qBAAqB,UAAU,QAAQ;AAC7C,kBAAQ,OAAO,MAAM,UAAU,WAAW,OAAO,SAAS;CAAI,GAC9D,QAAQ,OAAO,MAAM,eAAe,OAAO;CAAI,GAC/C,QAAQ,OAAO,MAAM;CAAuD,GAC5E,QAAQ,OAAO,MAAM;CAAiD;AACtE;QACF;AAEA,eAAO;MACT,SAAS,OAAO;AACd,gBAAQ,OAAO,MAAM,yBAAyB,SAAS,MAAM,OAAO;CAAK,GACrE,iBAAiB,SACnB,QAAQ,OAAO,MAAM,aAAa,MAAM,OAAO;CAAI,GAErD,QAAQ,OAAO,MAAM;CAAgB,GACrC,QAAQ,OAAO,MAAM;CAAkD,GACvE,QAAQ,OAAO,MAAM;CAAmC,GACxD,QAAQ,OAAO,MAAM;CAAqD,GAC1E,QAAQ,OAAO,MAAM;CAAgD,GACrE,QAAQ,OAAO,MAAM;CAAiD;AACtE;MACF;EACF,GAWM,mBACJ,YAAY,UAAU,QAAQ,IAAI,gBAAgB,GAAG,kBAAkB,KACvE,YAAY,MAAM,UAAU,yBAAyB,KACrD,YAAY,UAAU,QAAQ,IAAI,2BAA2B,GAAG,6BAA6B,GAEzF,uBACJ,YAAY,UAAU,QAAQ,IAAI,qBAAqB,GAAG,uBAAuB,KACjF,YAAY,MAAM,eAAe,8BAA8B,KAC/D,YAAY,UAAU,QAAQ,IAAI,gCAAgC,GAAG,kCAAkC;AAEzG,SAAO;IACL,UAAU,oBAAoB,SAAS;IACvC,cAAc,wBAAwB,SAAS;IAC/C,aACE,UAAU,QAAQ,IAAI,oBAAoB,KAC1C,MAAM,gBACN,UAAU,QAAQ,IAAI,iBAAiB,KACvC,SAAS;;;;IAIX,wBAAwB,CAAC,EAAE,oBAAoB;;AAEnD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/telemetry/index.js
CHANGED
|
@@ -21,7 +21,7 @@ async function initTelemetry() {
|
|
|
21
21
|
`), process.stderr.write(` - Logs endpoint: ${otlpConfig.logsEndpoint}
|
|
22
22
|
`), process.stderr.write(` - Service name: ${otlpConfig.serviceName}
|
|
23
23
|
`));
|
|
24
|
-
const cliVersion = "0.
|
|
24
|
+
const cliVersion = "0.3.0";
|
|
25
25
|
let projectName = "unknown";
|
|
26
26
|
try {
|
|
27
27
|
const [{ readFileSync, existsSync }, { parse }] = await Promise.all([
|
package/dist/types/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/types/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Core type definitions for Documentation Robotics CLI\n */\n\n// Import source reference types for use in Element interface\nimport type { SourceReference } from \"./source-reference.js\";\n\n// Export source reference types\nexport type {\n ProvenanceType,\n SourceLocation,\n RepositoryContext,\n SourceReference,\n} from \"./source-reference.js\";\n\n/**\n * Reference across layers\n */\nexport interface Reference {\n source: string; // Element ID\n target: string; // Element ID\n type: string; // Reference type\n description?: string;\n}\n\n/**\n * Intra-layer or cross-layer relationship\n */\nexport interface Relationship {\n source: string;\n target: string;\n predicate: string; // e.g., \"depends-on\", \"implements\"\n layer?: string; // Source element's layer ID\n targetLayer?: string; // Destination element's layer ID; present only for cross-layer relationships\n properties?: Record<string, unknown>;\n category?: \"structural\" | \"behavioral\"; // Relationship classification\n}\n\n/**\n * Element metadata for lifecycle and version tracking\n *\n * Note: created_at and updated_at should be treated as immutable after element initialization.\n * For safe external access with immutability guarantees, use Element.getMetadata() which\n * returns a defensive copy protecting against external mutations.\n */\nexport interface ElementMetadata {\n created_at?: string; // ISO 8601 timestamp (immutable after initialization)\n updated_at?: string; // ISO 8601 timestamp (immutable after initialization)\n created_by?: string;\n version?: number;\n}\n\n/**\n * Element representation\n *\n * Aligned with spec-node.schema.json structure for direct validation\n */\nexport interface Element {\n // Spec-node aligned fields (required in new format)\n id?: string; // UUIDv4 (e.g., \"550e8400-e29b-41d4-a716-446655440000\")\n path?: string; // Human-readable path: {layer}.{type}.{kebab-name} (e.g., \"motivation.goal.increase-revenue\")\n spec_node_id: string; // Reference to spec node type (e.g., \"motivation.goal\")\n type: string; // Denormalized node type (e.g., \"goal\", \"endpoint\")\n layer_id: string; // Denormalized layer ID (e.g., \"motivation\", \"api\")\n name: string;\n\n // Spec-node aligned optional fields\n description?: string;\n attributes?: Record<string, unknown>; // Type-specific properties\n source_reference?: SourceReference; // Provenance tracking\n metadata?: ElementMetadata; // Lifecycle tracking\n\n // Relationship tracking\n references?: Reference[];\n relationships?: Relationship[];\n\n // Internal tracking (unchanged)\n layer?: string;\n filePath?: string;\n rawData?: any;\n}\n\n/**\n * Layer container\n */\nexport interface LayerData {\n elements: Element[];\n metadata?: {\n layer: string;\n version: string;\n };\n}\n\n/**\n * Changeset application history entry\n * Records when changesets were committed or discarded in the model\n */\nexport interface ChangesetHistoryEntry {\n /** Name of the changeset that was committed or discarded */\n name: string;\n /** ISO 8601 timestamp when the action occurred */\n committed_at: string;\n /** Type of action performed */\n action: \"committed\" | \"discarded\";\n}\n\n/**\n * Manifest metadata\n */\nexport interface ManifestData {\n name: string;\n version: string;\n description?: string;\n author?: string;\n created?: string;\n modified?: string;\n specVersion?: string;\n /** Changeset history for the model */\n changeset_history?: ChangesetHistoryEntry[];\n}\n\n/**\n * Model options for customization\n */\nexport interface ModelOptions {\n enableCache?: boolean;\n lazyLoad?: boolean;\n referenceRegistry?: unknown; // Will be properly typed when implemented\n layers?: string[]; // If set, only these layers are loaded (selective loading)\n}\n\n/**\n * JSON Schema property definition\n * Represents a single property in a JSON Schema object\n */\nexport interface JsonSchemaProperty {\n type?: string | string[];\n description?: string;\n enum?: unknown[];\n default?: unknown;\n items?: JsonSchemaProperty;\n properties?: Record<string, JsonSchemaProperty>;\n required?: string[];\n [key: string]: unknown;\n}\n\n/**\n * Tool parameter definition for Claude AI tools\n * Describes a single input parameter for a tool\n */\nexport interface ToolParameter {\n type: string;\n description: string;\n enum?: string[];\n items?: { type: string };\n [key: string]: unknown;\n}\n\n/**\n * Tool input schema definition\n * Defines the structure of inputs for a Claude AI tool\n */\nexport interface ToolInputSchema {\n type: \"object\";\n properties: Record<string, ToolParameter>;\n required: string[];\n}\n\n/**\n * Tool definition for Claude AI integration\n * Represents a single tool that Claude can call\n */\nexport interface ToolDefinition {\n name: string;\n description: string;\n input_schema: ToolInputSchema;\n}\n\n/**\n * Result of executing a tool\n * All tool results are returned as JSON-serializable objects\n */\nexport interface ToolExecutionResult {\n [key: string]: unknown;\n error?: string;\n}\n\n/**\n * SHA256 hash branded type for compile-time safety\n * Prevents accidental misuse of arbitrary strings as cryptographic checksums\n */\nexport type Sha256Hash = string & { readonly __brand: \"Sha256Hash\" };\n\n/**\n * Create a Sha256Hash from a hex string\n * This is the only valid way to construct a Sha256Hash value\n *\n * @param hash - The hex string representation of a SHA256 hash\n * @returns A branded Sha256Hash type\n * @throws Error if the hash is not a valid 64-character hex string\n */\nexport function createSha256Hash(hash: string): Sha256Hash {\n if (!/^[a-f0-9]{64}$/.test(hash)) {\n throw new Error(`Invalid SHA256 hash format. Expected 64-character hex string, got: ${hash}`);\n }\n return hash as Sha256Hash;\n}\n\n/**\n * Backup manifest entry for a single file\n * All properties are readonly to enforce immutability of backup records\n */\nexport interface BackupManifestFile {\n readonly path: string; // Relative path to the file in the backup directory\n readonly checksum: Sha256Hash; // SHA256 hash of the file contents (branded type)\n readonly size: number; // File size in bytes\n}\n\n/**\n * Backup manifest tracking files and creation timestamp\n * Used for backup integrity validation and recovery\n * All properties are readonly to enforce immutability of backup records\n */\nexport interface BackupManifest {\n readonly files: ReadonlyArray<BackupManifestFile>; // Array of backed up files with metadata\n readonly timestamp: string; // ISO 8601 timestamp when backup was created\n}\n\n/**\n * Create and validate a BackupManifest from raw data\n * Validates structure and transforms string checksums to Sha256Hash branded type\n *\n * @param data - Unknown data to validate (typically from JSON parsing)\n * @returns Validated and typed BackupManifest object\n * @throws Error if data doesn't match expected structure or contains invalid checksums\n */\nexport function createBackupManifest(data: unknown): BackupManifest {\n if (!data || typeof data !== \"object\") {\n throw new Error(\"Backup manifest must be an object\");\n }\n\n const obj = data as Record<string, unknown>;\n\n if (!obj.files || !Array.isArray(obj.files)) {\n throw new Error(\"Backup manifest must have a files array\");\n }\n\n if (obj.timestamp && typeof obj.timestamp !== \"string\") {\n throw new Error(\"Backup manifest timestamp must be a string if provided\");\n }\n\n // Validate ISO 8601 timestamp if provided\n let timestamp: string;\n if (obj.timestamp) {\n const timestampDate = new Date(obj.timestamp as string);\n if (isNaN(timestampDate.getTime())) {\n throw new Error(`Invalid timestamp format: ${obj.timestamp}. Expected ISO 8601 string.`);\n }\n timestamp = obj.timestamp as string;\n } else {\n timestamp = new Date().toISOString();\n }\n\n // Validate and transform each file entry\n const files: readonly BackupManifestFile[] = obj.files.map((file: unknown, index: number) => {\n if (!file || typeof file !== \"object\") {\n throw new Error(`Backup manifest file entry ${index} must be an object`);\n }\n\n const fileObj = file as Record<string, unknown>;\n\n if (typeof fileObj.path !== \"string\" || !fileObj.path) {\n throw new Error(`Backup manifest file entry ${index} must have a non-empty path string`);\n }\n\n if (typeof fileObj.checksum !== \"string\") {\n throw new Error(`Backup manifest file entry ${index} must have a checksum string`);\n }\n\n if (typeof fileObj.size !== \"number\" || fileObj.size < 0) {\n throw new Error(`Backup manifest file entry ${index} must have a non-negative size number`);\n }\n\n return {\n path: fileObj.path,\n checksum: createSha256Hash(fileObj.checksum),\n size: fileObj.size,\n };\n });\n\n return {\n files,\n timestamp,\n };\n}\n\n/**\n * Verify backup manifest against actual file checksums\n * Checks that all files in the manifest exist and have matching checksums\n *\n * @param manifest - The backup manifest to verify\n * @param readFile - Function to read file contents by path\n * @param fileExists - Function to check if a file exists by path\n * @param backupDir - Base directory path for resolving relative file paths\n * @returns Promise resolving to verification result with detailed error information\n */\nexport async function verifyBackupIntegrity(\n manifest: BackupManifest,\n readFile: (path: string) => Promise<string>,\n fileExists: (path: string) => Promise<boolean>,\n backupDir: string\n): Promise<{\n isValid: boolean;\n filesChecked: number;\n errors: string[];\n}> {\n const { createHash } = await import(\"crypto\");\n const path = await import(\"path\");\n\n const errors: string[] = [];\n let filesChecked = 0;\n\n try {\n // Verify each file in the manifest\n for (const file of manifest.files) {\n filesChecked++;\n const backupFilePath = path.join(backupDir, file.path);\n\n // Check file exists\n if (!(await fileExists(backupFilePath))) {\n errors.push(`Missing: ${file.path}`);\n continue;\n }\n\n try {\n // Read file and verify checksum\n const content = await readFile(backupFilePath);\n const checksum = createHash(\"sha256\").update(content).digest(\"hex\") as Sha256Hash;\n\n if (checksum !== file.checksum) {\n errors.push(\n `Checksum mismatch: ${file.path} (expected ${file.checksum}, got ${checksum})`\n );\n continue;\n }\n\n // Verify size matches\n if (content.length !== file.size) {\n errors.push(`Size mismatch: ${file.path} (expected ${file.size}, got ${content.length})`);\n }\n } catch (err) {\n errors.push(\n `Failed to verify: ${file.path} (${err instanceof Error ? err.message : String(err)})`\n );\n }\n }\n\n return {\n isValid: errors.length === 0,\n filesChecked,\n errors,\n };\n } catch (err) {\n return {\n isValid: false,\n filesChecked,\n errors: [\n ...errors,\n `Integrity verification failed: ${err instanceof Error ? err.message : String(err)}`,\n ],\n };\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * Core type definitions for Documentation Robotics CLI\n */\n\n// Import source reference types for use in Element interface\nimport type { SourceReference } from \"./source-reference.js\";\n\n// Export source reference types\nexport type {\n ProvenanceType,\n SourceLocation,\n RepositoryContext,\n SourceReference,\n} from \"./source-reference.js\";\n\n// Export farm-related types\nexport type {\n FarmProject,\n FarmManifestData,\n} from \"../core/farm-manifest.js\";\n\n/**\n * Reference across layers\n */\nexport interface Reference {\n source: string; // Element ID\n target: string; // Element ID\n type: string; // Reference type\n description?: string;\n}\n\n/**\n * Intra-layer or cross-layer relationship\n */\nexport interface Relationship {\n source: string;\n target: string;\n predicate: string; // e.g., \"depends-on\", \"implements\"\n layer?: string; // Source element's layer ID\n targetLayer?: string; // Destination element's layer ID; present only for cross-layer relationships\n properties?: Record<string, unknown>;\n category?: \"structural\" | \"behavioral\"; // Relationship classification\n}\n\n/**\n * Element metadata for lifecycle and version tracking\n *\n * Note: created_at and updated_at should be treated as immutable after element initialization.\n * For safe external access with immutability guarantees, use Element.getMetadata() which\n * returns a defensive copy protecting against external mutations.\n */\nexport interface ElementMetadata {\n created_at?: string; // ISO 8601 timestamp (immutable after initialization)\n updated_at?: string; // ISO 8601 timestamp (immutable after initialization)\n created_by?: string;\n version?: number;\n}\n\n/**\n * Element representation\n *\n * Aligned with spec-node.schema.json structure for direct validation\n */\nexport interface Element {\n // Spec-node aligned fields (required in new format)\n id?: string; // UUIDv4 (e.g., \"550e8400-e29b-41d4-a716-446655440000\")\n path?: string; // Human-readable path: {layer}.{type}.{kebab-name} (e.g., \"motivation.goal.increase-revenue\")\n spec_node_id: string; // Reference to spec node type (e.g., \"motivation.goal\")\n type: string; // Denormalized node type (e.g., \"goal\", \"endpoint\")\n layer_id: string; // Denormalized layer ID (e.g., \"motivation\", \"api\")\n name: string;\n\n // Spec-node aligned optional fields\n description?: string;\n attributes?: Record<string, unknown>; // Type-specific properties\n source_reference?: SourceReference; // Provenance tracking\n metadata?: ElementMetadata; // Lifecycle tracking\n\n // Relationship tracking\n references?: Reference[];\n relationships?: Relationship[];\n\n // Internal tracking (unchanged)\n layer?: string;\n filePath?: string;\n rawData?: any;\n}\n\n/**\n * Layer container\n */\nexport interface LayerData {\n elements: Element[];\n metadata?: {\n layer: string;\n version: string;\n };\n}\n\n/**\n * Changeset application history entry\n * Records when changesets were committed or discarded in the model\n */\nexport interface ChangesetHistoryEntry {\n /** Name of the changeset that was committed or discarded */\n name: string;\n /** ISO 8601 timestamp when the action occurred */\n committed_at: string;\n /** Type of action performed */\n action: \"committed\" | \"discarded\";\n}\n\n/**\n * External model declaration in manifest\n * Declares a model that this model may reference via qualified paths (e.g., @model-name/...)\n */\nexport interface ExternalModelDeclaration {\n /** Optional git repository URL for documentation */\n url?: string;\n /** Optional informational role (e.g., \"shared\") - not interpreted by CLI */\n role?: string;\n}\n\n/**\n * Manifest metadata\n */\nexport interface ManifestData {\n name: string;\n version: string;\n description?: string;\n author?: string;\n created?: string;\n modified?: string;\n cliVersion?: string;\n specVersion?: string;\n /** Changeset history for the model */\n changeset_history?: ChangesetHistoryEntry[];\n /** External model declarations: model name to declaration metadata */\n models?: Record<string, ExternalModelDeclaration>;\n /** Relative path to the codebase root (for detached models). Resolved relative to model root. */\n codebase_path?: string;\n}\n\n/**\n * Model options for customization\n */\nexport interface ModelOptions {\n enableCache?: boolean;\n lazyLoad?: boolean;\n referenceRegistry?: unknown; // Will be properly typed when implemented\n layers?: string[]; // If set, only these layers are loaded (selective loading)\n codebaseRoot?: string; // If set, points to the codebase directory (for detached models)\n}\n\n/**\n * JSON Schema property definition\n * Represents a single property in a JSON Schema object\n */\nexport interface JsonSchemaProperty {\n type?: string | string[];\n description?: string;\n enum?: unknown[];\n default?: unknown;\n items?: JsonSchemaProperty;\n properties?: Record<string, JsonSchemaProperty>;\n required?: string[];\n [key: string]: unknown;\n}\n\n/**\n * Tool parameter definition for Claude AI tools\n * Describes a single input parameter for a tool\n */\nexport interface ToolParameter {\n type: string;\n description: string;\n enum?: string[];\n items?: { type: string };\n [key: string]: unknown;\n}\n\n/**\n * Tool input schema definition\n * Defines the structure of inputs for a Claude AI tool\n */\nexport interface ToolInputSchema {\n type: \"object\";\n properties: Record<string, ToolParameter>;\n required: string[];\n}\n\n/**\n * Tool definition for Claude AI integration\n * Represents a single tool that Claude can call\n */\nexport interface ToolDefinition {\n name: string;\n description: string;\n input_schema: ToolInputSchema;\n}\n\n/**\n * Result of executing a tool\n * All tool results are returned as JSON-serializable objects\n */\nexport interface ToolExecutionResult {\n [key: string]: unknown;\n error?: string;\n}\n\n/**\n * SHA256 hash branded type for compile-time safety\n * Prevents accidental misuse of arbitrary strings as cryptographic checksums\n */\nexport type Sha256Hash = string & { readonly __brand: \"Sha256Hash\" };\n\n/**\n * Create a Sha256Hash from a hex string\n * This is the only valid way to construct a Sha256Hash value\n *\n * @param hash - The hex string representation of a SHA256 hash\n * @returns A branded Sha256Hash type\n * @throws Error if the hash is not a valid 64-character hex string\n */\nexport function createSha256Hash(hash: string): Sha256Hash {\n if (!/^[a-f0-9]{64}$/.test(hash)) {\n throw new Error(`Invalid SHA256 hash format. Expected 64-character hex string, got: ${hash}`);\n }\n return hash as Sha256Hash;\n}\n\n/**\n * Backup manifest entry for a single file\n * All properties are readonly to enforce immutability of backup records\n */\nexport interface BackupManifestFile {\n readonly path: string; // Relative path to the file in the backup directory\n readonly checksum: Sha256Hash; // SHA256 hash of the file contents (branded type)\n readonly size: number; // File size in bytes\n}\n\n/**\n * Backup manifest tracking files and creation timestamp\n * Used for backup integrity validation and recovery\n * All properties are readonly to enforce immutability of backup records\n */\nexport interface BackupManifest {\n readonly files: ReadonlyArray<BackupManifestFile>; // Array of backed up files with metadata\n readonly timestamp: string; // ISO 8601 timestamp when backup was created\n}\n\n/**\n * Create and validate a BackupManifest from raw data\n * Validates structure and transforms string checksums to Sha256Hash branded type\n *\n * @param data - Unknown data to validate (typically from JSON parsing)\n * @returns Validated and typed BackupManifest object\n * @throws Error if data doesn't match expected structure or contains invalid checksums\n */\nexport function createBackupManifest(data: unknown): BackupManifest {\n if (!data || typeof data !== \"object\") {\n throw new Error(\"Backup manifest must be an object\");\n }\n\n const obj = data as Record<string, unknown>;\n\n if (!obj.files || !Array.isArray(obj.files)) {\n throw new Error(\"Backup manifest must have a files array\");\n }\n\n if (obj.timestamp && typeof obj.timestamp !== \"string\") {\n throw new Error(\"Backup manifest timestamp must be a string if provided\");\n }\n\n // Validate ISO 8601 timestamp if provided\n let timestamp: string;\n if (obj.timestamp) {\n const timestampDate = new Date(obj.timestamp as string);\n if (isNaN(timestampDate.getTime())) {\n throw new Error(`Invalid timestamp format: ${obj.timestamp}. Expected ISO 8601 string.`);\n }\n timestamp = obj.timestamp as string;\n } else {\n timestamp = new Date().toISOString();\n }\n\n // Validate and transform each file entry\n const files: readonly BackupManifestFile[] = obj.files.map((file: unknown, index: number) => {\n if (!file || typeof file !== \"object\") {\n throw new Error(`Backup manifest file entry ${index} must be an object`);\n }\n\n const fileObj = file as Record<string, unknown>;\n\n if (typeof fileObj.path !== \"string\" || !fileObj.path) {\n throw new Error(`Backup manifest file entry ${index} must have a non-empty path string`);\n }\n\n if (typeof fileObj.checksum !== \"string\") {\n throw new Error(`Backup manifest file entry ${index} must have a checksum string`);\n }\n\n if (typeof fileObj.size !== \"number\" || fileObj.size < 0) {\n throw new Error(`Backup manifest file entry ${index} must have a non-negative size number`);\n }\n\n return {\n path: fileObj.path,\n checksum: createSha256Hash(fileObj.checksum),\n size: fileObj.size,\n };\n });\n\n return {\n files,\n timestamp,\n };\n}\n\n/**\n * Verify backup manifest against actual file checksums\n * Checks that all files in the manifest exist and have matching checksums\n *\n * @param manifest - The backup manifest to verify\n * @param readFile - Function to read file contents by path\n * @param fileExists - Function to check if a file exists by path\n * @param backupDir - Base directory path for resolving relative file paths\n * @returns Promise resolving to verification result with detailed error information\n */\nexport async function verifyBackupIntegrity(\n manifest: BackupManifest,\n readFile: (path: string) => Promise<string>,\n fileExists: (path: string) => Promise<boolean>,\n backupDir: string\n): Promise<{\n isValid: boolean;\n filesChecked: number;\n errors: string[];\n}> {\n const { createHash } = await import(\"crypto\");\n const path = await import(\"path\");\n\n const errors: string[] = [];\n let filesChecked = 0;\n\n try {\n // Verify each file in the manifest\n for (const file of manifest.files) {\n filesChecked++;\n const backupFilePath = path.join(backupDir, file.path);\n\n // Check file exists\n if (!(await fileExists(backupFilePath))) {\n errors.push(`Missing: ${file.path}`);\n continue;\n }\n\n try {\n // Read file and verify checksum\n const content = await readFile(backupFilePath);\n const checksum = createHash(\"sha256\").update(content).digest(\"hex\") as Sha256Hash;\n\n if (checksum !== file.checksum) {\n errors.push(\n `Checksum mismatch: ${file.path} (expected ${file.checksum}, got ${checksum})`\n );\n continue;\n }\n\n // Verify size matches\n if (content.length !== file.size) {\n errors.push(`Size mismatch: ${file.path} (expected ${file.size}, got ${content.length})`);\n }\n } catch (err) {\n errors.push(\n `Failed to verify: ${file.path} (${err instanceof Error ? err.message : String(err)})`\n );\n }\n }\n\n return {\n isValid: errors.length === 0,\n filesChecked,\n errors,\n };\n } catch (err) {\n return {\n isValid: false,\n filesChecked,\n errors: [\n ...errors,\n `Integrity verification failed: ${err instanceof Error ? err.message : String(err)}`,\n ],\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "AAgOM,SAAU,iBAAiB,MAAY;AAC3C,MAAI,CAAC,iBAAiB,KAAK,IAAI;AAC7B,UAAM,IAAI,MAAM,sEAAsE,IAAI,EAAE;AAE9F,SAAO;AACT;AA8BM,SAAU,qBAAqB,MAAa;AAChD,MAAI,CAAC,QAAQ,OAAO,QAAS;AAC3B,UAAM,IAAI,MAAM,mCAAmC;AAGrD,QAAM,MAAM;AAEZ,MAAI,CAAC,IAAI,SAAS,CAAC,MAAM,QAAQ,IAAI,KAAK;AACxC,UAAM,IAAI,MAAM,yCAAyC;AAG3D,MAAI,IAAI,aAAa,OAAO,IAAI,aAAc;AAC5C,UAAM,IAAI,MAAM,wDAAwD;AAI1E,MAAI;AACJ,MAAI,IAAI,WAAW;AACjB,UAAM,gBAAgB,IAAI,KAAK,IAAI,SAAmB;AACtD,QAAI,MAAM,cAAc,QAAO,CAAE;AAC/B,YAAM,IAAI,MAAM,6BAA6B,IAAI,SAAS,6BAA6B;AAEzF,gBAAY,IAAI;EAClB;AACE,iBAAY,oBAAI,KAAI,GAAG,YAAW;AA8BpC,SAAO;IACL,OA3B2C,IAAI,MAAM,IAAI,CAAC,MAAe,UAAiB;AAC1F,UAAI,CAAC,QAAQ,OAAO,QAAS;AAC3B,cAAM,IAAI,MAAM,8BAA8B,KAAK,oBAAoB;AAGzE,YAAM,UAAU;AAEhB,UAAI,OAAO,QAAQ,QAAS,YAAY,CAAC,QAAQ;AAC/C,cAAM,IAAI,MAAM,8BAA8B,KAAK,oCAAoC;AAGzF,UAAI,OAAO,QAAQ,YAAa;AAC9B,cAAM,IAAI,MAAM,8BAA8B,KAAK,8BAA8B;AAGnF,UAAI,OAAO,QAAQ,QAAS,YAAY,QAAQ,OAAO;AACrD,cAAM,IAAI,MAAM,8BAA8B,KAAK,uCAAuC;AAG5F,aAAO;QACL,MAAM,QAAQ;QACd,UAAU,iBAAiB,QAAQ,QAAQ;QAC3C,MAAM,QAAQ;;IAElB,CAAC;IAIC;;AAEJ;AAYA,eAAsB,sBACpB,UACA,UACA,YACA,WAAiB;AAMjB,QAAM,EAAE,WAAU,IAAK,MAAM,OAAO,QAAQ,GACtC,OAAO,MAAM,OAAO,MAAM,GAE1B,SAAmB,CAAA;AACzB,MAAI,eAAe;AAEnB,MAAI;AAEF,eAAW,QAAQ,SAAS,OAAO;AACjC;AACA,YAAM,iBAAiB,KAAK,KAAK,WAAW,KAAK,IAAI;AAGrD,UAAI,CAAE,MAAM,WAAW,cAAc,GAAI;AACvC,eAAO,KAAK,YAAY,KAAK,IAAI,EAAE;AACnC;MACF;AAEA,UAAI;AAEF,cAAM,UAAU,MAAM,SAAS,cAAc,GACvC,WAAW,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAElE,YAAI,aAAa,KAAK,UAAU;AAC9B,iBAAO,KACL,sBAAsB,KAAK,IAAI,cAAc,KAAK,QAAQ,SAAS,QAAQ,GAAG;AAEhF;QACF;AAGA,QAAI,QAAQ,WAAW,KAAK,QAC1B,OAAO,KAAK,kBAAkB,KAAK,IAAI,cAAc,KAAK,IAAI,SAAS,QAAQ,MAAM,GAAG;MAE5F,SAAS,KAAK;AACZ,eAAO,KACL,qBAAqB,KAAK,IAAI,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG;MAE1F;IACF;AAEA,WAAO;MACL,SAAS,OAAO,WAAW;MAC3B;MACA;;EAEJ,SAAS,KAAK;AACZ,WAAO;MACL,SAAS;MACT;MACA,QAAQ;QACN,GAAG;QACH,kCAAkC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;;;EAGxF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function stripAnsi(text) {
|
|
2
|
+
return text.replace(/\x1b\[[0-9;]*m/g, "");
|
|
3
|
+
}
|
|
4
|
+
function installAnsiSuppressor() {
|
|
5
|
+
const originalLog = console.log, originalError = console.error, originalWarn = console.warn, originalInfo = console.info;
|
|
6
|
+
process.stdout.isTTY !== !0 && (console.log = function(...args) {
|
|
7
|
+
const stripped = args.map((arg) => typeof arg == "string" ? stripAnsi(arg) : arg);
|
|
8
|
+
return originalLog.apply(console, stripped);
|
|
9
|
+
}, console.info = function(...args) {
|
|
10
|
+
const stripped = args.map((arg) => typeof arg == "string" ? stripAnsi(arg) : arg);
|
|
11
|
+
return originalInfo.apply(console, stripped);
|
|
12
|
+
}), process.stderr.isTTY !== !0 && (console.error = function(...args) {
|
|
13
|
+
const stripped = args.map((arg) => typeof arg == "string" ? stripAnsi(arg) : arg);
|
|
14
|
+
return originalError.apply(console, stripped);
|
|
15
|
+
}, console.warn = function(...args) {
|
|
16
|
+
const stripped = args.map((arg) => typeof arg == "string" ? stripAnsi(arg) : arg);
|
|
17
|
+
return originalWarn.apply(console, stripped);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
installAnsiSuppressor
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=ansi-suppressor.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/ansi-suppressor.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Global ANSI code suppression for non-TTY output\n * Intercepts console output and strips ANSI escape sequences when the target stream is not a TTY\n * Handles stdout (log/info) and stderr (error/warn) independently based on their respective TTY status\n */\n\nfunction stripAnsi(text: string): string {\n // eslint-disable-next-line no-control-regex\n return text.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\nexport function installAnsiSuppressor(): void {\n const originalLog = console.log;\n const originalError = console.error;\n const originalWarn = console.warn;\n const originalInfo = console.info;\n\n // Suppress ANSI codes from stdout (log/info) if stdout is not a TTY\n const shouldSuppressStdout = process.stdout.isTTY !== true;\n if (shouldSuppressStdout) {\n console.log = function (...args: any[]) {\n const stripped = args.map((arg) => {\n if (typeof arg === \"string\") {\n return stripAnsi(arg);\n }\n return arg;\n });\n return originalLog.apply(console, stripped);\n };\n\n console.info = function (...args: any[]) {\n const stripped = args.map((arg) => {\n if (typeof arg === \"string\") {\n return stripAnsi(arg);\n }\n return arg;\n });\n return originalInfo.apply(console, stripped);\n };\n }\n\n // Suppress ANSI codes from stderr (error/warn) if stderr is not a TTY\n const shouldSuppressStderr = process.stderr.isTTY !== true;\n if (shouldSuppressStderr) {\n console.error = function (...args: any[]) {\n const stripped = args.map((arg) => {\n if (typeof arg === \"string\") {\n return stripAnsi(arg);\n }\n return arg;\n });\n return originalError.apply(console, stripped);\n };\n\n console.warn = function (...args: any[]) {\n const stripped = args.map((arg) => {\n if (typeof arg === \"string\") {\n return stripAnsi(arg);\n }\n return arg;\n });\n return originalWarn.apply(console, stripped);\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,UAAU,MAAY;AAE7B,SAAO,KAAK,QAAQ,mBAAmB,EAAE;AAC3C;AAEM,SAAU,wBAAqB;AACnC,QAAM,cAAc,QAAQ,KACtB,gBAAgB,QAAQ,OACxB,eAAe,QAAQ,MACvB,eAAe,QAAQ;AAI7B,EAD6B,QAAQ,OAAO,UAAU,OAEpD,QAAQ,MAAM,YAAa,MAAW;AACpC,UAAM,WAAW,KAAK,IAAI,CAAC,QACrB,OAAO,OAAQ,WACV,UAAU,GAAG,IAEf,GACR;AACD,WAAO,YAAY,MAAM,SAAS,QAAQ;EAC5C,GAEA,QAAQ,OAAO,YAAa,MAAW;AACrC,UAAM,WAAW,KAAK,IAAI,CAAC,QACrB,OAAO,OAAQ,WACV,UAAU,GAAG,IAEf,GACR;AACD,WAAO,aAAa,MAAM,SAAS,QAAQ;EAC7C,IAI2B,QAAQ,OAAO,UAAU,OAEpD,QAAQ,QAAQ,YAAa,MAAW;AACtC,UAAM,WAAW,KAAK,IAAI,CAAC,QACrB,OAAO,OAAQ,WACV,UAAU,GAAG,IAEf,GACR;AACD,WAAO,cAAc,MAAM,SAAS,QAAQ;EAC9C,GAEA,QAAQ,OAAO,YAAa,MAAW;AACrC,UAAM,WAAW,KAAK,IAAI,CAAC,QACrB,OAAO,OAAQ,WACV,UAAU,GAAG,IAEf,GACR;AACD,WAAO,aAAa,MAAM,SAAS,QAAQ;EAC7C;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CLIError, ErrorCategory } from "./errors.js";
|
|
2
|
+
function isPlainObject(value) {
|
|
3
|
+
return !!value && typeof value == "object" && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
function applyAttributePatch(current, patch) {
|
|
6
|
+
const merged = { ...current ?? {} };
|
|
7
|
+
for (const [key, value] of Object.entries(patch))
|
|
8
|
+
value === null ? delete merged[key] : value !== void 0 && (merged[key] = value);
|
|
9
|
+
return merged;
|
|
10
|
+
}
|
|
11
|
+
function effectiveAttributePatch(patch) {
|
|
12
|
+
return patch !== void 0 && Object.keys(patch).length > 0 ? patch : void 0;
|
|
13
|
+
}
|
|
14
|
+
function resolveAttributeUpdate(current, update, flags = { attributes: "attributes", attributePatch: "attributePatch" }) {
|
|
15
|
+
if (update.attributes !== void 0 && update.attributePatch !== void 0)
|
|
16
|
+
throw new CLIError(`Cannot use ${flags.attributes} and ${flags.attributePatch} together`, ErrorCategory.USER, [
|
|
17
|
+
`Use ${flags.attributes} to replace all attributes, or ${flags.attributePatch} to change only the keys it names`
|
|
18
|
+
]);
|
|
19
|
+
if (update.attributes !== void 0)
|
|
20
|
+
return update.attributes;
|
|
21
|
+
if (update.attributePatch !== void 0)
|
|
22
|
+
return applyAttributePatch(current, update.attributePatch);
|
|
23
|
+
}
|
|
24
|
+
function parseJsonObjectOption(raw, flag) {
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
parsed = JSON.parse(raw);
|
|
28
|
+
} catch {
|
|
29
|
+
throw new CLIError(`Invalid JSON in ${flag}`, ErrorCategory.USER, ["Ensure your JSON is valid and properly formatted"]);
|
|
30
|
+
}
|
|
31
|
+
if (!isPlainObject(parsed))
|
|
32
|
+
throw new CLIError(`${flag} must be a JSON object`, ErrorCategory.USER, [`Example: ${flag} '{"summary":"New summary"}'`]);
|
|
33
|
+
return parsed;
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
applyAttributePatch,
|
|
37
|
+
effectiveAttributePatch,
|
|
38
|
+
parseJsonObjectOption,
|
|
39
|
+
resolveAttributeUpdate
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=attribute-patch.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/attribute-patch.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Attribute updates for `dr update` and the MCP `model_update` tool.\n *\n * `attributes` replaces an element's attributes; `attributePatch` merges into them, so changing one\n * attribute does not mean repeating every required one. A `null` value in a patch removes that key.\n * Both callers resolve the new attributes here so they behave the same; schema validation then runs\n * on the result.\n */\n\nimport { CLIError, ErrorCategory } from \"./errors.js\";\n\nexport type AttributePatch = Record<string, unknown>;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * Merges `patch` over `current` (shallow: a patched key's value replaces the old one), removing keys\n * whose patch value is `null`. Returns a new object; `current` is not modified (staged `before`\n * snapshots share the element's attributes object).\n */\nexport function applyAttributePatch(\n current: Record<string, unknown> | undefined,\n patch: AttributePatch\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...(current ?? {}) };\n for (const [key, value] of Object.entries(patch)) {\n if (value === null) {\n delete merged[key];\n } else if (value !== undefined) {\n merged[key] = value;\n }\n }\n return merged;\n}\n\n/**\n * The patch as an update: an empty patch names no key, so it changes nothing and is not an update\n * (callers then report \"No fields specified\" and stage nothing).\n */\nexport function effectiveAttributePatch(patch: AttributePatch | undefined): AttributePatch | undefined {\n return patch !== undefined && Object.keys(patch).length > 0 ? patch : undefined;\n}\n\n/**\n * The attributes an update asks for: `attributes` as given (replace), or `attributePatch` merged\n * over `current`, or undefined when the update leaves attributes alone. Passing both is an error.\n *\n * @param flags how the two options are spelled to the caller, for the error message\n */\nexport function resolveAttributeUpdate(\n current: Record<string, unknown> | undefined,\n update: { attributes?: Record<string, unknown>; attributePatch?: AttributePatch },\n flags: { attributes: string; attributePatch: string } = { attributes: \"attributes\", attributePatch: \"attributePatch\" }\n): Record<string, unknown> | undefined {\n if (update.attributes !== undefined && update.attributePatch !== undefined) {\n throw new CLIError(`Cannot use ${flags.attributes} and ${flags.attributePatch} together`, ErrorCategory.USER, [\n `Use ${flags.attributes} to replace all attributes, or ${flags.attributePatch} to change only the keys it names`,\n ]);\n }\n if (update.attributes !== undefined) return update.attributes;\n if (update.attributePatch !== undefined) return applyAttributePatch(current, update.attributePatch);\n return undefined;\n}\n\n/** Parses a CLI JSON option that must be an object (`--attributes`, `--attribute-patch`). */\nexport function parseJsonObjectOption(raw: string, flag: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new CLIError(`Invalid JSON in ${flag}`, ErrorCategory.USER, [\"Ensure your JSON is valid and properly formatted\"]);\n }\n if (!isPlainObject(parsed)) {\n throw new CLIError(`${flag} must be a JSON object`, ErrorCategory.USER, [`Example: ${flag} '{\"summary\":\"New summary\"}'`]);\n }\n return parsed;\n}\n"],
|
|
5
|
+
"mappings": "AASA,SAAS,UAAU,qBAAqB;AAIxC,SAAS,cAAc,OAAc;AACnC,SAAO,CAAC,CAAC,SAAS,OAAO,SAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AACrE;AAOM,SAAU,oBACd,SACA,OAAqB;AAErB,QAAM,SAAkC,EAAE,GAAI,WAAW,CAAA,EAAG;AAC5D,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK;AAC7C,IAAI,UAAU,OACZ,OAAO,OAAO,GAAG,IACR,UAAU,WACnB,OAAO,GAAG,IAAI;AAGlB,SAAO;AACT;AAMM,SAAU,wBAAwB,OAAiC;AACvE,SAAO,UAAU,UAAa,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AACxE;AAQM,SAAU,uBACd,SACA,QACA,QAAwD,EAAE,YAAY,cAAc,gBAAgB,iBAAgB,GAAE;AAEtH,MAAI,OAAO,eAAe,UAAa,OAAO,mBAAmB;AAC/D,UAAM,IAAI,SAAS,cAAc,MAAM,UAAU,QAAQ,MAAM,cAAc,aAAa,cAAc,MAAM;MAC5G,OAAO,MAAM,UAAU,kCAAkC,MAAM,cAAc;KAC9E;AAEH,MAAI,OAAO,eAAe;AAAW,WAAO,OAAO;AACnD,MAAI,OAAO,mBAAmB;AAAW,WAAO,oBAAoB,SAAS,OAAO,cAAc;AAEpG;AAGM,SAAU,sBAAsB,KAAa,MAAY;AAC7D,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;EACzB,QAAQ;AACN,UAAM,IAAI,SAAS,mBAAmB,IAAI,IAAI,cAAc,MAAM,CAAC,kDAAkD,CAAC;EACxH;AACA,MAAI,CAAC,cAAc,MAAM;AACvB,UAAM,IAAI,SAAS,GAAG,IAAI,0BAA0B,cAAc,MAAM,CAAC,YAAY,IAAI,8BAA8B,CAAC;AAE1H,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import ansis from "ansis";
|
|
2
|
+
function shouldUseColors() {
|
|
3
|
+
return process.stdout.isTTY === !0;
|
|
4
|
+
}
|
|
5
|
+
const colors = {
|
|
6
|
+
red: (str) => shouldUseColors() ? ansis.red(str) : str,
|
|
7
|
+
green: (str) => shouldUseColors() ? ansis.green(str) : str,
|
|
8
|
+
yellow: (str) => shouldUseColors() ? ansis.yellow(str) : str,
|
|
9
|
+
blue: (str) => shouldUseColors() ? ansis.blue(str) : str,
|
|
10
|
+
gray: (str) => shouldUseColors() ? ansis.gray(str) : str,
|
|
11
|
+
dim: (str) => shouldUseColors() ? ansis.dim(str) : str,
|
|
12
|
+
bold: (str) => shouldUseColors() ? ansis.bold(str) : str,
|
|
13
|
+
cyan: (str) => shouldUseColors() ? ansis.cyan(str) : str,
|
|
14
|
+
get red_bold() {
|
|
15
|
+
return (str) => shouldUseColors() ? ansis.red.bold(str) : str;
|
|
16
|
+
},
|
|
17
|
+
get bold_yellow() {
|
|
18
|
+
return (str) => shouldUseColors() ? ansis.bold.yellow(str) : str;
|
|
19
|
+
},
|
|
20
|
+
get bold_blue() {
|
|
21
|
+
return (str) => shouldUseColors() ? ansis.bold.blue(str) : str;
|
|
22
|
+
},
|
|
23
|
+
get bold_green() {
|
|
24
|
+
return (str) => shouldUseColors() ? ansis.bold.green(str) : str;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
function isColorSupported() {
|
|
28
|
+
return shouldUseColors();
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
colors,
|
|
32
|
+
isColorSupported
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=color-utils.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/color-utils.ts"],
|
|
4
|
+
"sourcesContent": ["import ansis from \"ansis\";\n\nfunction shouldUseColors(): boolean {\n return process.stdout.isTTY === true;\n}\n\nexport const colors = {\n red: (str: string): string => (shouldUseColors() ? ansis.red(str) : str),\n green: (str: string): string => (shouldUseColors() ? ansis.green(str) : str),\n yellow: (str: string): string => (shouldUseColors() ? ansis.yellow(str) : str),\n blue: (str: string): string => (shouldUseColors() ? ansis.blue(str) : str),\n gray: (str: string): string => (shouldUseColors() ? ansis.gray(str) : str),\n dim: (str: string): string => (shouldUseColors() ? ansis.dim(str) : str),\n bold: (str: string): string => (shouldUseColors() ? ansis.bold(str) : str),\n cyan: (str: string): string => (shouldUseColors() ? ansis.cyan(str) : str),\n\n get red_bold() {\n return (str: string): string => (shouldUseColors() ? ansis.red.bold(str) : str);\n },\n get bold_yellow() {\n return (str: string): string => (shouldUseColors() ? ansis.bold.yellow(str) : str);\n },\n get bold_blue() {\n return (str: string): string => (shouldUseColors() ? ansis.bold.blue(str) : str);\n },\n get bold_green() {\n return (str: string): string => (shouldUseColors() ? ansis.bold.green(str) : str);\n },\n};\n\nexport function isColorSupported(): boolean {\n return shouldUseColors();\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,WAAW;AAElB,SAAS,kBAAe;AACtB,SAAO,QAAQ,OAAO,UAAU;AAClC;AAEO,MAAM,SAAS;EACpB,KAAK,CAAC,QAAyB,gBAAe,IAAK,MAAM,IAAI,GAAG,IAAI;EACpE,OAAO,CAAC,QAAyB,gBAAe,IAAK,MAAM,MAAM,GAAG,IAAI;EACxE,QAAQ,CAAC,QAAyB,gBAAe,IAAK,MAAM,OAAO,GAAG,IAAI;EAC1E,MAAM,CAAC,QAAyB,gBAAe,IAAK,MAAM,KAAK,GAAG,IAAI;EACtE,MAAM,CAAC,QAAyB,gBAAe,IAAK,MAAM,KAAK,GAAG,IAAI;EACtE,KAAK,CAAC,QAAyB,gBAAe,IAAK,MAAM,IAAI,GAAG,IAAI;EACpE,MAAM,CAAC,QAAyB,gBAAe,IAAK,MAAM,KAAK,GAAG,IAAI;EACtE,MAAM,CAAC,QAAyB,gBAAe,IAAK,MAAM,KAAK,GAAG,IAAI;EAEtE,IAAI,WAAQ;AACV,WAAO,CAAC,QAAyB,gBAAe,IAAK,MAAM,IAAI,KAAK,GAAG,IAAI;EAC7E;EACA,IAAI,cAAW;AACb,WAAO,CAAC,QAAyB,gBAAe,IAAK,MAAM,KAAK,OAAO,GAAG,IAAI;EAChF;EACA,IAAI,YAAS;AACX,WAAO,CAAC,QAAyB,gBAAe,IAAK,MAAM,KAAK,KAAK,GAAG,IAAI;EAC9E;EACA,IAAI,aAAU;AACZ,WAAO,CAAC,QAAyB,gBAAe,IAAK,MAAM,KAAK,MAAM,GAAG,IAAI;EAC/E;;AAGI,SAAU,mBAAgB;AAC9B,SAAO,gBAAe;AACxB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { getAllLayerIds } from "../generated/layer-registry.js";
|
|
2
|
-
|
|
2
|
+
import { UUID_PATTERN, QUALIFIED_PREFIX_PATTERN, parseReferencePath, ReferencePathParseError } from "./reference-path-parser.js";
|
|
3
|
+
const KNOWN_LAYERS = new Set(getAllLayerIds());
|
|
3
4
|
function looksLikeElementReference(value) {
|
|
4
5
|
if (UUID_PATTERN.test(value))
|
|
5
6
|
return !0;
|
|
7
|
+
if (QUALIFIED_PREFIX_PATTERN.test(value))
|
|
8
|
+
try {
|
|
9
|
+
const parsed = parseReferencePath(value), dotIndex2 = parsed.segment.indexOf(".");
|
|
10
|
+
if (dotIndex2 > 0) {
|
|
11
|
+
const layer = parsed.segment.slice(0, dotIndex2);
|
|
12
|
+
return KNOWN_LAYERS.has(layer);
|
|
13
|
+
}
|
|
14
|
+
return !1;
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error instanceof ReferencePathParseError)
|
|
17
|
+
return !1;
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
6
20
|
const dotIndex = value.indexOf(".");
|
|
7
21
|
return dotIndex <= 0 ? !1 : KNOWN_LAYERS.has(value.slice(0, dotIndex));
|
|
8
22
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/element-reference-shape.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Shape check for \"does this string plausibly identify a DR model element\" \u2014 a UUIDv4\n * (element.id)
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["/**\n * Shape check for \"does this string plausibly identify a DR model element\" \u2014 a UUIDv4\n * (element.id), a dot-separated `{layer}.{type}.{slug}` id whose first segment is a real,\n * known DR layer (matching the id scheme `NamingValidator` enforces on every element), or\n * a qualified cross-model reference in the format `@{model-name}/{layer}.{type}.{slug}`.\n *\n * Used by `ReferenceRegistry` to gate its `*Ref`/`*Reference` attribute-name heuristic: an\n * attribute NAME matching that convention is not, by itself, reliable evidence that its VALUE\n * is an element reference \u2014 `api.link.operationRef` is a schema-declared OpenAPI URL fragment\n * (e.g. \"#/paths/~1users/get\"), not an element id, and matches the naming convention purely by\n * coincidence. Checking the value's shape catches that case (and any future one like it)\n * without needing per-attribute schema annotations that don't exist today.\n *\n * Deliberately a shape check, not an existence check: a value that looks like an element id but\n * doesn't resolve to one is exactly what `ReferenceRegistry.findBrokenReferences()` is supposed\n * to catch, so this must not filter those out too.\n */\nimport { getAllLayerIds } from \"../generated/layer-registry.js\";\nimport {\n UUID_PATTERN,\n QUALIFIED_PREFIX_PATTERN,\n parseReferencePath,\n ReferencePathParseError,\n} from \"./reference-path-parser.js\";\n\nconst KNOWN_LAYERS = new Set(getAllLayerIds());\n\nexport function looksLikeElementReference(value: string): boolean {\n if (UUID_PATTERN.test(value)) return true;\n\n // Check for qualified reference: must match without whitespace\n if (QUALIFIED_PREFIX_PATTERN.test(value)) {\n try {\n const parsed = parseReferencePath(value);\n // Extract layer name from segment (first dot-separated component)\n const dotIndex = parsed.segment.indexOf(\".\");\n if (dotIndex > 0) {\n const layer = parsed.segment.slice(0, dotIndex);\n return KNOWN_LAYERS.has(layer);\n }\n return false;\n } catch (error) {\n // Malformed qualified reference\n if (error instanceof ReferencePathParseError) {\n return false;\n }\n throw error;\n }\n }\n\n // Check for unqualified reference: {layer}.{type}.{slug}\n const dotIndex = value.indexOf(\".\");\n if (dotIndex <= 0) return false;\n\n return KNOWN_LAYERS.has(value.slice(0, dotIndex));\n}\n"],
|
|
5
|
+
"mappings": "AAiBA,SAAS,sBAAsB;AAC/B,SACE,cACA,0BACA,oBACA,+BACK;AAEP,MAAM,eAAe,IAAI,IAAI,eAAc,CAAE;AAEvC,SAAU,0BAA0B,OAAa;AACrD,MAAI,aAAa,KAAK,KAAK;AAAG,WAAO;AAGrC,MAAI,yBAAyB,KAAK,KAAK;AACrC,QAAI;AACF,YAAM,SAAS,mBAAmB,KAAK,GAEjCA,YAAW,OAAO,QAAQ,QAAQ,GAAG;AAC3C,UAAIA,YAAW,GAAG;AAChB,cAAM,QAAQ,OAAO,QAAQ,MAAM,GAAGA,SAAQ;AAC9C,eAAO,aAAa,IAAI,KAAK;MAC/B;AACA,aAAO;IACT,SAAS,OAAO;AAEd,UAAI,iBAAiB;AACnB,eAAO;AAET,YAAM;IACR;AAIF,QAAM,WAAW,MAAM,QAAQ,GAAG;AAClC,SAAI,YAAY,IAAU,KAEnB,aAAa,IAAI,MAAM,MAAM,GAAG,QAAQ,CAAC;AAClD;",
|
|
6
|
+
"names": ["dotIndex"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const CLI_FLAGS = {
|
|
2
|
+
sourceFile: "--source-file",
|
|
3
|
+
sourceSymbol: "--source-symbol",
|
|
4
|
+
sourceProvenance: "--source-provenance",
|
|
5
|
+
sourceRepoRemote: "--source-repo-remote",
|
|
6
|
+
sourceRepoCommit: "--source-repo-commit",
|
|
7
|
+
clearSourceReference: "--clear-source-reference"
|
|
8
|
+
};
|
|
9
|
+
function optionName(surface, option) {
|
|
10
|
+
return surface === "mcp" ? option : CLI_FLAGS[option];
|
|
11
|
+
}
|
|
12
|
+
function optionExample(surface, option, value) {
|
|
13
|
+
return surface === "mcp" ? `${option}: "${value}"` : `${CLI_FLAGS[option]} "${value}"`;
|
|
14
|
+
}
|
|
15
|
+
function schemaLookupHint(surface, layer, type) {
|
|
16
|
+
return surface === "mcp" ? `Call "spec_type" with layer "${layer}" and type "${type}" to see the required attributes` : `Run "dr schema node ${layer}.${type}" to see the required attributes`;
|
|
17
|
+
}
|
|
18
|
+
function undefinedTypeWarning(surface, layer, elementId, type, replacements) {
|
|
19
|
+
const message = `Element '${elementId}' has type '${type}', which the spec does not define for the ${layer} layer, so its attributes were not checked against a type schema`, replacement = replacements[0];
|
|
20
|
+
let hint;
|
|
21
|
+
return surface === "mcp" ? hint = replacement ? `Pass type "${replacement}" to model_update to move the element to a type the spec defines` : `Call "spec_type" with layer "${layer}" and no type to list the layer's types, then pass one as type to model_update` : hint = replacement ? `Run "dr update ${elementId} --type ${replacement}" to move the element to a type the spec defines` : `Run "dr schema types ${layer}" to list the layer's types, then "dr update ${elementId} --type <type>"`, { message, hint };
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
optionExample,
|
|
25
|
+
optionName,
|
|
26
|
+
schemaLookupHint,
|
|
27
|
+
undefinedTypeWarning
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=error-hints.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/error-hints.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Surface-aware error hints.\n *\n * The CLI and the MCP server share validation code, but a user at the terminal passes\n * `--source-provenance` and runs `dr schema`, while an agent over MCP passes the\n * `sourceProvenance` parameter and calls the `spec_type` tool. Errors built from shared code\n * take a surface and name things the way that caller can act on them.\n */\n\nexport type HintSurface = \"cli\" | \"mcp\";\n\n/** Option keys that shared validators name in their messages. */\nexport type HintOption =\n | \"sourceFile\"\n | \"sourceSymbol\"\n | \"sourceProvenance\"\n | \"sourceRepoRemote\"\n | \"sourceRepoCommit\"\n | \"clearSourceReference\";\n\nconst CLI_FLAGS: Record<HintOption, string> = {\n sourceFile: \"--source-file\",\n sourceSymbol: \"--source-symbol\",\n sourceProvenance: \"--source-provenance\",\n sourceRepoRemote: \"--source-repo-remote\",\n sourceRepoCommit: \"--source-repo-commit\",\n clearSourceReference: \"--clear-source-reference\",\n};\n\n/** How the caller names an option: `--source-file` on the CLI, `sourceFile` over MCP. */\nexport function optionName(surface: HintSurface, option: HintOption): string {\n return surface === \"mcp\" ? option : CLI_FLAGS[option];\n}\n\n/** How the caller passes an option with a value, for examples in hints. */\nexport function optionExample(surface: HintSurface, option: HintOption, value: string): string {\n return surface === \"mcp\" ? `${option}: \"${value}\"` : `${CLI_FLAGS[option]} \"${value}\"`;\n}\n\n/** Where to look up a type's required attributes: `dr schema` on the CLI, `spec_type` over MCP. */\nexport function schemaLookupHint(surface: HintSurface, layer: string, type: string): string {\n return surface === \"mcp\"\n ? `Call \"spec_type\" with layer \"${layer}\" and type \"${type}\" to see the required attributes`\n : `Run \"dr schema node ${layer}.${type}\" to see the required attributes`;\n}\n\n/**\n * Warning for an update to an element whose current type the spec does not define (an obsolete\n * `product.capability`). With no type schema there is nothing to check its attributes against, so\n * the update goes through; the hint names the type change that fixes it, because looking up the\n * obsolete type with `spec_type` or `dr schema node` cannot work.\n */\nexport function undefinedTypeWarning(\n surface: HintSurface,\n layer: string,\n elementId: string,\n type: string,\n replacements: string[]\n): { message: string; hint: string } {\n const message =\n `Element '${elementId}' has type '${type}', which the spec does not define for the ${layer} layer, ` +\n `so its attributes were not checked against a type schema`;\n const replacement = replacements[0];\n let hint: string;\n if (surface === \"mcp\") {\n hint = replacement\n ? `Pass type \"${replacement}\" to model_update to move the element to a type the spec defines`\n : `Call \"spec_type\" with layer \"${layer}\" and no type to list the layer's types, then pass one as type to model_update`;\n } else {\n hint = replacement\n ? `Run \"dr update ${elementId} --type ${replacement}\" to move the element to a type the spec defines`\n : `Run \"dr schema types ${layer}\" to list the layer's types, then \"dr update ${elementId} --type <type>\"`;\n }\n return { message, hint };\n}\n"],
|
|
5
|
+
"mappings": "AAoBA,MAAM,YAAwC;EAC5C,YAAY;EACZ,cAAc;EACd,kBAAkB;EAClB,kBAAkB;EAClB,kBAAkB;EAClB,sBAAsB;;AAIlB,SAAU,WAAW,SAAsB,QAAkB;AACjE,SAAO,YAAY,QAAQ,SAAS,UAAU,MAAM;AACtD;AAGM,SAAU,cAAc,SAAsB,QAAoB,OAAa;AACnF,SAAO,YAAY,QAAQ,GAAG,MAAM,MAAM,KAAK,MAAM,GAAG,UAAU,MAAM,CAAC,KAAK,KAAK;AACrF;AAGM,SAAU,iBAAiB,SAAsB,OAAe,MAAY;AAChF,SAAO,YAAY,QACf,gCAAgC,KAAK,eAAe,IAAI,qCACxD,uBAAuB,KAAK,IAAI,IAAI;AAC1C;AAQM,SAAU,qBACd,SACA,OACA,WACA,MACA,cAAsB;AAEtB,QAAM,UACJ,YAAY,SAAS,eAAe,IAAI,6CAA6C,KAAK,oEAEtF,cAAc,aAAa,CAAC;AAClC,MAAI;AACJ,SAAI,YAAY,QACd,OAAO,cACH,cAAc,WAAW,qEACzB,gCAAgC,KAAK,mFAEzC,OAAO,cACH,kBAAkB,SAAS,WAAW,WAAW,qDACjD,wBAAwB,KAAK,gDAAgD,SAAS,mBAErF,EAAE,SAAS,KAAI;AACxB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/utils/errors.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ansis from "ansis";
|
|
2
|
+
import { isJson } from "./globals.js";
|
|
2
3
|
const MAX_SUGGESTIONS = 5;
|
|
3
4
|
var ErrorCategory;
|
|
4
5
|
(function(ErrorCategory2) {
|
|
@@ -105,20 +106,83 @@ class InvalidJSONError extends CLIError {
|
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
function handleError(error) {
|
|
108
|
-
|
|
109
|
+
if (error instanceof CLIError) {
|
|
110
|
+
if (isJson()) {
|
|
111
|
+
const output = {
|
|
112
|
+
status: "error",
|
|
113
|
+
code: error.exitCode,
|
|
114
|
+
message: error.message
|
|
115
|
+
};
|
|
116
|
+
error.suggestions && error.suggestions.length > 0 && (output.suggestions = error.suggestions), error.context && (error.context.operation && (output.operation = error.context.operation), error.context.relatedElements && error.context.relatedElements.length > 0 && (output.relatedElements = error.context.relatedElements), error.context.partialProgress && (output.partialProgress = error.context.partialProgress)), console.log(JSON.stringify(output));
|
|
117
|
+
} else
|
|
118
|
+
console.error(error.format());
|
|
119
|
+
throw error;
|
|
120
|
+
} else if (error instanceof Error) {
|
|
121
|
+
if (isJson()) {
|
|
122
|
+
const output = {
|
|
123
|
+
status: "error",
|
|
124
|
+
code: ErrorCategory.USER,
|
|
125
|
+
message: error.message
|
|
126
|
+
};
|
|
127
|
+
process.env.DEBUG && error.stack && (output.stack = error.stack), console.log(JSON.stringify(output));
|
|
128
|
+
} else
|
|
129
|
+
console.error(ansis.red(`Error: ${error.message}`)), process.env.DEBUG && console.error(ansis.dim(error.stack));
|
|
130
|
+
throw error;
|
|
131
|
+
} else {
|
|
132
|
+
if (isJson()) {
|
|
133
|
+
const output = {
|
|
134
|
+
status: "error",
|
|
135
|
+
code: ErrorCategory.USER,
|
|
136
|
+
message: "An unexpected error occurred"
|
|
137
|
+
};
|
|
138
|
+
process.env.DEBUG && (output.details = String(error)), console.log(JSON.stringify(output));
|
|
139
|
+
} else
|
|
140
|
+
console.error(ansis.red("An unexpected error occurred")), process.env.DEBUG && console.error(ansis.dim(String(error)));
|
|
141
|
+
throw new Error(String(error));
|
|
142
|
+
}
|
|
109
143
|
}
|
|
110
144
|
function handleWarning(message, suggestions) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
145
|
+
if (isJson()) {
|
|
146
|
+
const output = {
|
|
147
|
+
level: "warning",
|
|
148
|
+
message
|
|
149
|
+
};
|
|
150
|
+
suggestions && suggestions.length > 0 && (output.suggestions = suggestions), console.error(JSON.stringify(output));
|
|
151
|
+
} else {
|
|
152
|
+
const lines = [];
|
|
153
|
+
if (lines.push(ansis.yellow(`Warning: ${message}`)), suggestions && suggestions.length > 0) {
|
|
154
|
+
lines.push(""), lines.push(ansis.dim("Suggestions:"));
|
|
155
|
+
for (const suggestion of suggestions)
|
|
156
|
+
lines.push(ansis.dim(` \u2022 ${suggestion}`));
|
|
157
|
+
}
|
|
158
|
+
console.warn(lines.join(`
|
|
118
159
|
`));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function handleSuccess(message, details, options) {
|
|
163
|
+
if (isJson()) {
|
|
164
|
+
const output = {
|
|
165
|
+
...details,
|
|
166
|
+
status: "ok"
|
|
167
|
+
};
|
|
168
|
+
console.log(JSON.stringify(output));
|
|
169
|
+
} else if (console.log(ansis.green(`\u2713 ${message}`)), details && (options?.verbose || details.changesetStatus))
|
|
170
|
+
for (const [key, value] of Object.entries(details)) {
|
|
171
|
+
const displayKey = keyToDisplayName(key);
|
|
172
|
+
console.log(ansis.dim(` ${displayKey}: ${value}`));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function keyToDisplayName(key) {
|
|
176
|
+
return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
119
177
|
}
|
|
120
|
-
function
|
|
121
|
-
if (
|
|
178
|
+
function handleInfo(message, details) {
|
|
179
|
+
if (isJson()) {
|
|
180
|
+
const output = {
|
|
181
|
+
level: "info",
|
|
182
|
+
message
|
|
183
|
+
};
|
|
184
|
+
details && (output.details = details), console.error(JSON.stringify(output));
|
|
185
|
+
} else if (console.log(message), details)
|
|
122
186
|
for (const [key, value] of Object.entries(details))
|
|
123
187
|
console.log(ansis.dim(` ${key}: ${value}`));
|
|
124
188
|
}
|
|
@@ -172,6 +236,7 @@ export {
|
|
|
172
236
|
formatValidOptions,
|
|
173
237
|
getErrorMessage,
|
|
174
238
|
handleError,
|
|
239
|
+
handleInfo,
|
|
175
240
|
handleSuccess,
|
|
176
241
|
handleWarning
|
|
177
242
|
};
|