@seanmars/tospec 0.19.0-beta.7 → 0.20.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/CHANGELOG.md +60 -231
- package/README.md +69 -82
- package/assets/dashboard/app.js +14 -3
- package/assets/dashboard/style.css +7 -0
- package/assets/rules/tospec/decision.md +3 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +227 -86
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/config.d.ts +9 -17
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +366 -107
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/dashboard.d.ts +57 -99
- package/dist/commands/dashboard.d.ts.map +1 -1
- package/dist/commands/dashboard.js +224 -282
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/decision.d.ts +41 -19
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +385 -79
- package/dist/commands/decision.js.map +1 -1
- package/dist/commands/metrics.d.ts +28 -51
- package/dist/commands/metrics.d.ts.map +1 -1
- package/dist/commands/metrics.js +62 -93
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/shared-output.d.ts +18 -21
- package/dist/commands/shared-output.d.ts.map +1 -1
- package/dist/commands/shared-output.js +49 -23
- package/dist/commands/shared-output.js.map +1 -1
- package/dist/commands/show.d.ts +7 -0
- package/dist/commands/show.d.ts.map +1 -1
- package/dist/commands/show.js +29 -7
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/validate.d.ts +43 -45
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +262 -129
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/workflow/index.d.ts +6 -10
- package/dist/commands/workflow/index.d.ts.map +1 -1
- package/dist/commands/workflow/index.js +6 -10
- package/dist/commands/workflow/index.js.map +1 -1
- package/dist/commands/workflow/instructions.d.ts +21 -8
- package/dist/commands/workflow/instructions.d.ts.map +1 -1
- package/dist/commands/workflow/instructions.js +254 -95
- package/dist/commands/workflow/instructions.js.map +1 -1
- package/dist/commands/workflow/new-change.d.ts +4 -5
- package/dist/commands/workflow/new-change.d.ts.map +1 -1
- package/dist/commands/workflow/new-change.js +90 -25
- package/dist/commands/workflow/new-change.js.map +1 -1
- package/dist/commands/workflow/schemas.d.ts +3 -5
- package/dist/commands/workflow/schemas.d.ts.map +1 -1
- package/dist/commands/workflow/schemas.js +37 -11
- package/dist/commands/workflow/schemas.js.map +1 -1
- package/dist/commands/workflow/shared.d.ts +48 -21
- package/dist/commands/workflow/shared.d.ts.map +1 -1
- package/dist/commands/workflow/shared.js +36 -33
- package/dist/commands/workflow/shared.js.map +1 -1
- package/dist/commands/workflow/status.d.ts +10 -6
- package/dist/commands/workflow/status.d.ts.map +1 -1
- package/dist/commands/workflow/status.js +81 -42
- package/dist/commands/workflow/status.js.map +1 -1
- package/dist/commands/workflow/templates.d.ts +10 -3
- package/dist/commands/workflow/templates.d.ts.map +1 -1
- package/dist/commands/workflow/templates.js +39 -40
- package/dist/commands/workflow/templates.js.map +1 -1
- package/dist/core/archive.d.ts +26 -21
- package/dist/core/archive.d.ts.map +1 -1
- package/dist/core/archive.js +378 -235
- package/dist/core/archive.js.map +1 -1
- package/dist/core/artifact-graph/graph.d.ts +25 -42
- package/dist/core/artifact-graph/graph.d.ts.map +1 -1
- package/dist/core/artifact-graph/graph.js +45 -63
- package/dist/core/artifact-graph/graph.js.map +1 -1
- package/dist/core/artifact-graph/index.d.ts +1 -1
- package/dist/core/artifact-graph/index.d.ts.map +1 -1
- package/dist/core/artifact-graph/index.js +1 -1
- package/dist/core/artifact-graph/index.js.map +1 -1
- package/dist/core/artifact-graph/instruction-loader.d.ts +97 -103
- package/dist/core/artifact-graph/instruction-loader.d.ts.map +1 -1
- package/dist/core/artifact-graph/instruction-loader.js +146 -119
- package/dist/core/artifact-graph/instruction-loader.js.map +1 -1
- package/dist/core/artifact-graph/outputs.d.ts +9 -23
- package/dist/core/artifact-graph/outputs.d.ts.map +1 -1
- package/dist/core/artifact-graph/outputs.js +45 -38
- package/dist/core/artifact-graph/outputs.js.map +1 -1
- package/dist/core/artifact-graph/resolver.d.ts +44 -63
- package/dist/core/artifact-graph/resolver.d.ts.map +1 -1
- package/dist/core/artifact-graph/resolver.js +85 -86
- package/dist/core/artifact-graph/resolver.js.map +1 -1
- package/dist/core/artifact-graph/schema.d.ts +0 -6
- package/dist/core/artifact-graph/schema.d.ts.map +1 -1
- package/dist/core/artifact-graph/schema.js +7 -32
- package/dist/core/artifact-graph/schema.js.map +1 -1
- package/dist/core/artifact-graph/state.d.ts +1 -8
- package/dist/core/artifact-graph/state.d.ts.map +1 -1
- package/dist/core/artifact-graph/state.js +2 -17
- package/dist/core/artifact-graph/state.js.map +1 -1
- package/dist/core/artifact-graph/stub-detection.d.ts +12 -0
- package/dist/core/artifact-graph/stub-detection.d.ts.map +1 -0
- package/dist/core/artifact-graph/stub-detection.js +39 -0
- package/dist/core/artifact-graph/stub-detection.js.map +1 -0
- package/dist/core/artifact-graph/types.d.ts +4 -0
- package/dist/core/artifact-graph/types.d.ts.map +1 -1
- package/dist/core/artifact-graph/types.js +30 -10
- package/dist/core/artifact-graph/types.js.map +1 -1
- package/dist/core/available-tools.d.ts +3 -12
- package/dist/core/available-tools.d.ts.map +1 -1
- package/dist/core/available-tools.js +4 -13
- package/dist/core/available-tools.js.map +1 -1
- package/dist/core/change-metadata/schema.d.ts +1 -1
- package/dist/core/change-metadata/schema.d.ts.map +1 -1
- package/dist/core/change-metadata/schema.js +10 -7
- package/dist/core/change-metadata/schema.js.map +1 -1
- package/dist/core/change-presenter.d.ts +23 -18
- package/dist/core/change-presenter.d.ts.map +1 -1
- package/dist/core/change-presenter.js +102 -43
- package/dist/core/change-presenter.js.map +1 -1
- package/dist/core/change-status-policy.d.ts +8 -1
- package/dist/core/change-status-policy.d.ts.map +1 -1
- package/dist/core/change-status-policy.js +25 -1
- package/dist/core/change-status-policy.js.map +1 -1
- package/dist/core/codex-metrics.d.ts +25 -45
- package/dist/core/codex-metrics.d.ts.map +1 -1
- package/dist/core/codex-metrics.js +44 -88
- package/dist/core/codex-metrics.js.map +1 -1
- package/dist/core/codex-residue.d.ts +14 -15
- package/dist/core/codex-residue.d.ts.map +1 -1
- package/dist/core/codex-residue.js +18 -22
- package/dist/core/codex-residue.js.map +1 -1
- package/dist/core/command-generation/adapters/claude.d.ts +2 -9
- package/dist/core/command-generation/adapters/claude.d.ts.map +1 -1
- package/dist/core/command-generation/adapters/claude.js +2 -12
- package/dist/core/command-generation/adapters/claude.js.map +1 -1
- package/dist/core/command-generation/adapters/index.d.ts +1 -9
- package/dist/core/command-generation/adapters/index.d.ts.map +1 -1
- package/dist/core/command-generation/adapters/index.js +1 -9
- package/dist/core/command-generation/adapters/index.js.map +1 -1
- package/dist/core/command-generation/generator.d.ts +0 -17
- package/dist/core/command-generation/generator.d.ts.map +1 -1
- package/dist/core/command-generation/generator.js +0 -17
- package/dist/core/command-generation/generator.js.map +1 -1
- package/dist/core/command-generation/index.d.ts +2 -5
- package/dist/core/command-generation/index.d.ts.map +1 -1
- package/dist/core/command-generation/index.js +0 -9
- package/dist/core/command-generation/index.js.map +1 -1
- package/dist/core/command-generation/types.d.ts +10 -36
- package/dist/core/command-generation/types.d.ts.map +1 -1
- package/dist/core/command-generation/types.js +0 -6
- package/dist/core/command-generation/types.js.map +1 -1
- package/dist/core/command-generation/yaml.d.ts +3 -18
- package/dist/core/command-generation/yaml.d.ts.map +1 -1
- package/dist/core/command-generation/yaml.js +5 -23
- package/dist/core/command-generation/yaml.js.map +1 -1
- package/dist/core/config-prompts.d.ts +2 -4
- package/dist/core/config-prompts.d.ts.map +1 -1
- package/dist/core/config-prompts.js +2 -7
- package/dist/core/config-prompts.js.map +1 -1
- package/dist/core/config-schema.d.ts +8 -53
- package/dist/core/config-schema.d.ts.map +1 -1
- package/dist/core/config-schema.js +49 -62
- package/dist/core/config-schema.js.map +1 -1
- package/dist/core/config.d.ts +39 -26
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +36 -22
- package/dist/core/config.js.map +1 -1
- package/dist/core/dashboard-activity.d.ts +7 -9
- package/dist/core/dashboard-activity.d.ts.map +1 -1
- package/dist/core/dashboard-activity.js +26 -24
- package/dist/core/dashboard-activity.js.map +1 -1
- package/dist/core/dashboard-data.d.ts +40 -22
- package/dist/core/dashboard-data.d.ts.map +1 -1
- package/dist/core/dashboard-data.js +62 -70
- package/dist/core/dashboard-data.js.map +1 -1
- package/dist/core/global-config.d.ts +24 -53
- package/dist/core/global-config.d.ts.map +1 -1
- package/dist/core/global-config.js +38 -67
- package/dist/core/global-config.js.map +1 -1
- package/dist/core/init.d.ts +25 -19
- package/dist/core/init.d.ts.map +1 -1
- package/dist/core/init.js +168 -181
- package/dist/core/init.js.map +1 -1
- package/dist/core/list.d.ts +1 -1
- package/dist/core/list.d.ts.map +1 -1
- package/dist/core/list.js +121 -28
- package/dist/core/list.js.map +1 -1
- package/dist/core/local-server.d.ts +41 -83
- package/dist/core/local-server.d.ts.map +1 -1
- package/dist/core/local-server.js +53 -98
- package/dist/core/local-server.js.map +1 -1
- package/dist/core/markdown-render.d.ts +25 -0
- package/dist/core/markdown-render.d.ts.map +1 -0
- package/dist/core/markdown-render.js +94 -0
- package/dist/core/markdown-render.js.map +1 -0
- package/dist/core/migrate.d.ts +29 -14
- package/dist/core/migrate.d.ts.map +1 -1
- package/dist/core/migrate.js +184 -122
- package/dist/core/migrate.js.map +1 -1
- package/dist/core/parsers/change-parser.d.ts +7 -10
- package/dist/core/parsers/change-parser.d.ts.map +1 -1
- package/dist/core/parsers/change-parser.js +48 -56
- package/dist/core/parsers/change-parser.js.map +1 -1
- package/dist/core/parsers/markdown-parser.d.ts +8 -9
- package/dist/core/parsers/markdown-parser.d.ts.map +1 -1
- package/dist/core/parsers/markdown-parser.js +31 -22
- package/dist/core/parsers/markdown-parser.js.map +1 -1
- package/dist/core/parsers/requirement-blocks.d.ts +43 -15
- package/dist/core/parsers/requirement-blocks.d.ts.map +1 -1
- package/dist/core/parsers/requirement-blocks.js +142 -70
- package/dist/core/parsers/requirement-blocks.js.map +1 -1
- package/dist/core/parsers/requirement-text.d.ts +73 -79
- package/dist/core/parsers/requirement-text.d.ts.map +1 -1
- package/dist/core/parsers/requirement-text.js +137 -79
- package/dist/core/parsers/requirement-text.js.map +1 -1
- package/dist/core/parsers/spec-structure.d.ts.map +1 -1
- package/dist/core/parsers/spec-structure.js +10 -6
- package/dist/core/parsers/spec-structure.js.map +1 -1
- package/dist/core/profiles.d.ts +3 -10
- package/dist/core/profiles.d.ts.map +1 -1
- package/dist/core/profiles.js +5 -12
- package/dist/core/profiles.js.map +1 -1
- package/dist/core/project-config.d.ts +43 -44
- package/dist/core/project-config.d.ts.map +1 -1
- package/dist/core/project-config.js +107 -82
- package/dist/core/project-config.js.map +1 -1
- package/dist/core/project-layout.d.ts +9 -17
- package/dist/core/project-layout.d.ts.map +1 -1
- package/dist/core/project-layout.js +16 -26
- package/dist/core/project-layout.js.map +1 -1
- package/dist/core/root-selection.d.ts +11 -7
- package/dist/core/root-selection.d.ts.map +1 -1
- package/dist/core/root-selection.js +7 -8
- package/dist/core/root-selection.js.map +1 -1
- package/dist/core/rules.d.ts +6 -1
- package/dist/core/rules.d.ts.map +1 -1
- package/dist/core/rules.js +23 -2
- package/dist/core/rules.js.map +1 -1
- package/dist/core/schema-names.d.ts +16 -0
- package/dist/core/schema-names.d.ts.map +1 -0
- package/dist/core/schema-names.js +16 -0
- package/dist/core/schema-names.js.map +1 -0
- package/dist/core/schemas/base.schema.d.ts +3 -0
- package/dist/core/schemas/base.schema.d.ts.map +1 -1
- package/dist/core/schemas/base.schema.js +22 -6
- package/dist/core/schemas/base.schema.js.map +1 -1
- package/dist/core/schemas/change.schema.d.ts +16 -0
- package/dist/core/schemas/change.schema.d.ts.map +1 -1
- package/dist/core/schemas/change.schema.js +41 -10
- package/dist/core/schemas/change.schema.js.map +1 -1
- package/dist/core/schemas/spec.schema.d.ts +2 -0
- package/dist/core/schemas/spec.schema.d.ts.map +1 -1
- package/dist/core/shared/index.d.ts +3 -8
- package/dist/core/shared/index.d.ts.map +1 -1
- package/dist/core/shared/index.js +3 -8
- package/dist/core/shared/index.js.map +1 -1
- package/dist/core/shared/rules-generation.d.ts +19 -8
- package/dist/core/shared/rules-generation.d.ts.map +1 -1
- package/dist/core/shared/rules-generation.js +117 -50
- package/dist/core/shared/rules-generation.js.map +1 -1
- package/dist/core/shared/skill-generation.d.ts +28 -43
- package/dist/core/shared/skill-generation.d.ts.map +1 -1
- package/dist/core/shared/skill-generation.js +82 -51
- package/dist/core/shared/skill-generation.js.map +1 -1
- package/dist/core/shared/tool-detection.d.ts +39 -61
- package/dist/core/shared/tool-detection.d.ts.map +1 -1
- package/dist/core/shared/tool-detection.js +88 -80
- package/dist/core/shared/tool-detection.js.map +1 -1
- package/dist/core/skill-metrics.d.ts +36 -63
- package/dist/core/skill-metrics.d.ts.map +1 -1
- package/dist/core/skill-metrics.js +34 -73
- package/dist/core/skill-metrics.js.map +1 -1
- package/dist/core/spec-presenter.js +6 -6
- package/dist/core/spec-presenter.js.map +1 -1
- package/dist/core/specs-apply.d.ts +22 -23
- package/dist/core/specs-apply.d.ts.map +1 -1
- package/dist/core/specs-apply.js +166 -193
- package/dist/core/specs-apply.js.map +1 -1
- package/dist/core/templates/fragments/interview.d.ts +2 -6
- package/dist/core/templates/fragments/interview.d.ts.map +1 -1
- package/dist/core/templates/fragments/interview.js +2 -6
- package/dist/core/templates/fragments/interview.js.map +1 -1
- package/dist/core/templates/fragments/next-step.d.ts +4 -8
- package/dist/core/templates/fragments/next-step.d.ts.map +1 -1
- package/dist/core/templates/fragments/next-step.js +4 -8
- package/dist/core/templates/fragments/next-step.js.map +1 -1
- package/dist/core/templates/fragments/validate.d.ts +13 -0
- package/dist/core/templates/fragments/validate.d.ts.map +1 -0
- package/dist/core/templates/fragments/validate.js +13 -0
- package/dist/core/templates/fragments/validate.js.map +1 -0
- package/dist/core/templates/fragments/verify.d.ts +9 -12
- package/dist/core/templates/fragments/verify.d.ts.map +1 -1
- package/dist/core/templates/fragments/verify.js +9 -12
- package/dist/core/templates/fragments/verify.js.map +1 -1
- package/dist/core/templates/index.d.ts +0 -6
- package/dist/core/templates/index.d.ts.map +1 -1
- package/dist/core/templates/index.js +0 -7
- package/dist/core/templates/index.js.map +1 -1
- package/dist/core/templates/skill-templates.d.ts +1 -5
- package/dist/core/templates/skill-templates.d.ts.map +1 -1
- package/dist/core/templates/skill-templates.js +0 -5
- package/dist/core/templates/skill-templates.js.map +1 -1
- package/dist/core/templates/types.d.ts +3 -7
- package/dist/core/templates/types.d.ts.map +1 -1
- package/dist/core/templates/types.js +0 -3
- package/dist/core/templates/types.js.map +1 -1
- package/dist/core/templates/workflows/apply.d.ts +3 -9
- package/dist/core/templates/workflows/apply.d.ts.map +1 -1
- package/dist/core/templates/workflows/apply.js +11 -13
- package/dist/core/templates/workflows/apply.js.map +1 -1
- package/dist/core/templates/workflows/archive.d.ts +0 -6
- package/dist/core/templates/workflows/archive.d.ts.map +1 -1
- package/dist/core/templates/workflows/archive.js +19 -6
- package/dist/core/templates/workflows/archive.js.map +1 -1
- package/dist/core/templates/workflows/decision.js +4 -4
- package/dist/core/templates/workflows/decision.js.map +1 -1
- package/dist/core/templates/workflows/explore.js +1 -1
- package/dist/core/templates/workflows/grill.d.ts.map +1 -1
- package/dist/core/templates/workflows/grill.js +0 -2
- package/dist/core/templates/workflows/grill.js.map +1 -1
- package/dist/core/templates/workflows/issue.d.ts +0 -6
- package/dist/core/templates/workflows/issue.d.ts.map +1 -1
- package/dist/core/templates/workflows/issue.js +3 -2
- package/dist/core/templates/workflows/issue.js.map +1 -1
- package/dist/core/templates/workflows/propose.d.ts +0 -6
- package/dist/core/templates/workflows/propose.d.ts.map +1 -1
- package/dist/core/templates/workflows/propose.js +2 -2
- package/dist/core/templates/workflows/propose.js.map +1 -1
- package/dist/core/templates/workflows/sync.d.ts +2 -8
- package/dist/core/templates/workflows/sync.d.ts.map +1 -1
- package/dist/core/templates/workflows/sync.js +4 -3
- package/dist/core/templates/workflows/sync.js.map +1 -1
- package/dist/core/templates/workflows/update.d.ts +0 -6
- package/dist/core/templates/workflows/update.d.ts.map +1 -1
- package/dist/core/templates/workflows/update.js +9 -2
- package/dist/core/templates/workflows/update.js.map +1 -1
- package/dist/core/update.d.ts +23 -23
- package/dist/core/update.d.ts.map +1 -1
- package/dist/core/update.js +139 -118
- package/dist/core/update.js.map +1 -1
- package/dist/core/user-state-migration.d.ts +13 -15
- package/dist/core/user-state-migration.d.ts.map +1 -1
- package/dist/core/user-state-migration.js +16 -20
- package/dist/core/user-state-migration.js.map +1 -1
- package/dist/core/validation/constants.d.ts +4 -10
- package/dist/core/validation/constants.d.ts.map +1 -1
- package/dist/core/validation/constants.js +25 -20
- package/dist/core/validation/constants.js.map +1 -1
- package/dist/core/validation/prose-length.d.ts +15 -0
- package/dist/core/validation/prose-length.d.ts.map +1 -0
- package/dist/core/validation/prose-length.js +29 -0
- package/dist/core/validation/prose-length.js.map +1 -0
- package/dist/core/validation/purpose-placeholder.d.ts +9 -16
- package/dist/core/validation/purpose-placeholder.d.ts.map +1 -1
- package/dist/core/validation/purpose-placeholder.js +30 -44
- package/dist/core/validation/purpose-placeholder.js.map +1 -1
- package/dist/core/validation/section-validator.d.ts +4 -4
- package/dist/core/validation/section-validator.d.ts.map +1 -1
- package/dist/core/validation/section-validator.js +43 -7
- package/dist/core/validation/section-validator.js.map +1 -1
- package/dist/core/validation/task-numbering.d.ts +6 -3
- package/dist/core/validation/task-numbering.d.ts.map +1 -1
- package/dist/core/validation/task-numbering.js +23 -11
- package/dist/core/validation/task-numbering.js.map +1 -1
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.d.ts.map +1 -1
- package/dist/core/validation/types.js +12 -1
- package/dist/core/validation/types.js.map +1 -1
- package/dist/core/validation/validator.d.ts +43 -63
- package/dist/core/validation/validator.d.ts.map +1 -1
- package/dist/core/validation/validator.js +500 -267
- package/dist/core/validation/validator.js.map +1 -1
- package/dist/prompts/searchable-multi-select.d.ts +3 -8
- package/dist/prompts/searchable-multi-select.d.ts.map +1 -1
- package/dist/prompts/searchable-multi-select.js +16 -39
- package/dist/prompts/searchable-multi-select.js.map +1 -1
- package/dist/utils/change-metadata.d.ts +11 -50
- package/dist/utils/change-metadata.d.ts.map +1 -1
- package/dist/utils/change-metadata.js +48 -67
- package/dist/utils/change-metadata.js.map +1 -1
- package/dist/utils/change-utils.d.ts +30 -54
- package/dist/utils/change-utils.d.ts.map +1 -1
- package/dist/utils/change-utils.js +133 -91
- package/dist/utils/change-utils.js.map +1 -1
- package/dist/utils/file-lock.d.ts +39 -0
- package/dist/utils/file-lock.d.ts.map +1 -0
- package/dist/utils/file-lock.js +149 -0
- package/dist/utils/file-lock.js.map +1 -0
- package/dist/utils/file-system.d.ts +12 -32
- package/dist/utils/file-system.d.ts.map +1 -1
- package/dist/utils/file-system.js +16 -40
- package/dist/utils/file-system.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +7 -11
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +11 -11
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/interactive.d.ts +4 -9
- package/dist/utils/interactive.d.ts.map +1 -1
- package/dist/utils/interactive.js +2 -4
- package/dist/utils/interactive.js.map +1 -1
- package/dist/utils/item-discovery.d.ts +15 -10
- package/dist/utils/item-discovery.d.ts.map +1 -1
- package/dist/utils/item-discovery.js +42 -47
- package/dist/utils/item-discovery.js.map +1 -1
- package/dist/utils/link.d.ts +9 -18
- package/dist/utils/link.d.ts.map +1 -1
- package/dist/utils/link.js +9 -18
- package/dist/utils/link.js.map +1 -1
- package/dist/utils/requirement-diff.d.ts +13 -23
- package/dist/utils/requirement-diff.d.ts.map +1 -1
- package/dist/utils/requirement-diff.js +13 -23
- package/dist/utils/requirement-diff.js.map +1 -1
- package/dist/utils/spec-files.d.ts +7 -20
- package/dist/utils/spec-files.d.ts.map +1 -1
- package/dist/utils/spec-files.js +26 -51
- package/dist/utils/spec-files.js.map +1 -1
- package/dist/utils/task-progress.d.ts +11 -9
- package/dist/utils/task-progress.d.ts.map +1 -1
- package/dist/utils/task-progress.js +53 -32
- package/dist/utils/task-progress.js.map +1 -1
- package/dist/utils/timestamp.d.ts +5 -8
- package/dist/utils/timestamp.d.ts.map +1 -1
- package/dist/utils/timestamp.js +5 -8
- package/dist/utils/timestamp.js.map +1 -1
- package/package.json +2 -3
- package/schemas/decision/templates/decision.md +3 -1
- package/schemas/decision/templates/index.md +2 -2
- package/schemas/issue/schema.yaml +8 -1
- package/schemas/issue/templates/spec.md +27 -2
- package/schemas/sdd/schema.yaml +20 -1
- package/schemas/sdd/templates/spec.md +27 -2
- /package/assets/rules/tospec/{single-sourc-of-truth.md → single-source-of-truth.md} +0 -0
|
@@ -2,9 +2,6 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import fg from 'fast-glob';
|
|
4
4
|
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
5
|
-
/**
|
|
6
|
-
* Checks if a path contains glob pattern characters.
|
|
7
|
-
*/
|
|
8
5
|
export function isGlobPattern(pattern) {
|
|
9
6
|
return pattern.includes('*') || pattern.includes('?') || pattern.includes('[');
|
|
10
7
|
}
|
|
@@ -12,17 +9,13 @@ export function isGlobPattern(pattern) {
|
|
|
12
9
|
* A pattern whose wildcard occupies exactly one whole path segment, with every
|
|
13
10
|
* other segment literal — `specs/*` or `specs/<*>/spec.md`.
|
|
14
11
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* compilation and stream setup — the dominant cost on the dashboard's hot path,
|
|
20
|
-
* where the whole aggregation re-runs on every file save.
|
|
12
|
+
* The only glob shape any shipped schema declares. Answering it with `readdir` +
|
|
13
|
+
* `stat` skips a glob engine's per-call pattern compilation and stream setup —
|
|
14
|
+
* the dominant cost on the dashboard's hot path, which re-runs the whole
|
|
15
|
+
* aggregation on every file save.
|
|
21
16
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* something this cannot express; the fast path is an optimisation, not a
|
|
25
|
-
* narrowing of the contract.
|
|
17
|
+
* `null` for any other shape, so the caller falls back to fast-glob: the fast
|
|
18
|
+
* path is an optimisation, not a narrowing of the contract.
|
|
26
19
|
*/
|
|
27
20
|
function splitSingleWildcard(generates) {
|
|
28
21
|
const segments = FileSystemUtils.toPosixPath(generates).split('/');
|
|
@@ -40,16 +33,40 @@ function splitSingleWildcard(generates) {
|
|
|
40
33
|
return null;
|
|
41
34
|
return { prefix: segments.slice(0, wildcardIndex), suffix: segments.slice(wildcardIndex + 1) };
|
|
42
35
|
}
|
|
43
|
-
/** Shared tail so the sync and async resolvers
|
|
36
|
+
/** Shared tail, so the sync and async resolvers finish identically. */
|
|
44
37
|
function finalizeMatches(matches) {
|
|
45
38
|
return Array.from(new Set(matches)).sort();
|
|
46
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether each fixed segment after the wildcard is spelled on disk exactly as
|
|
42
|
+
* the pattern spells it. `stat` answers case-insensitively on Windows and
|
|
43
|
+
* macOS while fast-glob matches names literally, so without this the fast
|
|
44
|
+
* path counted `SPEC.MD` as done and the glob path did not.
|
|
45
|
+
*/
|
|
46
|
+
function hasExactSuffixSpelling(dir, suffix) {
|
|
47
|
+
let current = dir;
|
|
48
|
+
for (const segment of suffix) {
|
|
49
|
+
if (!fs.readdirSync(current).includes(segment))
|
|
50
|
+
return false;
|
|
51
|
+
current = path.join(current, segment);
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
async function hasExactSuffixSpellingAsync(dir, suffix) {
|
|
56
|
+
let current = dir;
|
|
57
|
+
for (const segment of suffix) {
|
|
58
|
+
if (!(await fs.promises.readdir(current)).includes(segment))
|
|
59
|
+
return false;
|
|
60
|
+
current = path.join(current, segment);
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
47
64
|
function globFallbackOptions(changeDir) {
|
|
48
65
|
return { cwd: changeDir, onlyFiles: true, absolute: true };
|
|
49
66
|
}
|
|
50
67
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
68
|
+
* Absolute paths of the files an artifact's `generates` currently resolves to.
|
|
69
|
+
* Sorted, for deterministic output.
|
|
53
70
|
*/
|
|
54
71
|
export function resolveArtifactOutputs(changeDir, generates) {
|
|
55
72
|
if (!isGlobPattern(generates)) {
|
|
@@ -81,10 +98,10 @@ export function resolveArtifactOutputs(changeDir, generates) {
|
|
|
81
98
|
continue;
|
|
82
99
|
const candidate = path.join(baseDir, entry, ...single.suffix);
|
|
83
100
|
try {
|
|
84
|
-
// statSync
|
|
85
|
-
// default followSymbolicLinks does
|
|
101
|
+
// statSync, not the Dirent type, so symlinks resolve as fast-glob's
|
|
102
|
+
// default followSymbolicLinks does and `onlyFiles` still holds for a
|
|
86
103
|
// *directory* named spec.md.
|
|
87
|
-
if (fs.statSync(candidate).isFile()) {
|
|
104
|
+
if (fs.statSync(candidate).isFile() && hasExactSuffixSpelling(path.join(baseDir, entry), single.suffix)) {
|
|
88
105
|
matches.push(FileSystemUtils.canonicalizeExistingPath(candidate));
|
|
89
106
|
}
|
|
90
107
|
}
|
|
@@ -101,24 +118,16 @@ export function resolveArtifactOutputs(changeDir, generates) {
|
|
|
101
118
|
return finalizeMatches(matches);
|
|
102
119
|
}
|
|
103
120
|
/**
|
|
104
|
-
* Async twin of {@link resolveArtifactOutputs}, for `collectChangeDetail
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* per-artifact resolution is the one that has something to interleave with.
|
|
121
|
+
* Async twin of {@link resolveArtifactOutputs}, for `collectChangeDetail`: a
|
|
122
|
+
* detail pane is fetched while the overview may still be aggregating, so it has
|
|
123
|
+
* something to interleave with.
|
|
108
124
|
*
|
|
109
|
-
* It does **not** serve the save-triggered overview,
|
|
110
|
-
*
|
|
111
|
-
* through `artifactSummaryFor` → `formatChangeStatus` → `artifactOutputExists`
|
|
112
|
-
* and through `listTasksForChange`, both synchronous — deliberately, and
|
|
113
|
-
* measured: dashboard-data.ts records 2.1 ms as the longest stall across 30
|
|
114
|
-
* changes with the sync resolver in place, because the awaits already sitting in
|
|
115
|
-
* that loop break the work across iterations. What removed the cost there was
|
|
116
|
-
* the single-wildcard `readdir` fast path above, not asynchrony.
|
|
125
|
+
* It does **not** serve the save-triggered overview, which reaches this module
|
|
126
|
+
* only through synchronous paths — see the measurement in dashboard-data.ts.
|
|
117
127
|
*
|
|
118
128
|
* The duplicated branch structure is held to the sync version by the parity
|
|
119
|
-
* cases in test/core/artifact-graph/outputs.test.ts
|
|
120
|
-
*
|
|
121
|
-
* and assert identical results. Any behaviour added to one belongs in that list.
|
|
129
|
+
* cases in test/core/artifact-graph/outputs.test.ts. Any behaviour added to one
|
|
130
|
+
* belongs in that list.
|
|
122
131
|
*/
|
|
123
132
|
export async function resolveArtifactOutputsAsync(changeDir, generates) {
|
|
124
133
|
if (!isGlobPattern(generates)) {
|
|
@@ -147,7 +156,8 @@ export async function resolveArtifactOutputsAsync(changeDir, generates) {
|
|
|
147
156
|
return null;
|
|
148
157
|
const candidate = path.join(baseDir, entry, ...single.suffix);
|
|
149
158
|
try {
|
|
150
|
-
return (await fs.promises.stat(candidate)).isFile()
|
|
159
|
+
return (await fs.promises.stat(candidate)).isFile() &&
|
|
160
|
+
(await hasExactSuffixSpellingAsync(path.join(baseDir, entry), single.suffix))
|
|
151
161
|
? FileSystemUtils.canonicalizeExistingPath(candidate)
|
|
152
162
|
: null;
|
|
153
163
|
}
|
|
@@ -161,9 +171,6 @@ export async function resolveArtifactOutputsAsync(changeDir, generates) {
|
|
|
161
171
|
const matches = (await fg(normalizedPattern, globFallbackOptions(changeDir))).map((match) => FileSystemUtils.canonicalizeExistingPath(path.normalize(match)));
|
|
162
172
|
return finalizeMatches(matches);
|
|
163
173
|
}
|
|
164
|
-
/**
|
|
165
|
-
* Checks if an artifact has at least one resolved output file.
|
|
166
|
-
*/
|
|
167
174
|
export function artifactOutputExists(changeDir, generates) {
|
|
168
175
|
return resolveArtifactOutputs(changeDir, generates).length > 0;
|
|
169
176
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outputs.js","sourceRoot":"","sources":["../../../src/core/artifact-graph/outputs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D
|
|
1
|
+
{"version":3,"file":"outputs.js","sourceRoot":"","sources":["../../../src/core/artifact-graph/outputs.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import type { SchemaYaml } from './types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Error thrown when loading a schema fails.
|
|
5
|
-
*/
|
|
6
3
|
export declare class SchemaLoadError extends Error {
|
|
7
4
|
readonly schemaPath: string;
|
|
8
5
|
readonly cause?: Error | undefined;
|
|
9
6
|
constructor(message: string, schemaPath: string, cause?: Error | undefined);
|
|
10
7
|
}
|
|
11
|
-
/**
|
|
12
|
-
* Gets the package's built-in schemas directory path.
|
|
13
|
-
* Uses import.meta.url to resolve relative to the current module.
|
|
14
|
-
*/
|
|
8
|
+
/** Walks up from dist/core/artifact-graph/ to the package root's schemas/. */
|
|
15
9
|
export declare function getPackageSchemasDir(): string;
|
|
16
10
|
/**
|
|
17
11
|
* The user's schema override directory: inside the config directory, unless
|
|
@@ -19,70 +13,50 @@ export declare function getPackageSchemasDir(): string;
|
|
|
19
13
|
* than adding to it, so exactly one user-level override directory is ever live.
|
|
20
14
|
*/
|
|
21
15
|
export declare function getUserSchemasDir(): string;
|
|
22
|
-
/**
|
|
23
|
-
* Gets the project-local schemas directory path.
|
|
24
|
-
* @param projectRoot - The project root directory
|
|
25
|
-
* @returns The path to the project's schemas directory
|
|
26
|
-
*/
|
|
27
16
|
export declare function getProjectSchemasDir(projectRoot: string): string;
|
|
28
17
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* `
|
|
32
|
-
* directory has `isDirectory() === false`; such entries are dereferenced via
|
|
33
|
-
* `statSync` to admit symlinked schema dirs while still rejecting
|
|
34
|
-
* symlinks-to-files and broken/dangling links.
|
|
18
|
+
* True for real directories and for symlinks pointing at one. `Dirent`'s
|
|
19
|
+
* `isDirectory()` reports the raw entry type, so a symlinked schema dir needs
|
|
20
|
+
* the `statSync` dereference below.
|
|
35
21
|
*/
|
|
36
22
|
export declare function isSchemaDir(parentDir: string, entry: fs.Dirent): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Resolves a schema name to its directory path.
|
|
39
|
-
*
|
|
40
|
-
* Resolution order (when projectRoot is provided):
|
|
41
|
-
* 1. Project-local: <projectRoot>/tospec/schemas/<name>/schema.yaml
|
|
42
|
-
* 2. User override: ${XDG_DATA_HOME}/tospec/schemas/<name>/schema.yaml
|
|
43
|
-
* 3. Package built-in: <package>/schemas/<name>/schema.yaml
|
|
44
|
-
*
|
|
45
|
-
* When projectRoot is not provided, only user override and package built-in are checked
|
|
46
|
-
* (backward compatible behavior).
|
|
47
|
-
*
|
|
48
|
-
* @param name - Schema name (e.g., "sdd")
|
|
49
|
-
* @param projectRoot - Optional project root directory for project-local schema resolution
|
|
50
|
-
* @returns The path to the schema directory, or null if not found
|
|
51
|
-
*/
|
|
52
23
|
/**
|
|
53
24
|
* Identity of a file's current contents, for cache invalidation. Null when the
|
|
54
25
|
* file cannot be stat'd, which disables caching for that path rather than
|
|
55
26
|
* risking a stale hit.
|
|
56
27
|
*/
|
|
57
28
|
export declare function fileStamp(filePath: string): string | null;
|
|
58
|
-
export declare function getSchemaDir(name: string, projectRoot?: string): string | null;
|
|
59
29
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* 2. User override: ${XDG_DATA_HOME}/tospec/schemas/<name>/schema.yaml
|
|
65
|
-
* 3. Package built-in: <package>/schemas/<name>/schema.yaml
|
|
30
|
+
* The directory holding `<name>/schema.yaml` and the layer it came from, or
|
|
31
|
+
* null when no layer has one. Project-local wins over the user override, which
|
|
32
|
+
* wins over the package built-in; without `projectRoot` only the last two are
|
|
33
|
+
* searched.
|
|
66
34
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* @param name - Schema name (e.g., "sdd")
|
|
71
|
-
* @param projectRoot - Optional project root directory for project-local schema resolution
|
|
72
|
-
* @returns The resolved schema object
|
|
73
|
-
* @throws Error if schema is not found in any location
|
|
35
|
+
* The layer is resolved here rather than re-derived from the path by each
|
|
36
|
+
* caller: a directory is the *whole* schema, templates included, so "which layer
|
|
37
|
+
* won" is what explains a file the winning layer does not have.
|
|
74
38
|
*/
|
|
75
|
-
export declare function
|
|
39
|
+
export declare function getSchemaDirWithSource(name: string, projectRoot?: string): {
|
|
40
|
+
dir: string;
|
|
41
|
+
source: SchemaInfo['source'];
|
|
42
|
+
} | null;
|
|
43
|
+
/** As `getSchemaDirWithSource`, for callers that only need the path. */
|
|
44
|
+
export declare function getSchemaDir(name: string, projectRoot?: string): string | null;
|
|
76
45
|
/**
|
|
77
|
-
*
|
|
78
|
-
* Combines project-local, user override, and package built-in schemas.
|
|
46
|
+
* The parsed schema, resolved through `getSchemaDir`'s precedence order.
|
|
79
47
|
*
|
|
80
|
-
* @
|
|
48
|
+
* @throws SchemaLoadError when the file cannot be read or does not parse.
|
|
81
49
|
*/
|
|
50
|
+
export declare function resolveSchema(name: string, projectRoot?: string): SchemaYaml;
|
|
51
|
+
/** Every schema name on disk across all three layers. */
|
|
82
52
|
export declare function listSchemas(projectRoot?: string): string[];
|
|
83
53
|
/**
|
|
84
|
-
*
|
|
54
|
+
* Names of the schemas that actually load — what an "Available schemas:" list
|
|
55
|
+
* has to mean. `listSchemas` reports directory names, so a schema.yaml with a
|
|
56
|
+
* typo in it would be offered as a choice. Anything phrased as advice to the
|
|
57
|
+
* user belongs here.
|
|
85
58
|
*/
|
|
59
|
+
export declare function listLoadableSchemas(projectRoot?: string): string[];
|
|
86
60
|
export interface SchemaInfo {
|
|
87
61
|
name: string;
|
|
88
62
|
description: string;
|
|
@@ -90,28 +64,35 @@ export interface SchemaInfo {
|
|
|
90
64
|
source: 'project' | 'user' | 'package';
|
|
91
65
|
/**
|
|
92
66
|
* Absolute path to the directory holding schema.yaml (and its templates/).
|
|
93
|
-
* `source` says which of the three layers won; this says which file to open
|
|
94
|
-
* the question a schema author actually has when a resolution surprises them.
|
|
67
|
+
* `source` says which of the three layers won; this says which file to open.
|
|
95
68
|
*/
|
|
96
69
|
path: string;
|
|
70
|
+
/**
|
|
71
|
+
* Why this schema could not be loaded, on a broken entry only (which also has
|
|
72
|
+
* an empty `artifacts` list). Carrying the failure in place rather than
|
|
73
|
+
* dropping the entry is the same rule `list` follows for an unreadable change:
|
|
74
|
+
* tospec/decisions/20260917_234821-batch-commands-degrade-per-item.md
|
|
75
|
+
*/
|
|
76
|
+
error?: string;
|
|
97
77
|
}
|
|
98
78
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
79
|
+
* Every schema with its description and artifact list, for agent skills that
|
|
80
|
+
* present a schema choice.
|
|
101
81
|
*
|
|
102
|
-
*
|
|
82
|
+
* A schema that fails to parse is reported with `error` set, but only when no
|
|
83
|
+
* lower-precedence layer supplies a working schema of that name — a broken
|
|
84
|
+
* project override must not hide the package schema it shadows.
|
|
103
85
|
*/
|
|
104
86
|
export declare function listSchemasWithInfo(projectRoot?: string): SchemaInfo[];
|
|
105
87
|
/**
|
|
106
88
|
* Union of every artifact ID across every available schema.
|
|
107
89
|
*
|
|
108
|
-
* Config keys
|
|
109
|
-
* legitimately name an artifact from any schema, so they
|
|
110
|
-
*
|
|
90
|
+
* Config keys scoped per-artifact but stored globally (`rules:`) can
|
|
91
|
+
* legitimately name an artifact from any schema, so they are checked against the
|
|
92
|
+
* union rather than the current change's schema.
|
|
111
93
|
*
|
|
112
|
-
* Built on listSchemasWithInfo
|
|
113
|
-
*
|
|
114
|
-
* custom schema must not turn every rules key into an unknown ID.
|
|
94
|
+
* Built on listSchemasWithInfo to inherit its tolerance for a schema that fails
|
|
95
|
+
* to parse: one broken custom schema must not turn every rules key unknown.
|
|
115
96
|
*/
|
|
116
97
|
export declare function collectAllArtifactIds(projectRoot?: string): Set<string>;
|
|
117
98
|
//# sourceMappingURL=resolver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/core/artifact-graph/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAK9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/core/artifact-graph/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAK9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,qBAAa,eAAgB,SAAQ,KAAK;aAGtB,UAAU,EAAE,MAAM;aAClB,KAAK,CAAC,EAAE,KAAK;IAH/B,YACE,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,KAAK,YAAA,EAI9B;CACF;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,IAAI,MAAM,CAG7C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAUD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,GAAG,OAAO,CAYxE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOzD;AA+CD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,GACnB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;CAAE,GAAG,IAAI,CAStD;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,GAAG,IAAI,CAEf;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CA+C5E;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ1D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAIlE;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACvC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE,CAuCtE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAEvE"}
|
|
@@ -3,9 +3,6 @@ import * as path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { getGlobalConfigDir, getLegacyDataDir } from '../global-config.js';
|
|
5
5
|
import { parseSchema, SchemaValidationError } from './schema.js';
|
|
6
|
-
/**
|
|
7
|
-
* Error thrown when loading a schema fails.
|
|
8
|
-
*/
|
|
9
6
|
export class SchemaLoadError extends Error {
|
|
10
7
|
schemaPath;
|
|
11
8
|
cause;
|
|
@@ -16,13 +13,9 @@ export class SchemaLoadError extends Error {
|
|
|
16
13
|
this.name = 'SchemaLoadError';
|
|
17
14
|
}
|
|
18
15
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Gets the package's built-in schemas directory path.
|
|
21
|
-
* Uses import.meta.url to resolve relative to the current module.
|
|
22
|
-
*/
|
|
16
|
+
/** Walks up from dist/core/artifact-graph/ to the package root's schemas/. */
|
|
23
17
|
export function getPackageSchemasDir() {
|
|
24
18
|
const currentFile = fileURLToPath(import.meta.url);
|
|
25
|
-
// Navigate from dist/core/artifact-graph/ to package root's schemas/
|
|
26
19
|
return path.join(path.dirname(currentFile), '..', '..', '..', 'schemas');
|
|
27
20
|
}
|
|
28
21
|
/**
|
|
@@ -38,27 +31,18 @@ export function getUserSchemasDir() {
|
|
|
38
31
|
}
|
|
39
32
|
/**
|
|
40
33
|
* Where overrides sit until an install migrates. Ranked below the current user
|
|
41
|
-
* directory, so a migrated copy wins and a not-yet-migrated one still applies
|
|
42
|
-
* per schema name, because every lookup walks this list name by name.
|
|
34
|
+
* directory, so a migrated copy wins and a not-yet-migrated one still applies.
|
|
43
35
|
*/
|
|
44
36
|
function getLegacySchemasDir() {
|
|
45
37
|
return path.join(getLegacyDataDir(), 'schemas');
|
|
46
38
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Gets the project-local schemas directory path.
|
|
49
|
-
* @param projectRoot - The project root directory
|
|
50
|
-
* @returns The path to the project's schemas directory
|
|
51
|
-
*/
|
|
52
39
|
export function getProjectSchemasDir(projectRoot) {
|
|
53
40
|
return path.join(projectRoot, 'tospec', 'schemas');
|
|
54
41
|
}
|
|
55
42
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* `
|
|
59
|
-
* directory has `isDirectory() === false`; such entries are dereferenced via
|
|
60
|
-
* `statSync` to admit symlinked schema dirs while still rejecting
|
|
61
|
-
* symlinks-to-files and broken/dangling links.
|
|
43
|
+
* True for real directories and for symlinks pointing at one. `Dirent`'s
|
|
44
|
+
* `isDirectory()` reports the raw entry type, so a symlinked schema dir needs
|
|
45
|
+
* the `statSync` dereference below.
|
|
62
46
|
*/
|
|
63
47
|
export function isSchemaDir(parentDir, entry) {
|
|
64
48
|
if (entry.isDirectory()) {
|
|
@@ -74,21 +58,6 @@ export function isSchemaDir(parentDir, entry) {
|
|
|
74
58
|
}
|
|
75
59
|
return false;
|
|
76
60
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Resolves a schema name to its directory path.
|
|
79
|
-
*
|
|
80
|
-
* Resolution order (when projectRoot is provided):
|
|
81
|
-
* 1. Project-local: <projectRoot>/tospec/schemas/<name>/schema.yaml
|
|
82
|
-
* 2. User override: ${XDG_DATA_HOME}/tospec/schemas/<name>/schema.yaml
|
|
83
|
-
* 3. Package built-in: <package>/schemas/<name>/schema.yaml
|
|
84
|
-
*
|
|
85
|
-
* When projectRoot is not provided, only user override and package built-in are checked
|
|
86
|
-
* (backward compatible behavior).
|
|
87
|
-
*
|
|
88
|
-
* @param name - Schema name (e.g., "sdd")
|
|
89
|
-
* @param projectRoot - Optional project root directory for project-local schema resolution
|
|
90
|
-
* @returns The path to the schema directory, or null if not found
|
|
91
|
-
*/
|
|
92
61
|
/**
|
|
93
62
|
* Identity of a file's current contents, for cache invalidation. Null when the
|
|
94
63
|
* file cannot be stat'd, which disables caching for that path rather than
|
|
@@ -105,6 +74,16 @@ export function fileStamp(filePath) {
|
|
|
105
74
|
}
|
|
106
75
|
/** Parsed schemas keyed by path, invalidated when the file's stamp changes. */
|
|
107
76
|
const schemaCache = new Map();
|
|
77
|
+
/**
|
|
78
|
+
* One wording for a schema that will not parse, so `tospec schemas` and
|
|
79
|
+
* `tospec templates --schema <name>` say the same thing about the same file.
|
|
80
|
+
*/
|
|
81
|
+
function schemaParseFailureMessage(schemaPath, error) {
|
|
82
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
83
|
+
return error instanceof SchemaValidationError
|
|
84
|
+
? `Invalid schema at '${schemaPath}': ${detail}`
|
|
85
|
+
: `Failed to parse schema at '${schemaPath}': ${detail}`;
|
|
86
|
+
}
|
|
108
87
|
/**
|
|
109
88
|
* The schema search path, **lowest precedence first** (package → user →
|
|
110
89
|
* project). Every lookup and listing walks this one list, so adding a source
|
|
@@ -113,9 +92,9 @@ const schemaCache = new Map();
|
|
|
113
92
|
function schemaSources(projectRoot) {
|
|
114
93
|
return [
|
|
115
94
|
{ dir: getPackageSchemasDir(), source: 'package' },
|
|
116
|
-
// Both report 'user'
|
|
117
|
-
// and a 'legacy' value would widen the agent-facing JSON contract
|
|
118
|
-
// something that stops existing once migration runs.
|
|
95
|
+
// Both report 'user': the legacy entry is another address for the same
|
|
96
|
+
// layer, and a 'legacy' value would widen the agent-facing JSON contract
|
|
97
|
+
// with something that stops existing once migration runs.
|
|
119
98
|
{ dir: getLegacySchemasDir(), source: 'user' },
|
|
120
99
|
{ dir: getUserSchemasDir(), source: 'user' },
|
|
121
100
|
...(projectRoot
|
|
@@ -132,51 +111,54 @@ function scanSchemaDir(dir) {
|
|
|
132
111
|
.filter((entry) => isSchemaDir(dir, entry) && fs.existsSync(path.join(dir, entry.name, 'schema.yaml')))
|
|
133
112
|
.map((entry) => entry.name);
|
|
134
113
|
}
|
|
135
|
-
|
|
114
|
+
/**
|
|
115
|
+
* The directory holding `<name>/schema.yaml` and the layer it came from, or
|
|
116
|
+
* null when no layer has one. Project-local wins over the user override, which
|
|
117
|
+
* wins over the package built-in; without `projectRoot` only the last two are
|
|
118
|
+
* searched.
|
|
119
|
+
*
|
|
120
|
+
* The layer is resolved here rather than re-derived from the path by each
|
|
121
|
+
* caller: a directory is the *whole* schema, templates included, so "which layer
|
|
122
|
+
* won" is what explains a file the winning layer does not have.
|
|
123
|
+
*/
|
|
124
|
+
export function getSchemaDirWithSource(name, projectRoot) {
|
|
136
125
|
// Highest precedence first: project overrides user overrides package.
|
|
137
|
-
for (const { dir } of schemaSources(projectRoot).reverse()) {
|
|
126
|
+
for (const { dir, source } of schemaSources(projectRoot).reverse()) {
|
|
138
127
|
const candidate = path.join(dir, name);
|
|
139
128
|
if (fs.existsSync(path.join(candidate, 'schema.yaml'))) {
|
|
140
|
-
return candidate;
|
|
129
|
+
return { dir: candidate, source };
|
|
141
130
|
}
|
|
142
131
|
}
|
|
143
132
|
return null;
|
|
144
133
|
}
|
|
134
|
+
/** As `getSchemaDirWithSource`, for callers that only need the path. */
|
|
135
|
+
export function getSchemaDir(name, projectRoot) {
|
|
136
|
+
return getSchemaDirWithSource(name, projectRoot)?.dir ?? null;
|
|
137
|
+
}
|
|
145
138
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* Resolution order (when projectRoot is provided):
|
|
149
|
-
* 1. Project-local: <projectRoot>/tospec/schemas/<name>/schema.yaml
|
|
150
|
-
* 2. User override: ${XDG_DATA_HOME}/tospec/schemas/<name>/schema.yaml
|
|
151
|
-
* 3. Package built-in: <package>/schemas/<name>/schema.yaml
|
|
139
|
+
* The parsed schema, resolved through `getSchemaDir`'s precedence order.
|
|
152
140
|
*
|
|
153
|
-
*
|
|
154
|
-
* (backward compatible behavior).
|
|
155
|
-
*
|
|
156
|
-
* @param name - Schema name (e.g., "sdd")
|
|
157
|
-
* @param projectRoot - Optional project root directory for project-local schema resolution
|
|
158
|
-
* @returns The resolved schema object
|
|
159
|
-
* @throws Error if schema is not found in any location
|
|
141
|
+
* @throws SchemaLoadError when the file cannot be read or does not parse.
|
|
160
142
|
*/
|
|
161
143
|
export function resolveSchema(name, projectRoot) {
|
|
162
|
-
// Normalize name (remove .yaml extension if provided)
|
|
163
144
|
const normalizedName = name.replace(/\.ya?ml$/, '');
|
|
164
145
|
const schemaDir = getSchemaDir(normalizedName, projectRoot);
|
|
165
146
|
if (!schemaDir) {
|
|
166
|
-
|
|
147
|
+
// Loadable, not merely present: a name whose schema.yaml does not parse is
|
|
148
|
+
// a choice that cannot work.
|
|
149
|
+
const availableSchemas = listLoadableSchemas(projectRoot);
|
|
167
150
|
throw new Error(`Schema '${normalizedName}' not found. Available schemas: ${availableSchemas.join(', ')}`);
|
|
168
151
|
}
|
|
169
152
|
const schemaPath = path.join(schemaDir, 'schema.yaml');
|
|
170
|
-
// A
|
|
171
|
-
//
|
|
172
|
-
// dominates
|
|
153
|
+
// A status/list run resolves the same schema once per change and the dashboard
|
|
154
|
+
// re-resolves on every refresh, where the yaml + Zod + cycle-check parse
|
|
155
|
+
// dominates. One statSync decides whether it can be skipped.
|
|
173
156
|
const stamp = fileStamp(schemaPath);
|
|
174
157
|
const cached = stamp === null ? undefined : schemaCache.get(schemaPath);
|
|
175
158
|
if (cached && cached.stamp === stamp) {
|
|
176
159
|
// Cloned so a caller mutating its schema cannot corrupt later resolutions.
|
|
177
160
|
return structuredClone(cached.schema);
|
|
178
161
|
}
|
|
179
|
-
// Load and parse the schema
|
|
180
162
|
let content;
|
|
181
163
|
try {
|
|
182
164
|
content = fs.readFileSync(schemaPath, 'utf-8');
|
|
@@ -193,19 +175,11 @@ export function resolveSchema(name, projectRoot) {
|
|
|
193
175
|
return schema;
|
|
194
176
|
}
|
|
195
177
|
catch (err) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
const parseError = err instanceof Error ? err : new Error(String(err));
|
|
200
|
-
throw new SchemaLoadError(`Failed to parse schema at '${schemaPath}': ${parseError.message}`, schemaPath, parseError);
|
|
178
|
+
const cause = err instanceof Error ? err : new Error(String(err));
|
|
179
|
+
throw new SchemaLoadError(schemaParseFailureMessage(schemaPath, err), schemaPath, cause);
|
|
201
180
|
}
|
|
202
181
|
}
|
|
203
|
-
/**
|
|
204
|
-
* Lists all available schema names.
|
|
205
|
-
* Combines project-local, user override, and package built-in schemas.
|
|
206
|
-
*
|
|
207
|
-
* @param projectRoot - Optional project root directory for project-local schema resolution
|
|
208
|
-
*/
|
|
182
|
+
/** Every schema name on disk across all three layers. */
|
|
209
183
|
export function listSchemas(projectRoot) {
|
|
210
184
|
const schemas = new Set();
|
|
211
185
|
for (const { dir } of schemaSources(projectRoot)) {
|
|
@@ -216,17 +190,33 @@ export function listSchemas(projectRoot) {
|
|
|
216
190
|
return Array.from(schemas).sort();
|
|
217
191
|
}
|
|
218
192
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
193
|
+
* Names of the schemas that actually load — what an "Available schemas:" list
|
|
194
|
+
* has to mean. `listSchemas` reports directory names, so a schema.yaml with a
|
|
195
|
+
* typo in it would be offered as a choice. Anything phrased as advice to the
|
|
196
|
+
* user belongs here.
|
|
197
|
+
*/
|
|
198
|
+
export function listLoadableSchemas(projectRoot) {
|
|
199
|
+
return listSchemasWithInfo(projectRoot)
|
|
200
|
+
.filter((schema) => schema.error === undefined)
|
|
201
|
+
.map((schema) => schema.name);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Every schema with its description and artifact list, for agent skills that
|
|
205
|
+
* present a schema choice.
|
|
221
206
|
*
|
|
222
|
-
*
|
|
207
|
+
* A schema that fails to parse is reported with `error` set, but only when no
|
|
208
|
+
* lower-precedence layer supplies a working schema of that name — a broken
|
|
209
|
+
* project override must not hide the package schema it shadows.
|
|
223
210
|
*/
|
|
224
211
|
export function listSchemasWithInfo(projectRoot) {
|
|
225
212
|
const schemas = [];
|
|
226
213
|
const seenNames = new Set();
|
|
214
|
+
// Keyed by name so the highest-precedence failure is the one reported, and a
|
|
215
|
+
// later success removes it.
|
|
216
|
+
const broken = new Map();
|
|
227
217
|
// Highest precedence first, so an overridden schema is skipped rather than
|
|
228
|
-
// replaced. A schema that fails to parse is not marked seen — the next
|
|
229
|
-
//
|
|
218
|
+
// replaced. A schema that fails to parse is not marked seen — the next source
|
|
219
|
+
// down still gets a chance to supply it.
|
|
230
220
|
for (const { dir, source } of schemaSources(projectRoot).reverse()) {
|
|
231
221
|
for (const name of scanSchemaDir(dir)) {
|
|
232
222
|
if (seenNames.has(name))
|
|
@@ -241,24 +231,33 @@ export function listSchemasWithInfo(projectRoot) {
|
|
|
241
231
|
path: path.join(dir, name),
|
|
242
232
|
});
|
|
243
233
|
seenNames.add(name);
|
|
234
|
+
broken.delete(name);
|
|
244
235
|
}
|
|
245
|
-
catch {
|
|
246
|
-
|
|
236
|
+
catch (error) {
|
|
237
|
+
if (broken.has(name))
|
|
238
|
+
continue;
|
|
239
|
+
broken.set(name, {
|
|
240
|
+
name,
|
|
241
|
+
description: '',
|
|
242
|
+
artifacts: [],
|
|
243
|
+
source,
|
|
244
|
+
path: path.join(dir, name),
|
|
245
|
+
error: schemaParseFailureMessage(path.join(dir, name, 'schema.yaml'), error),
|
|
246
|
+
});
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
-
return schemas.sort((a, b) => a.name.localeCompare(b.name));
|
|
250
|
+
return [...schemas, ...broken.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
251
251
|
}
|
|
252
252
|
/**
|
|
253
253
|
* Union of every artifact ID across every available schema.
|
|
254
254
|
*
|
|
255
|
-
* Config keys
|
|
256
|
-
* legitimately name an artifact from any schema, so they
|
|
257
|
-
*
|
|
255
|
+
* Config keys scoped per-artifact but stored globally (`rules:`) can
|
|
256
|
+
* legitimately name an artifact from any schema, so they are checked against the
|
|
257
|
+
* union rather than the current change's schema.
|
|
258
258
|
*
|
|
259
|
-
* Built on listSchemasWithInfo
|
|
260
|
-
*
|
|
261
|
-
* custom schema must not turn every rules key into an unknown ID.
|
|
259
|
+
* Built on listSchemasWithInfo to inherit its tolerance for a schema that fails
|
|
260
|
+
* to parse: one broken custom schema must not turn every rules key unknown.
|
|
262
261
|
*/
|
|
263
262
|
export function collectAllArtifactIds(projectRoot) {
|
|
264
263
|
return new Set(listSchemasWithInfo(projectRoot).flatMap((schema) => schema.artifacts));
|