@seanmars/tospec 0.4.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/LICENSE +21 -0
- package/README.md +114 -0
- package/assets/dashboard/app.js +1032 -0
- package/assets/dashboard/chart.umd.js +14 -0
- package/assets/dashboard/index.html +30 -0
- package/assets/dashboard/style.css +675 -0
- package/bin/tospec.js +5 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +330 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/config.d.ts +36 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +486 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/dashboard.d.ts +40 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +385 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/shared-output.d.ts +24 -0
- package/dist/commands/shared-output.d.ts.map +1 -0
- package/dist/commands/shared-output.js +51 -0
- package/dist/commands/shared-output.js.map +1 -0
- package/dist/commands/show.d.ts +17 -0
- package/dist/commands/show.d.ts.map +1 -0
- package/dist/commands/show.js +164 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/validate.d.ts +51 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +416 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.d.ts.map +1 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/index.js.map +1 -0
- package/dist/commands/workflow/instructions.d.ts +35 -0
- package/dist/commands/workflow/instructions.d.ts.map +1 -0
- package/dist/commands/workflow/instructions.js +359 -0
- package/dist/commands/workflow/instructions.js.map +1 -0
- package/dist/commands/workflow/new-change.d.ts +17 -0
- package/dist/commands/workflow/new-change.d.ts.map +1 -0
- package/dist/commands/workflow/new-change.js +97 -0
- package/dist/commands/workflow/new-change.js.map +1 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.d.ts.map +1 -0
- package/dist/commands/workflow/schemas.js +33 -0
- package/dist/commands/workflow/schemas.js.map +1 -0
- package/dist/commands/workflow/shared.d.ts +63 -0
- package/dist/commands/workflow/shared.d.ts.map +1 -0
- package/dist/commands/workflow/shared.js +111 -0
- package/dist/commands/workflow/shared.js.map +1 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.d.ts.map +1 -0
- package/dist/commands/workflow/status.js +77 -0
- package/dist/commands/workflow/status.js.map +1 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.d.ts.map +1 -0
- package/dist/commands/workflow/templates.js +60 -0
- package/dist/commands/workflow/templates.js.map +1 -0
- package/dist/core/archive.d.ts +33 -0
- package/dist/core/archive.d.ts.map +1 -0
- package/dist/core/archive.js +585 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/artifact-graph/graph.d.ts +56 -0
- package/dist/core/artifact-graph/graph.d.ts.map +1 -0
- package/dist/core/artifact-graph/graph.js +141 -0
- package/dist/core/artifact-graph/graph.js.map +1 -0
- package/dist/core/artifact-graph/index.d.ts +9 -0
- package/dist/core/artifact-graph/index.d.ts.map +1 -0
- package/dist/core/artifact-graph/index.js +14 -0
- package/dist/core/artifact-graph/index.js.map +1 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +188 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts.map +1 -0
- package/dist/core/artifact-graph/instruction-loader.js +243 -0
- package/dist/core/artifact-graph/instruction-loader.js.map +1 -0
- package/dist/core/artifact-graph/outputs.d.ts +14 -0
- package/dist/core/artifact-graph/outputs.d.ts.map +1 -0
- package/dist/core/artifact-graph/outputs.js +39 -0
- package/dist/core/artifact-graph/outputs.js.map +1 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.d.ts.map +1 -0
- package/dist/core/artifact-graph/resolver.js +257 -0
- package/dist/core/artifact-graph/resolver.js.map +1 -0
- package/dist/core/artifact-graph/schema.d.ts +13 -0
- package/dist/core/artifact-graph/schema.d.ts.map +1 -0
- package/dist/core/artifact-graph/schema.js +108 -0
- package/dist/core/artifact-graph/schema.js.map +1 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.d.ts.map +1 -0
- package/dist/core/artifact-graph/state.js +31 -0
- package/dist/core/artifact-graph/state.js.map +1 -0
- package/dist/core/artifact-graph/types.d.ts +55 -0
- package/dist/core/artifact-graph/types.d.ts.map +1 -0
- package/dist/core/artifact-graph/types.js +38 -0
- package/dist/core/artifact-graph/types.js.map +1 -0
- package/dist/core/available-tools.d.ts +17 -0
- package/dist/core/available-tools.d.ts.map +1 -0
- package/dist/core/available-tools.js +43 -0
- package/dist/core/available-tools.js.map +1 -0
- package/dist/core/change-metadata/index.d.ts +2 -0
- package/dist/core/change-metadata/index.d.ts.map +1 -0
- package/dist/core/change-metadata/index.js +2 -0
- package/dist/core/change-metadata/index.js.map +1 -0
- package/dist/core/change-metadata/schema.d.ts +12 -0
- package/dist/core/change-metadata/schema.d.ts.map +1 -0
- package/dist/core/change-metadata/schema.js +15 -0
- package/dist/core/change-metadata/schema.js.map +1 -0
- package/dist/core/change-presenter.d.ts +24 -0
- package/dist/core/change-presenter.d.ts.map +1 -0
- package/dist/core/change-presenter.js +135 -0
- package/dist/core/change-presenter.js.map +1 -0
- package/dist/core/change-status-policy.d.ts +35 -0
- package/dist/core/change-status-policy.d.ts.map +1 -0
- package/dist/core/change-status-policy.js +34 -0
- package/dist/core/change-status-policy.js.map +1 -0
- package/dist/core/command-generation/adapters/claude.d.ts +14 -0
- package/dist/core/command-generation/adapters/claude.d.ts.map +1 -0
- package/dist/core/command-generation/adapters/claude.js +38 -0
- package/dist/core/command-generation/adapters/claude.js.map +1 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.d.ts.map +1 -0
- package/dist/core/command-generation/adapters/cursor.js +31 -0
- package/dist/core/command-generation/adapters/cursor.js.map +1 -0
- package/dist/core/command-generation/adapters/index.d.ts +8 -0
- package/dist/core/command-generation/adapters/index.d.ts.map +1 -0
- package/dist/core/command-generation/adapters/index.js +8 -0
- package/dist/core/command-generation/adapters/index.js.map +1 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.d.ts.map +1 -0
- package/dist/core/command-generation/generator.js +27 -0
- package/dist/core/command-generation/generator.js.map +1 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.d.ts.map +1 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/index.js.map +1 -0
- package/dist/core/command-generation/registry.d.ts +24 -0
- package/dist/core/command-generation/registry.d.ts.map +1 -0
- package/dist/core/command-generation/registry.js +38 -0
- package/dist/core/command-generation/registry.js.map +1 -0
- package/dist/core/command-generation/types.d.ts +56 -0
- package/dist/core/command-generation/types.d.ts.map +1 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/command-generation/types.js.map +1 -0
- package/dist/core/command-generation/yaml.d.ts +22 -0
- package/dist/core/command-generation/yaml.d.ts.map +1 -0
- package/dist/core/command-generation/yaml.js +38 -0
- package/dist/core/command-generation/yaml.js.map +1 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.d.ts.map +1 -0
- package/dist/core/config-prompts.js +34 -0
- package/dist/core/config-prompts.js.map +1 -0
- package/dist/core/config-schema.d.ts +87 -0
- package/dist/core/config-schema.d.ts.map +1 -0
- package/dist/core/config-schema.js +239 -0
- package/dist/core/config-schema.js.map +1 -0
- package/dist/core/config.d.ts +19 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +14 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.d.ts.map +1 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/converters/json-converter.js.map +1 -0
- package/dist/core/dashboard-activity.d.ts +50 -0
- package/dist/core/dashboard-activity.d.ts.map +1 -0
- package/dist/core/dashboard-activity.js +147 -0
- package/dist/core/dashboard-activity.js.map +1 -0
- package/dist/core/dashboard-data.d.ts +100 -0
- package/dist/core/dashboard-data.d.ts.map +1 -0
- package/dist/core/dashboard-data.js +368 -0
- package/dist/core/dashboard-data.js.map +1 -0
- package/dist/core/global-config.d.ts +51 -0
- package/dist/core/global-config.d.ts.map +1 -0
- package/dist/core/global-config.js +124 -0
- package/dist/core/global-config.js.map +1 -0
- package/dist/core/id.d.ts +17 -0
- package/dist/core/id.d.ts.map +1 -0
- package/dist/core/id.js +30 -0
- package/dist/core/id.js.map +1 -0
- package/dist/core/init.d.ts +34 -0
- package/dist/core/init.d.ts.map +1 -0
- package/dist/core/init.js +495 -0
- package/dist/core/init.js.map +1 -0
- package/dist/core/list.d.ts +12 -0
- package/dist/core/list.d.ts.map +1 -0
- package/dist/core/list.js +192 -0
- package/dist/core/list.js.map +1 -0
- package/dist/core/migrate.d.ts +52 -0
- package/dist/core/migrate.d.ts.map +1 -0
- package/dist/core/migrate.js +300 -0
- package/dist/core/migrate.js.map +1 -0
- package/dist/core/parsers/change-parser.d.ts +19 -0
- package/dist/core/parsers/change-parser.d.ts.map +1 -0
- package/dist/core/parsers/change-parser.js +204 -0
- package/dist/core/parsers/change-parser.js.map +1 -0
- package/dist/core/parsers/markdown-parser.d.ts +29 -0
- package/dist/core/parsers/markdown-parser.d.ts.map +1 -0
- package/dist/core/parsers/markdown-parser.js +181 -0
- package/dist/core/parsers/markdown-parser.js.map +1 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.d.ts.map +1 -0
- package/dist/core/parsers/requirement-blocks.js +201 -0
- package/dist/core/parsers/requirement-blocks.js.map +1 -0
- package/dist/core/parsers/requirement-text.d.ts +55 -0
- package/dist/core/parsers/requirement-text.d.ts.map +1 -0
- package/dist/core/parsers/requirement-text.js +136 -0
- package/dist/core/parsers/requirement-text.js.map +1 -0
- package/dist/core/parsers/spec-structure.d.ts +9 -0
- package/dist/core/parsers/spec-structure.d.ts.map +1 -0
- package/dist/core/parsers/spec-structure.js +88 -0
- package/dist/core/parsers/spec-structure.js.map +1 -0
- package/dist/core/planning-home.d.ts +16 -0
- package/dist/core/planning-home.d.ts.map +1 -0
- package/dist/core/planning-home.js +67 -0
- package/dist/core/planning-home.js.map +1 -0
- package/dist/core/profiles.d.ts +24 -0
- package/dist/core/profiles.d.ts.map +1 -0
- package/dist/core/profiles.js +27 -0
- package/dist/core/profiles.js.map +1 -0
- package/dist/core/project-config.d.ts +100 -0
- package/dist/core/project-config.d.ts.map +1 -0
- package/dist/core/project-config.js +389 -0
- package/dist/core/project-config.js.map +1 -0
- package/dist/core/references.d.ts +40 -0
- package/dist/core/references.d.ts.map +1 -0
- package/dist/core/references.js +11 -0
- package/dist/core/references.js.map +1 -0
- package/dist/core/root-selection.d.ts +57 -0
- package/dist/core/root-selection.d.ts.map +1 -0
- package/dist/core/root-selection.js +98 -0
- package/dist/core/root-selection.js.map +1 -0
- package/dist/core/schemas/base.schema.d.ts +13 -0
- package/dist/core/schemas/base.schema.d.ts.map +1 -0
- package/dist/core/schemas/base.schema.js +18 -0
- package/dist/core/schemas/base.schema.js.map +1 -0
- package/dist/core/schemas/change.schema.d.ts +73 -0
- package/dist/core/schemas/change.schema.d.ts.map +1 -0
- package/dist/core/schemas/change.schema.js +31 -0
- package/dist/core/schemas/change.schema.js.map +1 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.d.ts.map +1 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/index.js.map +1 -0
- package/dist/core/schemas/spec.schema.d.ts +18 -0
- package/dist/core/schemas/spec.schema.d.ts.map +1 -0
- package/dist/core/schemas/spec.schema.js +15 -0
- package/dist/core/schemas/spec.schema.js.map +1 -0
- package/dist/core/shared/index.d.ts +8 -0
- package/dist/core/shared/index.d.ts.map +1 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/index.js.map +1 -0
- package/dist/core/shared/skill-generation.d.ts +63 -0
- package/dist/core/shared/skill-generation.d.ts.map +1 -0
- package/dist/core/shared/skill-generation.js +125 -0
- package/dist/core/shared/skill-generation.js.map +1 -0
- package/dist/core/shared/tool-detection.d.ts +96 -0
- package/dist/core/shared/tool-detection.d.ts.map +1 -0
- package/dist/core/shared/tool-detection.js +207 -0
- package/dist/core/shared/tool-detection.js.map +1 -0
- package/dist/core/spec-presenter.d.ts +17 -0
- package/dist/core/spec-presenter.d.ts.map +1 -0
- package/dist/core/spec-presenter.js +98 -0
- package/dist/core/spec-presenter.js.map +1 -0
- package/dist/core/specs-apply.d.ts +78 -0
- package/dist/core/specs-apply.d.ts.map +1 -0
- package/dist/core/specs-apply.js +429 -0
- package/dist/core/specs-apply.js.map +1 -0
- package/dist/core/templates/index.d.ts +8 -0
- package/dist/core/templates/index.d.ts.map +1 -0
- package/dist/core/templates/index.js +9 -0
- package/dist/core/templates/index.js.map +1 -0
- package/dist/core/templates/skill-templates.d.ts +14 -0
- package/dist/core/templates/skill-templates.d.ts.map +1 -0
- package/dist/core/templates/skill-templates.js +13 -0
- package/dist/core/templates/skill-templates.js.map +1 -0
- package/dist/core/templates/types.d.ts +20 -0
- package/dist/core/templates/types.d.ts.map +1 -0
- package/dist/core/templates/types.js +5 -0
- package/dist/core/templates/types.js.map +1 -0
- package/dist/core/templates/workflows/apply.d.ts +10 -0
- package/dist/core/templates/workflows/apply.d.ts.map +1 -0
- package/dist/core/templates/workflows/apply.js +81 -0
- package/dist/core/templates/workflows/apply.js.map +1 -0
- package/dist/core/templates/workflows/archive.d.ts +10 -0
- package/dist/core/templates/workflows/archive.d.ts.map +1 -0
- package/dist/core/templates/workflows/archive.js +75 -0
- package/dist/core/templates/workflows/archive.js.map +1 -0
- package/dist/core/templates/workflows/explore.d.ts +10 -0
- package/dist/core/templates/workflows/explore.d.ts.map +1 -0
- package/dist/core/templates/workflows/explore.js +75 -0
- package/dist/core/templates/workflows/explore.js.map +1 -0
- package/dist/core/templates/workflows/issue.d.ts +10 -0
- package/dist/core/templates/workflows/issue.d.ts.map +1 -0
- package/dist/core/templates/workflows/issue.js +89 -0
- package/dist/core/templates/workflows/issue.js.map +1 -0
- package/dist/core/templates/workflows/propose.d.ts +10 -0
- package/dist/core/templates/workflows/propose.d.ts.map +1 -0
- package/dist/core/templates/workflows/propose.js +77 -0
- package/dist/core/templates/workflows/propose.js.map +1 -0
- package/dist/core/templates/workflows/sync.d.ts +14 -0
- package/dist/core/templates/workflows/sync.d.ts.map +1 -0
- package/dist/core/templates/workflows/sync.js +86 -0
- package/dist/core/templates/workflows/sync.js.map +1 -0
- package/dist/core/templates/workflows/update.d.ts +10 -0
- package/dist/core/templates/workflows/update.d.ts.map +1 -0
- package/dist/core/templates/workflows/update.js +99 -0
- package/dist/core/templates/workflows/update.js.map +1 -0
- package/dist/core/templates/workflows/verify.d.ts +9 -0
- package/dist/core/templates/workflows/verify.d.ts.map +1 -0
- package/dist/core/templates/workflows/verify.js +44 -0
- package/dist/core/templates/workflows/verify.js.map +1 -0
- package/dist/core/update.d.ts +46 -0
- package/dist/core/update.d.ts.map +1 -0
- package/dist/core/update.js +296 -0
- package/dist/core/update.js.map +1 -0
- package/dist/core/validation/constants.d.ts +34 -0
- package/dist/core/validation/constants.d.ts.map +1 -0
- package/dist/core/validation/constants.js +40 -0
- package/dist/core/validation/constants.js.map +1 -0
- package/dist/core/validation/section-validator.d.ts +19 -0
- package/dist/core/validation/section-validator.d.ts.map +1 -0
- package/dist/core/validation/section-validator.js +59 -0
- package/dist/core/validation/section-validator.js.map +1 -0
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.d.ts.map +1 -0
- package/dist/core/validation/types.js +2 -0
- package/dist/core/validation/types.js.map +1 -0
- package/dist/core/validation/validator.d.ts +51 -0
- package/dist/core/validation/validator.d.ts.map +1 -0
- package/dist/core/validation/validator.js +469 -0
- package/dist/core/validation/validator.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/searchable-multi-select.d.ts +28 -0
- package/dist/prompts/searchable-multi-select.d.ts.map +1 -0
- package/dist/prompts/searchable-multi-select.js +158 -0
- package/dist/prompts/searchable-multi-select.js.map +1 -0
- package/dist/ui/welcome-screen.d.ts +5 -0
- package/dist/ui/welcome-screen.d.ts.map +1 -0
- package/dist/ui/welcome-screen.js +22 -0
- package/dist/ui/welcome-screen.js.map +1 -0
- package/dist/utils/change-metadata.d.ts +55 -0
- package/dist/utils/change-metadata.d.ts.map +1 -0
- package/dist/utils/change-metadata.js +141 -0
- package/dist/utils/change-metadata.js.map +1 -0
- package/dist/utils/change-utils.d.ts +73 -0
- package/dist/utils/change-utils.d.ts.map +1 -0
- package/dist/utils/change-utils.js +194 -0
- package/dist/utils/change-utils.js.map +1 -0
- package/dist/utils/command-references.d.ts +18 -0
- package/dist/utils/command-references.d.ts.map +1 -0
- package/dist/utils/command-references.js +20 -0
- package/dist/utils/command-references.js.map +1 -0
- package/dist/utils/file-system.d.ts +41 -0
- package/dist/utils/file-system.d.ts.map +1 -0
- package/dist/utils/file-system.js +320 -0
- package/dist/utils/file-system.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/interactive.d.ts +18 -0
- package/dist/utils/interactive.d.ts.map +1 -0
- package/dist/utils/interactive.js +21 -0
- package/dist/utils/interactive.js.map +1 -0
- package/dist/utils/item-discovery.d.ts +14 -0
- package/dist/utils/item-discovery.d.ts.map +1 -0
- package/dist/utils/item-discovery.js +104 -0
- package/dist/utils/item-discovery.js.map +1 -0
- package/dist/utils/link.d.ts +22 -0
- package/dist/utils/link.d.ts.map +1 -0
- package/dist/utils/link.js +85 -0
- package/dist/utils/link.js.map +1 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.d.ts.map +1 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/match.js.map +1 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.d.ts.map +1 -0
- package/dist/utils/shell-detection.js +41 -0
- package/dist/utils/shell-detection.js.map +1 -0
- package/dist/utils/task-progress.d.ts +32 -0
- package/dist/utils/task-progress.d.ts.map +1 -0
- package/dist/utils/task-progress.js +129 -0
- package/dist/utils/task-progress.js.map +1 -0
- package/dist/utils/timestamp.d.ts +9 -0
- package/dist/utils/timestamp.d.ts.map +1 -0
- package/dist/utils/timestamp.js +18 -0
- package/dist/utils/timestamp.js.map +1 -0
- package/package.json +55 -0
- package/schemas/issue/schema.yaml +34 -0
- package/schemas/issue/templates/spec.md +13 -0
- package/schemas/issue/templates/task.md +21 -0
- package/schemas/issue/templates/ticket.md +2 -0
- package/schemas/sdd/schema.yaml +55 -0
- package/schemas/sdd/templates/design.md +15 -0
- package/schemas/sdd/templates/proposal.md +15 -0
- package/schemas/sdd/templates/spec.md +13 -0
- package/schemas/sdd/templates/tasks.md +11 -0
- package/schemas/sdd/templates/ticket.md +2 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema for global Tospec configuration.
|
|
4
|
+
* Uses passthrough() to preserve unknown fields for forward compatibility.
|
|
5
|
+
*/
|
|
6
|
+
export declare const GlobalConfigSchema: z.ZodObject<{
|
|
7
|
+
featureFlags: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>>;
|
|
8
|
+
profile: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
core: "core";
|
|
10
|
+
custom: "custom";
|
|
11
|
+
}>>>;
|
|
12
|
+
delivery: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
13
|
+
skills: "skills";
|
|
14
|
+
commands: "commands";
|
|
15
|
+
both: "both";
|
|
16
|
+
}>>>;
|
|
17
|
+
workflows: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
18
|
+
}, z.core.$loose>;
|
|
19
|
+
export type GlobalConfigType = z.infer<typeof GlobalConfigSchema>;
|
|
20
|
+
/**
|
|
21
|
+
* Default configuration values.
|
|
22
|
+
*/
|
|
23
|
+
export declare const DEFAULT_CONFIG: GlobalConfigType;
|
|
24
|
+
/**
|
|
25
|
+
* Validate a config key path for CLI set operations.
|
|
26
|
+
* Unknown top-level keys are rejected unless explicitly allowed by the caller.
|
|
27
|
+
*/
|
|
28
|
+
export declare function validateConfigKeyPath(path: string): {
|
|
29
|
+
valid: boolean;
|
|
30
|
+
reason?: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Get a nested value from an object using dot notation.
|
|
34
|
+
*
|
|
35
|
+
* @param obj - The object to access
|
|
36
|
+
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
37
|
+
* @returns The value at the path, or undefined if not found
|
|
38
|
+
*/
|
|
39
|
+
export declare function getNestedValue(obj: Record<string, unknown>, path: string): unknown;
|
|
40
|
+
/**
|
|
41
|
+
* Set a nested value in an object using dot notation.
|
|
42
|
+
* Creates intermediate objects as needed.
|
|
43
|
+
*
|
|
44
|
+
* @param obj - The object to modify (mutated in place)
|
|
45
|
+
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
46
|
+
* @param value - The value to set
|
|
47
|
+
*/
|
|
48
|
+
export declare function setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void;
|
|
49
|
+
/**
|
|
50
|
+
* Delete a nested value from an object using dot notation.
|
|
51
|
+
*
|
|
52
|
+
* @param obj - The object to modify (mutated in place)
|
|
53
|
+
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
54
|
+
* @returns true if the key existed and was deleted, false otherwise
|
|
55
|
+
*/
|
|
56
|
+
export declare function deleteNestedValue(obj: Record<string, unknown>, path: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Coerce a string value to its appropriate type.
|
|
59
|
+
* - "true" / "false" -> boolean
|
|
60
|
+
* - Numeric strings -> number
|
|
61
|
+
* - JSON arrays/objects -> parsed containers
|
|
62
|
+
* - Everything else -> string
|
|
63
|
+
*
|
|
64
|
+
* @param value - The string value to coerce
|
|
65
|
+
* @param forceString - If true, always return the value as a string
|
|
66
|
+
* @returns The coerced value
|
|
67
|
+
*/
|
|
68
|
+
export declare function coerceValue(value: string, forceString?: boolean): string | number | boolean | unknown[] | Record<string, unknown>;
|
|
69
|
+
/**
|
|
70
|
+
* Format a value for YAML-like display.
|
|
71
|
+
*
|
|
72
|
+
* @param value - The value to format
|
|
73
|
+
* @param indent - Current indentation level
|
|
74
|
+
* @returns Formatted string
|
|
75
|
+
*/
|
|
76
|
+
export declare function formatValueYaml(value: unknown, indent?: number): string;
|
|
77
|
+
/**
|
|
78
|
+
* Validate a configuration object against the schema.
|
|
79
|
+
*
|
|
80
|
+
* @param config - The configuration to validate
|
|
81
|
+
* @returns Validation result with success status and optional error message
|
|
82
|
+
*/
|
|
83
|
+
export declare function validateConfig(config: unknown): {
|
|
84
|
+
success: boolean;
|
|
85
|
+
error?: string;
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=config-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["../../src/core/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;iBAkBf,CAAC;AAEjB,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,gBAI5B,CAAC;AAIF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBvF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAelF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAc/F;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBrF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,WAAW,GAAE,OAAe,GAC3B,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBjE;AA2BD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,GAAE,MAAU,GAAG,MAAM,CAuC1E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAYpF"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema for global Tospec configuration.
|
|
4
|
+
* Uses passthrough() to preserve unknown fields for forward compatibility.
|
|
5
|
+
*/
|
|
6
|
+
export const GlobalConfigSchema = z
|
|
7
|
+
.object({
|
|
8
|
+
featureFlags: z
|
|
9
|
+
.record(z.string(), z.boolean())
|
|
10
|
+
.optional()
|
|
11
|
+
.default({}),
|
|
12
|
+
profile: z
|
|
13
|
+
.enum(['core', 'custom'])
|
|
14
|
+
.optional()
|
|
15
|
+
.default('core'),
|
|
16
|
+
delivery: z
|
|
17
|
+
.enum(['both', 'skills', 'commands'])
|
|
18
|
+
.optional()
|
|
19
|
+
.default('skills'),
|
|
20
|
+
workflows: z
|
|
21
|
+
.array(z.string())
|
|
22
|
+
.optional(),
|
|
23
|
+
})
|
|
24
|
+
.passthrough();
|
|
25
|
+
/**
|
|
26
|
+
* Default configuration values.
|
|
27
|
+
*/
|
|
28
|
+
export const DEFAULT_CONFIG = {
|
|
29
|
+
featureFlags: {},
|
|
30
|
+
profile: 'core',
|
|
31
|
+
delivery: 'skills',
|
|
32
|
+
};
|
|
33
|
+
const KNOWN_TOP_LEVEL_KEYS = new Set([...Object.keys(DEFAULT_CONFIG), 'workflows']);
|
|
34
|
+
/**
|
|
35
|
+
* Validate a config key path for CLI set operations.
|
|
36
|
+
* Unknown top-level keys are rejected unless explicitly allowed by the caller.
|
|
37
|
+
*/
|
|
38
|
+
export function validateConfigKeyPath(path) {
|
|
39
|
+
const rawKeys = path.split('.');
|
|
40
|
+
if (rawKeys.length === 0 || rawKeys.some((key) => key.trim() === '')) {
|
|
41
|
+
return { valid: false, reason: 'Key path must not be empty' };
|
|
42
|
+
}
|
|
43
|
+
const rootKey = rawKeys[0];
|
|
44
|
+
if (!KNOWN_TOP_LEVEL_KEYS.has(rootKey)) {
|
|
45
|
+
return { valid: false, reason: `Unknown top-level key "${rootKey}"` };
|
|
46
|
+
}
|
|
47
|
+
if (rootKey === 'featureFlags') {
|
|
48
|
+
if (rawKeys.length > 2) {
|
|
49
|
+
return { valid: false, reason: 'featureFlags values are booleans and do not support nested keys' };
|
|
50
|
+
}
|
|
51
|
+
return { valid: true };
|
|
52
|
+
}
|
|
53
|
+
if (rawKeys.length > 1) {
|
|
54
|
+
return { valid: false, reason: `"${rootKey}" does not support nested keys` };
|
|
55
|
+
}
|
|
56
|
+
return { valid: true };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get a nested value from an object using dot notation.
|
|
60
|
+
*
|
|
61
|
+
* @param obj - The object to access
|
|
62
|
+
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
63
|
+
* @returns The value at the path, or undefined if not found
|
|
64
|
+
*/
|
|
65
|
+
export function getNestedValue(obj, path) {
|
|
66
|
+
const keys = path.split('.');
|
|
67
|
+
let current = obj;
|
|
68
|
+
for (const key of keys) {
|
|
69
|
+
if (current === null || current === undefined) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
if (typeof current !== 'object') {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
current = current[key];
|
|
76
|
+
}
|
|
77
|
+
return current;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Set a nested value in an object using dot notation.
|
|
81
|
+
* Creates intermediate objects as needed.
|
|
82
|
+
*
|
|
83
|
+
* @param obj - The object to modify (mutated in place)
|
|
84
|
+
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
85
|
+
* @param value - The value to set
|
|
86
|
+
*/
|
|
87
|
+
export function setNestedValue(obj, path, value) {
|
|
88
|
+
const keys = path.split('.');
|
|
89
|
+
let current = obj;
|
|
90
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
91
|
+
const key = keys[i];
|
|
92
|
+
if (current[key] === undefined || current[key] === null || typeof current[key] !== 'object') {
|
|
93
|
+
current[key] = {};
|
|
94
|
+
}
|
|
95
|
+
current = current[key];
|
|
96
|
+
}
|
|
97
|
+
const lastKey = keys[keys.length - 1];
|
|
98
|
+
current[lastKey] = value;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Delete a nested value from an object using dot notation.
|
|
102
|
+
*
|
|
103
|
+
* @param obj - The object to modify (mutated in place)
|
|
104
|
+
* @param path - Dot-separated path (e.g., "featureFlags.someFlag")
|
|
105
|
+
* @returns true if the key existed and was deleted, false otherwise
|
|
106
|
+
*/
|
|
107
|
+
export function deleteNestedValue(obj, path) {
|
|
108
|
+
const keys = path.split('.');
|
|
109
|
+
let current = obj;
|
|
110
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
111
|
+
const key = keys[i];
|
|
112
|
+
if (current[key] === undefined || current[key] === null || typeof current[key] !== 'object') {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
current = current[key];
|
|
116
|
+
}
|
|
117
|
+
const lastKey = keys[keys.length - 1];
|
|
118
|
+
if (lastKey in current) {
|
|
119
|
+
delete current[lastKey];
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Coerce a string value to its appropriate type.
|
|
126
|
+
* - "true" / "false" -> boolean
|
|
127
|
+
* - Numeric strings -> number
|
|
128
|
+
* - JSON arrays/objects -> parsed containers
|
|
129
|
+
* - Everything else -> string
|
|
130
|
+
*
|
|
131
|
+
* @param value - The string value to coerce
|
|
132
|
+
* @param forceString - If true, always return the value as a string
|
|
133
|
+
* @returns The coerced value
|
|
134
|
+
*/
|
|
135
|
+
export function coerceValue(value, forceString = false) {
|
|
136
|
+
if (forceString) {
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
// Boolean coercion
|
|
140
|
+
if (value === 'true') {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
if (value === 'false') {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
// Number coercion - must be a valid finite number
|
|
147
|
+
const num = Number(value);
|
|
148
|
+
if (!isNaN(num) && isFinite(num) && value.trim() !== '') {
|
|
149
|
+
return num;
|
|
150
|
+
}
|
|
151
|
+
const jsonContainer = parseJsonContainer(value);
|
|
152
|
+
if (jsonContainer !== undefined) {
|
|
153
|
+
return jsonContainer;
|
|
154
|
+
}
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
function parseJsonContainer(value) {
|
|
158
|
+
const trimmed = value.trim();
|
|
159
|
+
const looksLikeContainer = (trimmed.startsWith('[') && trimmed.endsWith(']')) ||
|
|
160
|
+
(trimmed.startsWith('{') && trimmed.endsWith('}'));
|
|
161
|
+
if (!looksLikeContainer) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const parsed = JSON.parse(trimmed);
|
|
166
|
+
if (Array.isArray(parsed)) {
|
|
167
|
+
return parsed;
|
|
168
|
+
}
|
|
169
|
+
if (parsed !== null && typeof parsed === 'object') {
|
|
170
|
+
return parsed;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Format a value for YAML-like display.
|
|
180
|
+
*
|
|
181
|
+
* @param value - The value to format
|
|
182
|
+
* @param indent - Current indentation level
|
|
183
|
+
* @returns Formatted string
|
|
184
|
+
*/
|
|
185
|
+
export function formatValueYaml(value, indent = 0) {
|
|
186
|
+
const indentStr = ' '.repeat(indent);
|
|
187
|
+
if (value === null || value === undefined) {
|
|
188
|
+
return 'null';
|
|
189
|
+
}
|
|
190
|
+
if (typeof value === 'boolean' || typeof value === 'number') {
|
|
191
|
+
return String(value);
|
|
192
|
+
}
|
|
193
|
+
if (typeof value === 'string') {
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
if (Array.isArray(value)) {
|
|
197
|
+
if (value.length === 0) {
|
|
198
|
+
return '[]';
|
|
199
|
+
}
|
|
200
|
+
return value.map((item) => `${indentStr}- ${formatValueYaml(item, indent + 1)}`).join('\n');
|
|
201
|
+
}
|
|
202
|
+
if (typeof value === 'object') {
|
|
203
|
+
const entries = Object.entries(value);
|
|
204
|
+
if (entries.length === 0) {
|
|
205
|
+
return '{}';
|
|
206
|
+
}
|
|
207
|
+
return entries
|
|
208
|
+
.map(([key, val]) => {
|
|
209
|
+
const formattedVal = formatValueYaml(val, indent + 1);
|
|
210
|
+
if (typeof val === 'object' && val !== null && Object.keys(val).length > 0) {
|
|
211
|
+
return `${indentStr}${key}:\n${formattedVal}`;
|
|
212
|
+
}
|
|
213
|
+
return `${indentStr}${key}: ${formattedVal}`;
|
|
214
|
+
})
|
|
215
|
+
.join('\n');
|
|
216
|
+
}
|
|
217
|
+
return String(value);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Validate a configuration object against the schema.
|
|
221
|
+
*
|
|
222
|
+
* @param config - The configuration to validate
|
|
223
|
+
* @returns Validation result with success status and optional error message
|
|
224
|
+
*/
|
|
225
|
+
export function validateConfig(config) {
|
|
226
|
+
try {
|
|
227
|
+
GlobalConfigSchema.parse(config);
|
|
228
|
+
return { success: true };
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
if (error instanceof z.ZodError) {
|
|
232
|
+
const zodError = error;
|
|
233
|
+
const messages = zodError.issues.map((e) => `${e.path.join('.')}: ${e.message}`);
|
|
234
|
+
return { success: false, error: messages.join('; ') };
|
|
235
|
+
}
|
|
236
|
+
return { success: false, error: 'Unknown validation error' };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=config-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../src/core/config-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const TOSPEC_DIR_NAME = "tospec";
|
|
2
|
+
export declare const TOSPEC_MARKERS: {
|
|
3
|
+
start: string;
|
|
4
|
+
end: string;
|
|
5
|
+
};
|
|
6
|
+
export interface TospecConfig {
|
|
7
|
+
aiTools: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface AIToolOption {
|
|
10
|
+
name: string;
|
|
11
|
+
value: string;
|
|
12
|
+
available: boolean;
|
|
13
|
+
successLabel?: string;
|
|
14
|
+
skillsDir?: string;
|
|
15
|
+
detectionPaths?: string[];
|
|
16
|
+
}
|
|
17
|
+
export declare const AI_TOOLS: AIToolOption[];
|
|
18
|
+
export declare const HARD_LINK_TOOLS: readonly string[];
|
|
19
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC,eAAO,MAAM,cAAc;;;CAG1B,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,QAAQ,EAAE,YAAY,EAGlC,CAAC;AAKF,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAAe,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const TOSPEC_DIR_NAME = 'tospec';
|
|
2
|
+
export const TOSPEC_MARKERS = {
|
|
3
|
+
start: '<!-- TOSPEC:START -->',
|
|
4
|
+
end: '<!-- TOSPEC:END -->'
|
|
5
|
+
};
|
|
6
|
+
export const AI_TOOLS = [
|
|
7
|
+
{ name: 'Claude Code', value: 'claude', available: true, successLabel: 'Claude Code', skillsDir: '.claude' },
|
|
8
|
+
{ name: 'Codex', value: 'codex', available: true, successLabel: 'Codex', skillsDir: '.codex' }
|
|
9
|
+
];
|
|
10
|
+
// Tools (by tool.value) that get hard-linked skill files; anything not listed
|
|
11
|
+
// lands as a plain recursive copy instead. Claude Code reads hard-linked skill
|
|
12
|
+
// files; other agents (e.g. codex) are fine with ordinary files.
|
|
13
|
+
export const HARD_LINK_TOOLS = ['claude'];
|
|
14
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;AAExC,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,uBAAuB;IAC9B,GAAG,EAAE,qBAAqB;CAC3B,CAAC;AAeF,MAAM,CAAC,MAAM,QAAQ,GAAmB;IACtC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE;IAC5G,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE;CAC/F,CAAC;AAEF,8EAA8E;AAC9E,+EAA+E;AAC/E,iEAAiE;AACjE,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-converter.d.ts","sourceRoot":"","sources":["../../../src/core/converters/json-converter.ts"],"names":[],"mappings":"AAOA,qBAAa,aAAa;IACxB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAkBrC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmB5D,OAAO,CAAC,mBAAmB;CAgB5B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { MarkdownParser } from '../parsers/markdown-parser.js';
|
|
4
|
+
import { ChangeParser } from '../parsers/change-parser.js';
|
|
5
|
+
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
6
|
+
export class JsonConverter {
|
|
7
|
+
convertSpecToJson(filePath) {
|
|
8
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
9
|
+
const parser = new MarkdownParser(content);
|
|
10
|
+
const specName = this.extractNameFromPath(filePath);
|
|
11
|
+
const spec = parser.parseSpec(specName);
|
|
12
|
+
const jsonSpec = {
|
|
13
|
+
...spec,
|
|
14
|
+
metadata: {
|
|
15
|
+
...spec.metadata,
|
|
16
|
+
sourcePath: filePath,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
return JSON.stringify(jsonSpec, null, 2);
|
|
20
|
+
}
|
|
21
|
+
async convertChangeToJson(filePath) {
|
|
22
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
23
|
+
const changeName = this.extractNameFromPath(filePath);
|
|
24
|
+
const changeDir = path.dirname(filePath);
|
|
25
|
+
const parser = new ChangeParser(content, changeDir);
|
|
26
|
+
const change = await parser.parseChangeWithDeltas(changeName);
|
|
27
|
+
const jsonChange = {
|
|
28
|
+
...change,
|
|
29
|
+
metadata: {
|
|
30
|
+
...change.metadata,
|
|
31
|
+
sourcePath: filePath,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
return JSON.stringify(jsonChange, null, 2);
|
|
35
|
+
}
|
|
36
|
+
extractNameFromPath(filePath) {
|
|
37
|
+
const normalizedPath = FileSystemUtils.toPosixPath(filePath);
|
|
38
|
+
const parts = normalizedPath.split('/');
|
|
39
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
40
|
+
if (parts[i] === 'specs' || parts[i] === 'changes') {
|
|
41
|
+
if (i < parts.length - 1) {
|
|
42
|
+
return parts[i + 1];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const fileName = parts[parts.length - 1] ?? '';
|
|
47
|
+
const dotIndex = fileName.lastIndexOf('.');
|
|
48
|
+
return dotIndex > 0 ? fileName.slice(0, dotIndex) : fileName;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=json-converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-converter.js","sourceRoot":"","sources":["../../../src/core/converters/json-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,MAAM,OAAO,aAAa;IACxB,iBAAiB,CAAC,QAAgB;QAChC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAEpD,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAExC,MAAM,QAAQ,GAAG;YACf,GAAG,IAAI;YACP,QAAQ,EAAE;gBACR,GAAG,IAAI,CAAC,QAAQ;gBAChB,UAAU,EAAE,QAAQ;aACrB;SACF,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,QAAgB;QACxC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAEpD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;QAE9D,MAAM,UAAU,GAAG;YACjB,GAAG,MAAM;YACT,QAAQ,EAAE;gBACR,GAAG,MAAM,CAAC,QAAQ;gBAClB,UAAU,EAAE,QAAQ;aACrB;SACF,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEO,mBAAmB,CAAC,QAAgB;QAC1C,MAAM,cAAc,GAAG,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAExC,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;gBACnD,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzB,OAAO,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC3C,OAAO,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC/D,CAAC;CACF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard git activity + health signals (ADR 001, D4-D7, D12, D16).
|
|
3
|
+
*
|
|
4
|
+
* Two `git log` runs produce a 30-day daily series: commits repo-wide vs
|
|
5
|
+
* commits touching `tospec/`. The gap between the two is the spec-drift
|
|
6
|
+
* signal. Pure aggregation is split from the git-spawning wrapper so vitest
|
|
7
|
+
* can exercise it without a repo.
|
|
8
|
+
*/
|
|
9
|
+
export declare const DEFAULT_STALE_DAYS = 14;
|
|
10
|
+
/** Series window: trailing day count, or 'all' for the full git history. */
|
|
11
|
+
export type ActivityWindow = number | 'all';
|
|
12
|
+
export interface ActivityDay {
|
|
13
|
+
date: string;
|
|
14
|
+
repo: number;
|
|
15
|
+
tospec: number;
|
|
16
|
+
}
|
|
17
|
+
export interface DashboardActivity {
|
|
18
|
+
available: boolean;
|
|
19
|
+
reason?: string;
|
|
20
|
+
days: ActivityDay[];
|
|
21
|
+
specDrift: boolean;
|
|
22
|
+
staleDays: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Buckets two lists of commit dates (yyyy-mm-dd, from `git log --date=short`)
|
|
26
|
+
* into a zero-filled daily series covering the last `days` days ending `today`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function aggregateDaily(repoDates: string[], tospecDates: string[], days?: number, today?: Date): ActivityDay[];
|
|
29
|
+
/**
|
|
30
|
+
* Spec drift (D12): >=1 repo commit in the last `windowDays`, zero commits
|
|
31
|
+
* touching tospec/ in the same window, and at least one active change.
|
|
32
|
+
*/
|
|
33
|
+
export declare function computeSpecDrift(days: ActivityDay[], activeChangeCount: number, windowDays?: number): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Days needed to cover every date in both series ending today (inclusive),
|
|
36
|
+
* never less than `minDays`. Dates are yyyy-mm-dd, so lexicographic min is
|
|
37
|
+
* the earliest.
|
|
38
|
+
*/
|
|
39
|
+
export declare function historySpanDays(repoDates: string[], tospecDates: string[], minDays?: number, today?: Date): number;
|
|
40
|
+
/** Stale-change threshold from tospec/config.yaml, defaulting to 14 days. */
|
|
41
|
+
export declare function resolveStaleDays(projectRoot: string): number;
|
|
42
|
+
/**
|
|
43
|
+
* Collects the activity payload. `changeName` narrows the tospec series to
|
|
44
|
+
* that change's directory (detail view); the repo series stays repo-wide.
|
|
45
|
+
* `window` is the trailing day count (default 30) or 'all' for full history.
|
|
46
|
+
* Git being unavailable degrades to `{available: false}` (D6) — staleDays is
|
|
47
|
+
* config, not git, so it is always populated.
|
|
48
|
+
*/
|
|
49
|
+
export declare function collectActivity(projectRoot: string, changeName?: string, window?: ActivityWindow): Promise<DashboardActivity>;
|
|
50
|
+
//# sourceMappingURL=dashboard-activity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-activity.d.ts","sourceRoot":"","sources":["../../src/core/dashboard-activity.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAIrC,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAcD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,MAAM,EAAE,EACrB,IAAI,GAAE,MAAsB,EAC5B,KAAK,GAAE,IAAiB,GACvB,WAAW,EAAE,CAaf;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EAAE,EACnB,iBAAiB,EAAE,MAAM,EACzB,UAAU,GAAE,MAA0B,GACrC,OAAO,CAMT;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE,MAAsB,EAC/B,KAAK,GAAE,IAAiB,GACvB,MAAM,CAWR;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAM5D;AA8BD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,GAAE,cAA8B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAgC5B"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard git activity + health signals (ADR 001, D4-D7, D12, D16).
|
|
3
|
+
*
|
|
4
|
+
* Two `git log` runs produce a 30-day daily series: commits repo-wide vs
|
|
5
|
+
* commits touching `tospec/`. The gap between the two is the spec-drift
|
|
6
|
+
* signal. Pure aggregation is split from the git-spawning wrapper so vitest
|
|
7
|
+
* can exercise it without a repo.
|
|
8
|
+
*/
|
|
9
|
+
import { execFile } from 'node:child_process';
|
|
10
|
+
import { promisify } from 'node:util';
|
|
11
|
+
import { readProjectConfig } from './project-config.js';
|
|
12
|
+
import { getActiveChangeIds } from '../utils/item-discovery.js';
|
|
13
|
+
const execFileAsync = promisify(execFile);
|
|
14
|
+
export const DEFAULT_STALE_DAYS = 14;
|
|
15
|
+
const ACTIVITY_DAYS = 30;
|
|
16
|
+
const DRIFT_WINDOW_DAYS = 7;
|
|
17
|
+
// -----------------------------------------------------------------------------
|
|
18
|
+
// Pure aggregation (unit-testable)
|
|
19
|
+
// -----------------------------------------------------------------------------
|
|
20
|
+
/** yyyy-mm-dd in local time. */
|
|
21
|
+
function isoDay(d) {
|
|
22
|
+
const y = d.getFullYear();
|
|
23
|
+
const m = String(d.getMonth() + 1).padStart(2, '0');
|
|
24
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
25
|
+
return `${y}-${m}-${day}`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Buckets two lists of commit dates (yyyy-mm-dd, from `git log --date=short`)
|
|
29
|
+
* into a zero-filled daily series covering the last `days` days ending `today`.
|
|
30
|
+
*/
|
|
31
|
+
export function aggregateDaily(repoDates, tospecDates, days = ACTIVITY_DAYS, today = new Date()) {
|
|
32
|
+
const repoCounts = new Map();
|
|
33
|
+
for (const d of repoDates)
|
|
34
|
+
repoCounts.set(d, (repoCounts.get(d) ?? 0) + 1);
|
|
35
|
+
const tospecCounts = new Map();
|
|
36
|
+
for (const d of tospecDates)
|
|
37
|
+
tospecCounts.set(d, (tospecCounts.get(d) ?? 0) + 1);
|
|
38
|
+
const out = [];
|
|
39
|
+
for (let i = days - 1; i >= 0; i--) {
|
|
40
|
+
const d = new Date(today.getFullYear(), today.getMonth(), today.getDate() - i);
|
|
41
|
+
const key = isoDay(d);
|
|
42
|
+
out.push({ date: key, repo: repoCounts.get(key) ?? 0, tospec: tospecCounts.get(key) ?? 0 });
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Spec drift (D12): >=1 repo commit in the last `windowDays`, zero commits
|
|
48
|
+
* touching tospec/ in the same window, and at least one active change.
|
|
49
|
+
*/
|
|
50
|
+
export function computeSpecDrift(days, activeChangeCount, windowDays = DRIFT_WINDOW_DAYS) {
|
|
51
|
+
if (activeChangeCount === 0)
|
|
52
|
+
return false;
|
|
53
|
+
const recent = days.slice(-windowDays);
|
|
54
|
+
const repoCommits = recent.reduce((sum, d) => sum + d.repo, 0);
|
|
55
|
+
const tospecCommits = recent.reduce((sum, d) => sum + d.tospec, 0);
|
|
56
|
+
return repoCommits > 0 && tospecCommits === 0;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Days needed to cover every date in both series ending today (inclusive),
|
|
60
|
+
* never less than `minDays`. Dates are yyyy-mm-dd, so lexicographic min is
|
|
61
|
+
* the earliest.
|
|
62
|
+
*/
|
|
63
|
+
export function historySpanDays(repoDates, tospecDates, minDays = ACTIVITY_DAYS, today = new Date()) {
|
|
64
|
+
let earliest = '';
|
|
65
|
+
for (const d of [...repoDates, ...tospecDates]) {
|
|
66
|
+
if (!earliest || d < earliest)
|
|
67
|
+
earliest = d;
|
|
68
|
+
}
|
|
69
|
+
if (!earliest)
|
|
70
|
+
return minDays;
|
|
71
|
+
const [y, m, day] = earliest.split('-').map(Number);
|
|
72
|
+
const start = new Date(y, m - 1, day);
|
|
73
|
+
const end = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
|
74
|
+
const span = Math.round((end.getTime() - start.getTime()) / 86400000) + 1;
|
|
75
|
+
return Math.max(span, minDays);
|
|
76
|
+
}
|
|
77
|
+
/** Stale-change threshold from tospec/config.yaml, defaulting to 14 days. */
|
|
78
|
+
export function resolveStaleDays(projectRoot) {
|
|
79
|
+
try {
|
|
80
|
+
return readProjectConfig(projectRoot)?.dashboard?.staleDays ?? DEFAULT_STALE_DAYS;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return DEFAULT_STALE_DAYS;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// -----------------------------------------------------------------------------
|
|
87
|
+
// Git wrapper
|
|
88
|
+
// -----------------------------------------------------------------------------
|
|
89
|
+
/** Commit dates (yyyy-mm-dd, one per commit), newest first. */
|
|
90
|
+
async function gitLogDates(projectRoot, window, pathFilters) {
|
|
91
|
+
const args = ['log', '--format=%cd', '--date=short'];
|
|
92
|
+
if (window !== 'all')
|
|
93
|
+
args.splice(1, 0, `--since=${window} days ago`);
|
|
94
|
+
if (pathFilters)
|
|
95
|
+
args.push('--', ...pathFilters);
|
|
96
|
+
const { stdout } = await execFileAsync('git', args, { cwd: projectRoot });
|
|
97
|
+
return stdout.split(/\r?\n/).filter((line) => /^\d{4}-\d{2}-\d{2}$/.test(line));
|
|
98
|
+
}
|
|
99
|
+
/** null when git is usable, otherwise the reason string for the API payload. */
|
|
100
|
+
async function gitUnavailableReason(projectRoot) {
|
|
101
|
+
try {
|
|
102
|
+
await execFileAsync('git', ['rev-parse', '--is-inside-work-tree'], { cwd: projectRoot });
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
const code = err.code;
|
|
107
|
+
return code === 'ENOENT' ? 'git not found' : 'not a git repository';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Collects the activity payload. `changeName` narrows the tospec series to
|
|
112
|
+
* that change's directory (detail view); the repo series stays repo-wide.
|
|
113
|
+
* `window` is the trailing day count (default 30) or 'all' for full history.
|
|
114
|
+
* Git being unavailable degrades to `{available: false}` (D6) — staleDays is
|
|
115
|
+
* config, not git, so it is always populated.
|
|
116
|
+
*/
|
|
117
|
+
export async function collectActivity(projectRoot, changeName, window = ACTIVITY_DAYS) {
|
|
118
|
+
const staleDays = resolveStaleDays(projectRoot);
|
|
119
|
+
const reason = await gitUnavailableReason(projectRoot);
|
|
120
|
+
if (reason !== null) {
|
|
121
|
+
return { available: false, reason, days: [], specDrift: false, staleDays };
|
|
122
|
+
}
|
|
123
|
+
// `tospec migrate` copies openspec/ into tospec/, so commit history for
|
|
124
|
+
// migrated changes lives under openspec/ paths. A pathspec that matches
|
|
125
|
+
// nothing is harmless, so always include the legacy prefix.
|
|
126
|
+
// ponytail: only covers the default `openspec` source dir; record custom
|
|
127
|
+
// migrate source dirs in config if anyone needs them counted.
|
|
128
|
+
const pathFilters = changeName
|
|
129
|
+
? [`tospec/changes/${changeName}/`, `openspec/changes/${changeName}/`]
|
|
130
|
+
: ['tospec/', 'openspec/'];
|
|
131
|
+
const [repoDates, tospecDates] = await Promise.all([
|
|
132
|
+
gitLogDates(projectRoot, window),
|
|
133
|
+
gitLogDates(projectRoot, window, pathFilters),
|
|
134
|
+
]);
|
|
135
|
+
// ponytail: 'all' zero-fills one entry per day since the first commit; a
|
|
136
|
+
// decade-old repo means a few thousand points, coarser buckets if that hurts.
|
|
137
|
+
const spanDays = window === 'all' ? historySpanDays(repoDates, tospecDates) : window;
|
|
138
|
+
const days = aggregateDaily(repoDates, tospecDates, spanDays);
|
|
139
|
+
// Drift only makes sense repo-wide, not for a single change's series.
|
|
140
|
+
let specDrift = false;
|
|
141
|
+
if (!changeName) {
|
|
142
|
+
const activeChanges = await getActiveChangeIds(projectRoot);
|
|
143
|
+
specDrift = computeSpecDrift(days, activeChanges.length);
|
|
144
|
+
}
|
|
145
|
+
return { available: true, days, specDrift, staleDays };
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=dashboard-activity.js.map
|