@devtrack-solution/codesdd 1.2.2
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/.sdd/skills/curated/api-clean-flask-langgraph/SKILL.md +2751 -0
- package/.sdd/skills/curated/devtrack-api/SKILL.md +137 -0
- package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +4 -0
- package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +381 -0
- package/.sdd/skills/curated/devtrack-api/references/architecture-governance.md +219 -0
- package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +359 -0
- package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +127 -0
- package/.sdd/skills/curated/devtrack-api/references/imports-lint.md +207 -0
- package/.sdd/skills/curated/devtrack-api/references/testing-validation.md +167 -0
- package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +334 -0
- package/LICENSE +21 -0
- package/README.md +842 -0
- package/bin/codesdd.js +10 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +560 -0
- package/dist/commands/change.d.ts +35 -0
- package/dist/commands/change.js +296 -0
- package/dist/commands/completion.d.ts +72 -0
- package/dist/commands/completion.js +258 -0
- package/dist/commands/config.d.ts +36 -0
- package/dist/commands/config.js +552 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +184 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +870 -0
- package/dist/commands/sdd/execution.d.ts +3 -0
- package/dist/commands/sdd/execution.js +409 -0
- package/dist/commands/sdd/shared.d.ts +9 -0
- package/dist/commands/sdd/shared.js +84 -0
- package/dist/commands/sdd/skills.d.ts +3 -0
- package/dist/commands/sdd/skills.js +154 -0
- package/dist/commands/sdd.d.ts +3 -0
- package/dist/commands/sdd.js +769 -0
- package/dist/commands/show.d.ts +14 -0
- package/dist/commands/show.js +133 -0
- package/dist/commands/spec.d.ts +15 -0
- package/dist/commands/spec.js +228 -0
- package/dist/commands/validate.d.ts +24 -0
- package/dist/commands/validate.js +295 -0
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/instructions.d.ts +29 -0
- package/dist/commands/workflow/instructions.js +383 -0
- package/dist/commands/workflow/new-change.d.ts +11 -0
- package/dist/commands/workflow/new-change.js +45 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/shared.d.ts +57 -0
- package/dist/commands/workflow/shared.js +117 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +76 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +68 -0
- package/dist/core/archive.d.ts +16 -0
- package/dist/core/archive.js +487 -0
- package/dist/core/artifact-graph/graph.d.ts +56 -0
- package/dist/core/artifact-graph/graph.js +141 -0
- package/dist/core/artifact-graph/index.d.ts +7 -0
- package/dist/core/artifact-graph/index.js +13 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
- package/dist/core/artifact-graph/instruction-loader.js +215 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.js +258 -0
- package/dist/core/artifact-graph/schema.d.ts +13 -0
- package/dist/core/artifact-graph/schema.js +108 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.js +54 -0
- package/dist/core/artifact-graph/types.d.ts +45 -0
- package/dist/core/artifact-graph/types.js +43 -0
- package/dist/core/available-tools.d.ts +16 -0
- package/dist/core/available-tools.js +30 -0
- package/dist/core/branding.d.ts +8 -0
- package/dist/core/branding.js +12 -0
- package/dist/core/cli/command-matrix.d.ts +23 -0
- package/dist/core/cli/command-matrix.js +123 -0
- package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
- package/dist/core/command-generation/adapters/amazon-q.js +26 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +26 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +27 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +50 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +28 -0
- package/dist/core/command-generation/adapters/codex.d.ts +16 -0
- package/dist/core/command-generation/adapters/codex.js +39 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +28 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +27 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +44 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +26 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +26 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +29 -0
- package/dist/core/command-generation/adapters/index.d.ts +29 -0
- package/dist/core/command-generation/adapters/index.js +29 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
- package/dist/core/command-generation/adapters/kiro.js +26 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +29 -0
- package/dist/core/command-generation/adapters/pi.d.ts +14 -0
- package/dist/core/command-generation/adapters/pi.js +41 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
- package/dist/core/command-generation/adapters/qwen.js +26 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
- package/dist/core/command-generation/adapters/windsurf.js +51 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.js +27 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +92 -0
- package/dist/core/command-generation/types.d.ts +56 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/completions/command-registry.d.ts +7 -0
- package/dist/core/completions/command-registry.js +461 -0
- package/dist/core/completions/completion-provider.d.ts +60 -0
- package/dist/core/completions/completion-provider.js +102 -0
- package/dist/core/completions/factory.d.ts +64 -0
- package/dist/core/completions/factory.js +75 -0
- package/dist/core/completions/generators/bash-generator.d.ts +32 -0
- package/dist/core/completions/generators/bash-generator.js +174 -0
- package/dist/core/completions/generators/fish-generator.d.ts +32 -0
- package/dist/core/completions/generators/fish-generator.js +157 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
- package/dist/core/completions/generators/powershell-generator.js +207 -0
- package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
- package/dist/core/completions/generators/zsh-generator.js +250 -0
- package/dist/core/completions/installers/bash-installer.d.ts +87 -0
- package/dist/core/completions/installers/bash-installer.js +318 -0
- package/dist/core/completions/installers/fish-installer.d.ts +43 -0
- package/dist/core/completions/installers/fish-installer.js +143 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +88 -0
- package/dist/core/completions/installers/powershell-installer.js +327 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +125 -0
- package/dist/core/completions/installers/zsh-installer.js +452 -0
- package/dist/core/completions/templates/bash-templates.d.ts +6 -0
- package/dist/core/completions/templates/bash-templates.js +24 -0
- package/dist/core/completions/templates/fish-templates.d.ts +7 -0
- package/dist/core/completions/templates/fish-templates.js +39 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
- package/dist/core/completions/templates/powershell-templates.js +25 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
- package/dist/core/completions/templates/zsh-templates.js +36 -0
- package/dist/core/completions/types.d.ts +79 -0
- package/dist/core/completions/types.js +2 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +34 -0
- package/dist/core/config-schema.d.ts +86 -0
- package/dist/core/config-schema.js +213 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.js +33 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/global-config.d.ts +44 -0
- package/dist/core/global-config.js +125 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +3 -0
- package/dist/core/init.d.ts +36 -0
- package/dist/core/init.js +576 -0
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +512 -0
- package/dist/core/list.d.ts +9 -0
- package/dist/core/list.js +173 -0
- package/dist/core/migration.d.ts +23 -0
- package/dist/core/migration.js +108 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +193 -0
- package/dist/core/parsers/markdown-parser.d.ts +22 -0
- package/dist/core/parsers/markdown-parser.js +187 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.js +201 -0
- package/dist/core/profile-sync-drift.d.ts +38 -0
- package/dist/core/profile-sync-drift.js +201 -0
- package/dist/core/profiles.d.ts +26 -0
- package/dist/core/profiles.js +41 -0
- package/dist/core/project-config.d.ts +64 -0
- package/dist/core/project-config.js +223 -0
- package/dist/core/schemas/base.schema.d.ts +13 -0
- package/dist/core/schemas/base.schema.js +13 -0
- package/dist/core/schemas/change.schema.d.ts +73 -0
- package/dist/core/schemas/change.schema.js +31 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/spec.schema.d.ts +18 -0
- package/dist/core/schemas/spec.schema.js +15 -0
- package/dist/core/sdd/adr-policy.d.ts +7 -0
- package/dist/core/sdd/adr-policy.js +47 -0
- package/dist/core/sdd/adr.d.ts +4 -0
- package/dist/core/sdd/adr.js +27 -0
- package/dist/core/sdd/bootstrap.d.ts +28 -0
- package/dist/core/sdd/bootstrap.js +353 -0
- package/dist/core/sdd/check.d.ts +51 -0
- package/dist/core/sdd/check.js +831 -0
- package/dist/core/sdd/coordination/coordination-adapters.d.ts +73 -0
- package/dist/core/sdd/coordination/coordination-adapters.js +87 -0
- package/dist/core/sdd/coordination/index.d.ts +2 -0
- package/dist/core/sdd/coordination/index.js +2 -0
- package/dist/core/sdd/dedup.d.ts +23 -0
- package/dist/core/sdd/dedup.js +62 -0
- package/dist/core/sdd/default-bootstrap-files.d.ts +23 -0
- package/dist/core/sdd/default-bootstrap-files.js +385 -0
- package/dist/core/sdd/default-skills.d.ts +16 -0
- package/dist/core/sdd/default-skills.js +427 -0
- package/dist/core/sdd/diagnose.d.ts +25 -0
- package/dist/core/sdd/diagnose.js +1312 -0
- package/dist/core/sdd/docs-sync.d.ts +21 -0
- package/dist/core/sdd/docs-sync.js +231 -0
- package/dist/core/sdd/domain/helpers.d.ts +6 -0
- package/dist/core/sdd/domain/helpers.js +37 -0
- package/dist/core/sdd/domain/lifecycle-guardrails.d.ts +22 -0
- package/dist/core/sdd/domain/lifecycle-guardrails.js +31 -0
- package/dist/core/sdd/domain/lifecycle-hooks.d.ts +16 -0
- package/dist/core/sdd/domain/lifecycle-hooks.js +27 -0
- package/dist/core/sdd/domain/post-active-validation.d.ts +15 -0
- package/dist/core/sdd/domain/post-active-validation.js +71 -0
- package/dist/core/sdd/domain/traceability.d.ts +8 -0
- package/dist/core/sdd/domain/traceability.js +83 -0
- package/dist/core/sdd/domain/transition-engine.d.ts +49 -0
- package/dist/core/sdd/domain/transition-engine.js +120 -0
- package/dist/core/sdd/fingerprint.d.ts +23 -0
- package/dist/core/sdd/fingerprint.js +146 -0
- package/dist/core/sdd/import-openspec.d.ts +31 -0
- package/dist/core/sdd/import-openspec.js +232 -0
- package/dist/core/sdd/init.d.ts +36 -0
- package/dist/core/sdd/init.js +65 -0
- package/dist/core/sdd/json-schema.d.ts +6 -0
- package/dist/core/sdd/json-schema.js +59 -0
- package/dist/core/sdd/legacy-operations.d.ts +286 -0
- package/dist/core/sdd/legacy-operations.js +2175 -0
- package/dist/core/sdd/lenses.d.ts +14 -0
- package/dist/core/sdd/lenses.js +97 -0
- package/dist/core/sdd/merge-catalog.d.ts +9 -0
- package/dist/core/sdd/merge-catalog.js +70 -0
- package/dist/core/sdd/migrate-workspace.d.ts +36 -0
- package/dist/core/sdd/migrate-workspace.js +344 -0
- package/dist/core/sdd/migrate.d.ts +24 -0
- package/dist/core/sdd/migrate.js +385 -0
- package/dist/core/sdd/resolve-project-root.d.ts +15 -0
- package/dist/core/sdd/resolve-project-root.js +46 -0
- package/dist/core/sdd/root-resolver.d.ts +16 -0
- package/dist/core/sdd/root-resolver.js +62 -0
- package/dist/core/sdd/sanitize.d.ts +35 -0
- package/dist/core/sdd/sanitize.js +750 -0
- package/dist/core/sdd/services/approve.service.d.ts +20 -0
- package/dist/core/sdd/services/approve.service.js +82 -0
- package/dist/core/sdd/services/audit.service.d.ts +53 -0
- package/dist/core/sdd/services/audit.service.js +136 -0
- package/dist/core/sdd/services/breakdown.service.d.ts +35 -0
- package/dist/core/sdd/services/breakdown.service.js +185 -0
- package/dist/core/sdd/services/context.service.d.ts +346 -0
- package/dist/core/sdd/services/context.service.js +278 -0
- package/dist/core/sdd/services/debate.service.d.ts +16 -0
- package/dist/core/sdd/services/debate.service.js +73 -0
- package/dist/core/sdd/services/decide.service.d.ts +23 -0
- package/dist/core/sdd/services/decide.service.js +81 -0
- package/dist/core/sdd/services/dedup-apply.service.d.ts +39 -0
- package/dist/core/sdd/services/dedup-apply.service.js +259 -0
- package/dist/core/sdd/services/feature-lint.service.d.ts +29 -0
- package/dist/core/sdd/services/feature-lint.service.js +146 -0
- package/dist/core/sdd/services/finalize.service.d.ts +33 -0
- package/dist/core/sdd/services/finalize.service.js +707 -0
- package/dist/core/sdd/services/frontend-gap.service.d.ts +23 -0
- package/dist/core/sdd/services/frontend-gap.service.js +117 -0
- package/dist/core/sdd/services/frontend-impact.service.d.ts +19 -0
- package/dist/core/sdd/services/frontend-impact.service.js +46 -0
- package/dist/core/sdd/services/ingest-deposito.service.d.ts +32 -0
- package/dist/core/sdd/services/ingest-deposito.service.js +231 -0
- package/dist/core/sdd/services/insight.service.d.ts +21 -0
- package/dist/core/sdd/services/insight.service.js +81 -0
- package/dist/core/sdd/services/legacy-capability.service.d.ts +24 -0
- package/dist/core/sdd/services/legacy-capability.service.js +59 -0
- package/dist/core/sdd/services/mcp-runtime.service.d.ts +42 -0
- package/dist/core/sdd/services/mcp-runtime.service.js +144 -0
- package/dist/core/sdd/services/metrics.service.d.ts +49 -0
- package/dist/core/sdd/services/metrics.service.js +181 -0
- package/dist/core/sdd/services/next.service.d.ts +35 -0
- package/dist/core/sdd/services/next.service.js +54 -0
- package/dist/core/sdd/services/onboard.service.d.ts +9 -0
- package/dist/core/sdd/services/onboard.service.js +165 -0
- package/dist/core/sdd/services/rebuild.service.d.ts +31 -0
- package/dist/core/sdd/services/rebuild.service.js +482 -0
- package/dist/core/sdd/services/scan-naming.service.d.ts +43 -0
- package/dist/core/sdd/services/scan-naming.service.js +246 -0
- package/dist/core/sdd/services/skills-invoke.service.d.ts +24 -0
- package/dist/core/sdd/services/skills-invoke.service.js +63 -0
- package/dist/core/sdd/services/skills-sync.service.d.ts +15 -0
- package/dist/core/sdd/services/skills-sync.service.js +117 -0
- package/dist/core/sdd/services/start.service.d.ts +26 -0
- package/dist/core/sdd/services/start.service.js +237 -0
- package/dist/core/sdd/skills.d.ts +15 -0
- package/dist/core/sdd/skills.js +46 -0
- package/dist/core/sdd/state-lock.d.ts +19 -0
- package/dist/core/sdd/state-lock.js +144 -0
- package/dist/core/sdd/state.d.ts +155 -0
- package/dist/core/sdd/state.js +1000 -0
- package/dist/core/sdd/store/in-memory-adapter.d.ts +12 -0
- package/dist/core/sdd/store/in-memory-adapter.js +27 -0
- package/dist/core/sdd/store/index.d.ts +5 -0
- package/dist/core/sdd/store/index.js +5 -0
- package/dist/core/sdd/store/sdd-stores.d.ts +25 -0
- package/dist/core/sdd/store/sdd-stores.js +59 -0
- package/dist/core/sdd/store/state-store.d.ts +32 -0
- package/dist/core/sdd/store/state-store.js +2 -0
- package/dist/core/sdd/store/yaml-file-adapter.d.ts +12 -0
- package/dist/core/sdd/store/yaml-file-adapter.js +43 -0
- package/dist/core/sdd/structural-health.d.ts +557 -0
- package/dist/core/sdd/structural-health.js +187 -0
- package/dist/core/sdd/transaction.d.ts +14 -0
- package/dist/core/sdd/transaction.js +100 -0
- package/dist/core/sdd/types.d.ts +1570 -0
- package/dist/core/sdd/types.js +617 -0
- package/dist/core/sdd/views.d.ts +3 -0
- package/dist/core/sdd/views.js +560 -0
- package/dist/core/sdd/workspace-schemas.d.ts +620 -0
- package/dist/core/sdd/workspace-schemas.js +254 -0
- package/dist/core/sdd/write-manifest.d.ts +25 -0
- package/dist/core/sdd/write-manifest.js +353 -0
- package/dist/core/shared/index.d.ts +8 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/skill-generation.d.ts +49 -0
- package/dist/core/shared/skill-generation.js +106 -0
- package/dist/core/shared/tool-detection.d.ts +71 -0
- package/dist/core/shared/tool-detection.js +158 -0
- package/dist/core/specs-apply.d.ts +73 -0
- package/dist/core/specs-apply.js +385 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/index.d.ts +8 -0
- package/dist/core/templates/index.js +9 -0
- package/dist/core/templates/skill-templates.d.ts +20 -0
- package/dist/core/templates/skill-templates.js +19 -0
- package/dist/core/templates/types.d.ts +19 -0
- package/dist/core/templates/types.js +5 -0
- package/dist/core/templates/workflows/apply-change.d.ts +10 -0
- package/dist/core/templates/workflows/apply-change.js +308 -0
- package/dist/core/templates/workflows/archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/archive-change.js +277 -0
- package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/bulk-archive-change.js +502 -0
- package/dist/core/templates/workflows/continue-change.d.ts +10 -0
- package/dist/core/templates/workflows/continue-change.js +232 -0
- package/dist/core/templates/workflows/explore.d.ts +10 -0
- package/dist/core/templates/workflows/explore.js +475 -0
- package/dist/core/templates/workflows/feedback.d.ts +9 -0
- package/dist/core/templates/workflows/feedback.js +108 -0
- package/dist/core/templates/workflows/ff-change.d.ts +10 -0
- package/dist/core/templates/workflows/ff-change.js +206 -0
- package/dist/core/templates/workflows/new-change.d.ts +10 -0
- package/dist/core/templates/workflows/new-change.js +151 -0
- package/dist/core/templates/workflows/onboard.d.ts +10 -0
- package/dist/core/templates/workflows/onboard.js +573 -0
- package/dist/core/templates/workflows/propose.d.ts +10 -0
- package/dist/core/templates/workflows/propose.js +224 -0
- package/dist/core/templates/workflows/sdd.d.ts +10 -0
- package/dist/core/templates/workflows/sdd.js +107 -0
- package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
- package/dist/core/templates/workflows/sync-specs.js +286 -0
- package/dist/core/templates/workflows/verify-change.d.ts +10 -0
- package/dist/core/templates/workflows/verify-change.js +346 -0
- package/dist/core/update.d.ts +77 -0
- package/dist/core/update.js +538 -0
- package/dist/core/validation/constants.d.ts +34 -0
- package/dist/core/validation/constants.js +40 -0
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.js +2 -0
- package/dist/core/validation/validator.d.ts +33 -0
- package/dist/core/validation/validator.js +409 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +170 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +28 -0
- package/dist/prompts/searchable-multi-select.js +159 -0
- package/dist/telemetry/config.d.ts +32 -0
- package/dist/telemetry/config.js +68 -0
- package/dist/telemetry/index.d.ts +44 -0
- package/dist/telemetry/index.js +207 -0
- package/dist/ui/ascii-patterns.d.ts +16 -0
- package/dist/ui/ascii-patterns.js +133 -0
- package/dist/ui/welcome-screen.d.ts +10 -0
- package/dist/ui/welcome-screen.js +146 -0
- package/dist/utils/change-metadata.d.ts +51 -0
- package/dist/utils/change-metadata.js +147 -0
- package/dist/utils/change-utils.d.ts +62 -0
- package/dist/utils/change-utils.js +121 -0
- package/dist/utils/command-references.d.ts +18 -0
- package/dist/utils/command-references.js +20 -0
- package/dist/utils/file-system.d.ts +36 -0
- package/dist/utils/file-system.js +281 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/interactive.d.ts +18 -0
- package/dist/utils/interactive.js +21 -0
- package/dist/utils/item-discovery.d.ts +4 -0
- package/dist/utils/item-discovery.js +73 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/openspec-compat.d.ts +2 -0
- package/dist/utils/openspec-compat.js +2 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +41 -0
- package/dist/utils/task-progress.d.ts +8 -0
- package/dist/utils/task-progress.js +36 -0
- package/package.json +111 -0
- package/schemas/sdd/1-spec.schema.json +221 -0
- package/schemas/sdd/2-plan.schema.json +199 -0
- package/schemas/sdd/3-tasks.schema.json +102 -0
- package/schemas/sdd/4-changelog.schema.json +55 -0
- package/schemas/sdd/5-quality.schema.json +427 -0
- package/schemas/sdd/workspace-catalog.schema.json +1012 -0
- package/schemas/spec-driven/schema.yaml +153 -0
- package/schemas/spec-driven/templates/design.md +19 -0
- package/schemas/spec-driven/templates/proposal.md +23 -0
- package/schemas/spec-driven/templates/spec.md +8 -0
- package/schemas/spec-driven/templates/tasks.md +9 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
4
|
+
import { CLI_NAME, } from '../branding.js';
|
|
5
|
+
import { findMarkdownWorkspaceFiles, MigrateWorkspaceCommand } from './migrate-workspace.js';
|
|
6
|
+
import { loadProjectSddConfig, loadStateSnapshot, resolveSddPaths, saveBacklogState, saveDiscoveryIndexState, saveFinalizeQueueState, saveFrontendDecisionsState, saveFrontendGapsState, saveFrontendMapState, saveIntegrationContractsState, saveRepoMapState, saveServiceCatalogState, saveSourceIndexState, saveTechDebtState, saveTechStackState, saveUnblockEventsState, } from './state.js';
|
|
7
|
+
import { runLifecycleHooks } from './domain/lifecycle-hooks.js';
|
|
8
|
+
export const CURRENT_SDD_STATE_VERSION = 2;
|
|
9
|
+
const ID_PREFIXES = new Set(['INS', 'DEB', 'RAD', 'EPIC', 'FEAT', 'FGAP', 'TD', 'SRC']);
|
|
10
|
+
const REFERENCE_LIKE_VALUE = /\b(?:INS|DEB|RAD|EPIC|FEAT|FGAP|TD|SRC)-\d+\b/;
|
|
11
|
+
const MIGRATABLE_FILE_EXTENSIONS = new Set(['.md', '.yaml', '.yml', '.txt']);
|
|
12
|
+
function normalizeId(rawId) {
|
|
13
|
+
const match = /^([A-Z]+)-(\d+)$/.exec(rawId);
|
|
14
|
+
if (!match)
|
|
15
|
+
return rawId;
|
|
16
|
+
const [, prefix, digits] = match;
|
|
17
|
+
if (!ID_PREFIXES.has(prefix))
|
|
18
|
+
return rawId;
|
|
19
|
+
const canonicalPrefix = prefix === 'RAD' ? 'EPIC' : prefix;
|
|
20
|
+
return `${canonicalPrefix}-${digits.padStart(4, '0')}`;
|
|
21
|
+
}
|
|
22
|
+
function isLegacyId(rawId) {
|
|
23
|
+
const normalized = normalizeId(rawId);
|
|
24
|
+
return normalized !== rawId;
|
|
25
|
+
}
|
|
26
|
+
function collectReferenceConversions(value, conversions) {
|
|
27
|
+
if (!value)
|
|
28
|
+
return;
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
for (const item of value) {
|
|
31
|
+
collectReferenceConversions(item, conversions);
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (typeof value === 'object') {
|
|
36
|
+
for (const nested of Object.values(value)) {
|
|
37
|
+
collectReferenceConversions(nested, conversions);
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (typeof value !== 'string')
|
|
42
|
+
return;
|
|
43
|
+
const matches = value.match(/\b(?:INS|DEB|RAD|EPIC|FEAT|FGAP|TD|SRC)-\d+\b/g);
|
|
44
|
+
if (!matches)
|
|
45
|
+
return;
|
|
46
|
+
for (const match of matches) {
|
|
47
|
+
const normalized = normalizeId(match);
|
|
48
|
+
if (normalized !== match) {
|
|
49
|
+
conversions.set(match, normalized);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function replaceExactReferences(value, conversions) {
|
|
54
|
+
let next = value;
|
|
55
|
+
for (const [oldId, newId] of conversions.entries()) {
|
|
56
|
+
next = next.replace(new RegExp(`\\b${oldId}\\b`, 'g'), newId);
|
|
57
|
+
}
|
|
58
|
+
return next;
|
|
59
|
+
}
|
|
60
|
+
function traverseAndConvertReferences(value, conversions) {
|
|
61
|
+
if (Array.isArray(value)) {
|
|
62
|
+
return value.map((item) => traverseAndConvertReferences(item, conversions));
|
|
63
|
+
}
|
|
64
|
+
if (value && typeof value === 'object') {
|
|
65
|
+
const updatedEntries = Object.entries(value).map(([key, entry]) => [
|
|
66
|
+
key,
|
|
67
|
+
traverseAndConvertReferences(entry, conversions),
|
|
68
|
+
]);
|
|
69
|
+
return Object.fromEntries(updatedEntries);
|
|
70
|
+
}
|
|
71
|
+
if (typeof value === 'string') {
|
|
72
|
+
return replaceExactReferences(value, conversions);
|
|
73
|
+
}
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
async function readStateConfigVersion(configPath) {
|
|
77
|
+
try {
|
|
78
|
+
const raw = parseYaml(await fs.readFile(configPath, 'utf-8'));
|
|
79
|
+
const version = raw?.state_version;
|
|
80
|
+
return typeof version === 'number' && Number.isFinite(version) ? version : 1;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function writeStateConfigVersion(configPath) {
|
|
87
|
+
let payload = {};
|
|
88
|
+
try {
|
|
89
|
+
const parsed = parseYaml(await fs.readFile(configPath, 'utf-8'));
|
|
90
|
+
if (parsed && typeof parsed === 'object') {
|
|
91
|
+
payload = parsed;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
payload = {};
|
|
96
|
+
}
|
|
97
|
+
payload.version = 1;
|
|
98
|
+
payload.generatedBy = payload.generatedBy || `${CLI_NAME} sdd init`;
|
|
99
|
+
payload.state_version = CURRENT_SDD_STATE_VERSION;
|
|
100
|
+
payload.last_migrated_at = new Date().toISOString();
|
|
101
|
+
await fs.writeFile(configPath, stringifyYaml(payload), 'utf-8');
|
|
102
|
+
}
|
|
103
|
+
async function listAllFiles(rootDir) {
|
|
104
|
+
const files = [];
|
|
105
|
+
async function walk(currentDir) {
|
|
106
|
+
let entries;
|
|
107
|
+
try {
|
|
108
|
+
entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
115
|
+
if (entry.isDirectory()) {
|
|
116
|
+
await walk(fullPath);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
files.push(fullPath);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
await walk(rootDir);
|
|
124
|
+
return files;
|
|
125
|
+
}
|
|
126
|
+
async function safeRenameEntry(entryPath, nextPath) {
|
|
127
|
+
try {
|
|
128
|
+
await fs.rename(entryPath, nextPath);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
const err = error;
|
|
133
|
+
if (err.code !== 'EEXIST' && err.code !== 'ENOTEMPTY') {
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const entryStat = await fs.lstat(entryPath);
|
|
138
|
+
if (entryStat.isDirectory()) {
|
|
139
|
+
await fs.rm(entryPath, { recursive: true, force: true });
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
await fs.rm(entryPath, { force: true });
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
async function renameFilesystemEntries(rootDir, conversions) {
|
|
146
|
+
const entries = await listAllFiles(rootDir);
|
|
147
|
+
const directories = new Set();
|
|
148
|
+
for (const filePath of entries) {
|
|
149
|
+
let current = path.dirname(filePath);
|
|
150
|
+
while (current.startsWith(rootDir) && current !== rootDir) {
|
|
151
|
+
directories.add(current);
|
|
152
|
+
current = path.dirname(current);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const targets = [...entries, ...directories].sort((a, b) => b.length - a.length);
|
|
156
|
+
let renamed = 0;
|
|
157
|
+
for (const entryPath of targets) {
|
|
158
|
+
let nextPath = entryPath;
|
|
159
|
+
for (const [oldId, newId] of conversions.entries()) {
|
|
160
|
+
nextPath = nextPath.replace(new RegExp(`\\b${oldId}\\b`, 'g'), newId);
|
|
161
|
+
}
|
|
162
|
+
if (nextPath === entryPath)
|
|
163
|
+
continue;
|
|
164
|
+
try {
|
|
165
|
+
await fs.access(entryPath);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
await fs.mkdir(path.dirname(nextPath), { recursive: true });
|
|
171
|
+
if (await safeRenameEntry(entryPath, nextPath)) {
|
|
172
|
+
renamed += 1;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return renamed;
|
|
176
|
+
}
|
|
177
|
+
async function rewriteFilesystemContents(rootDir, conversions) {
|
|
178
|
+
const files = await listAllFiles(rootDir);
|
|
179
|
+
let updated = 0;
|
|
180
|
+
for (const filePath of files) {
|
|
181
|
+
if (!MIGRATABLE_FILE_EXTENSIONS.has(path.extname(filePath))) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const original = await fs.readFile(filePath, 'utf8');
|
|
185
|
+
const next = replaceExactReferences(original, conversions)
|
|
186
|
+
.replace(/\borigin_type:\s*radar\b/g, 'origin_type: epic')
|
|
187
|
+
.replace(/\bOrigem:\s*radar\b/g, 'Origem: epic')
|
|
188
|
+
.replace(/\b## Por EPIC\/RAD\b/g, '## Por EPIC')
|
|
189
|
+
.replace(/\|\s*EPIC\/RAD\s*\|/g, '| EPIC |');
|
|
190
|
+
if (next !== original) {
|
|
191
|
+
await fs.writeFile(filePath, next, 'utf8');
|
|
192
|
+
updated += 1;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return updated;
|
|
196
|
+
}
|
|
197
|
+
export async function assessSddMigration(projectRoot) {
|
|
198
|
+
const config = await loadProjectSddConfig(projectRoot);
|
|
199
|
+
const paths = resolveSddPaths(projectRoot, config);
|
|
200
|
+
const snapshot = await loadStateSnapshot(paths, config);
|
|
201
|
+
const currentVersion = await readStateConfigVersion(paths.configFile);
|
|
202
|
+
const conversions = new Map();
|
|
203
|
+
collectReferenceConversions(snapshot.discoveryIndex, conversions);
|
|
204
|
+
collectReferenceConversions(snapshot.backlog, conversions);
|
|
205
|
+
collectReferenceConversions(snapshot.techDebt, conversions);
|
|
206
|
+
collectReferenceConversions(snapshot.finalizeQueue, conversions);
|
|
207
|
+
collectReferenceConversions(snapshot.unblockEvents, conversions);
|
|
208
|
+
collectReferenceConversions(snapshot.serviceCatalog, conversions);
|
|
209
|
+
collectReferenceConversions(snapshot.techStack, conversions);
|
|
210
|
+
collectReferenceConversions(snapshot.integrationContracts, conversions);
|
|
211
|
+
collectReferenceConversions(snapshot.repoMap, conversions);
|
|
212
|
+
collectReferenceConversions(snapshot.sourceIndex, conversions);
|
|
213
|
+
if (snapshot.frontendGaps)
|
|
214
|
+
collectReferenceConversions(snapshot.frontendGaps, conversions);
|
|
215
|
+
if (snapshot.frontendMap)
|
|
216
|
+
collectReferenceConversions(snapshot.frontendMap, conversions);
|
|
217
|
+
if (snapshot.frontendDecisions)
|
|
218
|
+
collectReferenceConversions(snapshot.frontendDecisions, conversions);
|
|
219
|
+
const legacyRecords = snapshot.discoveryIndex.records
|
|
220
|
+
.filter((record) => record.type === 'RAD' || isLegacyId(record.id))
|
|
221
|
+
.map((record) => record.id);
|
|
222
|
+
const reasons = [];
|
|
223
|
+
if (currentVersion < CURRENT_SDD_STATE_VERSION) {
|
|
224
|
+
reasons.push(`state_version=${currentVersion} esta abaixo da versao requerida ${CURRENT_SDD_STATE_VERSION}`);
|
|
225
|
+
}
|
|
226
|
+
if (legacyRecords.length > 0) {
|
|
227
|
+
reasons.push(`registros legacy detectados: ${legacyRecords.join(', ')}`);
|
|
228
|
+
}
|
|
229
|
+
if (snapshot.backlog.items.some((item) => item.origin_type === 'radar')) {
|
|
230
|
+
reasons.push('backlog ainda usa origin_type=radar');
|
|
231
|
+
}
|
|
232
|
+
if (snapshot.backlog.items.some((item) => !!item.origin_ref && isLegacyId(item.origin_ref))) {
|
|
233
|
+
reasons.push('backlog ainda referencia IDs legados');
|
|
234
|
+
}
|
|
235
|
+
if (snapshot.discoveryIndex.records.some((record) => record.related_ids.some(isLegacyId))) {
|
|
236
|
+
reasons.push('related_ids ainda apontam para IDs legados');
|
|
237
|
+
}
|
|
238
|
+
if ([...conversions.keys()].some((id) => REFERENCE_LIKE_VALUE.test(id))) {
|
|
239
|
+
reasons.push('existem referencias SDD fora do formato canonico de quatro digitos');
|
|
240
|
+
}
|
|
241
|
+
const workspaceMarkdownFiles = await findMarkdownWorkspaceFiles(projectRoot);
|
|
242
|
+
if (workspaceMarkdownFiles.length > 0) {
|
|
243
|
+
reasons.push(`workspaces com Markdown legado detectados: ${workspaceMarkdownFiles.length}`);
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
currentVersion,
|
|
247
|
+
targetVersion: CURRENT_SDD_STATE_VERSION,
|
|
248
|
+
needsMigration: reasons.length > 0,
|
|
249
|
+
reasons,
|
|
250
|
+
conversions: [...conversions.entries()].map(([from, to]) => ({ from, to })),
|
|
251
|
+
legacyRecords,
|
|
252
|
+
workspaceMarkdownFiles,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
export class SddMigrateCommand {
|
|
256
|
+
async execute(projectRoot, options) {
|
|
257
|
+
const assessment = await assessSddMigration(projectRoot);
|
|
258
|
+
const messages = [];
|
|
259
|
+
if (!assessment.needsMigration) {
|
|
260
|
+
messages.push(`Estado SDD ja esta na versao ${assessment.targetVersion}. Nenhuma migracao necessaria.`);
|
|
261
|
+
return { converted: 0, messages, assessment };
|
|
262
|
+
}
|
|
263
|
+
if (options?.radToEpic === false) {
|
|
264
|
+
throw new Error('Migracao SDD mandatória nao pode ser desabilitada.');
|
|
265
|
+
}
|
|
266
|
+
await runLifecycleHooks('before-migrate', {
|
|
267
|
+
projectRoot,
|
|
268
|
+
entityId: 'sdd-state',
|
|
269
|
+
options: options,
|
|
270
|
+
metadata: {
|
|
271
|
+
assessment,
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
const config = await loadProjectSddConfig(projectRoot);
|
|
275
|
+
const paths = resolveSddPaths(projectRoot, config);
|
|
276
|
+
const snapshot = await loadStateSnapshot(paths, config);
|
|
277
|
+
const conversions = new Map(assessment.conversions.map((entry) => [entry.from, entry.to]));
|
|
278
|
+
let workspaceFilesMigrated = 0;
|
|
279
|
+
snapshot.discoveryIndex.records = snapshot.discoveryIndex.records.map((record) => ({
|
|
280
|
+
...traverseAndConvertReferences(record, conversions),
|
|
281
|
+
id: conversions.get(record.id) || record.id,
|
|
282
|
+
type: record.type === 'RAD' ? 'EPIC' : record.type,
|
|
283
|
+
}));
|
|
284
|
+
const highestByPrefix = new Map();
|
|
285
|
+
for (const record of snapshot.discoveryIndex.records) {
|
|
286
|
+
const match = /^([A-Z]+)-(\d+)$/.exec(record.id);
|
|
287
|
+
if (!match)
|
|
288
|
+
continue;
|
|
289
|
+
const [, prefix, digits] = match;
|
|
290
|
+
highestByPrefix.set(prefix, Math.max(highestByPrefix.get(prefix) || 0, Number(digits)));
|
|
291
|
+
}
|
|
292
|
+
for (const [prefix, current] of Object.entries(snapshot.discoveryIndex.counters)) {
|
|
293
|
+
const candidate = highestByPrefix.get(prefix) || current || 0;
|
|
294
|
+
snapshot.discoveryIndex.counters[prefix] = Math.max(current || 0, candidate);
|
|
295
|
+
}
|
|
296
|
+
snapshot.discoveryIndex.counters.RAD = 0;
|
|
297
|
+
snapshot.backlog.items = traverseAndConvertReferences(snapshot.backlog.items, conversions).map((item) => ({
|
|
298
|
+
...item,
|
|
299
|
+
id: conversions.get(item.id) || item.id,
|
|
300
|
+
origin_type: item.origin_type === 'radar' ? 'epic' : item.origin_type,
|
|
301
|
+
}));
|
|
302
|
+
snapshot.techDebt.items = traverseAndConvertReferences(snapshot.techDebt.items, conversions).map((item) => ({
|
|
303
|
+
...item,
|
|
304
|
+
id: conversions.get(item.id) || item.id,
|
|
305
|
+
}));
|
|
306
|
+
snapshot.finalizeQueue.items = traverseAndConvertReferences(snapshot.finalizeQueue.items, conversions);
|
|
307
|
+
snapshot.unblockEvents.events = traverseAndConvertReferences(snapshot.unblockEvents.events, conversions);
|
|
308
|
+
snapshot.serviceCatalog.services = traverseAndConvertReferences(snapshot.serviceCatalog.services, conversions);
|
|
309
|
+
snapshot.techStack.items = traverseAndConvertReferences(snapshot.techStack.items, conversions);
|
|
310
|
+
snapshot.integrationContracts.contracts = traverseAndConvertReferences(snapshot.integrationContracts.contracts, conversions);
|
|
311
|
+
snapshot.repoMap.items = traverseAndConvertReferences(snapshot.repoMap.items, conversions);
|
|
312
|
+
snapshot.sourceIndex.sources = traverseAndConvertReferences(snapshot.sourceIndex.sources, conversions);
|
|
313
|
+
if (snapshot.frontendGaps) {
|
|
314
|
+
snapshot.frontendGaps.items = traverseAndConvertReferences(snapshot.frontendGaps.items, conversions).map((item) => ({
|
|
315
|
+
...item,
|
|
316
|
+
id: conversions.get(item.id) || item.id,
|
|
317
|
+
}));
|
|
318
|
+
}
|
|
319
|
+
if (snapshot.frontendMap) {
|
|
320
|
+
snapshot.frontendMap.routes = traverseAndConvertReferences(snapshot.frontendMap.routes, conversions);
|
|
321
|
+
}
|
|
322
|
+
if (snapshot.frontendDecisions) {
|
|
323
|
+
snapshot.frontendDecisions.items = traverseAndConvertReferences(snapshot.frontendDecisions.items, conversions);
|
|
324
|
+
}
|
|
325
|
+
await saveDiscoveryIndexState(paths, snapshot.discoveryIndex);
|
|
326
|
+
await saveBacklogState(paths, snapshot.backlog);
|
|
327
|
+
await saveTechDebtState(paths, snapshot.techDebt);
|
|
328
|
+
await saveFinalizeQueueState(paths, snapshot.finalizeQueue);
|
|
329
|
+
await saveUnblockEventsState(paths, snapshot.unblockEvents);
|
|
330
|
+
await saveServiceCatalogState(paths, snapshot.serviceCatalog);
|
|
331
|
+
await saveTechStackState(paths, snapshot.techStack);
|
|
332
|
+
await saveIntegrationContractsState(paths, snapshot.integrationContracts);
|
|
333
|
+
await saveRepoMapState(paths, snapshot.repoMap);
|
|
334
|
+
await saveSourceIndexState(paths, snapshot.sourceIndex);
|
|
335
|
+
if (snapshot.frontendGaps) {
|
|
336
|
+
await saveFrontendGapsState(paths, snapshot.frontendGaps);
|
|
337
|
+
}
|
|
338
|
+
if (snapshot.frontendMap) {
|
|
339
|
+
await saveFrontendMapState(paths, snapshot.frontendMap);
|
|
340
|
+
}
|
|
341
|
+
if (snapshot.frontendDecisions) {
|
|
342
|
+
await saveFrontendDecisionsState(paths, snapshot.frontendDecisions);
|
|
343
|
+
}
|
|
344
|
+
const renamedEntries = await renameFilesystemEntries(paths.memoryRoot, conversions);
|
|
345
|
+
const rewrittenFiles = await rewriteFilesystemContents(paths.memoryRoot, conversions);
|
|
346
|
+
if (assessment.workspaceMarkdownFiles.length > 0) {
|
|
347
|
+
const workspaceMigration = await new MigrateWorkspaceCommand().execute(projectRoot);
|
|
348
|
+
workspaceFilesMigrated = workspaceMigration.migrated;
|
|
349
|
+
if (workspaceMigration.incomplete.length > 0) {
|
|
350
|
+
messages.push(`Workspaces migrados com campos incompletos: ${workspaceMigration.incomplete.length}. Revise marcadores MIGRATION.`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
await writeStateConfigVersion(paths.configFile);
|
|
354
|
+
const converted = conversions.size;
|
|
355
|
+
messages.push(`Migracao SDD concluida para state_version=${CURRENT_SDD_STATE_VERSION}. Referencias convertidas: ${converted}.`);
|
|
356
|
+
if (assessment.legacyRecords.length > 0) {
|
|
357
|
+
messages.push(`Registros canonizados: ${assessment.legacyRecords.join(', ')}`);
|
|
358
|
+
}
|
|
359
|
+
messages.push(`Entradas renomeadas no filesystem: ${renamedEntries}.`);
|
|
360
|
+
messages.push(`Arquivos reescritos com referencias canonicas: ${rewrittenFiles}.`);
|
|
361
|
+
messages.push(`Arquivos de workspace Markdown migrados para YAML: ${workspaceFilesMigrated}.`);
|
|
362
|
+
const result = {
|
|
363
|
+
converted,
|
|
364
|
+
messages,
|
|
365
|
+
assessment: {
|
|
366
|
+
...assessment,
|
|
367
|
+
currentVersion: CURRENT_SDD_STATE_VERSION,
|
|
368
|
+
needsMigration: false,
|
|
369
|
+
reasons: [],
|
|
370
|
+
workspaceMarkdownFiles: [],
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
await runLifecycleHooks('after-migrate', {
|
|
374
|
+
projectRoot,
|
|
375
|
+
entityId: 'sdd-state',
|
|
376
|
+
options: options,
|
|
377
|
+
metadata: {
|
|
378
|
+
converted,
|
|
379
|
+
assessment: result.assessment,
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
return result;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the project root by walking up from `startDir` until we find a
|
|
3
|
+
* directory that looks like a project root (contains `openspec/`, `package.json`,
|
|
4
|
+
* or `.git`).
|
|
5
|
+
*
|
|
6
|
+
* This handles the common case where the CLI is invoked from inside `.sdd/` or
|
|
7
|
+
* another subdirectory, preventing the double-nesting bug (e.g. `.sdd/.sdd`).
|
|
8
|
+
*
|
|
9
|
+
* Strategy:
|
|
10
|
+
* 1. If `startDir` itself has a project-root marker → return it.
|
|
11
|
+
* 2. Walk up until we find one, stop at filesystem root.
|
|
12
|
+
* 3. If nothing found, fall back to `startDir` (CWD).
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveProjectRoot(startDir?: string): string;
|
|
15
|
+
//# sourceMappingURL=resolve-project-root.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the project root by walking up from `startDir` until we find a
|
|
5
|
+
* directory that looks like a project root (contains `openspec/`, `package.json`,
|
|
6
|
+
* or `.git`).
|
|
7
|
+
*
|
|
8
|
+
* This handles the common case where the CLI is invoked from inside `.sdd/` or
|
|
9
|
+
* another subdirectory, preventing the double-nesting bug (e.g. `.sdd/.sdd`).
|
|
10
|
+
*
|
|
11
|
+
* Strategy:
|
|
12
|
+
* 1. If `startDir` itself has a project-root marker → return it.
|
|
13
|
+
* 2. Walk up until we find one, stop at filesystem root.
|
|
14
|
+
* 3. If nothing found, fall back to `startDir` (CWD).
|
|
15
|
+
*/
|
|
16
|
+
export function resolveProjectRoot(startDir = process.cwd()) {
|
|
17
|
+
const absoluteStart = path.resolve(startDir);
|
|
18
|
+
let current = absoluteStart;
|
|
19
|
+
while (true) {
|
|
20
|
+
if (isProjectRoot(current)) {
|
|
21
|
+
return current;
|
|
22
|
+
}
|
|
23
|
+
const parent = path.dirname(current);
|
|
24
|
+
if (parent === current) {
|
|
25
|
+
// Reached filesystem root without finding a project root.
|
|
26
|
+
// Fall back to original startDir so the existing error messages
|
|
27
|
+
// (e.g. "Run opensdd sdd init") still make sense.
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
current = parent;
|
|
31
|
+
}
|
|
32
|
+
return absoluteStart;
|
|
33
|
+
}
|
|
34
|
+
function isProjectRoot(dir) {
|
|
35
|
+
// openspec/ is the canonical config directory for this tool
|
|
36
|
+
if (existsSync(path.join(dir, 'openspec')))
|
|
37
|
+
return true;
|
|
38
|
+
// package.json is a strong signal for Node.js project roots
|
|
39
|
+
if (existsSync(path.join(dir, 'package.json')))
|
|
40
|
+
return true;
|
|
41
|
+
// .git is a universal project root marker
|
|
42
|
+
if (existsSync(path.join(dir, '.git')))
|
|
43
|
+
return true;
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=resolve-project-root.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class SddBoundaryError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare class RootResolver {
|
|
5
|
+
/**
|
|
6
|
+
* Resolves a path relative to the project root and ensures it does not logically escape the SDD memory root.
|
|
7
|
+
* This performs path normalization but does NOT check symlinks on disk.
|
|
8
|
+
*/
|
|
9
|
+
static resolveInSddRoot(projectRoot: string, memoryRoot: string, targetPath: string, label: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Checks if the physical path (following symlinks) is contained within the physical memory root.
|
|
12
|
+
* Traverses up to find the deepest existing directory to catch symlink escapes even for files that do not exist yet.
|
|
13
|
+
*/
|
|
14
|
+
static verifyRealpathContainment(projectRoot: string, memoryRoot: string, targetPath: string, label: string): Promise<string>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=root-resolver.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { realpath } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export class SddBoundaryError extends Error {
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'SddBoundaryError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class RootResolver {
|
|
10
|
+
/**
|
|
11
|
+
* Resolves a path relative to the project root and ensures it does not logically escape the SDD memory root.
|
|
12
|
+
* This performs path normalization but does NOT check symlinks on disk.
|
|
13
|
+
*/
|
|
14
|
+
static resolveInSddRoot(projectRoot, memoryRoot, targetPath, label) {
|
|
15
|
+
const resolved = path.resolve(projectRoot, targetPath);
|
|
16
|
+
const relative = path.relative(memoryRoot, resolved);
|
|
17
|
+
// An empty relative path means it's exactly the memoryRoot.
|
|
18
|
+
// If it starts with '..', it escaped. If it is absolute, it means memoryRoot and resolved are on different drives.
|
|
19
|
+
if (relative !== '' && (relative.startsWith('..') || path.isAbsolute(relative))) {
|
|
20
|
+
throw new SddBoundaryError(`${label} must stay inside the active SDD root: ${targetPath}`);
|
|
21
|
+
}
|
|
22
|
+
return resolved;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Checks if the physical path (following symlinks) is contained within the physical memory root.
|
|
26
|
+
* Traverses up to find the deepest existing directory to catch symlink escapes even for files that do not exist yet.
|
|
27
|
+
*/
|
|
28
|
+
static async verifyRealpathContainment(projectRoot, memoryRoot, targetPath, label) {
|
|
29
|
+
const resolved = this.resolveInSddRoot(projectRoot, memoryRoot, targetPath, label);
|
|
30
|
+
// To check symlinks, we need to find the deepest existing directory in the target path
|
|
31
|
+
let currentPath = resolved;
|
|
32
|
+
let existingPath = null;
|
|
33
|
+
// Walk up the directory tree until we find a path that actually exists on disk
|
|
34
|
+
while (currentPath !== path.parse(currentPath).root) {
|
|
35
|
+
try {
|
|
36
|
+
existingPath = await realpath(currentPath);
|
|
37
|
+
break; // found the deepest existing path
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
const nextPath = path.dirname(currentPath);
|
|
41
|
+
if (nextPath === currentPath)
|
|
42
|
+
break; // Reached root without finding anything
|
|
43
|
+
currentPath = nextPath;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (existingPath) {
|
|
47
|
+
let physicalMemoryRoot = memoryRoot;
|
|
48
|
+
try {
|
|
49
|
+
physicalMemoryRoot = await realpath(memoryRoot);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// If memoryRoot doesn't exist, we fall back to its logical path
|
|
53
|
+
}
|
|
54
|
+
const relativePhysical = path.relative(physicalMemoryRoot, existingPath);
|
|
55
|
+
if (relativePhysical !== '' && (relativePhysical.startsWith('..') || path.isAbsolute(relativePhysical))) {
|
|
56
|
+
throw new SddBoundaryError(`${label} resolves to a symlink outside the SDD root: ${targetPath}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return resolved;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=root-resolver.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type StructuralDiagnosticReport, type StructuralSanitizerReport, type StructuralSanitizerTransactionManifest } from './structural-health.js';
|
|
2
|
+
export interface SddSanitizeCommandOptions {
|
|
3
|
+
dryRun?: boolean;
|
|
4
|
+
apply?: boolean;
|
|
5
|
+
yes?: boolean;
|
|
6
|
+
fromReport?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SddSanitizeResult {
|
|
9
|
+
source: 'diagnose' | 'report';
|
|
10
|
+
diagnosticReport: StructuralDiagnosticReport;
|
|
11
|
+
report: StructuralSanitizerReport;
|
|
12
|
+
transaction?: StructuralSanitizerTransactionManifest;
|
|
13
|
+
}
|
|
14
|
+
export interface SddSanitizeRollbackOptions {
|
|
15
|
+
reason: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SddSanitizeRollbackResult {
|
|
18
|
+
transactionId: string;
|
|
19
|
+
rolledBack: number;
|
|
20
|
+
skipped: number;
|
|
21
|
+
manifestPath: string;
|
|
22
|
+
auditLogPath: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class SddSanitizeOptionsError extends Error {
|
|
25
|
+
constructor(message: string);
|
|
26
|
+
}
|
|
27
|
+
export declare class SddSanitizeApplyError extends Error {
|
|
28
|
+
constructor(message: string);
|
|
29
|
+
}
|
|
30
|
+
export declare function formatSanitizerText(report: StructuralSanitizerReport): string;
|
|
31
|
+
export declare class SddSanitizeCommand {
|
|
32
|
+
execute(projectRoot: string, options?: SddSanitizeCommandOptions): Promise<SddSanitizeResult>;
|
|
33
|
+
rollback(projectRoot: string, transactionId: string, options: SddSanitizeRollbackOptions): Promise<SddSanitizeRollbackResult>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=sanitize.d.ts.map
|