@shrkcrft/cli 0.1.0-alpha.1
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 +15 -0
- package/dist/asset-preview/apply-action-hint-stub.d.ts +28 -0
- package/dist/asset-preview/apply-action-hint-stub.d.ts.map +1 -0
- package/dist/asset-preview/apply-action-hint-stub.js +170 -0
- package/dist/asset-preview/apply-asset-preview.d.ts +31 -0
- package/dist/asset-preview/apply-asset-preview.d.ts.map +1 -0
- package/dist/asset-preview/apply-asset-preview.js +210 -0
- package/dist/asset-preview/apply-knowledge-stale-fix.d.ts +37 -0
- package/dist/asset-preview/apply-knowledge-stale-fix.d.ts.map +1 -0
- package/dist/asset-preview/apply-knowledge-stale-fix.js +344 -0
- package/dist/asset-preview/apply-missing-barrel.d.ts +15 -0
- package/dist/asset-preview/apply-missing-barrel.d.ts.map +1 -0
- package/dist/asset-preview/apply-missing-barrel.js +65 -0
- package/dist/asset-preview/apply-template-drift-fix.d.ts +21 -0
- package/dist/asset-preview/apply-template-drift-fix.d.ts.map +1 -0
- package/dist/asset-preview/apply-template-drift-fix.js +125 -0
- package/dist/asset-preview/apply-template-update.d.ts +43 -0
- package/dist/asset-preview/apply-template-update.d.ts.map +1 -0
- package/dist/asset-preview/apply-template-update.js +257 -0
- package/dist/asset-preview/entry-mutator.d.ts +106 -0
- package/dist/asset-preview/entry-mutator.d.ts.map +1 -0
- package/dist/asset-preview/entry-mutator.js +428 -0
- package/dist/authoring/authoring-kit.d.ts +36 -0
- package/dist/authoring/authoring-kit.d.ts.map +1 -0
- package/dist/authoring/authoring-kit.js +106 -0
- package/dist/command-registry.d.ts +158 -0
- package/dist/command-registry.d.ts.map +1 -0
- package/dist/command-registry.js +348 -0
- package/dist/commands/apply.command.d.ts +3 -0
- package/dist/commands/apply.command.d.ts.map +1 -0
- package/dist/commands/apply.command.js +879 -0
- package/dist/commands/architecture.command.d.ts +5 -0
- package/dist/commands/architecture.command.d.ts.map +1 -0
- package/dist/commands/architecture.command.js +141 -0
- package/dist/commands/ask.command.d.ts +3 -0
- package/dist/commands/ask.command.d.ts.map +1 -0
- package/dist/commands/ask.command.js +58 -0
- package/dist/commands/audit.command.d.ts +3 -0
- package/dist/commands/audit.command.d.ts.map +1 -0
- package/dist/commands/audit.command.js +141 -0
- package/dist/commands/biome.command.d.ts +7 -0
- package/dist/commands/biome.command.d.ts.map +1 -0
- package/dist/commands/biome.command.js +350 -0
- package/dist/commands/boundaries.command.d.ts +9 -0
- package/dist/commands/boundaries.command.d.ts.map +1 -0
- package/dist/commands/boundaries.command.js +326 -0
- package/dist/commands/brief.command.d.ts +3 -0
- package/dist/commands/brief.command.d.ts.map +1 -0
- package/dist/commands/brief.command.js +206 -0
- package/dist/commands/bundle.command.d.ts +3 -0
- package/dist/commands/bundle.command.d.ts.map +1 -0
- package/dist/commands/bundle.command.js +1183 -0
- package/dist/commands/changes.command.d.ts +3 -0
- package/dist/commands/changes.command.d.ts.map +1 -0
- package/dist/commands/changes.command.js +155 -0
- package/dist/commands/check.command.d.ts +3 -0
- package/dist/commands/check.command.d.ts.map +1 -0
- package/dist/commands/check.command.js +580 -0
- package/dist/commands/checks.command.d.ts +29 -0
- package/dist/commands/checks.command.d.ts.map +1 -0
- package/dist/commands/checks.command.js +521 -0
- package/dist/commands/ci.command.d.ts +3 -0
- package/dist/commands/ci.command.d.ts.map +1 -0
- package/dist/commands/ci.command.js +680 -0
- package/dist/commands/codemod.command.d.ts +3 -0
- package/dist/commands/codemod.command.d.ts.map +1 -0
- package/dist/commands/codemod.command.js +130 -0
- package/dist/commands/command-catalog.d.ts +265 -0
- package/dist/commands/command-catalog.d.ts.map +1 -0
- package/dist/commands/command-catalog.js +3255 -0
- package/dist/commands/commands.command.d.ts +92 -0
- package/dist/commands/commands.command.d.ts.map +1 -0
- package/dist/commands/commands.command.js +1208 -0
- package/dist/commands/constructs.command.d.ts +15 -0
- package/dist/commands/constructs.command.d.ts.map +1 -0
- package/dist/commands/constructs.command.js +669 -0
- package/dist/commands/context.command.d.ts +3 -0
- package/dist/commands/context.command.d.ts.map +1 -0
- package/dist/commands/context.command.js +120 -0
- package/dist/commands/contract-gate.command.d.ts +5 -0
- package/dist/commands/contract-gate.command.d.ts.map +1 -0
- package/dist/commands/contract-gate.command.js +208 -0
- package/dist/commands/contract-templates.command.d.ts +8 -0
- package/dist/commands/contract-templates.command.d.ts.map +1 -0
- package/dist/commands/contract-templates.command.js +151 -0
- package/dist/commands/contract.command.d.ts +3 -0
- package/dist/commands/contract.command.d.ts.map +1 -0
- package/dist/commands/contract.command.js +105 -0
- package/dist/commands/conventions.command.d.ts +8 -0
- package/dist/commands/conventions.command.d.ts.map +1 -0
- package/dist/commands/conventions.command.js +169 -0
- package/dist/commands/coverage.command.d.ts +3 -0
- package/dist/commands/coverage.command.d.ts.map +1 -0
- package/dist/commands/coverage.command.js +56 -0
- package/dist/commands/daily.commands.d.ts +5 -0
- package/dist/commands/daily.commands.d.ts.map +1 -0
- package/dist/commands/daily.commands.js +224 -0
- package/dist/commands/dashboard-export.command.d.ts +4 -0
- package/dist/commands/dashboard-export.command.d.ts.map +1 -0
- package/dist/commands/dashboard-export.command.js +86 -0
- package/dist/commands/dashboard.command.d.ts +3 -0
- package/dist/commands/dashboard.command.d.ts.map +1 -0
- package/dist/commands/dashboard.command.js +106 -0
- package/dist/commands/dev.command.d.ts +3 -0
- package/dist/commands/dev.command.d.ts.map +1 -0
- package/dist/commands/dev.command.js +1392 -0
- package/dist/commands/diagnostics.command.d.ts +5 -0
- package/dist/commands/diagnostics.command.d.ts.map +1 -0
- package/dist/commands/diagnostics.command.js +97 -0
- package/dist/commands/docs.command.d.ts +4 -0
- package/dist/commands/docs.command.d.ts.map +1 -0
- package/dist/commands/docs.command.js +34 -0
- package/dist/commands/doctor.command.d.ts +7 -0
- package/dist/commands/doctor.command.d.ts.map +1 -0
- package/dist/commands/doctor.command.js +682 -0
- package/dist/commands/drift.command.d.ts +3 -0
- package/dist/commands/drift.command.d.ts.map +1 -0
- package/dist/commands/drift.command.js +124 -0
- package/dist/commands/eslint.command.d.ts +7 -0
- package/dist/commands/eslint.command.d.ts.map +1 -0
- package/dist/commands/eslint.command.js +423 -0
- package/dist/commands/explore.command.d.ts +3 -0
- package/dist/commands/explore.command.d.ts.map +1 -0
- package/dist/commands/explore.command.js +65 -0
- package/dist/commands/export-bundle.command.d.ts +6 -0
- package/dist/commands/export-bundle.command.d.ts.map +1 -0
- package/dist/commands/export-bundle.command.js +96 -0
- package/dist/commands/export.command.d.ts +3 -0
- package/dist/commands/export.command.d.ts.map +1 -0
- package/dist/commands/export.command.js +83 -0
- package/dist/commands/feedback-dispatch.command.d.ts +12 -0
- package/dist/commands/feedback-dispatch.command.d.ts.map +1 -0
- package/dist/commands/feedback-dispatch.command.js +63 -0
- package/dist/commands/feedback.command.d.ts +11 -0
- package/dist/commands/feedback.command.d.ts.map +1 -0
- package/dist/commands/feedback.command.js +336 -0
- package/dist/commands/fix.command.d.ts +3 -0
- package/dist/commands/fix.command.d.ts.map +1 -0
- package/dist/commands/fix.command.js +776 -0
- package/dist/commands/gen.command.d.ts +3 -0
- package/dist/commands/gen.command.d.ts.map +1 -0
- package/dist/commands/gen.command.js +136 -0
- package/dist/commands/git.command.d.ts +6 -0
- package/dist/commands/git.command.d.ts.map +1 -0
- package/dist/commands/git.command.js +81 -0
- package/dist/commands/graph.command.d.ts +3 -0
- package/dist/commands/graph.command.d.ts.map +1 -0
- package/dist/commands/graph.command.js +287 -0
- package/dist/commands/grounding.command.d.ts +7 -0
- package/dist/commands/grounding.command.d.ts.map +1 -0
- package/dist/commands/grounding.command.js +54 -0
- package/dist/commands/help.command.d.ts +20 -0
- package/dist/commands/help.command.d.ts.map +1 -0
- package/dist/commands/help.command.js +129 -0
- package/dist/commands/helper.command.d.ts +6 -0
- package/dist/commands/helper.command.d.ts.map +1 -0
- package/dist/commands/helper.command.js +170 -0
- package/dist/commands/ide.command.d.ts +6 -0
- package/dist/commands/ide.command.d.ts.map +1 -0
- package/dist/commands/ide.command.js +340 -0
- package/dist/commands/impact.command.d.ts +3 -0
- package/dist/commands/impact.command.d.ts.map +1 -0
- package/dist/commands/impact.command.js +819 -0
- package/dist/commands/import.command.d.ts +3 -0
- package/dist/commands/import.command.d.ts.map +1 -0
- package/dist/commands/import.command.js +115 -0
- package/dist/commands/infer.command.d.ts +3 -0
- package/dist/commands/infer.command.d.ts.map +1 -0
- package/dist/commands/infer.command.js +227 -0
- package/dist/commands/ingest.command.d.ts +6 -0
- package/dist/commands/ingest.command.d.ts.map +1 -0
- package/dist/commands/ingest.command.js +532 -0
- package/dist/commands/init.command.d.ts +3 -0
- package/dist/commands/init.command.d.ts.map +1 -0
- package/dist/commands/init.command.js +300 -0
- package/dist/commands/inspect.command.d.ts +3 -0
- package/dist/commands/inspect.command.d.ts.map +1 -0
- package/dist/commands/inspect.command.js +122 -0
- package/dist/commands/knowledge-author.command.d.ts +22 -0
- package/dist/commands/knowledge-author.command.d.ts.map +1 -0
- package/dist/commands/knowledge-author.command.js +366 -0
- package/dist/commands/knowledge-propose.command.d.ts +3 -0
- package/dist/commands/knowledge-propose.command.d.ts.map +1 -0
- package/dist/commands/knowledge-propose.command.js +125 -0
- package/dist/commands/knowledge.command.d.ts +18 -0
- package/dist/commands/knowledge.command.d.ts.map +1 -0
- package/dist/commands/knowledge.command.js +538 -0
- package/dist/commands/languages.command.d.ts +3 -0
- package/dist/commands/languages.command.d.ts.map +1 -0
- package/dist/commands/languages.command.js +300 -0
- package/dist/commands/lint.command.d.ts +15 -0
- package/dist/commands/lint.command.d.ts.map +1 -0
- package/dist/commands/lint.command.js +194 -0
- package/dist/commands/mcp.command.d.ts +3 -0
- package/dist/commands/mcp.command.d.ts.map +1 -0
- package/dist/commands/mcp.command.js +203 -0
- package/dist/commands/memory.command.d.ts +11 -0
- package/dist/commands/memory.command.d.ts.map +1 -0
- package/dist/commands/memory.command.js +264 -0
- package/dist/commands/onboard.command.d.ts +3 -0
- package/dist/commands/onboard.command.d.ts.map +1 -0
- package/dist/commands/onboard.command.js +662 -0
- package/dist/commands/orchestrate.command.d.ts +3 -0
- package/dist/commands/orchestrate.command.d.ts.map +1 -0
- package/dist/commands/orchestrate.command.js +49 -0
- package/dist/commands/owners.command.d.ts +5 -0
- package/dist/commands/owners.command.d.ts.map +1 -0
- package/dist/commands/owners.command.js +113 -0
- package/dist/commands/ownership.command.d.ts +5 -0
- package/dist/commands/ownership.command.d.ts.map +1 -0
- package/dist/commands/ownership.command.js +117 -0
- package/dist/commands/pack-author.command.d.ts +30 -0
- package/dist/commands/pack-author.command.d.ts.map +1 -0
- package/dist/commands/pack-author.command.js +242 -0
- package/dist/commands/packs-new.d.ts +27 -0
- package/dist/commands/packs-new.d.ts.map +1 -0
- package/dist/commands/packs-new.js +805 -0
- package/dist/commands/packs.command.d.ts +15 -0
- package/dist/commands/packs.command.d.ts.map +1 -0
- package/dist/commands/packs.command.js +964 -0
- package/dist/commands/paths.command.d.ts +6 -0
- package/dist/commands/paths.command.d.ts.map +1 -0
- package/dist/commands/paths.command.js +97 -0
- package/dist/commands/pipelines.command.d.ts +9 -0
- package/dist/commands/pipelines.command.d.ts.map +1 -0
- package/dist/commands/pipelines.command.js +308 -0
- package/dist/commands/plan-check.command.d.ts +27 -0
- package/dist/commands/plan-check.command.d.ts.map +1 -0
- package/dist/commands/plan-check.command.js +150 -0
- package/dist/commands/plan-simulate.command.d.ts +3 -0
- package/dist/commands/plan-simulate.command.d.ts.map +1 -0
- package/dist/commands/plan-simulate.command.js +60 -0
- package/dist/commands/plan.command.d.ts +8 -0
- package/dist/commands/plan.command.d.ts.map +1 -0
- package/dist/commands/plan.command.js +139 -0
- package/dist/commands/playbooks.command.d.ts +10 -0
- package/dist/commands/playbooks.command.d.ts.map +1 -0
- package/dist/commands/playbooks.command.js +296 -0
- package/dist/commands/plugin.command.d.ts +11 -0
- package/dist/commands/plugin.command.d.ts.map +1 -0
- package/dist/commands/plugin.command.js +394 -0
- package/dist/commands/policy.command.d.ts +8 -0
- package/dist/commands/policy.command.d.ts.map +1 -0
- package/dist/commands/policy.command.js +451 -0
- package/dist/commands/pr.command.d.ts +3 -0
- package/dist/commands/pr.command.d.ts.map +1 -0
- package/dist/commands/pr.command.js +132 -0
- package/dist/commands/preflight.command.d.ts +3 -0
- package/dist/commands/preflight.command.d.ts.map +1 -0
- package/dist/commands/preflight.command.js +102 -0
- package/dist/commands/presets.command.d.ts +17 -0
- package/dist/commands/presets.command.d.ts.map +1 -0
- package/dist/commands/presets.command.js +647 -0
- package/dist/commands/profiles.command.d.ts +7 -0
- package/dist/commands/profiles.command.d.ts.map +1 -0
- package/dist/commands/profiles.command.js +151 -0
- package/dist/commands/provenance.command.d.ts +26 -0
- package/dist/commands/provenance.command.d.ts.map +1 -0
- package/dist/commands/provenance.command.js +237 -0
- package/dist/commands/quality.command.d.ts +5 -0
- package/dist/commands/quality.command.d.ts.map +1 -0
- package/dist/commands/quality.command.js +69 -0
- package/dist/commands/recommend.command.d.ts +4 -0
- package/dist/commands/recommend.command.d.ts.map +1 -0
- package/dist/commands/recommend.command.js +270 -0
- package/dist/commands/registrations.command.d.ts +3 -0
- package/dist/commands/registrations.command.d.ts.map +1 -0
- package/dist/commands/registrations.command.js +300 -0
- package/dist/commands/registry.command.d.ts +4 -0
- package/dist/commands/registry.command.d.ts.map +1 -0
- package/dist/commands/registry.command.js +37 -0
- package/dist/commands/release.command.d.ts +4 -0
- package/dist/commands/release.command.d.ts.map +1 -0
- package/dist/commands/release.command.js +639 -0
- package/dist/commands/repo.command.d.ts +3 -0
- package/dist/commands/repo.command.d.ts.map +1 -0
- package/dist/commands/repo.command.js +24 -0
- package/dist/commands/report.command.d.ts +3 -0
- package/dist/commands/report.command.d.ts.map +1 -0
- package/dist/commands/report.command.js +511 -0
- package/dist/commands/reposet.command.d.ts +6 -0
- package/dist/commands/reposet.command.d.ts.map +1 -0
- package/dist/commands/reposet.command.js +120 -0
- package/dist/commands/review.command.d.ts +3 -0
- package/dist/commands/review.command.d.ts.map +1 -0
- package/dist/commands/review.command.js +380 -0
- package/dist/commands/risk.command.d.ts +3 -0
- package/dist/commands/risk.command.d.ts.map +1 -0
- package/dist/commands/risk.command.js +56 -0
- package/dist/commands/rounds.command.d.ts +8 -0
- package/dist/commands/rounds.command.d.ts.map +1 -0
- package/dist/commands/rounds.command.js +180 -0
- package/dist/commands/rules.command.d.ts +49 -0
- package/dist/commands/rules.command.d.ts.map +1 -0
- package/dist/commands/rules.command.js +435 -0
- package/dist/commands/runtime.command.d.ts +3 -0
- package/dist/commands/runtime.command.d.ts.map +1 -0
- package/dist/commands/runtime.command.js +56 -0
- package/dist/commands/safety.command.d.ts +3 -0
- package/dist/commands/safety.command.d.ts.map +1 -0
- package/dist/commands/safety.command.js +117 -0
- package/dist/commands/scaffolds.command.d.ts +5 -0
- package/dist/commands/scaffolds.command.d.ts.map +1 -0
- package/dist/commands/scaffolds.command.js +122 -0
- package/dist/commands/schemas.command.d.ts +21 -0
- package/dist/commands/schemas.command.d.ts.map +1 -0
- package/dist/commands/schemas.command.js +296 -0
- package/dist/commands/search.command.d.ts +12 -0
- package/dist/commands/search.command.d.ts.map +1 -0
- package/dist/commands/search.command.js +275 -0
- package/dist/commands/self-config.command.d.ts +7 -0
- package/dist/commands/self-config.command.d.ts.map +1 -0
- package/dist/commands/self-config.command.js +156 -0
- package/dist/commands/self.command.d.ts +3 -0
- package/dist/commands/self.command.d.ts.map +1 -0
- package/dist/commands/self.command.js +117 -0
- package/dist/commands/simulate.command.d.ts +3 -0
- package/dist/commands/simulate.command.d.ts.map +1 -0
- package/dist/commands/simulate.command.js +54 -0
- package/dist/commands/spec.command.d.ts +29 -0
- package/dist/commands/spec.command.d.ts.map +1 -0
- package/dist/commands/spec.command.js +985 -0
- package/dist/commands/start-here.command.d.ts +3 -0
- package/dist/commands/start-here.command.d.ts.map +1 -0
- package/dist/commands/start-here.command.js +35 -0
- package/dist/commands/stats.command.d.ts +3 -0
- package/dist/commands/stats.command.d.ts.map +1 -0
- package/dist/commands/stats.command.js +88 -0
- package/dist/commands/surface.command.d.ts +15 -0
- package/dist/commands/surface.command.d.ts.map +1 -0
- package/dist/commands/surface.command.js +328 -0
- package/dist/commands/task-context.command.d.ts +7 -0
- package/dist/commands/task-context.command.d.ts.map +1 -0
- package/dist/commands/task-context.command.js +646 -0
- package/dist/commands/task.command.d.ts +3 -0
- package/dist/commands/task.command.d.ts.map +1 -0
- package/dist/commands/task.command.js +301 -0
- package/dist/commands/template-quality.command.d.ts +5 -0
- package/dist/commands/template-quality.command.d.ts.map +1 -0
- package/dist/commands/template-quality.command.js +128 -0
- package/dist/commands/templates.command.d.ts +26 -0
- package/dist/commands/templates.command.d.ts.map +1 -0
- package/dist/commands/templates.command.js +964 -0
- package/dist/commands/test.command.d.ts +3 -0
- package/dist/commands/test.command.d.ts.map +1 -0
- package/dist/commands/test.command.js +262 -0
- package/dist/commands/tests.command.d.ts +5 -0
- package/dist/commands/tests.command.d.ts.map +1 -0
- package/dist/commands/tests.command.js +97 -0
- package/dist/commands/trace.command.d.ts +3 -0
- package/dist/commands/trace.command.d.ts.map +1 -0
- package/dist/commands/trace.command.js +121 -0
- package/dist/commands/upgrade.command.d.ts +4 -0
- package/dist/commands/upgrade.command.d.ts.map +1 -0
- package/dist/commands/upgrade.command.js +43 -0
- package/dist/commands/version.command.d.ts +3 -0
- package/dist/commands/version.command.d.ts.map +1 -0
- package/dist/commands/version.command.js +10 -0
- package/dist/commands/why.command.d.ts +24 -0
- package/dist/commands/why.command.d.ts.map +1 -0
- package/dist/commands/why.command.js +119 -0
- package/dist/dashboard/dashboard-api-server.d.ts +21 -0
- package/dist/dashboard/dashboard-api-server.d.ts.map +1 -0
- package/dist/dashboard/dashboard-api-server.js +410 -0
- package/dist/dashboard/live-session-server.d.ts +18 -0
- package/dist/dashboard/live-session-server.d.ts.map +1 -0
- package/dist/dashboard/live-session-server.js +133 -0
- package/dist/diff/collect-changed-paths.d.ts +27 -0
- package/dist/diff/collect-changed-paths.d.ts.map +1 -0
- package/dist/diff/collect-changed-paths.js +68 -0
- package/dist/doctor/doctor-tags.d.ts +63 -0
- package/dist/doctor/doctor-tags.d.ts.map +1 -0
- package/dist/doctor/doctor-tags.js +146 -0
- package/dist/export/export-formats.d.ts +22 -0
- package/dist/export/export-formats.d.ts.map +1 -0
- package/dist/export/export-formats.js +135 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/init/detected-block.d.ts +57 -0
- package/dist/init/detected-block.d.ts.map +1 -0
- package/dist/init/detected-block.js +197 -0
- package/dist/init/gitignore.d.ts +30 -0
- package/dist/init/gitignore.d.ts.map +1 -0
- package/dist/init/gitignore.js +110 -0
- package/dist/init/init-templates.d.ts +6 -0
- package/dist/init/init-templates.d.ts.map +1 -0
- package/dist/init/init-templates.js +413 -0
- package/dist/main.d.ts +18 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +721 -0
- package/dist/output/failure-hints.d.ts +63 -0
- package/dist/output/failure-hints.d.ts.map +1 -0
- package/dist/output/failure-hints.js +165 -0
- package/dist/output/format-output.d.ts +9 -0
- package/dist/output/format-output.d.ts.map +1 -0
- package/dist/output/format-output.js +26 -0
- package/dist/output/print-error.d.ts +3 -0
- package/dist/output/print-error.d.ts.map +1 -0
- package/dist/output/print-error.js +14 -0
- package/dist/output/watch-loop.d.ts +37 -0
- package/dist/output/watch-loop.d.ts.map +1 -0
- package/dist/output/watch-loop.js +115 -0
- package/dist/schemas/json-schemas.d.ts +1630 -0
- package/dist/schemas/json-schemas.d.ts.map +1 -0
- package/dist/schemas/json-schemas.js +811 -0
- package/dist/surface/about.d.ts +10 -0
- package/dist/surface/about.d.ts.map +1 -0
- package/dist/surface/about.js +31 -0
- package/dist/surface/load-surface-context.d.ts +34 -0
- package/dist/surface/load-surface-context.d.ts.map +1 -0
- package/dist/surface/load-surface-context.js +100 -0
- package/dist/surface/no-args-landing.d.ts +7 -0
- package/dist/surface/no-args-landing.d.ts.map +1 -0
- package/dist/surface/no-args-landing.js +40 -0
- package/dist/surface/not-enabled-error.d.ts +24 -0
- package/dist/surface/not-enabled-error.d.ts.map +1 -0
- package/dist/surface/not-enabled-error.js +36 -0
- package/dist/surface/profiles.d.ts +37 -0
- package/dist/surface/profiles.d.ts.map +1 -0
- package/dist/surface/profiles.js +151 -0
- package/dist/surface/shape-defaults.d.ts +21 -0
- package/dist/surface/shape-defaults.d.ts.map +1 -0
- package/dist/surface/shape-defaults.js +50 -0
- package/dist/surface/spine-extractor.d.ts +38 -0
- package/dist/surface/spine-extractor.d.ts.map +1 -0
- package/dist/surface/spine-extractor.js +100 -0
- package/dist/surface/surface-config-writer.d.ts +59 -0
- package/dist/surface/surface-config-writer.d.ts.map +1 -0
- package/dist/surface/surface-config-writer.js +135 -0
- package/dist/surface/surface-summary.d.ts +66 -0
- package/dist/surface/surface-summary.d.ts.map +1 -0
- package/dist/surface/surface-summary.js +162 -0
- package/dist/surface/tier.d.ts +100 -0
- package/dist/surface/tier.d.ts.map +1 -0
- package/dist/surface/tier.js +172 -0
- package/dist/task-next/apply-batch-runner.d.ts +42 -0
- package/dist/task-next/apply-batch-runner.d.ts.map +1 -0
- package/dist/task-next/apply-batch-runner.js +192 -0
- package/dist/task-next/task-next-ranker.d.ts +75 -0
- package/dist/task-next/task-next-ranker.d.ts.map +1 -0
- package/dist/task-next/task-next-ranker.js +179 -0
- package/dist/usage/usage-log.d.ts +54 -0
- package/dist/usage/usage-log.d.ts.map +1 -0
- package/dist/usage/usage-log.js +105 -0
- package/dist/validation/run-validation-loop.d.ts +38 -0
- package/dist/validation/run-validation-loop.d.ts.map +1 -0
- package/dist/validation/run-validation-loop.js +100 -0
- package/package.json +72 -0
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import * as nodePath from 'node:path';
|
|
3
|
+
import { AssetKind, AssetProvenanceOperation, AssetProvenanceSource, buildTemplateAuthoringPreview, buildTemplateDriftReport, inspectSharkcraft, recordProvenance, TemplateAuthoringOperation, TemplateDriftStatus, } from '@shrkcrft/inspector';
|
|
4
|
+
import { detectAuthoringSource, multiFlagValues, writeAuthoringDrafts, } from "../authoring/authoring-kit.js";
|
|
5
|
+
import { applyTemplateUpdate } from "../asset-preview/apply-template-update.js";
|
|
6
|
+
import { previewTemplate } from '@shrkcrft/templates';
|
|
7
|
+
import { buildNameVariables } from '@shrkcrft/generator';
|
|
8
|
+
import { flagBool, flagList, flagString, flagVars, resolveCwd, } from "../command-registry.js";
|
|
9
|
+
import { asJson, header, kv } from "../output/format-output.js";
|
|
10
|
+
import { maybeRunInWatchMode } from "../output/watch-loop.js";
|
|
11
|
+
import { renderFailureHints, templateDriftHints } from "../output/failure-hints.js";
|
|
12
|
+
export const templatesVarsCommand = {
|
|
13
|
+
name: 'vars',
|
|
14
|
+
description: 'Show the variables a template accepts (required/optional/defaults/examples).',
|
|
15
|
+
usage: 'shrk [--cwd <dir>] templates vars <templateId> [--json]',
|
|
16
|
+
async run(args) {
|
|
17
|
+
const id = args.positional[0];
|
|
18
|
+
if (!id) {
|
|
19
|
+
process.stderr.write('Usage: shrk templates vars <templateId>\n');
|
|
20
|
+
return 2;
|
|
21
|
+
}
|
|
22
|
+
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
23
|
+
const template = inspection.templateRegistry.get(id);
|
|
24
|
+
if (!template) {
|
|
25
|
+
process.stderr.write(`No template with id "${id}".\n`);
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
if (flagBool(args, 'json')) {
|
|
29
|
+
process.stdout.write(asJson({
|
|
30
|
+
id: template.id,
|
|
31
|
+
name: template.name,
|
|
32
|
+
description: template.description,
|
|
33
|
+
variables: template.variables.map((v) => ({
|
|
34
|
+
name: v.name,
|
|
35
|
+
required: v.required ?? false,
|
|
36
|
+
description: v.description ?? '',
|
|
37
|
+
default: v.default,
|
|
38
|
+
choices: v.choices ?? [],
|
|
39
|
+
examples: v.examples ?? [],
|
|
40
|
+
pattern: v.pattern ? v.pattern.source : undefined,
|
|
41
|
+
})),
|
|
42
|
+
}) + '\n');
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
process.stdout.write(header(`Template variables: ${template.id}`));
|
|
46
|
+
process.stdout.write(kv('name', template.name) + '\n');
|
|
47
|
+
process.stdout.write(kv('description', template.description) + '\n\n');
|
|
48
|
+
if (template.variables.length === 0) {
|
|
49
|
+
process.stdout.write('(no variables)\n');
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
for (const v of template.variables) {
|
|
53
|
+
const tag = v.required ? '*required' : ' optional';
|
|
54
|
+
process.stdout.write(` ${tag} ${v.name}\n`);
|
|
55
|
+
if (v.description)
|
|
56
|
+
process.stdout.write(` ${v.description}\n`);
|
|
57
|
+
if (v.default)
|
|
58
|
+
process.stdout.write(` default: ${v.default}\n`);
|
|
59
|
+
if (v.choices?.length) {
|
|
60
|
+
process.stdout.write(` choices: ${v.choices.join(', ')}\n`);
|
|
61
|
+
}
|
|
62
|
+
if (v.examples?.length) {
|
|
63
|
+
process.stdout.write(` examples: ${v.examples.join(', ')}\n`);
|
|
64
|
+
}
|
|
65
|
+
if (v.pattern)
|
|
66
|
+
process.stdout.write(` pattern: ${v.pattern.source}\n`);
|
|
67
|
+
}
|
|
68
|
+
const exampleVars = template.variables
|
|
69
|
+
.map((v) => `--var ${v.name}=${v.examples?.[0] ?? v.default ?? '<value>'}`)
|
|
70
|
+
.join(' ');
|
|
71
|
+
process.stdout.write(`\nExample:\n $ shrk gen ${template.id} <name> ${exampleVars} --dry-run\n`);
|
|
72
|
+
return 0;
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
export const templatesListCommand = {
|
|
76
|
+
name: 'list',
|
|
77
|
+
description: 'List available templates.',
|
|
78
|
+
usage: 'shrk templates list [--json]',
|
|
79
|
+
async run(args) {
|
|
80
|
+
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
81
|
+
const list = inspection.templateRegistry.list();
|
|
82
|
+
if (flagBool(args, 'json')) {
|
|
83
|
+
process.stdout.write(asJson(list.map((t) => ({ id: t.id, name: t.name, description: t.description, tags: t.tags }))) + '\n');
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
process.stdout.write(header(`Templates (${list.length})`));
|
|
87
|
+
for (const t of list) {
|
|
88
|
+
process.stdout.write(` ${t.id.padEnd(28)} — ${t.name}\n`);
|
|
89
|
+
process.stdout.write(` ${t.description}\n`);
|
|
90
|
+
if (t.tags.length)
|
|
91
|
+
process.stdout.write(` tags: ${t.tags.join(', ')}\n`);
|
|
92
|
+
}
|
|
93
|
+
return 0;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
export const templatesGetCommand = {
|
|
97
|
+
name: 'get',
|
|
98
|
+
description: 'Show one template.',
|
|
99
|
+
usage: 'shrk templates get <id> [--json]',
|
|
100
|
+
async run(args) {
|
|
101
|
+
const id = args.positional[0];
|
|
102
|
+
if (!id) {
|
|
103
|
+
process.stderr.write('Usage: shrk templates get <id>\n');
|
|
104
|
+
return 2;
|
|
105
|
+
}
|
|
106
|
+
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
107
|
+
const template = inspection.templateRegistry.get(id);
|
|
108
|
+
if (!template) {
|
|
109
|
+
process.stderr.write(`No template with id "${id}".\n`);
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
if (flagBool(args, 'json')) {
|
|
113
|
+
const safe = {
|
|
114
|
+
id: template.id,
|
|
115
|
+
name: template.name,
|
|
116
|
+
description: template.description,
|
|
117
|
+
tags: template.tags,
|
|
118
|
+
scope: template.scope,
|
|
119
|
+
appliesWhen: template.appliesWhen,
|
|
120
|
+
variables: template.variables,
|
|
121
|
+
postGenerationNotes: template.postGenerationNotes ?? [],
|
|
122
|
+
related: template.related ?? [],
|
|
123
|
+
};
|
|
124
|
+
process.stdout.write(asJson(safe) + '\n');
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
process.stdout.write(header(`Template: ${template.id}`));
|
|
128
|
+
process.stdout.write(`Name: ${template.name}\n`);
|
|
129
|
+
process.stdout.write(`Description: ${template.description}\n`);
|
|
130
|
+
if (template.tags.length)
|
|
131
|
+
process.stdout.write(`Tags: ${template.tags.join(', ')}\n`);
|
|
132
|
+
if (template.scope.length)
|
|
133
|
+
process.stdout.write(`Scope: ${template.scope.join(', ')}\n`);
|
|
134
|
+
if (template.appliesWhen.length)
|
|
135
|
+
process.stdout.write(`appliesWhen: ${template.appliesWhen.join(', ')}\n`);
|
|
136
|
+
if (template.variables.length) {
|
|
137
|
+
process.stdout.write(`Variables:\n`);
|
|
138
|
+
for (const v of template.variables) {
|
|
139
|
+
process.stdout.write(` - ${v.name}${v.required ? ' (required)' : ''}${v.default ? ` = ${v.default}` : ''}${v.description ? ` — ${v.description}` : ''}\n`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return 0;
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
export const templatesSearchCommand = {
|
|
146
|
+
name: 'search',
|
|
147
|
+
description: 'Search templates.',
|
|
148
|
+
usage: 'shrk templates search <query>',
|
|
149
|
+
async run(args) {
|
|
150
|
+
const query = args.positional.join(' ');
|
|
151
|
+
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
152
|
+
const results = inspection.templateRegistry.search(query);
|
|
153
|
+
if (flagBool(args, 'json')) {
|
|
154
|
+
process.stdout.write(asJson(results.map((t) => ({ id: t.id, name: t.name, description: t.description }))) + '\n');
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
process.stdout.write(header(`Templates (${results.length})`));
|
|
158
|
+
for (const t of results)
|
|
159
|
+
process.stdout.write(` ${t.id.padEnd(28)} — ${t.name}\n`);
|
|
160
|
+
return 0;
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
export const templatesPreviewCommand = {
|
|
164
|
+
name: 'preview',
|
|
165
|
+
description: 'Render a template preview without writing files.',
|
|
166
|
+
usage: 'shrk templates preview <id> [--var key=value ...] [<name>]',
|
|
167
|
+
async run(args) {
|
|
168
|
+
const id = args.positional[0];
|
|
169
|
+
const maybeName = args.positional[1];
|
|
170
|
+
if (!id) {
|
|
171
|
+
process.stderr.write('Usage: shrk templates preview <id> [--var key=value ...]\n');
|
|
172
|
+
return 2;
|
|
173
|
+
}
|
|
174
|
+
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
175
|
+
const template = inspection.templateRegistry.get(id);
|
|
176
|
+
if (!template) {
|
|
177
|
+
process.stderr.write(`No template with id "${id}".\n`);
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
const nameVars = maybeName ? buildNameVariables(maybeName) : {};
|
|
181
|
+
const values = { ...nameVars, ...flagVars(args) };
|
|
182
|
+
const preview = previewTemplate(template, values);
|
|
183
|
+
if (flagBool(args, 'json')) {
|
|
184
|
+
process.stdout.write(asJson(preview) + '\n');
|
|
185
|
+
return preview.validation.valid && preview.rendered ? 0 : 1;
|
|
186
|
+
}
|
|
187
|
+
if (!preview.validation.valid) {
|
|
188
|
+
process.stderr.write('Variable validation failed:\n');
|
|
189
|
+
for (const issue of preview.validation.issues) {
|
|
190
|
+
process.stderr.write(` - ${issue.variable}: ${issue.message}\n`);
|
|
191
|
+
}
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
process.stdout.write(header(`Template preview: ${template.id}`));
|
|
195
|
+
for (const f of preview.rendered.files) {
|
|
196
|
+
process.stdout.write(`\n--- ${f.targetPath} ---\n`);
|
|
197
|
+
process.stdout.write(f.content);
|
|
198
|
+
if (!f.content.endsWith('\n'))
|
|
199
|
+
process.stdout.write('\n');
|
|
200
|
+
}
|
|
201
|
+
if (preview.rendered.postGenerationNotes.length) {
|
|
202
|
+
process.stdout.write('\nPost-generation notes:\n');
|
|
203
|
+
for (const note of preview.rendered.postGenerationNotes) {
|
|
204
|
+
process.stdout.write(` • ${note}\n`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return 0;
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
export const templatesDriftCommand = {
|
|
211
|
+
name: 'drift',
|
|
212
|
+
description: 'Verify every registered template against the workspace. Severity controls and `--watch [--once] [--debounce N]` supported. Read-only.',
|
|
213
|
+
usage: 'shrk templates drift [--template <id>] [--pack <packId>] [--var key=value ...] [--min-severity error|warning|info] [--hide <code>[,<code>...]] [--strict] [--ci] [--format text|markdown|html|json] [--report] [--output <path>] [--json] [--watch [--once] [--debounce N]]',
|
|
214
|
+
async run(args) {
|
|
215
|
+
const watchExit = await maybeRunInWatchMode(args, templatesDriftImpl);
|
|
216
|
+
if (watchExit !== null)
|
|
217
|
+
return watchExit;
|
|
218
|
+
return templatesDriftImpl(args);
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
async function templatesDriftImpl(args) {
|
|
222
|
+
const cwd = resolveCwd(args);
|
|
223
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
224
|
+
const report = buildTemplateDriftReport(inspection, {
|
|
225
|
+
...(flagString(args, 'template') ? { templateId: flagString(args, 'template') } : {}),
|
|
226
|
+
...(flagString(args, 'pack') ? { packId: flagString(args, 'pack') } : {}),
|
|
227
|
+
sampleVars: flagVars(args),
|
|
228
|
+
});
|
|
229
|
+
// Severity + hide + strict + ci controls.
|
|
230
|
+
const minSeverityRaw = (flagString(args, 'min-severity') ?? '').toLowerCase();
|
|
231
|
+
const hideCodes = new Set((flagString(args, 'hide') ?? '')
|
|
232
|
+
.split(',')
|
|
233
|
+
.map((s) => s.trim())
|
|
234
|
+
.filter(Boolean));
|
|
235
|
+
const strict = flagBool(args, 'strict');
|
|
236
|
+
const ci = flagBool(args, 'ci');
|
|
237
|
+
const formatRaw = (flagString(args, 'format') ?? '').toLowerCase();
|
|
238
|
+
const wantJson = flagBool(args, 'json') || formatRaw === 'json';
|
|
239
|
+
const wantMarkdown = formatRaw === 'markdown' || formatRaw === 'md';
|
|
240
|
+
const wantHtml = formatRaw === 'html';
|
|
241
|
+
const wantReport = flagBool(args, 'report');
|
|
242
|
+
const output = flagString(args, 'output');
|
|
243
|
+
const severityRank = { info: 1, warning: 2, error: 3 };
|
|
244
|
+
const minRank = severityRank[minSeverityRaw] ?? 1;
|
|
245
|
+
// Filter / re-classify issues per template entry.
|
|
246
|
+
const filteredEntries = report.entries.map((e) => {
|
|
247
|
+
const issues = e.issues.filter((i) => {
|
|
248
|
+
if (hideCodes.has(i.code))
|
|
249
|
+
return false;
|
|
250
|
+
const rank = severityRank[i.severity] ?? 1;
|
|
251
|
+
return rank >= minRank;
|
|
252
|
+
});
|
|
253
|
+
// Strict mode upgrades warnings → errors for the purpose of exit code.
|
|
254
|
+
const effectiveIssues = strict
|
|
255
|
+
? issues.map((i) => (i.severity === 'warning' ? { ...i, severity: 'error' } : i))
|
|
256
|
+
: issues;
|
|
257
|
+
const status = effectiveIssues.some((i) => i.severity === 'error')
|
|
258
|
+
? TemplateDriftStatus.Fail
|
|
259
|
+
: effectiveIssues.some((i) => i.severity === 'warning')
|
|
260
|
+
? TemplateDriftStatus.Warn
|
|
261
|
+
: TemplateDriftStatus.Pass;
|
|
262
|
+
return { ...e, issues: effectiveIssues, status };
|
|
263
|
+
});
|
|
264
|
+
let filteredPass = 0;
|
|
265
|
+
let filteredWarn = 0;
|
|
266
|
+
let filteredFail = 0;
|
|
267
|
+
for (const e of filteredEntries) {
|
|
268
|
+
if (e.status === TemplateDriftStatus.Pass)
|
|
269
|
+
filteredPass++;
|
|
270
|
+
else if (e.status === TemplateDriftStatus.Warn)
|
|
271
|
+
filteredWarn++;
|
|
272
|
+
else
|
|
273
|
+
filteredFail++;
|
|
274
|
+
}
|
|
275
|
+
const ciPayload = {
|
|
276
|
+
...report,
|
|
277
|
+
entries: filteredEntries,
|
|
278
|
+
pass: filteredPass,
|
|
279
|
+
warn: filteredWarn,
|
|
280
|
+
fail: filteredFail,
|
|
281
|
+
ci: {
|
|
282
|
+
ci,
|
|
283
|
+
strict,
|
|
284
|
+
minSeverity: minSeverityRaw || 'info',
|
|
285
|
+
hideCodes: [...hideCodes],
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
const exitNonZero = ci
|
|
289
|
+
? filteredFail > 0 || (strict && filteredWarn > 0)
|
|
290
|
+
: filteredFail > 0;
|
|
291
|
+
if (wantReport || output) {
|
|
292
|
+
const reportsDir = nodePath.join(cwd, '.sharkcraft', 'reports');
|
|
293
|
+
mkdirSync(reportsDir, { recursive: true });
|
|
294
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
295
|
+
const outPath = output
|
|
296
|
+
? nodePath.isAbsolute(output)
|
|
297
|
+
? output
|
|
298
|
+
: nodePath.resolve(cwd, output)
|
|
299
|
+
: nodePath.join(reportsDir, `template-drift-${ts}.json`);
|
|
300
|
+
writeFileSync(outPath, JSON.stringify(ciPayload, null, 2), 'utf8');
|
|
301
|
+
if (!wantJson && !wantMarkdown && !wantHtml) {
|
|
302
|
+
process.stdout.write(`Wrote report → ${outPath}\n`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (wantJson) {
|
|
306
|
+
process.stdout.write(asJson(ciPayload) + '\n');
|
|
307
|
+
return exitNonZero ? 1 : 0;
|
|
308
|
+
}
|
|
309
|
+
if (wantMarkdown) {
|
|
310
|
+
process.stdout.write(renderDriftMarkdown(ciPayload));
|
|
311
|
+
return exitNonZero ? 1 : 0;
|
|
312
|
+
}
|
|
313
|
+
if (wantHtml) {
|
|
314
|
+
process.stdout.write(renderDriftHtml(ciPayload));
|
|
315
|
+
return exitNonZero ? 1 : 0;
|
|
316
|
+
}
|
|
317
|
+
process.stdout.write(header(`Template drift (${ciPayload.totalTemplates})`));
|
|
318
|
+
process.stdout.write(`pass=${ciPayload.pass} warn=${ciPayload.warn} fail=${ciPayload.fail}\n\n`);
|
|
319
|
+
for (const e of filteredEntries) {
|
|
320
|
+
if (e.issues.length === 0 && e.status === TemplateDriftStatus.Pass)
|
|
321
|
+
continue;
|
|
322
|
+
const tag = e.status === TemplateDriftStatus.Pass ? 'PASS' : e.status === TemplateDriftStatus.Warn ? 'WARN' : 'FAIL';
|
|
323
|
+
process.stdout.write(` ${tag.padEnd(5)} ${e.templateId}${e.templateName ? ` — ${e.templateName}` : ''}\n`);
|
|
324
|
+
for (const i of e.issues) {
|
|
325
|
+
process.stdout.write(` ${i.severity}: ${i.code} — ${i.message}\n`);
|
|
326
|
+
if (i.suggestedFix)
|
|
327
|
+
process.stdout.write(` ↳ ${i.suggestedFix}\n`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (exitNonZero) {
|
|
331
|
+
process.stdout.write(renderFailureHints(templateDriftHints()));
|
|
332
|
+
}
|
|
333
|
+
return exitNonZero ? 1 : 0;
|
|
334
|
+
}
|
|
335
|
+
function renderDriftMarkdown(p) {
|
|
336
|
+
const out = [];
|
|
337
|
+
out.push('# Template drift');
|
|
338
|
+
out.push('');
|
|
339
|
+
out.push(`- total: ${p.totalTemplates}`);
|
|
340
|
+
out.push(`- pass=${p.pass}, warn=${p.warn}, fail=${p.fail}`);
|
|
341
|
+
if (p.ci.minSeverity !== 'info' || p.ci.hideCodes.length > 0 || p.ci.strict) {
|
|
342
|
+
out.push(`- filters: min-severity=${p.ci.minSeverity}, strict=${p.ci.strict}, hide=[${p.ci.hideCodes.join(', ')}]`);
|
|
343
|
+
}
|
|
344
|
+
out.push('');
|
|
345
|
+
for (const e of p.entries) {
|
|
346
|
+
if (e.issues.length === 0 && e.status === TemplateDriftStatus.Pass)
|
|
347
|
+
continue;
|
|
348
|
+
const tag = e.status === TemplateDriftStatus.Pass ? 'PASS' : e.status === TemplateDriftStatus.Warn ? 'WARN' : 'FAIL';
|
|
349
|
+
out.push(`## ${tag} — \`${e.templateId}\`${e.templateName ? ` (${e.templateName})` : ''}`);
|
|
350
|
+
for (const i of e.issues) {
|
|
351
|
+
out.push(`- **${i.severity}** \`${i.code}\` — ${i.message}`);
|
|
352
|
+
if (i.suggestedFix)
|
|
353
|
+
out.push(` - ↳ ${i.suggestedFix}`);
|
|
354
|
+
}
|
|
355
|
+
out.push('');
|
|
356
|
+
}
|
|
357
|
+
return out.join('\n');
|
|
358
|
+
}
|
|
359
|
+
function renderDriftHtml(p) {
|
|
360
|
+
const esc = (s) => s.replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
|
|
361
|
+
const blocks = [];
|
|
362
|
+
for (const e of p.entries) {
|
|
363
|
+
if (e.issues.length === 0 && e.status === TemplateDriftStatus.Pass)
|
|
364
|
+
continue;
|
|
365
|
+
const items = e.issues
|
|
366
|
+
.map((i) => `<li><b>${esc(i.severity)}</b> <code>${esc(i.code)}</code> — ${esc(i.message)}${i.suggestedFix ? `<br><small>↳ ${esc(i.suggestedFix)}</small>` : ''}</li>`)
|
|
367
|
+
.join('');
|
|
368
|
+
blocks.push(`<section><h2>${esc(e.status)} — <code>${esc(e.templateId)}</code></h2><ul>${items}</ul></section>`);
|
|
369
|
+
}
|
|
370
|
+
return `<!doctype html><meta charset="utf-8"><title>Template drift</title>
|
|
371
|
+
<style>body{font:14px/1.4 sans-serif;margin:1rem}h2{margin-top:1rem}code{background:#f6f8fa;padding:0 .25rem}</style>
|
|
372
|
+
<h1>Template drift</h1>
|
|
373
|
+
<p>total=${p.totalTemplates}, pass=${p.pass}, warn=${p.warn}, fail=${p.fail}</p>
|
|
374
|
+
${blocks.join('')}
|
|
375
|
+
`;
|
|
376
|
+
}
|
|
377
|
+
export const templatesVerifyPathsCommand = {
|
|
378
|
+
name: 'verify-paths',
|
|
379
|
+
description: 'Verify template sample paths against registered path conventions. Subset of `templates drift`.',
|
|
380
|
+
usage: 'shrk templates verify-paths [--template <id>] [--json]',
|
|
381
|
+
async run(args) {
|
|
382
|
+
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
383
|
+
const report = buildTemplateDriftReport(inspection, {
|
|
384
|
+
...(flagString(args, 'template') ? { templateId: flagString(args, 'template') } : {}),
|
|
385
|
+
});
|
|
386
|
+
const filtered = report.entries.filter((e) => e.issues.some((i) => i.code === 'forbidden-legacy-path' || i.code === 'path-no-convention'));
|
|
387
|
+
if (flagBool(args, 'json')) {
|
|
388
|
+
process.stdout.write(asJson({ entries: filtered }) + '\n');
|
|
389
|
+
return filtered.some((e) => e.issues.some((i) => i.severity === 'error')) ? 1 : 0;
|
|
390
|
+
}
|
|
391
|
+
process.stdout.write(header(`Template path verification (${filtered.length})`));
|
|
392
|
+
if (filtered.length === 0) {
|
|
393
|
+
process.stdout.write(' all templates align with path conventions.\n');
|
|
394
|
+
return 0;
|
|
395
|
+
}
|
|
396
|
+
for (const e of filtered) {
|
|
397
|
+
process.stdout.write(` ${e.templateId}:\n`);
|
|
398
|
+
for (const i of e.issues) {
|
|
399
|
+
if (i.code !== 'forbidden-legacy-path' && i.code !== 'path-no-convention')
|
|
400
|
+
continue;
|
|
401
|
+
process.stdout.write(` ${i.severity}: ${i.message}\n`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return 0;
|
|
405
|
+
},
|
|
406
|
+
};
|
|
407
|
+
export const templatesSmokeCommand = {
|
|
408
|
+
name: 'smoke',
|
|
409
|
+
description: 'Render every template with a sample name and report errors. Same as `templates drift` for now.',
|
|
410
|
+
usage: 'shrk templates smoke [--json]',
|
|
411
|
+
async run(args) {
|
|
412
|
+
return templatesDriftCommand.run(args);
|
|
413
|
+
},
|
|
414
|
+
};
|
|
415
|
+
function slugifyId(s) {
|
|
416
|
+
return s.replace(/[^a-z0-9.-]/gi, '-').toLowerCase();
|
|
417
|
+
}
|
|
418
|
+
function buildTemplateScaffold(input) {
|
|
419
|
+
const ts = `// Template scaffold preview. TODO bodies only — fill in before
|
|
420
|
+
// running \`shrk apply --asset-preview\`.
|
|
421
|
+
//
|
|
422
|
+
// Id: ${input.id}
|
|
423
|
+
// Title: ${input.title}
|
|
424
|
+
import type { ITemplateDefinition } from '@shrkcrft/templates';
|
|
425
|
+
|
|
426
|
+
export const template: ITemplateDefinition = {
|
|
427
|
+
id: '${input.id}',
|
|
428
|
+
title: '${input.title.replace(/'/g, "\\'")}',
|
|
429
|
+
description: '${input.description.replace(/'/g, "\\'")}',
|
|
430
|
+
tags: ${JSON.stringify(input.tags)},
|
|
431
|
+
scope: ${JSON.stringify(input.scope)},
|
|
432
|
+
appliesWhen: ${JSON.stringify(input.appliesWhen)},
|
|
433
|
+
// Required metadata (fill in or remove if not applicable).
|
|
434
|
+
producedAnchors: ${JSON.stringify(input.producedAnchors)},
|
|
435
|
+
requiredAnchors: ${JSON.stringify(input.requiredAnchors)},
|
|
436
|
+
requiredProfileIds: ${JSON.stringify(input.requiredProfileIds)},
|
|
437
|
+
requiredHelperIds: ${JSON.stringify(input.requiredHelperIds)},
|
|
438
|
+
registrationHintIds: ${JSON.stringify(input.registrationHintIds)},
|
|
439
|
+
variables: [
|
|
440
|
+
{
|
|
441
|
+
name: 'name',
|
|
442
|
+
required: true,
|
|
443
|
+
description: 'TODO: describe the primary variable.',
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
// TODO: fill in. Forbidden path fragments to avoid: ${JSON.stringify(input.forbiddenPaths)}.
|
|
447
|
+
files: (vars: Record<string, string>) => {
|
|
448
|
+
const name = vars['name'] ?? 'placeholder';
|
|
449
|
+
return [
|
|
450
|
+
{
|
|
451
|
+
// TODO: confirm canonical targetPath before \`shrk apply --write\`.
|
|
452
|
+
targetPath: \`.sharkcraft/preview/${input.id}/\${name}.ts\`,
|
|
453
|
+
content: '// TODO: template body for ${input.id}.\\n',
|
|
454
|
+
},
|
|
455
|
+
];
|
|
456
|
+
},
|
|
457
|
+
postGenerationNotes: [
|
|
458
|
+
'Confirm canonical targetPath before running shrk apply --write.',
|
|
459
|
+
],
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
export default template;
|
|
463
|
+
`;
|
|
464
|
+
const explainer = `# Template scaffold: ${input.id}
|
|
465
|
+
|
|
466
|
+
Generated by \`shrk templates scaffold\`.
|
|
467
|
+
|
|
468
|
+
## Next
|
|
469
|
+
|
|
470
|
+
1. Edit the draft at \`.sharkcraft/authoring/templates/${slugifyId(input.id)}.draft.ts\` —
|
|
471
|
+
fill in \`files\`, variables, and metadata.
|
|
472
|
+
2. Validate with:
|
|
473
|
+
- \`shrk templates drift --min-severity warning\`
|
|
474
|
+
- \`shrk self-config doctor\`
|
|
475
|
+
- \`shrk packs signature-status\` (if this is a pack-contributed template)
|
|
476
|
+
3. When the draft looks right, copy it into the pack or local
|
|
477
|
+
\`sharkcraft/templates.ts\` using:
|
|
478
|
+
\`\`\`
|
|
479
|
+
shrk apply --asset-preview .sharkcraft/authoring/templates/${slugifyId(input.id)}.draft.ts \\
|
|
480
|
+
--target <path-to-templates.ts>
|
|
481
|
+
\`\`\`
|
|
482
|
+
|
|
483
|
+
Forbidden path fragments (do not let \`files\` emit these): ${input.forbiddenPaths.join(', ') || '(none)'}.
|
|
484
|
+
`;
|
|
485
|
+
return { tsBody: ts, explainer };
|
|
486
|
+
}
|
|
487
|
+
function validateTemplateId(id) {
|
|
488
|
+
if (!id || !/^[a-z][a-z0-9.-]*$/.test(id)) {
|
|
489
|
+
return `Invalid id "${id}". Use lowercase letters, digits, dots and hyphens (e.g. app.my-template).`;
|
|
490
|
+
}
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
export const templatesScaffoldCommand = {
|
|
494
|
+
name: 'scaffold',
|
|
495
|
+
description: 'Scaffold a new template. Preview-only by default; --write-preview materialises a TS draft under .sharkcraft/authoring/templates/. Pair with `shrk apply --asset-preview` to insert into the target file.',
|
|
496
|
+
usage: 'shrk templates scaffold --id <id> [--title <t>] [--description <d>] [--tag a,b] [--scope a,b] [--applies-when a,b] [--produced-anchor a,b] [--required-anchor a,b] [--required-profile a,b] [--required-helper a,b] [--registration-hint a,b] [--forbidden-path a,b] [--reason <text>] [--write-preview] [--json]',
|
|
497
|
+
async run(args) {
|
|
498
|
+
const id = flagString(args, 'id');
|
|
499
|
+
if (!id) {
|
|
500
|
+
process.stderr.write('Usage: shrk templates scaffold --id <id> [...] [--write-preview]\n');
|
|
501
|
+
return 2;
|
|
502
|
+
}
|
|
503
|
+
const idError = validateTemplateId(id);
|
|
504
|
+
if (idError) {
|
|
505
|
+
process.stderr.write(`Refused: ${idError}\n`);
|
|
506
|
+
return 1;
|
|
507
|
+
}
|
|
508
|
+
const input = {
|
|
509
|
+
id,
|
|
510
|
+
title: flagString(args, 'title') ?? id,
|
|
511
|
+
description: flagString(args, 'description') ?? 'TODO: describe what this template generates.',
|
|
512
|
+
tags: flagList(args, 'tag'),
|
|
513
|
+
scope: flagList(args, 'scope'),
|
|
514
|
+
appliesWhen: flagList(args, 'applies-when'),
|
|
515
|
+
producedAnchors: flagList(args, 'produced-anchor'),
|
|
516
|
+
requiredAnchors: flagList(args, 'required-anchor'),
|
|
517
|
+
requiredProfileIds: flagList(args, 'required-profile'),
|
|
518
|
+
requiredHelperIds: flagList(args, 'required-helper'),
|
|
519
|
+
registrationHintIds: flagList(args, 'registration-hint'),
|
|
520
|
+
forbiddenPaths: flagList(args, 'forbidden-path'),
|
|
521
|
+
};
|
|
522
|
+
const { tsBody, explainer } = buildTemplateScaffold(input);
|
|
523
|
+
const cwd = resolveCwd(args);
|
|
524
|
+
const slug = slugifyId(id);
|
|
525
|
+
const tsRel = nodePath.join('.sharkcraft', 'authoring', 'templates', `${slug}.draft.ts`);
|
|
526
|
+
const mdRel = nodePath.join('.sharkcraft', 'authoring', 'templates', `${slug}.md`);
|
|
527
|
+
const tsAbs = nodePath.join(cwd, tsRel);
|
|
528
|
+
const mdAbs = nodePath.join(cwd, mdRel);
|
|
529
|
+
const result = {
|
|
530
|
+
schema: 'sharkcraft.template-scaffold/v1',
|
|
531
|
+
generatedAt: new Date().toISOString(),
|
|
532
|
+
id,
|
|
533
|
+
title: input.title,
|
|
534
|
+
preview: { ts: tsRel, explainer: mdRel },
|
|
535
|
+
nextCommands: [
|
|
536
|
+
`shrk apply --asset-preview ${tsRel} --target <path-to-templates.ts>`,
|
|
537
|
+
`shrk templates drift --min-severity warning`,
|
|
538
|
+
`shrk self-config doctor`,
|
|
539
|
+
`shrk packs signature-status`,
|
|
540
|
+
],
|
|
541
|
+
};
|
|
542
|
+
if (flagBool(args, 'json')) {
|
|
543
|
+
process.stdout.write(asJson(result) + '\n');
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
process.stdout.write(header(`Template scaffold preview: ${id}`));
|
|
547
|
+
process.stdout.write(` title: ${input.title}\n`);
|
|
548
|
+
process.stdout.write(` files:\n ${tsRel}\n ${mdRel}\n`);
|
|
549
|
+
process.stdout.write('\n--- TypeScript draft ---\n');
|
|
550
|
+
process.stdout.write(tsBody);
|
|
551
|
+
process.stdout.write('\n--- Next ---\n');
|
|
552
|
+
for (const c of result.nextCommands)
|
|
553
|
+
process.stdout.write(` $ ${c}\n`);
|
|
554
|
+
if (!flagBool(args, 'write-preview')) {
|
|
555
|
+
process.stdout.write('\n(preview only — pass --write-preview to materialise under .sharkcraft/authoring/templates/)\n');
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (flagBool(args, 'write-preview')) {
|
|
559
|
+
mkdirSync(nodePath.dirname(tsAbs), { recursive: true });
|
|
560
|
+
writeFileSync(tsAbs, tsBody, 'utf8');
|
|
561
|
+
writeFileSync(mdAbs, explainer, 'utf8');
|
|
562
|
+
try {
|
|
563
|
+
const isAgent = Boolean(process.env['SHARKCRAFT_AGENT']) ||
|
|
564
|
+
Boolean(process.env['CLAUDE_CODE_SESSION']);
|
|
565
|
+
recordProvenance({
|
|
566
|
+
projectRoot: cwd,
|
|
567
|
+
entry: {
|
|
568
|
+
operation: AssetProvenanceOperation.Add,
|
|
569
|
+
assetKind: AssetKind.Template,
|
|
570
|
+
assetId: id,
|
|
571
|
+
source: isAgent ? AssetProvenanceSource.Agent : AssetProvenanceSource.Cli,
|
|
572
|
+
previewPath: tsRel,
|
|
573
|
+
...(flagString(args, 'reason') ? { reason: flagString(args, 'reason') } : {}),
|
|
574
|
+
},
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
catch {
|
|
578
|
+
// best-effort
|
|
579
|
+
}
|
|
580
|
+
if (!flagBool(args, 'json')) {
|
|
581
|
+
process.stdout.write(`\nWrote 2 files under ${nodePath.join(cwd, '.sharkcraft', 'authoring', 'templates')}\n`);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return 0;
|
|
585
|
+
},
|
|
586
|
+
};
|
|
587
|
+
/**
|
|
588
|
+
* `shrk templates add` is an alias of `templates scaffold`.
|
|
589
|
+
*/
|
|
590
|
+
export const templatesAddCommand = {
|
|
591
|
+
...templatesScaffoldCommand,
|
|
592
|
+
name: 'add',
|
|
593
|
+
description: 'Alias of `templates scaffold` — preview-only TS draft for a new template.',
|
|
594
|
+
};
|
|
595
|
+
/**
|
|
596
|
+
* `shrk templates doctor` aggregates the existing drift + lint
|
|
597
|
+
* signals into one structured report. Read-only.
|
|
598
|
+
*
|
|
599
|
+
* Distinct from `templates lint` (which surfaces test-style findings)
|
|
600
|
+
* and `templates drift` (which compares declared vs. rendered output)
|
|
601
|
+
* by combining them with a clean/dirty verdict + per-template summary.
|
|
602
|
+
*/
|
|
603
|
+
export const templatesDoctorCommand = {
|
|
604
|
+
name: 'doctor',
|
|
605
|
+
description: 'Template-quality doctor — combines drift + lint signals into one clean/dirty verdict per template. Read-only.',
|
|
606
|
+
usage: 'shrk templates doctor [--strict] [--json]',
|
|
607
|
+
async run(args) {
|
|
608
|
+
const cwd = resolveCwd(args);
|
|
609
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
610
|
+
const drift = buildTemplateDriftReport(inspection);
|
|
611
|
+
const totals = {
|
|
612
|
+
total: drift.entries.length,
|
|
613
|
+
pass: drift.entries.filter((e) => e.status === TemplateDriftStatus.Pass).length,
|
|
614
|
+
warn: drift.entries.filter((e) => e.status === TemplateDriftStatus.Warn).length,
|
|
615
|
+
fail: drift.entries.filter((e) => e.status === TemplateDriftStatus.Fail).length,
|
|
616
|
+
};
|
|
617
|
+
const strict = flagBool(args, 'strict');
|
|
618
|
+
const exit = totals.fail > 0 || (strict && totals.warn > 0) ? 1 : 0;
|
|
619
|
+
if (flagBool(args, 'json')) {
|
|
620
|
+
process.stdout.write(asJson({
|
|
621
|
+
schema: 'sharkcraft.templates-doctor/v1',
|
|
622
|
+
generatedAt: new Date().toISOString(),
|
|
623
|
+
totals,
|
|
624
|
+
entries: drift.entries,
|
|
625
|
+
}) + '\n');
|
|
626
|
+
return exit;
|
|
627
|
+
}
|
|
628
|
+
process.stdout.write(header('Templates doctor'));
|
|
629
|
+
process.stdout.write(kv('totals', `${totals.pass} pass, ${totals.warn} warn, ${totals.fail} fail`) + '\n\n');
|
|
630
|
+
for (const e of drift.entries) {
|
|
631
|
+
const label = (e.templateName ?? e.templateId);
|
|
632
|
+
process.stdout.write(` ${e.status.toUpperCase().padEnd(8)} ${label}\n`);
|
|
633
|
+
for (const issue of e.issues) {
|
|
634
|
+
process.stdout.write(` [${issue.severity}] ${issue.message}\n`);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
if (exit === 0)
|
|
638
|
+
process.stdout.write('\nClean. ✓\n');
|
|
639
|
+
else
|
|
640
|
+
process.stdout.write('\nIssues found. Run `shrk templates drift --min-severity warning` for detail.\n');
|
|
641
|
+
return exit;
|
|
642
|
+
},
|
|
643
|
+
};
|
|
644
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
645
|
+
// Templates authoring parity: update / remove.
|
|
646
|
+
//
|
|
647
|
+
// Mirrors `shrk knowledge update` / `shrk knowledge remove` shape. Drafts
|
|
648
|
+
// land under `.sharkcraft/authoring/templates/` only — never mutate source.
|
|
649
|
+
// Reference-checking for remove uses knowledge/pipelines/presets/packs
|
|
650
|
+
// already loaded by inspect.
|
|
651
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
652
|
+
function buildTemplateUpdateOps(args) {
|
|
653
|
+
const addTags = multiFlagValues(args, 'add-tag');
|
|
654
|
+
const removeTags = multiFlagValues(args, 'remove-tag');
|
|
655
|
+
const addScope = multiFlagValues(args, 'add-scope');
|
|
656
|
+
const removeScope = multiFlagValues(args, 'remove-scope');
|
|
657
|
+
const addAppliesWhen = multiFlagValues(args, 'add-applies-when');
|
|
658
|
+
const removeAppliesWhen = multiFlagValues(args, 'remove-applies-when');
|
|
659
|
+
const addProfile = multiFlagValues(args, 'add-required-profile');
|
|
660
|
+
const removeProfile = multiFlagValues(args, 'remove-required-profile');
|
|
661
|
+
const addForbid = multiFlagValues(args, 'add-forbidden-path');
|
|
662
|
+
const removeForbid = multiFlagValues(args, 'remove-forbidden-path');
|
|
663
|
+
const addRelated = multiFlagValues(args, 'add-related');
|
|
664
|
+
const removeRelated = multiFlagValues(args, 'remove-related');
|
|
665
|
+
const name = flagString(args, 'name');
|
|
666
|
+
const description = flagString(args, 'description');
|
|
667
|
+
const postNote = flagString(args, 'add-post-note');
|
|
668
|
+
return {
|
|
669
|
+
...(name !== undefined && name !== null ? { setName: name } : {}),
|
|
670
|
+
...(description !== undefined && description !== null ? { setDescription: description } : {}),
|
|
671
|
+
...(addTags.length ? { addTags } : {}),
|
|
672
|
+
...(removeTags.length ? { removeTags } : {}),
|
|
673
|
+
...(addScope.length ? { addScope } : {}),
|
|
674
|
+
...(removeScope.length ? { removeScope } : {}),
|
|
675
|
+
...(addAppliesWhen.length ? { addAppliesWhen } : {}),
|
|
676
|
+
...(removeAppliesWhen.length ? { removeAppliesWhen } : {}),
|
|
677
|
+
...(addProfile.length ? { addRequiredProfileIds: addProfile } : {}),
|
|
678
|
+
...(removeProfile.length ? { removeRequiredProfileIds: removeProfile } : {}),
|
|
679
|
+
...(addForbid.length ? { addForbiddenPathFragments: addForbid } : {}),
|
|
680
|
+
...(removeForbid.length ? { removeForbiddenPathFragments: removeForbid } : {}),
|
|
681
|
+
...(addRelated.length ? { addRelated } : {}),
|
|
682
|
+
...(removeRelated.length ? { removeRelated } : {}),
|
|
683
|
+
...(postNote ? { addPostGenerationNote: postNote } : {}),
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Project the preview's `next` template definition onto the
|
|
688
|
+
* `applyTemplateUpdate` field shape. The preview generator merges
|
|
689
|
+
* add/remove ops into the current state, so the apply receives the final
|
|
690
|
+
* desired values for each top-level array and for `metadata.*`. The apply
|
|
691
|
+
* splicer uses `mode: 'set'` for arrays (i.e. wholesale replace with the
|
|
692
|
+
* already-merged set), and for metadata it forwards both scalar and
|
|
693
|
+
* array fields. Function resolvers (`files` etc.) are excluded — the
|
|
694
|
+
* draft cannot represent them.
|
|
695
|
+
*/
|
|
696
|
+
function buildApplyFieldsFromNext(next) {
|
|
697
|
+
const fields = {};
|
|
698
|
+
if (next.name !== undefined)
|
|
699
|
+
fields.name = next.name;
|
|
700
|
+
if (next.description !== undefined)
|
|
701
|
+
fields.description = next.description;
|
|
702
|
+
if (next.tags !== undefined)
|
|
703
|
+
fields.tags = { mode: 'set', values: [...next.tags] };
|
|
704
|
+
if (next.scope !== undefined)
|
|
705
|
+
fields.scope = { mode: 'set', values: [...next.scope] };
|
|
706
|
+
if (next.appliesWhen !== undefined) {
|
|
707
|
+
fields.appliesWhen = { mode: 'set', values: [...next.appliesWhen] };
|
|
708
|
+
}
|
|
709
|
+
if (next.related !== undefined) {
|
|
710
|
+
fields.related = { mode: 'set', values: [...next.related] };
|
|
711
|
+
}
|
|
712
|
+
if (next.metadata) {
|
|
713
|
+
const md = next.metadata;
|
|
714
|
+
const metaOut = {};
|
|
715
|
+
for (const k of ['priority', 'maturity', 'dryRunOnly', 'requiresApproval']) {
|
|
716
|
+
if (md[k] !== undefined)
|
|
717
|
+
metaOut[k] = md[k];
|
|
718
|
+
}
|
|
719
|
+
for (const k of [
|
|
720
|
+
'requiredAnchors',
|
|
721
|
+
'requiredProfileIds',
|
|
722
|
+
'forbiddenPathFragments',
|
|
723
|
+
'requiredVerificationCommandIds',
|
|
724
|
+
]) {
|
|
725
|
+
const v = md[k];
|
|
726
|
+
if (Array.isArray(v)) {
|
|
727
|
+
metaOut[k] = { mode: 'set', values: [...v] };
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
if (Object.keys(metaOut).length > 0) {
|
|
731
|
+
fields.metadata = metaOut;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return fields;
|
|
735
|
+
}
|
|
736
|
+
function recordTemplateAuthoringProvenance(cwd, id, op, previewPath, reason) {
|
|
737
|
+
const src = detectAuthoringSource();
|
|
738
|
+
recordProvenance({
|
|
739
|
+
projectRoot: cwd,
|
|
740
|
+
entry: {
|
|
741
|
+
operation: AssetProvenanceOperation.Preview,
|
|
742
|
+
assetKind: AssetKind.Template,
|
|
743
|
+
assetId: id,
|
|
744
|
+
source: src.source,
|
|
745
|
+
...(src.author ? { author: src.author } : {}),
|
|
746
|
+
...(src.sessionId ? { sessionId: src.sessionId } : {}),
|
|
747
|
+
...(reason ? { reason } : {}),
|
|
748
|
+
previewPath,
|
|
749
|
+
extra: { authoringOp: op },
|
|
750
|
+
},
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
export const templatesUpdateCommand = {
|
|
754
|
+
name: 'update',
|
|
755
|
+
description: 'Preview an update to an existing template, or apply it in place with --apply. Mirror of `knowledge update` for preview; --write-preview materialises a draft under .sharkcraft/authoring/templates/. --apply splices the patch into the source template literal directly (preview-first, refuses pack-contributed templates and function-resolver replacement).',
|
|
756
|
+
usage: 'shrk templates update <id> [--name <n>] [--description <d>] [--add-tag a,b] [--remove-tag a,b] [--add-scope a,b] [--remove-scope a,b] [--add-applies-when a,b] [--remove-applies-when a,b] [--add-required-profile a,b] [--remove-required-profile a,b] [--add-forbidden-path a,b] [--remove-forbidden-path a,b] [--add-related a,b] [--remove-related a,b] [--add-post-note <text>] [--reason <text>] [--write-preview | --apply [--allow-divergent]] [--json]',
|
|
757
|
+
async run(args) {
|
|
758
|
+
const id = args.positional[0] ?? flagString(args, 'id');
|
|
759
|
+
if (!id) {
|
|
760
|
+
process.stderr.write('Usage: shrk templates update <id> [...]\n');
|
|
761
|
+
return 2;
|
|
762
|
+
}
|
|
763
|
+
const cwd = resolveCwd(args);
|
|
764
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
765
|
+
const input = {
|
|
766
|
+
operation: TemplateAuthoringOperation.Update,
|
|
767
|
+
id,
|
|
768
|
+
...(flagString(args, 'reason') ? { reason: flagString(args, 'reason') } : {}),
|
|
769
|
+
updateOps: buildTemplateUpdateOps(args),
|
|
770
|
+
};
|
|
771
|
+
const result = buildTemplateAuthoringPreview(input, {
|
|
772
|
+
templates: inspection.templateRegistry.list(),
|
|
773
|
+
knowledgeEntries: inspection.knowledgeEntries,
|
|
774
|
+
});
|
|
775
|
+
// `--apply` path. Splices the projected metadata fields into
|
|
776
|
+
// the source template literal in place. Refuses pack-contributed
|
|
777
|
+
// templates (their source lives in the pack package).
|
|
778
|
+
if (flagBool(args, 'apply')) {
|
|
779
|
+
if (!result.ok) {
|
|
780
|
+
if (flagBool(args, 'json'))
|
|
781
|
+
process.stdout.write(asJson(result) + '\n');
|
|
782
|
+
else {
|
|
783
|
+
process.stdout.write(header(`Template update --apply refused: ${id}`));
|
|
784
|
+
process.stdout.write(` refusal: ${result.refusal}\n`);
|
|
785
|
+
}
|
|
786
|
+
return 1;
|
|
787
|
+
}
|
|
788
|
+
const src = inspection.templateSources.get(id);
|
|
789
|
+
if (!src || src.type === 'pack') {
|
|
790
|
+
process.stderr.write(`Refused: template "${id}" is pack-contributed. Edit the pack source and re-sign instead.\n`);
|
|
791
|
+
return 1;
|
|
792
|
+
}
|
|
793
|
+
// Locate the local source file for this template.
|
|
794
|
+
const cfg = inspection.config;
|
|
795
|
+
const sharkDir = inspection.sharkcraftDir;
|
|
796
|
+
let sourceFile = null;
|
|
797
|
+
const candidates = [];
|
|
798
|
+
if (cfg && sharkDir) {
|
|
799
|
+
for (const f of (cfg.templateFiles ?? [])) {
|
|
800
|
+
candidates.push(nodePath.join(sharkDir, f));
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
for (const candidate of candidates) {
|
|
804
|
+
try {
|
|
805
|
+
const body = (await import('node:fs')).readFileSync(candidate, 'utf8');
|
|
806
|
+
if (new RegExp(`id\\s*:\\s*['"]${id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}['"]`).test(body)) {
|
|
807
|
+
sourceFile = candidate;
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
catch {
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
if (!sourceFile) {
|
|
816
|
+
process.stderr.write(`Refused: could not locate local source file for template "${id}". Configured templateFiles: ${candidates.map((c) => nodePath.relative(cwd, c)).join(', ') || '(none)'}.\n`);
|
|
817
|
+
return 1;
|
|
818
|
+
}
|
|
819
|
+
const next = result.next;
|
|
820
|
+
const fieldsForApply = buildApplyFieldsFromNext(next);
|
|
821
|
+
const apply = applyTemplateUpdate({
|
|
822
|
+
cwd,
|
|
823
|
+
targetPath: nodePath.relative(cwd, sourceFile),
|
|
824
|
+
templateId: id,
|
|
825
|
+
fields: fieldsForApply,
|
|
826
|
+
write: false,
|
|
827
|
+
});
|
|
828
|
+
if (!apply.ok) {
|
|
829
|
+
process.stderr.write(`Refused: ${apply.refusal}\n`);
|
|
830
|
+
return 1;
|
|
831
|
+
}
|
|
832
|
+
const written = applyTemplateUpdate({
|
|
833
|
+
cwd,
|
|
834
|
+
targetPath: nodePath.relative(cwd, sourceFile),
|
|
835
|
+
templateId: id,
|
|
836
|
+
fields: fieldsForApply,
|
|
837
|
+
write: true,
|
|
838
|
+
});
|
|
839
|
+
try {
|
|
840
|
+
recordTemplateAuthoringProvenance(cwd, id, 'update', nodePath.relative(cwd, sourceFile), input.reason);
|
|
841
|
+
}
|
|
842
|
+
catch {
|
|
843
|
+
// best-effort
|
|
844
|
+
}
|
|
845
|
+
if (flagBool(args, 'json')) {
|
|
846
|
+
process.stdout.write(asJson({
|
|
847
|
+
mode: 'applied',
|
|
848
|
+
templateId: id,
|
|
849
|
+
sourceFile: nodePath.relative(cwd, sourceFile),
|
|
850
|
+
fieldChanges: written.fieldChanges,
|
|
851
|
+
wrote: written.wrote,
|
|
852
|
+
}) + '\n');
|
|
853
|
+
}
|
|
854
|
+
else {
|
|
855
|
+
process.stdout.write(header(`Template update --apply: ${id}`));
|
|
856
|
+
process.stdout.write(` source: ${nodePath.relative(cwd, sourceFile)}\n`);
|
|
857
|
+
process.stdout.write(` fields applied (${written.fieldChanges.length}):\n`);
|
|
858
|
+
for (const f of written.fieldChanges) {
|
|
859
|
+
process.stdout.write(` • ${f.field} (${f.mode})\n`);
|
|
860
|
+
}
|
|
861
|
+
process.stdout.write('\nRe-run `shrk templates drift --min-severity warning` to confirm the update lands cleanly.\n');
|
|
862
|
+
}
|
|
863
|
+
return 0;
|
|
864
|
+
}
|
|
865
|
+
if (flagBool(args, 'json')) {
|
|
866
|
+
process.stdout.write(asJson(result) + '\n');
|
|
867
|
+
}
|
|
868
|
+
else {
|
|
869
|
+
process.stdout.write(header(`Template update preview: ${id}`));
|
|
870
|
+
process.stdout.write(` ok: ${result.ok}\n`);
|
|
871
|
+
if (!result.ok)
|
|
872
|
+
process.stdout.write(` refusal: ${result.refusal}\n`);
|
|
873
|
+
process.stdout.write(` files:\n ${result.tsDraft.path}\n ${result.explainer.path}\n`);
|
|
874
|
+
if (result.patch) {
|
|
875
|
+
process.stdout.write(`\n patch changes: ${result.patch.changes.length}\n`);
|
|
876
|
+
for (const c of result.patch.changes) {
|
|
877
|
+
process.stdout.write(` - ${c.op} ${c.field}\n`);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (result.warnings.length > 0) {
|
|
881
|
+
process.stdout.write('\n warnings:\n');
|
|
882
|
+
for (const w of result.warnings)
|
|
883
|
+
process.stdout.write(` • ${w}\n`);
|
|
884
|
+
}
|
|
885
|
+
process.stdout.write('\n--- TypeScript draft (next) ---\n');
|
|
886
|
+
process.stdout.write(result.tsDraft.body);
|
|
887
|
+
process.stdout.write('\n--- Next commands ---\n');
|
|
888
|
+
for (const c of result.nextCommands)
|
|
889
|
+
process.stdout.write(` $ ${c}\n`);
|
|
890
|
+
if (!flagBool(args, 'write-preview')) {
|
|
891
|
+
process.stdout.write('\n (preview only — pass --write-preview to materialise under .sharkcraft/authoring/templates/)\n');
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
if (flagBool(args, 'write-preview') && result.ok) {
|
|
895
|
+
writeAuthoringDrafts(cwd, [result.tsDraft, result.explainer]);
|
|
896
|
+
recordTemplateAuthoringProvenance(cwd, id, 'update', result.tsDraft.path, input.reason);
|
|
897
|
+
}
|
|
898
|
+
return result.ok ? 0 : 1;
|
|
899
|
+
},
|
|
900
|
+
};
|
|
901
|
+
export const templatesRemoveCommand = {
|
|
902
|
+
name: 'remove',
|
|
903
|
+
description: 'Preview removal of a template. Refuses if anything references it; pass --force-preview to override. Preview-only.',
|
|
904
|
+
usage: 'shrk templates remove <id> [--force-preview] [--reason <text>] [--write-preview] [--json]',
|
|
905
|
+
async run(args) {
|
|
906
|
+
const id = args.positional[0] ?? flagString(args, 'id');
|
|
907
|
+
if (!id) {
|
|
908
|
+
process.stderr.write('Usage: shrk templates remove <id> [--force-preview]\n');
|
|
909
|
+
return 2;
|
|
910
|
+
}
|
|
911
|
+
const cwd = resolveCwd(args);
|
|
912
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
913
|
+
// Build pack-template-id map so the reference-check flags pack ownership.
|
|
914
|
+
const packTemplateIds = new Map();
|
|
915
|
+
for (const p of inspection.packs.validPacks ?? []) {
|
|
916
|
+
const tmpls = p.manifest?.contributions?.templateFiles ?? [];
|
|
917
|
+
for (const t of tmpls) {
|
|
918
|
+
// Best-effort — we don't know the template id from the file name alone.
|
|
919
|
+
// Use the file path as a marker so the reverse-ref note still surfaces.
|
|
920
|
+
packTemplateIds.set(t, p.packageName);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
const input = {
|
|
924
|
+
operation: TemplateAuthoringOperation.Remove,
|
|
925
|
+
id,
|
|
926
|
+
forcePreview: flagBool(args, 'force-preview'),
|
|
927
|
+
...(flagString(args, 'reason') ? { reason: flagString(args, 'reason') } : {}),
|
|
928
|
+
};
|
|
929
|
+
const result = buildTemplateAuthoringPreview(input, {
|
|
930
|
+
templates: inspection.templateRegistry.list(),
|
|
931
|
+
knowledgeEntries: inspection.knowledgeEntries,
|
|
932
|
+
pipelines: inspection.pipelineRegistry.list(),
|
|
933
|
+
presets: inspection.presetRegistry.list(),
|
|
934
|
+
});
|
|
935
|
+
if (flagBool(args, 'json')) {
|
|
936
|
+
process.stdout.write(asJson(result) + '\n');
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
process.stdout.write(header(`Template remove preview: ${id}`));
|
|
940
|
+
process.stdout.write(` ok: ${result.ok}\n`);
|
|
941
|
+
if (!result.ok)
|
|
942
|
+
process.stdout.write(` refusal: ${result.refusal}\n`);
|
|
943
|
+
if (result.reverseReferences && result.reverseReferences.length > 0) {
|
|
944
|
+
process.stdout.write(`\n reverse references (${result.reverseReferences.length}):\n`);
|
|
945
|
+
for (const r of result.reverseReferences) {
|
|
946
|
+
process.stdout.write(` - ${r.fromKind} ${r.fromId} (${r.field})${r.note ? ` — ${r.note}` : ''}\n`);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
process.stdout.write('\n--- Next commands ---\n');
|
|
950
|
+
for (const c of result.nextCommands)
|
|
951
|
+
process.stdout.write(` $ ${c}\n`);
|
|
952
|
+
if (!flagBool(args, 'write-preview')) {
|
|
953
|
+
process.stdout.write('\n (preview only — pass --write-preview to materialise under .sharkcraft/authoring/templates/)\n');
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
if (flagBool(args, 'write-preview') && result.ok) {
|
|
957
|
+
writeAuthoringDrafts(cwd, [result.tsDraft, result.explainer]);
|
|
958
|
+
recordTemplateAuthoringProvenance(cwd, id, 'remove', result.explainer.path, input.reason);
|
|
959
|
+
}
|
|
960
|
+
return result.ok ? 0 : 1;
|
|
961
|
+
},
|
|
962
|
+
};
|
|
963
|
+
// Silence unused-import warnings if the surface ever rolls back.
|
|
964
|
+
void AssetProvenanceSource;
|