@shrkcrft/cli 0.1.0-alpha.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 +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 +314 -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 +553 -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 +3242 -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 +681 -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 +127 -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 +301 -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 +74 -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 +650 -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 +958 -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 +354 -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 +699 -0
- package/dist/output/failure-hints.d.ts +55 -0
- package/dist/output/failure-hints.d.ts.map +1 -0
- package/dist/output/failure-hints.js +159 -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 +53 -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 +36 -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 +73 -0
|
@@ -0,0 +1,1208 @@
|
|
|
1
|
+
import { flagBool, flagString, } from "../command-registry.js";
|
|
2
|
+
import { asJson, header } from "../output/format-output.js";
|
|
3
|
+
import { COMMAND_CATALOG, CommandLifecycle, CommandSurface, R46_OVERLAY, SafetyLevel, buildCommandSafetyMatrix, commandLifecycle, commandSurface, commandTaskRole, defaultShowInHelp, renderCommandSafetyMatrixMarkdown, } from "./command-catalog.js";
|
|
4
|
+
import { buildCommandTaxonomy, buildPrimaryCommandsReport, renderCommandTaxonomyMarkdown, renderCommandTaxonomyText, renderPrimaryCommandsText, } from '@shrkcrft/inspector';
|
|
5
|
+
export function makeCommandsCommand(registry) {
|
|
6
|
+
return {
|
|
7
|
+
name: 'commands',
|
|
8
|
+
description: 'Browse the command catalog. Default view is compact (primary + common); pass --all for the full catalog. Subcommands: primary | advanced | deprecated | hidden | retirement-plan | docs-check | surface | machine | legacy | overlaps | taxonomy | matrix | tree | search | suggest | explain | entrypoints | doctor | ux-check.',
|
|
9
|
+
usage: 'shrk commands [primary|advanced|deprecated|hidden|retirement-plan|docs-check|surface <s>|machine|legacy|overlaps|taxonomy|matrix|tree|search <q>|suggest <p>|explain <cmd>|entrypoints|doctor|ux-check] [--all] [--safety <level>] [--category <name>] [--json]',
|
|
10
|
+
async run(args) {
|
|
11
|
+
const sub = args.positional[0];
|
|
12
|
+
if (sub === 'doctor') {
|
|
13
|
+
return runCommandsDoctor(args, registry);
|
|
14
|
+
}
|
|
15
|
+
if (sub === 'ux-check') {
|
|
16
|
+
return runCommandsUxCheck(args);
|
|
17
|
+
}
|
|
18
|
+
if (sub === 'primary') {
|
|
19
|
+
const report = buildPrimaryCommandsReport();
|
|
20
|
+
if (flagBool(args, 'json')) {
|
|
21
|
+
process.stdout.write(asJson(report) + '\n');
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
process.stdout.write(renderPrimaryCommandsText(report));
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
if (sub === 'tree') {
|
|
28
|
+
return printTree(args);
|
|
29
|
+
}
|
|
30
|
+
if (sub === 'taxonomy') {
|
|
31
|
+
const report = buildCommandTaxonomy({ catalog: COMMAND_CATALOG });
|
|
32
|
+
const explicitOutput = flagString(args, 'output');
|
|
33
|
+
const writeDocs = flagBool(args, 'write-docs');
|
|
34
|
+
const format = flagString(args, 'format') ?? (flagBool(args, 'json') ? 'json' : 'text');
|
|
35
|
+
if (writeDocs || explicitOutput) {
|
|
36
|
+
const { mkdirSync, writeFileSync } = await import('node:fs');
|
|
37
|
+
const { dirname, isAbsolute, resolve } = await import('node:path');
|
|
38
|
+
const cwd = process.cwd();
|
|
39
|
+
const target = explicitOutput
|
|
40
|
+
? isAbsolute(explicitOutput)
|
|
41
|
+
? explicitOutput
|
|
42
|
+
: resolve(cwd, explicitOutput)
|
|
43
|
+
: resolve(cwd, 'docs/commands-taxonomy.md');
|
|
44
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
45
|
+
const header = '<!-- generated by `shrk commands taxonomy --write-docs` — do not edit by hand -->\n\n';
|
|
46
|
+
const body = renderCommandTaxonomyMarkdown(report);
|
|
47
|
+
writeFileSync(target, header + body, 'utf8');
|
|
48
|
+
process.stdout.write(`Wrote ${target}\n`);
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
if (format === 'json') {
|
|
52
|
+
process.stdout.write(asJson(report) + '\n');
|
|
53
|
+
}
|
|
54
|
+
else if (format === 'markdown') {
|
|
55
|
+
process.stdout.write(renderCommandTaxonomyMarkdown(report));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
process.stdout.write(renderCommandTaxonomyText(report));
|
|
59
|
+
}
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
if (sub === 'matrix') {
|
|
63
|
+
const rows = buildCommandSafetyMatrix();
|
|
64
|
+
const fmt = flagString(args, 'format') ?? (flagBool(args, 'json') ? 'json' : 'markdown');
|
|
65
|
+
if (fmt === 'json') {
|
|
66
|
+
process.stdout.write(asJson(rows) + '\n');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
process.stdout.write(renderCommandSafetyMatrixMarkdown(rows));
|
|
70
|
+
}
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
// `shrk commands entrypoints` / `shrk commands workflows` renders
|
|
74
|
+
// the entrypoint matrix that classifies entrypoints by class
|
|
75
|
+
// (human-interactive / agent-mcp / machine-json / debug-explainability).
|
|
76
|
+
if (sub === 'entrypoints' || sub === 'workflows') {
|
|
77
|
+
const { buildEntrypointMatrix, renderEntrypointMatrixText } = await import('@shrkcrft/inspector');
|
|
78
|
+
const report = buildEntrypointMatrix();
|
|
79
|
+
if (flagBool(args, 'json')) {
|
|
80
|
+
process.stdout.write(asJson(report) + '\n');
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
process.stdout.write(renderEntrypointMatrixText(report));
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
if (sub === 'search') {
|
|
87
|
+
const query = args.positional.slice(1).join(' ').toLowerCase().trim();
|
|
88
|
+
const filtered = COMMAND_CATALOG.filter((c) => !query ||
|
|
89
|
+
c.command.toLowerCase().includes(query) ||
|
|
90
|
+
c.description.toLowerCase().includes(query) ||
|
|
91
|
+
c.aliases.some((a) => a.toLowerCase().includes(query)));
|
|
92
|
+
return printCatalog(args, filtered);
|
|
93
|
+
}
|
|
94
|
+
// Surface / machine / legacy / overlaps views.
|
|
95
|
+
if (sub === 'surface') {
|
|
96
|
+
return runCommandsSurface(args);
|
|
97
|
+
}
|
|
98
|
+
if (sub === 'machine') {
|
|
99
|
+
return runCommandsMachine(args);
|
|
100
|
+
}
|
|
101
|
+
if (sub === 'legacy') {
|
|
102
|
+
return runCommandsLegacy(args);
|
|
103
|
+
}
|
|
104
|
+
if (sub === 'overlaps') {
|
|
105
|
+
return runCommandsOverlaps(args);
|
|
106
|
+
}
|
|
107
|
+
// Advanced / deprecated / hidden / retirement-plan / docs-check.
|
|
108
|
+
if (sub === 'advanced') {
|
|
109
|
+
return runCommandsAdvanced(args);
|
|
110
|
+
}
|
|
111
|
+
if (sub === 'deprecated') {
|
|
112
|
+
return runCommandsDeprecated(args);
|
|
113
|
+
}
|
|
114
|
+
if (sub === 'hidden') {
|
|
115
|
+
return runCommandsHidden(args);
|
|
116
|
+
}
|
|
117
|
+
if (sub === 'retirement-plan') {
|
|
118
|
+
return runCommandsRetirementPlan(args);
|
|
119
|
+
}
|
|
120
|
+
if (sub === 'docs-check') {
|
|
121
|
+
return runCommandsDocsCheck(args);
|
|
122
|
+
}
|
|
123
|
+
const safetyFilter = flagString(args, 'safety');
|
|
124
|
+
const categoryFilter = flagString(args, 'category');
|
|
125
|
+
const wantsAll = flagBool(args, 'all');
|
|
126
|
+
let entries = COMMAND_CATALOG;
|
|
127
|
+
if (safetyFilter) {
|
|
128
|
+
entries = entries.filter((e) => e.safetyLevel === safetyFilter);
|
|
129
|
+
}
|
|
130
|
+
if (categoryFilter) {
|
|
131
|
+
entries = entries.filter((e) => e.category === categoryFilter);
|
|
132
|
+
}
|
|
133
|
+
// Default view shrinks to "what new users should see first":
|
|
134
|
+
// primary + common (visible per `defaultShowInHelp`). `--all` brings
|
|
135
|
+
// back the full catalog. `--safety` / `--category` filters force the
|
|
136
|
+
// entire catalog through (operators using them know what they're
|
|
137
|
+
// doing).
|
|
138
|
+
if (!wantsAll && !safetyFilter && !categoryFilter) {
|
|
139
|
+
return printCompactCatalog(args, entries);
|
|
140
|
+
}
|
|
141
|
+
return printCatalog(args, entries);
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* `shrk commands surface <surface>` filters by the new surface
|
|
147
|
+
* classification. With no argument, prints a one-line summary per surface.
|
|
148
|
+
*/
|
|
149
|
+
function runCommandsSurface(args) {
|
|
150
|
+
const wanted = args.positional[1];
|
|
151
|
+
if (!wanted) {
|
|
152
|
+
const counts = new Map();
|
|
153
|
+
for (const e of COMMAND_CATALOG) {
|
|
154
|
+
const s = commandSurface(e);
|
|
155
|
+
counts.set(s, (counts.get(s) ?? 0) + 1);
|
|
156
|
+
}
|
|
157
|
+
if (flagBool(args, 'json')) {
|
|
158
|
+
const out = {};
|
|
159
|
+
for (const [k, v] of counts)
|
|
160
|
+
out[k] = v;
|
|
161
|
+
process.stdout.write(asJson({ surfaces: out, total: COMMAND_CATALOG.length }) + '\n');
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
process.stdout.write(header('Command surfaces'));
|
|
165
|
+
for (const s of Object.values(CommandSurface)) {
|
|
166
|
+
const n = counts.get(s) ?? 0;
|
|
167
|
+
process.stdout.write(` ${s.padEnd(10)} ${n}\n`);
|
|
168
|
+
}
|
|
169
|
+
process.stdout.write(`\nUsage: shrk commands surface <${Object.values(CommandSurface).join('|')}> [--json]\n`);
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
const surface = wanted;
|
|
173
|
+
if (!Object.values(CommandSurface).includes(surface)) {
|
|
174
|
+
process.stderr.write(`Unknown surface "${wanted}". Valid: ${Object.values(CommandSurface).join(', ')}\n`);
|
|
175
|
+
return 2;
|
|
176
|
+
}
|
|
177
|
+
const matches = COMMAND_CATALOG.filter((e) => commandSurface(e) === surface);
|
|
178
|
+
if (flagBool(args, 'json')) {
|
|
179
|
+
process.stdout.write(asJson({ surface, total: matches.length, entries: matches }) + '\n');
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
process.stdout.write(header(`Commands — surface=${surface} (${matches.length})`));
|
|
183
|
+
for (const e of matches) {
|
|
184
|
+
const tag = safetyTag(e.safetyLevel);
|
|
185
|
+
process.stdout.write(` ${tag} ${e.command.padEnd(34)} ${e.description}\n`);
|
|
186
|
+
}
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
|
189
|
+
/** `shrk commands machine` lists machine-oriented commands. */
|
|
190
|
+
function runCommandsMachine(args) {
|
|
191
|
+
const matches = COMMAND_CATALOG.filter((e) => commandSurface(e) === CommandSurface.Machine || e.machineOnly === true);
|
|
192
|
+
if (flagBool(args, 'json')) {
|
|
193
|
+
process.stdout.write(asJson({ total: matches.length, entries: matches }) + '\n');
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
process.stdout.write(header(`Machine-oriented commands (${matches.length})`));
|
|
197
|
+
if (matches.length === 0) {
|
|
198
|
+
process.stdout.write(' (none)\n');
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
for (const e of matches) {
|
|
202
|
+
const tag = safetyTag(e.safetyLevel);
|
|
203
|
+
const prefer = e.preferredCommand ? ` → prefer: ${e.preferredCommand}` : '';
|
|
204
|
+
process.stdout.write(` ${tag} ${e.command.padEnd(28)} ${e.description}${prefer}\n`);
|
|
205
|
+
}
|
|
206
|
+
return 0;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* `shrk commands advanced` lists every advanced surface (typically
|
|
210
|
+
* maintainer / pack-author / one-off diagnostic commands).
|
|
211
|
+
*/
|
|
212
|
+
function runCommandsAdvanced(args) {
|
|
213
|
+
const matches = COMMAND_CATALOG.filter((e) => commandSurface(e) === CommandSurface.Advanced);
|
|
214
|
+
if (flagBool(args, 'json')) {
|
|
215
|
+
process.stdout.write(asJson({ total: matches.length, entries: matches }) + '\n');
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
process.stdout.write(header(`Advanced commands (${matches.length})`));
|
|
219
|
+
if (matches.length === 0) {
|
|
220
|
+
process.stdout.write(' (none)\n');
|
|
221
|
+
return 0;
|
|
222
|
+
}
|
|
223
|
+
for (const e of matches) {
|
|
224
|
+
const tag = safetyTag(e.safetyLevel);
|
|
225
|
+
process.stdout.write(` ${tag} ${e.command.padEnd(34)} ${e.description}\n`);
|
|
226
|
+
}
|
|
227
|
+
return 0;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* `shrk commands deprecated` lists every command with `lifecycle =
|
|
231
|
+
* Deprecated` / `Retired` (also picks up entries that have `replacedBy` but
|
|
232
|
+
* inherited the default lifecycle).
|
|
233
|
+
*/
|
|
234
|
+
function runCommandsDeprecated(args) {
|
|
235
|
+
const matches = COMMAND_CATALOG.filter((e) => {
|
|
236
|
+
const lc = commandLifecycle(e);
|
|
237
|
+
return lc === CommandLifecycle.Deprecated || lc === CommandLifecycle.Retired;
|
|
238
|
+
});
|
|
239
|
+
if (flagBool(args, 'json')) {
|
|
240
|
+
process.stdout.write(asJson({ total: matches.length, entries: matches }) + '\n');
|
|
241
|
+
return 0;
|
|
242
|
+
}
|
|
243
|
+
process.stdout.write(header(`Deprecated / retired commands (${matches.length})`));
|
|
244
|
+
if (matches.length === 0) {
|
|
245
|
+
process.stdout.write(' (none)\n');
|
|
246
|
+
return 0;
|
|
247
|
+
}
|
|
248
|
+
for (const e of matches) {
|
|
249
|
+
const lc = commandLifecycle(e);
|
|
250
|
+
const dest = e.replacedBy ?? e.preferredCommand ?? '(no replacement)';
|
|
251
|
+
const since = e.deprecatedSince ? ` since=${e.deprecatedSince}` : '';
|
|
252
|
+
const removeAfter = e.removeAfter ? ` removeAfter=${e.removeAfter}` : '';
|
|
253
|
+
process.stdout.write(` [${lc}] shrk ${e.command.padEnd(28)} → ${dest}${since}${removeAfter}\n`);
|
|
254
|
+
if (e.reason) {
|
|
255
|
+
process.stdout.write(` reason: ${e.reason}\n`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* `shrk commands hidden` lists every catalog entry that is hidden
|
|
262
|
+
* from default help (advanced / machine / internal / legacy / deprecated /
|
|
263
|
+
* retired / alias / explicit `showInDefaultHelp=false`).
|
|
264
|
+
*/
|
|
265
|
+
function runCommandsHidden(args) {
|
|
266
|
+
const matches = COMMAND_CATALOG.filter((e) => !defaultShowInHelp(e));
|
|
267
|
+
if (flagBool(args, 'json')) {
|
|
268
|
+
process.stdout.write(asJson({ total: matches.length, entries: matches }) + '\n');
|
|
269
|
+
return 0;
|
|
270
|
+
}
|
|
271
|
+
process.stdout.write(header(`Hidden-from-default-help commands (${matches.length})`));
|
|
272
|
+
if (matches.length === 0) {
|
|
273
|
+
process.stdout.write(' (none)\n');
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
const byReason = new Map();
|
|
277
|
+
for (const e of matches) {
|
|
278
|
+
const reason = hiddenReason(e);
|
|
279
|
+
const arr = byReason.get(reason) ?? [];
|
|
280
|
+
arr.push(e);
|
|
281
|
+
byReason.set(reason, arr);
|
|
282
|
+
}
|
|
283
|
+
for (const [reason, list] of byReason) {
|
|
284
|
+
process.stdout.write(`\n${reason} (${list.length}):\n`);
|
|
285
|
+
for (const e of list) {
|
|
286
|
+
process.stdout.write(` shrk ${e.command.padEnd(32)} ${e.description}\n`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return 0;
|
|
290
|
+
}
|
|
291
|
+
function hiddenReason(e) {
|
|
292
|
+
if (e.showInDefaultHelp === false)
|
|
293
|
+
return 'explicit showInDefaultHelp=false';
|
|
294
|
+
const lc = commandLifecycle(e);
|
|
295
|
+
if (lc === CommandLifecycle.Retired)
|
|
296
|
+
return 'retired';
|
|
297
|
+
if (lc === CommandLifecycle.Deprecated)
|
|
298
|
+
return 'deprecated';
|
|
299
|
+
if (lc === CommandLifecycle.Alias)
|
|
300
|
+
return 'alias';
|
|
301
|
+
const surface = commandSurface(e);
|
|
302
|
+
if (surface === CommandSurface.Advanced)
|
|
303
|
+
return 'surface=advanced';
|
|
304
|
+
if (surface === CommandSurface.Machine)
|
|
305
|
+
return 'surface=machine';
|
|
306
|
+
if (surface === CommandSurface.Internal)
|
|
307
|
+
return 'surface=internal';
|
|
308
|
+
if (surface === CommandSurface.Legacy)
|
|
309
|
+
return 'surface=legacy';
|
|
310
|
+
return 'other';
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Build the retirement plan: groups every entry that needs lifecycle
|
|
314
|
+
* attention. Pure for testing.
|
|
315
|
+
*/
|
|
316
|
+
export function buildRetirementPlanReport() {
|
|
317
|
+
const deprecated = [];
|
|
318
|
+
const aliases = [];
|
|
319
|
+
const machineInHelp = [];
|
|
320
|
+
const overlapping = [];
|
|
321
|
+
const missingReplacedBy = [];
|
|
322
|
+
const legacyNoRemoveAfter = [];
|
|
323
|
+
for (const e of COMMAND_CATALOG) {
|
|
324
|
+
const lc = commandLifecycle(e);
|
|
325
|
+
if (lc === CommandLifecycle.Deprecated || lc === CommandLifecycle.Retired) {
|
|
326
|
+
const row = { command: e.command };
|
|
327
|
+
if (e.replacedBy)
|
|
328
|
+
row.replacedBy = e.replacedBy;
|
|
329
|
+
if (e.preferredCommand)
|
|
330
|
+
row.preferredCommand = e.preferredCommand;
|
|
331
|
+
if (e.reason)
|
|
332
|
+
row.reason = e.reason;
|
|
333
|
+
if (e.deprecatedSince)
|
|
334
|
+
row.deprecatedSince = e.deprecatedSince;
|
|
335
|
+
deprecated.push(row);
|
|
336
|
+
if (!e.replacedBy && !e.preferredCommand) {
|
|
337
|
+
missingReplacedBy.push({ command: e.command });
|
|
338
|
+
}
|
|
339
|
+
if (commandSurface(e) === CommandSurface.Legacy && !e.removeAfter) {
|
|
340
|
+
legacyNoRemoveAfter.push({ command: e.command });
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (lc === CommandLifecycle.Alias) {
|
|
344
|
+
const row = { command: e.command };
|
|
345
|
+
if (e.replacedBy)
|
|
346
|
+
row.replacedBy = e.replacedBy;
|
|
347
|
+
if (e.preferredCommand)
|
|
348
|
+
row.preferredCommand = e.preferredCommand;
|
|
349
|
+
aliases.push(row);
|
|
350
|
+
}
|
|
351
|
+
if ((commandSurface(e) === CommandSurface.Machine || e.machineOnly === true) &&
|
|
352
|
+
defaultShowInHelp(e)) {
|
|
353
|
+
machineInHelp.push({ command: e.command });
|
|
354
|
+
}
|
|
355
|
+
if (e.overlapsWith && e.overlapsWith.length > 0) {
|
|
356
|
+
overlapping.push({ command: e.command, overlapsWith: e.overlapsWith });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const groups = [];
|
|
360
|
+
if (deprecated.length)
|
|
361
|
+
groups.push({ reason: 'deprecated', entries: deprecated });
|
|
362
|
+
if (aliases.length)
|
|
363
|
+
groups.push({ reason: 'aliases', entries: aliases });
|
|
364
|
+
if (machineInHelp.length)
|
|
365
|
+
groups.push({ reason: 'machine-in-help', entries: machineInHelp });
|
|
366
|
+
if (overlapping.length)
|
|
367
|
+
groups.push({ reason: 'overlapping', entries: overlapping });
|
|
368
|
+
if (missingReplacedBy.length)
|
|
369
|
+
groups.push({ reason: 'missing-replacedBy', entries: missingReplacedBy });
|
|
370
|
+
if (legacyNoRemoveAfter.length)
|
|
371
|
+
groups.push({ reason: 'legacy-no-removeAfter', entries: legacyNoRemoveAfter });
|
|
372
|
+
return {
|
|
373
|
+
schema: 'sharkcraft.commands-retirement-plan/v1',
|
|
374
|
+
total: groups.reduce((sum, g) => sum + g.entries.length, 0),
|
|
375
|
+
groups,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function runCommandsRetirementPlan(args) {
|
|
379
|
+
const report = buildRetirementPlanReport();
|
|
380
|
+
if (flagBool(args, 'json')) {
|
|
381
|
+
process.stdout.write(asJson(report) + '\n');
|
|
382
|
+
return 0;
|
|
383
|
+
}
|
|
384
|
+
process.stdout.write(header(`Retirement plan (${report.total} entries)`));
|
|
385
|
+
if (report.groups.length === 0) {
|
|
386
|
+
process.stdout.write(' No lifecycle attention needed. ✓\n');
|
|
387
|
+
return 0;
|
|
388
|
+
}
|
|
389
|
+
for (const g of report.groups) {
|
|
390
|
+
process.stdout.write(`\n${g.reason} (${g.entries.length}):\n`);
|
|
391
|
+
for (const e of g.entries) {
|
|
392
|
+
const dest = e.replacedBy ?? e.preferredCommand;
|
|
393
|
+
const arrow = dest ? ` → ${dest}` : '';
|
|
394
|
+
const overlaps = e.overlapsWith ? ` overlaps: ${e.overlapsWith.join(', ')}` : '';
|
|
395
|
+
const since = e.deprecatedSince ? ` since=${e.deprecatedSince}` : '';
|
|
396
|
+
process.stdout.write(` shrk ${e.command}${arrow}${overlaps}${since}\n`);
|
|
397
|
+
if (e.reason)
|
|
398
|
+
process.stdout.write(` reason: ${e.reason}\n`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
process.stdout.write('\nThis report prepares pruning — no commands are removed yet.\n');
|
|
402
|
+
return 0;
|
|
403
|
+
}
|
|
404
|
+
/** `shrk commands legacy` lists deprecated / replaced commands. */
|
|
405
|
+
function runCommandsLegacy(args) {
|
|
406
|
+
const matches = COMMAND_CATALOG.filter((e) => commandSurface(e) === CommandSurface.Legacy || e.replacedBy);
|
|
407
|
+
if (flagBool(args, 'json')) {
|
|
408
|
+
process.stdout.write(asJson({ total: matches.length, entries: matches }) + '\n');
|
|
409
|
+
return 0;
|
|
410
|
+
}
|
|
411
|
+
process.stdout.write(header(`Legacy / replaced commands (${matches.length})`));
|
|
412
|
+
if (matches.length === 0) {
|
|
413
|
+
process.stdout.write(' (none)\n');
|
|
414
|
+
return 0;
|
|
415
|
+
}
|
|
416
|
+
for (const e of matches) {
|
|
417
|
+
const replacedBy = e.replacedBy ? ` → ${e.replacedBy}` : '';
|
|
418
|
+
process.stdout.write(` shrk ${e.command.padEnd(32)} ${e.description}${replacedBy}\n`);
|
|
419
|
+
}
|
|
420
|
+
return 0;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* `shrk commands overlaps` lists commands that declare overlap with
|
|
424
|
+
* others, plus their preferredCommand pointer (or `(none)` for unresolved).
|
|
425
|
+
*/
|
|
426
|
+
function runCommandsOverlaps(args) {
|
|
427
|
+
const rows = [];
|
|
428
|
+
for (const e of COMMAND_CATALOG) {
|
|
429
|
+
if (e.overlapsWith && e.overlapsWith.length > 0) {
|
|
430
|
+
rows.push({
|
|
431
|
+
command: e.command,
|
|
432
|
+
overlapsWith: e.overlapsWith,
|
|
433
|
+
preferredCommand: e.preferredCommand ?? null,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (flagBool(args, 'json')) {
|
|
438
|
+
process.stdout.write(asJson({ total: rows.length, entries: rows }) + '\n');
|
|
439
|
+
return 0;
|
|
440
|
+
}
|
|
441
|
+
process.stdout.write(header(`Overlapping commands (${rows.length})`));
|
|
442
|
+
if (rows.length === 0) {
|
|
443
|
+
process.stdout.write(' (none)\n');
|
|
444
|
+
return 0;
|
|
445
|
+
}
|
|
446
|
+
for (const r of rows) {
|
|
447
|
+
process.stdout.write(` shrk ${r.command}\n`);
|
|
448
|
+
process.stdout.write(` overlaps with: ${r.overlapsWith.join(', ')}\n`);
|
|
449
|
+
process.stdout.write(` prefer: ${r.preferredCommand ?? '(none — add preferredCommand)'}\n`);
|
|
450
|
+
}
|
|
451
|
+
return 0;
|
|
452
|
+
}
|
|
453
|
+
/** Back-compat: the simple top-level entry kept so existing tests still work. */
|
|
454
|
+
export const commandsCommand = {
|
|
455
|
+
name: 'commands',
|
|
456
|
+
description: 'List every `shrk` command with its safety level, side effects, and MCP availability. Use `shrk commands search <query>` to filter.',
|
|
457
|
+
usage: 'shrk commands [search <query>|tree|doctor] [--safety <level>] [--category <name>] [--json]',
|
|
458
|
+
async run(args) {
|
|
459
|
+
const sub = args.positional[0];
|
|
460
|
+
if (sub === 'doctor') {
|
|
461
|
+
return runCommandsDoctor(args, null);
|
|
462
|
+
}
|
|
463
|
+
if (sub === 'tree') {
|
|
464
|
+
return printTree(args);
|
|
465
|
+
}
|
|
466
|
+
// `shrk commands entrypoints` renders the entrypoint matrix
|
|
467
|
+
// (which entrypoint should I use for X?). The pre-existing
|
|
468
|
+
// `shrk commands matrix` continues to print the command safety matrix.
|
|
469
|
+
if (sub === 'entrypoints' || sub === 'workflows') {
|
|
470
|
+
const { buildEntrypointMatrix, renderEntrypointMatrixText } = await import('@shrkcrft/inspector');
|
|
471
|
+
const report = buildEntrypointMatrix();
|
|
472
|
+
if (flagBool(args, 'json')) {
|
|
473
|
+
process.stdout.write(asJson(report) + '\n');
|
|
474
|
+
return 0;
|
|
475
|
+
}
|
|
476
|
+
process.stdout.write(renderEntrypointMatrixText(report));
|
|
477
|
+
return 0;
|
|
478
|
+
}
|
|
479
|
+
if (sub === 'search') {
|
|
480
|
+
const query = args.positional.slice(1).join(' ').toLowerCase().trim();
|
|
481
|
+
const filtered = COMMAND_CATALOG.filter((c) => !query ||
|
|
482
|
+
c.command.toLowerCase().includes(query) ||
|
|
483
|
+
c.description.toLowerCase().includes(query) ||
|
|
484
|
+
c.aliases.some((a) => a.toLowerCase().includes(query)));
|
|
485
|
+
return printCatalog(args, filtered);
|
|
486
|
+
}
|
|
487
|
+
// Keep the new views available even via the back-compat entry.
|
|
488
|
+
if (sub === 'surface')
|
|
489
|
+
return runCommandsSurface(args);
|
|
490
|
+
if (sub === 'machine')
|
|
491
|
+
return runCommandsMachine(args);
|
|
492
|
+
if (sub === 'legacy')
|
|
493
|
+
return runCommandsLegacy(args);
|
|
494
|
+
if (sub === 'overlaps')
|
|
495
|
+
return runCommandsOverlaps(args);
|
|
496
|
+
if (sub === 'advanced')
|
|
497
|
+
return runCommandsAdvanced(args);
|
|
498
|
+
if (sub === 'deprecated')
|
|
499
|
+
return runCommandsDeprecated(args);
|
|
500
|
+
if (sub === 'hidden')
|
|
501
|
+
return runCommandsHidden(args);
|
|
502
|
+
if (sub === 'retirement-plan')
|
|
503
|
+
return runCommandsRetirementPlan(args);
|
|
504
|
+
if (sub === 'docs-check')
|
|
505
|
+
return await runCommandsDocsCheck(args);
|
|
506
|
+
const safetyFilter = flagString(args, 'safety');
|
|
507
|
+
const categoryFilter = flagString(args, 'category');
|
|
508
|
+
let entries = COMMAND_CATALOG;
|
|
509
|
+
if (safetyFilter) {
|
|
510
|
+
entries = entries.filter((e) => e.safetyLevel === safetyFilter);
|
|
511
|
+
}
|
|
512
|
+
if (categoryFilter) {
|
|
513
|
+
entries = entries.filter((e) => e.category === categoryFilter);
|
|
514
|
+
}
|
|
515
|
+
return printCatalog(args, entries);
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
const PRIMARY_COMMAND_HINTS = [
|
|
519
|
+
'doctor',
|
|
520
|
+
'context',
|
|
521
|
+
'task',
|
|
522
|
+
'search',
|
|
523
|
+
'impact',
|
|
524
|
+
'brief',
|
|
525
|
+
'dev start',
|
|
526
|
+
'quality',
|
|
527
|
+
'review packet',
|
|
528
|
+
'report site',
|
|
529
|
+
'release readiness',
|
|
530
|
+
'commands',
|
|
531
|
+
'start-here',
|
|
532
|
+
'onboard',
|
|
533
|
+
// `map` and `handoff` were folded into `architecture map` and `brief`.
|
|
534
|
+
];
|
|
535
|
+
export function buildCommandsUxReport() {
|
|
536
|
+
const issues = [];
|
|
537
|
+
const seenAliases = new Map();
|
|
538
|
+
let primaryReferenced = 0;
|
|
539
|
+
for (const e of COMMAND_CATALOG) {
|
|
540
|
+
if (!e.description || e.description.trim().length < 5) {
|
|
541
|
+
issues.push({
|
|
542
|
+
code: e.description ? 'short-description' : 'missing-description',
|
|
543
|
+
severity: e.description ? 'warning' : 'error',
|
|
544
|
+
message: e.description
|
|
545
|
+
? `description for "${e.command}" is < 5 chars — would not help a reader picking the command`
|
|
546
|
+
: `catalog entry "${e.command}" has no description`,
|
|
547
|
+
command: e.command,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
if (!e.safetyLevel) {
|
|
551
|
+
issues.push({
|
|
552
|
+
code: 'missing-safety-metadata',
|
|
553
|
+
severity: 'error',
|
|
554
|
+
message: `catalog entry "${e.command}" missing safetyLevel`,
|
|
555
|
+
command: e.command,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
if (e.aliases && e.aliases.length > 0) {
|
|
559
|
+
for (const a of e.aliases) {
|
|
560
|
+
const prior = seenAliases.get(a);
|
|
561
|
+
if (prior && prior !== e.command) {
|
|
562
|
+
issues.push({
|
|
563
|
+
code: 'duplicate-alias',
|
|
564
|
+
severity: 'warning',
|
|
565
|
+
message: `alias "${a}" used by both "${prior}" and "${e.command}"`,
|
|
566
|
+
command: e.command,
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
seenAliases.set(a, e.command);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (PRIMARY_COMMAND_HINTS.some((p) => e.command === p || e.command.startsWith(p + ' '))) {
|
|
573
|
+
primaryReferenced += 1;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// Each primary hint should map to at least one catalog entry.
|
|
577
|
+
for (const hint of PRIMARY_COMMAND_HINTS) {
|
|
578
|
+
const found = COMMAND_CATALOG.some((e) => e.command === hint || e.command.startsWith(hint + ' '));
|
|
579
|
+
if (!found) {
|
|
580
|
+
issues.push({
|
|
581
|
+
code: 'unreferenced-primary',
|
|
582
|
+
severity: 'warning',
|
|
583
|
+
message: `primary command "${hint}" has no catalog entry`,
|
|
584
|
+
command: hint,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// Metadata-driven UX checks. Warnings, not errors, unless the
|
|
589
|
+
// issue is clearly structural (none of these currently rise to error).
|
|
590
|
+
for (const e of COMMAND_CATALOG) {
|
|
591
|
+
const surface = commandSurface(e);
|
|
592
|
+
// (a) primary commands should declare an audience (so adopters can see
|
|
593
|
+
// who the command is for at a glance).
|
|
594
|
+
if (surface === CommandSurface.Primary && (!e.intendedAudience || e.intendedAudience.length === 0)) {
|
|
595
|
+
issues.push({
|
|
596
|
+
code: 'primary-without-audience',
|
|
597
|
+
severity: 'warning',
|
|
598
|
+
message: `primary command "${e.command}" has no explicit intendedAudience — readers can't tell who it's for`,
|
|
599
|
+
command: e.command,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
// (b) primary commands should declare a taskRole.
|
|
603
|
+
if (surface === CommandSurface.Primary && !e.taskRole) {
|
|
604
|
+
issues.push({
|
|
605
|
+
code: 'primary-without-role',
|
|
606
|
+
severity: 'warning',
|
|
607
|
+
message: `primary command "${e.command}" has no taskRole — readers can't slot it into the start/context/search/... map`,
|
|
608
|
+
command: e.command,
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
// (c) machine-only commands should not be marked primary. If they're
|
|
612
|
+
// primary they end up promoted to humans on `shrk commands primary`,
|
|
613
|
+
// which is the problem we're trying to fix.
|
|
614
|
+
if (surface === CommandSurface.Primary && e.machineOnly === true) {
|
|
615
|
+
issues.push({
|
|
616
|
+
code: 'machine-marked-primary',
|
|
617
|
+
severity: 'warning',
|
|
618
|
+
message: `command "${e.command}" is marked machineOnly but surface=primary — set surface=machine or remove machineOnly`,
|
|
619
|
+
command: e.command,
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
// (d) legacy entries need a replacement pointer.
|
|
623
|
+
if (surface === CommandSurface.Legacy && !e.replacedBy && !e.preferredCommand) {
|
|
624
|
+
issues.push({
|
|
625
|
+
code: 'legacy-without-replacement',
|
|
626
|
+
severity: 'warning',
|
|
627
|
+
message: `legacy command "${e.command}" has no replacedBy / preferredCommand — readers won't know where to go`,
|
|
628
|
+
command: e.command,
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
// (e) commands that declare an overlap must point to a preferred path
|
|
632
|
+
// (or be the canonical entry — surface=Primary + role=Start). Otherwise
|
|
633
|
+
// the operator doesn't know which of the overlapping ones to pick.
|
|
634
|
+
if (e.overlapsWith && e.overlapsWith.length > 0 && !e.preferredCommand) {
|
|
635
|
+
const isCanonical = surface === CommandSurface.Primary && e.taskRole === 'start';
|
|
636
|
+
if (!isCanonical) {
|
|
637
|
+
issues.push({
|
|
638
|
+
code: 'overlap-without-preferred',
|
|
639
|
+
severity: 'warning',
|
|
640
|
+
message: `command "${e.command}" declares overlapsWith=[${e.overlapsWith.join(', ')}] but no preferredCommand — operator can't tell which one to pick`,
|
|
641
|
+
command: e.command,
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
// (f) description "explains purpose" heuristic: descriptions ≤ 30 chars
|
|
646
|
+
// typically describe what without saying when. We flag this for primary
|
|
647
|
+
// commands only — advanced/internal commands can afford to be terse.
|
|
648
|
+
if (surface === CommandSurface.Primary && e.description.trim().length < 30) {
|
|
649
|
+
issues.push({
|
|
650
|
+
code: 'description-without-purpose',
|
|
651
|
+
severity: 'info',
|
|
652
|
+
message: `primary command "${e.command}" has a short description (${e.description.trim().length} chars) — consider explaining when to use it`,
|
|
653
|
+
command: e.command,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
// (h) deprecated lifecycle requires replacedBy or reason.
|
|
658
|
+
// Overlay-supplied `replacedBy`/`reason` count as well, so the audit
|
|
659
|
+
// can mark batches deprecated without re-shuffling 40+ catalog literals.
|
|
660
|
+
for (const e of COMMAND_CATALOG) {
|
|
661
|
+
const lc = commandLifecycle(e);
|
|
662
|
+
const r46 = R46_OVERLAY[e.command];
|
|
663
|
+
if (lc === CommandLifecycle.Deprecated &&
|
|
664
|
+
!e.replacedBy &&
|
|
665
|
+
!e.preferredCommand &&
|
|
666
|
+
!e.reason &&
|
|
667
|
+
!r46?.replacedBy &&
|
|
668
|
+
!r46?.reason) {
|
|
669
|
+
issues.push({
|
|
670
|
+
code: 'deprecated-without-replacement',
|
|
671
|
+
severity: 'warning',
|
|
672
|
+
message: `deprecated command "${e.command}" has no replacedBy / preferredCommand / reason`,
|
|
673
|
+
command: e.command,
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
if (lc === CommandLifecycle.Alias && !e.replacedBy && !e.preferredCommand) {
|
|
677
|
+
issues.push({
|
|
678
|
+
code: 'alias-without-target',
|
|
679
|
+
severity: 'warning',
|
|
680
|
+
message: `alias command "${e.command}" has no replacedBy / preferredCommand — readers can't find the canonical command`,
|
|
681
|
+
command: e.command,
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
// (i) Non-standard verbosity flags surfaced via description.
|
|
685
|
+
const descLower = e.description.toLowerCase();
|
|
686
|
+
const nonStandard = ['--detailed', '--long', '--more', '--with-detail', '--expand'];
|
|
687
|
+
for (const flag of nonStandard) {
|
|
688
|
+
if (descLower.includes(flag)) {
|
|
689
|
+
issues.push({
|
|
690
|
+
code: 'nonstandard-verbosity-flag',
|
|
691
|
+
severity: 'warning',
|
|
692
|
+
message: `command "${e.command}" advertises non-standard verbosity flag ${flag} — prefer --verbose / --full / --json (see docs/verbosity-vocabulary.md)`,
|
|
693
|
+
command: e.command,
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// (g) too many primary commands for the same taskRole. The agent / new
|
|
699
|
+
// user shouldn't see 5 "start" primary commands; one canonical wins.
|
|
700
|
+
const primaryByRole = new Map();
|
|
701
|
+
for (const e of COMMAND_CATALOG) {
|
|
702
|
+
if (commandSurface(e) === CommandSurface.Primary && e.taskRole) {
|
|
703
|
+
const arr = primaryByRole.get(e.taskRole) ?? [];
|
|
704
|
+
arr.push(e.command);
|
|
705
|
+
primaryByRole.set(e.taskRole, arr);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
for (const [role, cmds] of primaryByRole) {
|
|
709
|
+
if (cmds.length > 4) {
|
|
710
|
+
issues.push({
|
|
711
|
+
code: 'too-many-primary-for-role',
|
|
712
|
+
severity: 'info',
|
|
713
|
+
message: `${cmds.length} primary commands share taskRole="${role}" (${cmds.join(', ')}) — consider promoting one canonical and demoting the rest to common`,
|
|
714
|
+
command: cmds.join(','),
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
const errors = issues.filter((i) => i.severity === 'error').length;
|
|
719
|
+
const warnings = issues.filter((i) => i.severity === 'warning').length;
|
|
720
|
+
return {
|
|
721
|
+
schema: 'sharkcraft.commands-ux-check/v1',
|
|
722
|
+
passed: errors === 0,
|
|
723
|
+
issues,
|
|
724
|
+
summary: {
|
|
725
|
+
catalogEntries: COMMAND_CATALOG.length,
|
|
726
|
+
primaryReferenced,
|
|
727
|
+
errors,
|
|
728
|
+
warnings,
|
|
729
|
+
},
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
async function runCommandsUxCheck(args) {
|
|
733
|
+
const report = buildCommandsUxReport();
|
|
734
|
+
if (flagBool(args, 'json')) {
|
|
735
|
+
process.stdout.write(asJson(report) + '\n');
|
|
736
|
+
return report.passed ? 0 : 1;
|
|
737
|
+
}
|
|
738
|
+
process.stdout.write(header('Commands UX check'));
|
|
739
|
+
process.stdout.write(` catalog ${report.summary.catalogEntries} primary referenced ${report.summary.primaryReferenced} errors ${report.summary.errors} warnings ${report.summary.warnings}\n\n`);
|
|
740
|
+
if (report.issues.length === 0) {
|
|
741
|
+
process.stdout.write('No UX issues found.\n');
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
for (const i of report.issues) {
|
|
745
|
+
process.stdout.write(` [${i.severity.padEnd(8)}] ${i.code.padEnd(24)} ${i.command} — ${i.message}\n`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return report.passed ? 0 : 1;
|
|
749
|
+
}
|
|
750
|
+
/** Pure: build the doctor report. Exported for tests. */
|
|
751
|
+
export function buildCommandsDoctorReport(registry) {
|
|
752
|
+
const issues = [];
|
|
753
|
+
// 1. No duplicate commands.
|
|
754
|
+
const seen = new Set();
|
|
755
|
+
for (const e of COMMAND_CATALOG) {
|
|
756
|
+
if (seen.has(e.command)) {
|
|
757
|
+
issues.push({
|
|
758
|
+
code: 'duplicate-command',
|
|
759
|
+
message: `duplicate catalog entry for "${e.command}"`,
|
|
760
|
+
severity: 'error',
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
seen.add(e.command);
|
|
764
|
+
}
|
|
765
|
+
// 2. Every entry has a safety level + description + category.
|
|
766
|
+
const validLevels = new Set(Object.values(SafetyLevel));
|
|
767
|
+
for (const e of COMMAND_CATALOG) {
|
|
768
|
+
if (!e.description || e.description.trim().length === 0) {
|
|
769
|
+
issues.push({
|
|
770
|
+
code: 'missing-description',
|
|
771
|
+
message: `catalog entry "${e.command}" has empty description`,
|
|
772
|
+
severity: 'error',
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
if (!validLevels.has(e.safetyLevel)) {
|
|
776
|
+
issues.push({
|
|
777
|
+
code: 'invalid-safety-level',
|
|
778
|
+
message: `catalog entry "${e.command}" has invalid safetyLevel "${e.safetyLevel}"`,
|
|
779
|
+
severity: 'error',
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
if (!e.category || e.category.trim().length === 0) {
|
|
783
|
+
issues.push({
|
|
784
|
+
code: 'missing-category',
|
|
785
|
+
message: `catalog entry "${e.command}" has empty category`,
|
|
786
|
+
severity: 'warning',
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
// 3. writes-source ⇒ not MCP-available.
|
|
791
|
+
for (const e of COMMAND_CATALOG) {
|
|
792
|
+
if (e.writesSource && e.mcpAvailable) {
|
|
793
|
+
issues.push({
|
|
794
|
+
code: 'writes-source-via-mcp',
|
|
795
|
+
message: `catalog entry "${e.command}" writes source but is marked mcpAvailable`,
|
|
796
|
+
severity: 'error',
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
// 4. writesSource ⇒ writesFiles.
|
|
801
|
+
for (const e of COMMAND_CATALOG) {
|
|
802
|
+
if (e.writesSource && !e.writesFiles) {
|
|
803
|
+
issues.push({
|
|
804
|
+
code: 'writes-source-without-writes-files',
|
|
805
|
+
message: `catalog entry "${e.command}" sets writesSource but not writesFiles`,
|
|
806
|
+
severity: 'warning',
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
// 5. runs-shell safety level ⇒ runsShell flag (and vice versa).
|
|
811
|
+
for (const e of COMMAND_CATALOG) {
|
|
812
|
+
if (e.safetyLevel === SafetyLevel.RunsShell && !e.runsShell) {
|
|
813
|
+
issues.push({
|
|
814
|
+
code: 'shell-level-without-flag',
|
|
815
|
+
message: `catalog entry "${e.command}" is labeled runs-shell but runsShell=false`,
|
|
816
|
+
severity: 'warning',
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
// 6. Registry coverage: every catalog top-level verb resolves in the registry.
|
|
821
|
+
let registered = 0;
|
|
822
|
+
let registeredSub = 0;
|
|
823
|
+
if (registry) {
|
|
824
|
+
for (const cmd of registry.list())
|
|
825
|
+
registered += 1;
|
|
826
|
+
for (const g of registry.listGroups()) {
|
|
827
|
+
const sub = registry.listGroup(g);
|
|
828
|
+
registeredSub += sub.length;
|
|
829
|
+
}
|
|
830
|
+
for (const e of COMMAND_CATALOG) {
|
|
831
|
+
const parts = e.command.split(' ');
|
|
832
|
+
const top = parts[0];
|
|
833
|
+
const second = parts[1];
|
|
834
|
+
if (!registry.get(top) && !registry.listGroups().includes(top)) {
|
|
835
|
+
issues.push({
|
|
836
|
+
code: 'unregistered-command',
|
|
837
|
+
message: `catalog mentions "${e.command}" but "${top}" is not registered`,
|
|
838
|
+
severity: 'error',
|
|
839
|
+
});
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
if (second && registry.listGroups().includes(top)) {
|
|
843
|
+
// Sub-verbs may be options/flags (e.g. "onboard --write-drafts");
|
|
844
|
+
// only treat the registered subcommand groups as ground truth.
|
|
845
|
+
const knownSub = registry.getSub(top, second);
|
|
846
|
+
// 3-level commands (e.g. `pack author status`) almost always
|
|
847
|
+
// go through an internal dispatcher in the parent command handler;
|
|
848
|
+
// the second level is a verb name, not a registered subcommand.
|
|
849
|
+
// Don't flag those as drift — the parent's existence is enough.
|
|
850
|
+
const isInternalDispatch = parts.length >= 3;
|
|
851
|
+
if (!knownSub && !second.startsWith('--') && !isInternalDispatch) {
|
|
852
|
+
// Promoted from info to error: the catalog must tell the
|
|
853
|
+
// truth about what's wired up. If the catalog claims a verb the
|
|
854
|
+
// registry can't dispatch, that's drift the user shouldn't
|
|
855
|
+
// discover by trying to run the command.
|
|
856
|
+
issues.push({
|
|
857
|
+
code: 'unregistered-subcommand',
|
|
858
|
+
message: `catalog mentions "${e.command}" but no handler for "${top} ${second}"`,
|
|
859
|
+
severity: 'error',
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
// 7. Registered commands without a catalog entry.
|
|
865
|
+
for (const c of registry.list()) {
|
|
866
|
+
const inCatalog = COMMAND_CATALOG.some((e) => e.command === c.name || e.command.startsWith(c.name + ' '));
|
|
867
|
+
if (!inCatalog) {
|
|
868
|
+
// Promoted to error for primary verbs: if a user types
|
|
869
|
+
// `shrk help <cmd>` we should be able to print catalog metadata
|
|
870
|
+
// for it.
|
|
871
|
+
issues.push({
|
|
872
|
+
code: 'missing-catalog-entry',
|
|
873
|
+
message: `command "${c.name}" is registered but has no catalog entry`,
|
|
874
|
+
severity: 'error',
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
if (!c.usage || c.usage.trim().length === 0) {
|
|
878
|
+
issues.push({
|
|
879
|
+
code: 'missing-usage',
|
|
880
|
+
message: `command "${c.name}" has empty usage`,
|
|
881
|
+
severity: 'warning',
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
const errors = issues.filter((i) => i.severity === 'error').length;
|
|
887
|
+
const warnings = issues.filter((i) => i.severity === 'warning').length;
|
|
888
|
+
return {
|
|
889
|
+
passed: errors === 0,
|
|
890
|
+
issues,
|
|
891
|
+
summary: {
|
|
892
|
+
catalogEntries: COMMAND_CATALOG.length,
|
|
893
|
+
registeredCommands: registered,
|
|
894
|
+
registeredSubcommands: registeredSub,
|
|
895
|
+
errors,
|
|
896
|
+
warnings,
|
|
897
|
+
},
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
function runCommandsDoctor(args, registry) {
|
|
901
|
+
const report = buildCommandsDoctorReport(registry);
|
|
902
|
+
const strict = flagBool(args, 'strict');
|
|
903
|
+
// `--strict` promotes any catalog drift (warnings AND info) to a
|
|
904
|
+
// failing verdict. Without --strict, only errors fail the verdict.
|
|
905
|
+
const failed = report.summary.errors > 0 || (strict && report.summary.warnings > 0);
|
|
906
|
+
if (flagBool(args, 'json')) {
|
|
907
|
+
process.stdout.write(asJson({
|
|
908
|
+
...report,
|
|
909
|
+
strict,
|
|
910
|
+
verdict: failed ? 'drift' : 'clean',
|
|
911
|
+
}) + '\n');
|
|
912
|
+
return failed ? 1 : 0;
|
|
913
|
+
}
|
|
914
|
+
process.stdout.write(header('Command catalog doctor'));
|
|
915
|
+
process.stdout.write(` catalogEntries: ${report.summary.catalogEntries}\n` +
|
|
916
|
+
` registered: ${report.summary.registeredCommands}\n` +
|
|
917
|
+
` subcommands: ${report.summary.registeredSubcommands}\n` +
|
|
918
|
+
` errors: ${report.summary.errors}\n` +
|
|
919
|
+
` warnings: ${report.summary.warnings}\n` +
|
|
920
|
+
(strict ? ` strict: on\n` : '') +
|
|
921
|
+
'\n');
|
|
922
|
+
if (report.issues.length === 0) {
|
|
923
|
+
process.stdout.write('No issues.\n');
|
|
924
|
+
return 0;
|
|
925
|
+
}
|
|
926
|
+
for (const i of report.issues) {
|
|
927
|
+
process.stdout.write(` ${i.severity.toUpperCase().padEnd(8)} ${i.code.padEnd(34)} ${i.message}\n`);
|
|
928
|
+
}
|
|
929
|
+
process.stdout.write(`\nVerdict: ${failed ? 'CATALOG DRIFT' : 'OK ✓'}\n`);
|
|
930
|
+
return failed ? 1 : 0;
|
|
931
|
+
}
|
|
932
|
+
function printCatalog(args, entries) {
|
|
933
|
+
if (flagBool(args, 'json')) {
|
|
934
|
+
process.stdout.write(asJson(entries) + '\n');
|
|
935
|
+
return 0;
|
|
936
|
+
}
|
|
937
|
+
process.stdout.write(header(`SharkCraft commands (${entries.length})`));
|
|
938
|
+
const grouped = new Map();
|
|
939
|
+
for (const e of entries) {
|
|
940
|
+
const arr = grouped.get(e.category) ?? [];
|
|
941
|
+
arr.push(e);
|
|
942
|
+
grouped.set(e.category, arr);
|
|
943
|
+
}
|
|
944
|
+
for (const [cat, items] of [...grouped.entries()].sort(([a], [b]) => a.localeCompare(b))) {
|
|
945
|
+
process.stdout.write(`\n## ${cat}\n`);
|
|
946
|
+
for (const e of items.sort((a, b) => a.command.localeCompare(b.command))) {
|
|
947
|
+
const safety = safetyTag(e.safetyLevel);
|
|
948
|
+
process.stdout.write(` ${safety} ${e.command.padEnd(34)} ${e.description}\n`);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
return 0;
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Compact default-view renderer. Only entries that pass
|
|
955
|
+
* {@link defaultShowInHelp} are listed, and they are grouped into three
|
|
956
|
+
* fixed sections (start / common-validation / common-generation+review+apply).
|
|
957
|
+
* Advanced / machine / deprecated / hidden are reachable via dedicated
|
|
958
|
+
* subcommands, surfaced in the trailing "See more" block.
|
|
959
|
+
*/
|
|
960
|
+
function printCompactCatalog(args, entries) {
|
|
961
|
+
if (flagBool(args, 'json')) {
|
|
962
|
+
// JSON keeps the legacy unfiltered shape so downstream tools don't break;
|
|
963
|
+
// the compaction is human-output-only.
|
|
964
|
+
process.stdout.write(asJson(entries) + '\n');
|
|
965
|
+
return 0;
|
|
966
|
+
}
|
|
967
|
+
const visible = entries.filter((e) => defaultShowInHelp(e));
|
|
968
|
+
const primary = visible.filter((e) => commandSurface(e) === CommandSurface.Primary);
|
|
969
|
+
const common = visible.filter((e) => commandSurface(e) === CommandSurface.Common);
|
|
970
|
+
process.stdout.write(header(`SharkCraft commands (default view — ${visible.length} of ${entries.length})`));
|
|
971
|
+
process.stdout.write('Primary commands (start here — canonical answers for common questions):\n');
|
|
972
|
+
for (const e of sortByCommand(primary)) {
|
|
973
|
+
const safety = safetyTag(e.safetyLevel);
|
|
974
|
+
process.stdout.write(` ${safety} ${e.command.padEnd(34)} ${e.description}\n`);
|
|
975
|
+
}
|
|
976
|
+
if (common.length > 0) {
|
|
977
|
+
// Surface only the common verbs that pair with one of the
|
|
978
|
+
// canonical task-roles users reach for from the start screen
|
|
979
|
+
// (generate / review / apply / validate / inspect / diagnose / config).
|
|
980
|
+
// Everything else stays one flag away (`--all`).
|
|
981
|
+
const allowedRoles = new Set(['generate', 'review', 'apply', 'validate', 'inspect', 'diagnose', 'config', 'release']);
|
|
982
|
+
const featured = sortByCommand(common).filter((e) => {
|
|
983
|
+
const role = commandTaskRole(e);
|
|
984
|
+
if (role && allowedRoles.has(role))
|
|
985
|
+
return true;
|
|
986
|
+
// Top-level verbs without subcommand suffix are still featured even
|
|
987
|
+
// without a role — they're the "front door" surfaces.
|
|
988
|
+
return !e.command.includes(' ');
|
|
989
|
+
});
|
|
990
|
+
const featuredLimit = 12;
|
|
991
|
+
process.stdout.write('\nCommon commands (frequent / well-documented surfaces):\n');
|
|
992
|
+
for (const e of featured.slice(0, featuredLimit)) {
|
|
993
|
+
const safety = safetyTag(e.safetyLevel);
|
|
994
|
+
process.stdout.write(` ${safety} ${e.command.padEnd(34)} ${e.description}\n`);
|
|
995
|
+
}
|
|
996
|
+
const remaining = common.length - Math.min(featured.length, featuredLimit);
|
|
997
|
+
if (remaining > 0) {
|
|
998
|
+
process.stdout.write(` … (${remaining} more — pass --all to see every common command)\n`);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
process.stdout.write('\nSee more:\n');
|
|
1002
|
+
process.stdout.write(' $ shrk commands --all — full catalog\n');
|
|
1003
|
+
process.stdout.write(' $ shrk commands advanced — advanced surfaces\n');
|
|
1004
|
+
process.stdout.write(' $ shrk commands machine — machine / JSON-pipe surfaces\n');
|
|
1005
|
+
process.stdout.write(' $ shrk commands deprecated — deprecated / replaced commands\n');
|
|
1006
|
+
process.stdout.write(' $ shrk commands hidden — every hidden-from-default command\n');
|
|
1007
|
+
process.stdout.write(' $ shrk commands overlaps — overlapping surfaces + preferred entrypoint\n');
|
|
1008
|
+
process.stdout.write(' $ shrk commands retirement-plan — lifecycle backlog\n');
|
|
1009
|
+
process.stdout.write(' $ shrk commands taxonomy — domain grouping\n');
|
|
1010
|
+
process.stdout.write(' $ shrk commands explain <cmd> — detail for one command\n');
|
|
1011
|
+
return 0;
|
|
1012
|
+
}
|
|
1013
|
+
function sortByCommand(entries) {
|
|
1014
|
+
return [...entries].sort((a, b) => a.command.localeCompare(b.command));
|
|
1015
|
+
}
|
|
1016
|
+
const DOCS_TO_CHECK = [
|
|
1017
|
+
'docs/command-entrypoints.md',
|
|
1018
|
+
'docs/start-here.md',
|
|
1019
|
+
'docs/overview.md',
|
|
1020
|
+
];
|
|
1021
|
+
export async function buildDocsCheckReport(cwd) {
|
|
1022
|
+
const { readFileSync, existsSync } = await import('node:fs');
|
|
1023
|
+
const { resolve } = await import('node:path');
|
|
1024
|
+
const root = cwd ?? process.cwd();
|
|
1025
|
+
const issues = [];
|
|
1026
|
+
const catalogByCommand = new Map();
|
|
1027
|
+
for (const e of COMMAND_CATALOG)
|
|
1028
|
+
catalogByCommand.set(e.command, e);
|
|
1029
|
+
// (a) replacedBy / preferredCommand pointers must resolve to a real
|
|
1030
|
+
// catalog command — these are structural and rise to error.
|
|
1031
|
+
for (const e of COMMAND_CATALOG) {
|
|
1032
|
+
if (e.replacedBy) {
|
|
1033
|
+
const target = stripShrkPrefix(e.replacedBy);
|
|
1034
|
+
if (!targetMatchesCatalog(target, catalogByCommand)) {
|
|
1035
|
+
issues.push({
|
|
1036
|
+
code: 'replaced-by-missing',
|
|
1037
|
+
severity: 'error',
|
|
1038
|
+
command: e.command,
|
|
1039
|
+
message: `replacedBy "${e.replacedBy}" does not resolve to a catalog command`,
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
if (e.preferredCommand) {
|
|
1044
|
+
const target = stripShrkPrefix(e.preferredCommand);
|
|
1045
|
+
if (!targetMatchesCatalog(target, catalogByCommand)) {
|
|
1046
|
+
issues.push({
|
|
1047
|
+
code: 'preferred-command-missing',
|
|
1048
|
+
severity: 'warning',
|
|
1049
|
+
command: e.command,
|
|
1050
|
+
message: `preferredCommand "${e.preferredCommand}" does not resolve to a catalog command`,
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
// (b) walk DOCS_TO_CHECK, extract `shrk <verb>` references, warn on stale
|
|
1056
|
+
// or deprecated targets.
|
|
1057
|
+
let filesChecked = 0;
|
|
1058
|
+
for (const rel of DOCS_TO_CHECK) {
|
|
1059
|
+
const abs = resolve(root, rel);
|
|
1060
|
+
if (!existsSync(abs))
|
|
1061
|
+
continue;
|
|
1062
|
+
filesChecked += 1;
|
|
1063
|
+
const content = readFileSync(abs, 'utf8');
|
|
1064
|
+
const refs = extractShrkRefs(content);
|
|
1065
|
+
for (const ref of refs) {
|
|
1066
|
+
const stripped = stripShrkPrefix(ref);
|
|
1067
|
+
const match = matchCatalogEntry(stripped, catalogByCommand);
|
|
1068
|
+
if (!match) {
|
|
1069
|
+
issues.push({
|
|
1070
|
+
code: 'stale-doc-reference',
|
|
1071
|
+
severity: 'info',
|
|
1072
|
+
file: rel,
|
|
1073
|
+
command: ref,
|
|
1074
|
+
message: `${rel} references \`shrk ${stripped}\` but no catalog command matches`,
|
|
1075
|
+
});
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
const lc = commandLifecycle(match);
|
|
1079
|
+
if (lc === CommandLifecycle.Deprecated || lc === CommandLifecycle.Retired) {
|
|
1080
|
+
const r46 = R46_OVERLAY[match.command];
|
|
1081
|
+
const replacement = match.replacedBy ?? match.preferredCommand ?? r46?.replacedBy ?? '(no replacement)';
|
|
1082
|
+
issues.push({
|
|
1083
|
+
code: 'doc-promotes-deprecated',
|
|
1084
|
+
severity: 'warning',
|
|
1085
|
+
file: rel,
|
|
1086
|
+
command: match.command,
|
|
1087
|
+
message: `${rel} promotes deprecated command \`shrk ${match.command}\` — prefer \`${replacement}\``,
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
const errors = issues.filter((i) => i.severity === 'error').length;
|
|
1093
|
+
const warnings = issues.filter((i) => i.severity === 'warning').length;
|
|
1094
|
+
const info = issues.filter((i) => i.severity === 'info').length;
|
|
1095
|
+
return {
|
|
1096
|
+
schema: 'sharkcraft.commands-docs-check/v1',
|
|
1097
|
+
passed: errors === 0,
|
|
1098
|
+
filesChecked,
|
|
1099
|
+
issues,
|
|
1100
|
+
summary: { errors, warnings, info },
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
function stripShrkPrefix(s) {
|
|
1104
|
+
return s.replace(/^shrk\s+/, '').replace(/[`"<]+/g, '').replace(/[`">]+$/, '').trim();
|
|
1105
|
+
}
|
|
1106
|
+
function targetMatchesCatalog(target, byCommand) {
|
|
1107
|
+
return matchCatalogEntry(target, byCommand) !== undefined;
|
|
1108
|
+
}
|
|
1109
|
+
function matchCatalogEntry(target, byCommand) {
|
|
1110
|
+
const head = target.split(/\s+/).filter((t) => !t.startsWith('<')).join(' ').trim();
|
|
1111
|
+
if (!head)
|
|
1112
|
+
return undefined;
|
|
1113
|
+
const direct = byCommand.get(head);
|
|
1114
|
+
if (direct)
|
|
1115
|
+
return direct;
|
|
1116
|
+
const parts = head.split(/\s+/);
|
|
1117
|
+
while (parts.length > 0) {
|
|
1118
|
+
const joined = parts.join(' ');
|
|
1119
|
+
const m = byCommand.get(joined);
|
|
1120
|
+
if (m)
|
|
1121
|
+
return m;
|
|
1122
|
+
// Group prefix match (e.g. `report site` → any `report …` catalog entry).
|
|
1123
|
+
const groupHit = [...byCommand.values()].find((e) => e.command.startsWith(joined + ' '));
|
|
1124
|
+
if (groupHit)
|
|
1125
|
+
return groupHit;
|
|
1126
|
+
parts.pop();
|
|
1127
|
+
}
|
|
1128
|
+
return undefined;
|
|
1129
|
+
}
|
|
1130
|
+
const SHRK_REF_RE = /shrk\s+([a-z][a-z0-9_\-]*(?:\s+[a-z][a-z0-9_\-]*)*)/gi;
|
|
1131
|
+
function extractShrkRefs(content) {
|
|
1132
|
+
const out = new Set();
|
|
1133
|
+
let match;
|
|
1134
|
+
SHRK_REF_RE.lastIndex = 0;
|
|
1135
|
+
while ((match = SHRK_REF_RE.exec(content)) !== null) {
|
|
1136
|
+
const candidate = match[1].trim();
|
|
1137
|
+
if (!candidate)
|
|
1138
|
+
continue;
|
|
1139
|
+
// Skip references to flags / quoted tokens — they're not real commands.
|
|
1140
|
+
if (candidate.startsWith('-'))
|
|
1141
|
+
continue;
|
|
1142
|
+
out.add(candidate);
|
|
1143
|
+
}
|
|
1144
|
+
return [...out];
|
|
1145
|
+
}
|
|
1146
|
+
async function runCommandsDocsCheck(args) {
|
|
1147
|
+
const report = await buildDocsCheckReport();
|
|
1148
|
+
if (flagBool(args, 'json')) {
|
|
1149
|
+
process.stdout.write(asJson(report) + '\n');
|
|
1150
|
+
return report.passed ? 0 : 1;
|
|
1151
|
+
}
|
|
1152
|
+
process.stdout.write(header('Commands docs-check'));
|
|
1153
|
+
process.stdout.write(` files ${report.filesChecked} errors ${report.summary.errors} warnings ${report.summary.warnings} info ${report.summary.info}\n\n`);
|
|
1154
|
+
if (report.issues.length === 0) {
|
|
1155
|
+
process.stdout.write('No docs drift detected. ✓\n');
|
|
1156
|
+
return 0;
|
|
1157
|
+
}
|
|
1158
|
+
for (const i of report.issues) {
|
|
1159
|
+
const tag = `[${i.severity.padEnd(8)}] ${i.code.padEnd(28)}`;
|
|
1160
|
+
const file = i.file ? ` ${i.file}:` : '';
|
|
1161
|
+
process.stdout.write(` ${tag}${file} ${i.message}\n`);
|
|
1162
|
+
}
|
|
1163
|
+
return report.passed ? 0 : 1;
|
|
1164
|
+
}
|
|
1165
|
+
function printTree(args) {
|
|
1166
|
+
if (flagBool(args, 'json')) {
|
|
1167
|
+
const tree = {};
|
|
1168
|
+
for (const e of COMMAND_CATALOG) {
|
|
1169
|
+
const top = e.command.split(' ')[0];
|
|
1170
|
+
tree[top] = tree[top] ?? [];
|
|
1171
|
+
tree[top].push(e);
|
|
1172
|
+
}
|
|
1173
|
+
process.stdout.write(asJson(tree) + '\n');
|
|
1174
|
+
return 0;
|
|
1175
|
+
}
|
|
1176
|
+
const seen = new Set();
|
|
1177
|
+
process.stdout.write(header('Command tree'));
|
|
1178
|
+
for (const e of COMMAND_CATALOG) {
|
|
1179
|
+
const top = e.command.split(' ')[0];
|
|
1180
|
+
if (!seen.has(top)) {
|
|
1181
|
+
process.stdout.write(`\n${top}\n`);
|
|
1182
|
+
seen.add(top);
|
|
1183
|
+
}
|
|
1184
|
+
if (e.command !== top) {
|
|
1185
|
+
process.stdout.write(` • ${e.command}\n`);
|
|
1186
|
+
}
|
|
1187
|
+
else {
|
|
1188
|
+
process.stdout.write(` • (top-level) ${e.description}\n`);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return 0;
|
|
1192
|
+
}
|
|
1193
|
+
function safetyTag(level) {
|
|
1194
|
+
switch (level) {
|
|
1195
|
+
case SafetyLevel.ReadOnly:
|
|
1196
|
+
return 'READ ';
|
|
1197
|
+
case SafetyLevel.WritesSessionOnly:
|
|
1198
|
+
return 'SESS ';
|
|
1199
|
+
case SafetyLevel.WritesDraftsOnly:
|
|
1200
|
+
return 'DRAFT';
|
|
1201
|
+
case SafetyLevel.WritesSource:
|
|
1202
|
+
return 'WRITE';
|
|
1203
|
+
case SafetyLevel.RunsShell:
|
|
1204
|
+
return 'SHELL';
|
|
1205
|
+
case SafetyLevel.RequiresReview:
|
|
1206
|
+
return 'REVW ';
|
|
1207
|
+
}
|
|
1208
|
+
}
|