@opengsd/gsd-core 1.2.0-rc.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.ja-JP.md +870 -0
- package/README.ko-KR.md +861 -0
- package/README.md +301 -0
- package/README.pt-BR.md +492 -0
- package/README.zh-CN.md +842 -0
- package/agents/gsd-advisor-researcher.md +127 -0
- package/agents/gsd-ai-researcher.md +133 -0
- package/agents/gsd-assumptions-analyzer.md +105 -0
- package/agents/gsd-code-fixer.md +668 -0
- package/agents/gsd-code-reviewer.md +387 -0
- package/agents/gsd-codebase-mapper.md +853 -0
- package/agents/gsd-debug-session-manager.md +314 -0
- package/agents/gsd-debugger.md +1452 -0
- package/agents/gsd-doc-classifier.md +168 -0
- package/agents/gsd-doc-synthesizer.md +204 -0
- package/agents/gsd-doc-verifier.md +217 -0
- package/agents/gsd-doc-writer.md +615 -0
- package/agents/gsd-domain-researcher.md +153 -0
- package/agents/gsd-eval-auditor.md +191 -0
- package/agents/gsd-eval-planner.md +154 -0
- package/agents/gsd-executor.md +772 -0
- package/agents/gsd-framework-selector.md +160 -0
- package/agents/gsd-integration-checker.md +470 -0
- package/agents/gsd-intel-updater.md +342 -0
- package/agents/gsd-nyquist-auditor.md +203 -0
- package/agents/gsd-pattern-mapper.md +335 -0
- package/agents/gsd-phase-researcher.md +928 -0
- package/agents/gsd-plan-checker.md +978 -0
- package/agents/gsd-planner.md +1218 -0
- package/agents/gsd-project-researcher.md +677 -0
- package/agents/gsd-research-synthesizer.md +255 -0
- package/agents/gsd-roadmapper.md +688 -0
- package/agents/gsd-security-auditor.md +155 -0
- package/agents/gsd-ui-auditor.md +495 -0
- package/agents/gsd-ui-checker.md +309 -0
- package/agents/gsd-ui-researcher.md +380 -0
- package/agents/gsd-user-profiler.md +171 -0
- package/agents/gsd-verifier.md +917 -0
- package/bin/install.js +10936 -0
- package/bin/lib/ui-safety-gate.cjs +107 -0
- package/commands/gsd/add-tests.md +42 -0
- package/commands/gsd/ai-integration-phase.md +37 -0
- package/commands/gsd/audit-fix.md +34 -0
- package/commands/gsd/audit-milestone.md +37 -0
- package/commands/gsd/audit-uat.md +24 -0
- package/commands/gsd/autonomous.md +46 -0
- package/commands/gsd/capture.md +62 -0
- package/commands/gsd/cleanup.md +24 -0
- package/commands/gsd/code-review.md +59 -0
- package/commands/gsd/complete-milestone.md +143 -0
- package/commands/gsd/config.md +56 -0
- package/commands/gsd/debug.md +52 -0
- package/commands/gsd/discuss-phase.md +76 -0
- package/commands/gsd/docs-update.md +49 -0
- package/commands/gsd/eval-review.md +33 -0
- package/commands/gsd/execute-phase.md +64 -0
- package/commands/gsd/explore.md +27 -0
- package/commands/gsd/extract-learnings.md +23 -0
- package/commands/gsd/fast.md +31 -0
- package/commands/gsd/forensics.md +57 -0
- package/commands/gsd/graphify.md +199 -0
- package/commands/gsd/health.md +31 -0
- package/commands/gsd/help.md +28 -0
- package/commands/gsd/import.md +41 -0
- package/commands/gsd/inbox.md +39 -0
- package/commands/gsd/ingest-docs.md +42 -0
- package/commands/gsd/manager.md +45 -0
- package/commands/gsd/map-codebase.md +83 -0
- package/commands/gsd/milestone-summary.md +51 -0
- package/commands/gsd/mvp-phase.md +45 -0
- package/commands/gsd/new-milestone.md +45 -0
- package/commands/gsd/new-project.md +47 -0
- package/commands/gsd/ns-context.md +23 -0
- package/commands/gsd/ns-ideate.md +24 -0
- package/commands/gsd/ns-manage.md +29 -0
- package/commands/gsd/ns-project.md +22 -0
- package/commands/gsd/ns-review.md +26 -0
- package/commands/gsd/ns-workflow.md +28 -0
- package/commands/gsd/pause-work.md +43 -0
- package/commands/gsd/phase.md +56 -0
- package/commands/gsd/plan-phase.md +62 -0
- package/commands/gsd/plan-review-convergence.md +59 -0
- package/commands/gsd/pr-branch.md +26 -0
- package/commands/gsd/profile-user.md +46 -0
- package/commands/gsd/progress.md +47 -0
- package/commands/gsd/quick.md +174 -0
- package/commands/gsd/resume-work.md +30 -0
- package/commands/gsd/review-backlog.md +63 -0
- package/commands/gsd/review.md +41 -0
- package/commands/gsd/secure-phase.md +36 -0
- package/commands/gsd/settings.md +29 -0
- package/commands/gsd/ship.md +24 -0
- package/commands/gsd/sketch.md +60 -0
- package/commands/gsd/spec-phase.md +63 -0
- package/commands/gsd/spike.md +57 -0
- package/commands/gsd/stats.md +19 -0
- package/commands/gsd/surface.md +155 -0
- package/commands/gsd/thread.md +24 -0
- package/commands/gsd/ui-phase.md +35 -0
- package/commands/gsd/ui-review.md +33 -0
- package/commands/gsd/ultraplan-phase.md +34 -0
- package/commands/gsd/undo.md +35 -0
- package/commands/gsd/update.md +48 -0
- package/commands/gsd/validate-phase.md +36 -0
- package/commands/gsd/verify-work.md +39 -0
- package/commands/gsd/workspace.md +52 -0
- package/commands/gsd/workstreams.md +70 -0
- package/get-shit-done/bin/check-latest-version.cjs +106 -0
- package/get-shit-done/bin/gsd-tools.cjs +1676 -0
- package/get-shit-done/bin/lib/active-workstream-store.cjs +302 -0
- package/get-shit-done/bin/lib/adr-parser.cjs +394 -0
- package/get-shit-done/bin/lib/agent-command-router.cjs +65 -0
- package/get-shit-done/bin/lib/artifacts.cjs +53 -0
- package/get-shit-done/bin/lib/audit.cjs +755 -0
- package/get-shit-done/bin/lib/check-command-router.cjs +333 -0
- package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +118 -0
- package/get-shit-done/bin/lib/clock.cjs +96 -0
- package/get-shit-done/bin/lib/clusters.cjs +135 -0
- package/get-shit-done/bin/lib/code-review-flags.cjs +74 -0
- package/get-shit-done/bin/lib/command-aliases.cjs +815 -0
- package/get-shit-done/bin/lib/command-arg-projection.cjs +62 -0
- package/get-shit-done/bin/lib/command-routing-hub.cjs +388 -0
- package/get-shit-done/bin/lib/commands.cjs +1188 -0
- package/get-shit-done/bin/lib/config-schema.cjs +31 -0
- package/get-shit-done/bin/lib/config.cjs +728 -0
- package/get-shit-done/bin/lib/configuration.cjs +248 -0
- package/get-shit-done/bin/lib/context-utilization.cjs +47 -0
- package/get-shit-done/bin/lib/core.cjs +2121 -0
- package/get-shit-done/bin/lib/decisions.cjs +116 -0
- package/get-shit-done/bin/lib/docs.cjs +270 -0
- package/get-shit-done/bin/lib/drift.cjs +388 -0
- package/get-shit-done/bin/lib/fallow-runner.cjs +109 -0
- package/get-shit-done/bin/lib/frontmatter.cjs +389 -0
- package/get-shit-done/bin/lib/gap-checker.cjs +205 -0
- package/get-shit-done/bin/lib/graphify.cjs +592 -0
- package/get-shit-done/bin/lib/gsd2-import.cjs +514 -0
- package/get-shit-done/bin/lib/init-command-router.cjs +58 -0
- package/get-shit-done/bin/lib/init.cjs +2112 -0
- package/get-shit-done/bin/lib/install-profiles.cjs +603 -0
- package/get-shit-done/bin/lib/installer-migration-authoring.cjs +117 -0
- package/get-shit-done/bin/lib/installer-migration-report.cjs +354 -0
- package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +220 -0
- package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +41 -0
- package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +80 -0
- package/get-shit-done/bin/lib/installer-migrations.cjs +778 -0
- package/get-shit-done/bin/lib/intel.cjs +708 -0
- package/get-shit-done/bin/lib/learnings.cjs +421 -0
- package/get-shit-done/bin/lib/milestone.cjs +314 -0
- package/get-shit-done/bin/lib/model-catalog.cjs +212 -0
- package/get-shit-done/bin/lib/model-profiles.cjs +31 -0
- package/get-shit-done/bin/lib/observability/event.cjs +82 -0
- package/get-shit-done/bin/lib/observability/logger.cjs +174 -0
- package/get-shit-done/bin/lib/observability/redaction.cjs +50 -0
- package/get-shit-done/bin/lib/package-identity.cjs +31 -0
- package/get-shit-done/bin/lib/phase-command-router.cjs +191 -0
- package/get-shit-done/bin/lib/phase-lifecycle.cjs +80 -0
- package/get-shit-done/bin/lib/phase.cjs +1607 -0
- package/get-shit-done/bin/lib/phases-command-router.cjs +39 -0
- package/get-shit-done/bin/lib/plan-scan.cjs +97 -0
- package/get-shit-done/bin/lib/planning-workspace.cjs +238 -0
- package/get-shit-done/bin/lib/profile-output.cjs +1141 -0
- package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
- package/get-shit-done/bin/lib/project-root.cjs +112 -0
- package/get-shit-done/bin/lib/prompt-budget.cjs +399 -0
- package/get-shit-done/bin/lib/review-reviewer-selection.cjs +125 -0
- package/get-shit-done/bin/lib/roadmap-command-router.cjs +28 -0
- package/get-shit-done/bin/lib/roadmap.cjs +650 -0
- package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +301 -0
- package/get-shit-done/bin/lib/runtime-homes.cjs +222 -0
- package/get-shit-done/bin/lib/runtime-name-policy.cjs +83 -0
- package/get-shit-done/bin/lib/runtime-slash.cjs +112 -0
- package/get-shit-done/bin/lib/schema-detect.cjs +165 -0
- package/get-shit-done/bin/lib/secrets.cjs +32 -0
- package/get-shit-done/bin/lib/security.cjs +600 -0
- package/get-shit-done/bin/lib/semver-compare.cjs +35 -0
- package/get-shit-done/bin/lib/shell-command-projection.cjs +500 -0
- package/get-shit-done/bin/lib/state-command-router.cjs +252 -0
- package/get-shit-done/bin/lib/state-document.cjs +263 -0
- package/get-shit-done/bin/lib/state.cjs +2038 -0
- package/get-shit-done/bin/lib/surface.cjs +470 -0
- package/get-shit-done/bin/lib/task-command-router.cjs +81 -0
- package/get-shit-done/bin/lib/template.cjs +228 -0
- package/get-shit-done/bin/lib/uat.cjs +289 -0
- package/get-shit-done/bin/lib/update-context.cjs +209 -0
- package/get-shit-done/bin/lib/validate-command-router.cjs +83 -0
- package/get-shit-done/bin/lib/validate.cjs +92 -0
- package/get-shit-done/bin/lib/verify-command-router.cjs +40 -0
- package/get-shit-done/bin/lib/verify.cjs +1511 -0
- package/get-shit-done/bin/lib/workstream-inventory-builder.cjs +74 -0
- package/get-shit-done/bin/lib/workstream-inventory.cjs +146 -0
- package/get-shit-done/bin/lib/workstream-name-policy.cjs +94 -0
- package/get-shit-done/bin/lib/workstream.cjs +389 -0
- package/get-shit-done/bin/lib/worktree-safety.cjs +985 -0
- package/get-shit-done/bin/shared/config-defaults.manifest.json +97 -0
- package/get-shit-done/bin/shared/config-schema.manifest.json +175 -0
- package/get-shit-done/bin/shared/model-catalog.json +122 -0
- package/get-shit-done/bin/shared/runtime-aliases.manifest.json +75 -0
- package/get-shit-done/bin/verify-reapply-patches.cjs +352 -0
- package/get-shit-done/contexts/dev.md +21 -0
- package/get-shit-done/contexts/research.md +22 -0
- package/get-shit-done/contexts/review.md +23 -0
- package/get-shit-done/references/agent-contracts.md +79 -0
- package/get-shit-done/references/ai-evals.md +156 -0
- package/get-shit-done/references/ai-frameworks.md +186 -0
- package/get-shit-done/references/artifact-types.md +131 -0
- package/get-shit-done/references/autonomous-smart-discuss.md +277 -0
- package/get-shit-done/references/checkpoints.md +814 -0
- package/get-shit-done/references/common-bug-patterns.md +114 -0
- package/get-shit-done/references/context-budget.md +85 -0
- package/get-shit-done/references/continuation-format.md +253 -0
- package/get-shit-done/references/debugger-philosophy.md +76 -0
- package/get-shit-done/references/decimal-phase-calculation.md +64 -0
- package/get-shit-done/references/doc-conflict-engine.md +91 -0
- package/get-shit-done/references/domain-probes.md +125 -0
- package/get-shit-done/references/execute-mvp-tdd.md +81 -0
- package/get-shit-done/references/executor-examples.md +110 -0
- package/get-shit-done/references/few-shot-examples/plan-checker.md +73 -0
- package/get-shit-done/references/few-shot-examples/verifier.md +109 -0
- package/get-shit-done/references/gate-prompts.md +100 -0
- package/get-shit-done/references/gates.md +70 -0
- package/get-shit-done/references/git-integration.md +298 -0
- package/get-shit-done/references/git-planning-commit.md +40 -0
- package/get-shit-done/references/ios-scaffold.md +123 -0
- package/get-shit-done/references/mandatory-initial-read.md +2 -0
- package/get-shit-done/references/model-profile-resolution.md +38 -0
- package/get-shit-done/references/model-profiles.md +245 -0
- package/get-shit-done/references/mvp-concepts.md +49 -0
- package/get-shit-done/references/phase-argument-parsing.md +61 -0
- package/get-shit-done/references/planner-antipatterns.md +89 -0
- package/get-shit-done/references/planner-chunked.md +49 -0
- package/get-shit-done/references/planner-gap-closure.md +62 -0
- package/get-shit-done/references/planner-graphify-auto-update.md +67 -0
- package/get-shit-done/references/planner-human-verify-mode.md +57 -0
- package/get-shit-done/references/planner-interface-context.md +62 -0
- package/get-shit-done/references/planner-mvp-mode.md +53 -0
- package/get-shit-done/references/planner-reviews.md +39 -0
- package/get-shit-done/references/planner-revision.md +87 -0
- package/get-shit-done/references/planner-source-audit.md +73 -0
- package/get-shit-done/references/planning-config.md +471 -0
- package/get-shit-done/references/project-skills-discovery.md +19 -0
- package/get-shit-done/references/questioning.md +162 -0
- package/get-shit-done/references/revision-loop.md +97 -0
- package/get-shit-done/references/scout-codebase.md +51 -0
- package/get-shit-done/references/skeleton-template.md +48 -0
- package/get-shit-done/references/sketch-interactivity.md +41 -0
- package/get-shit-done/references/sketch-theme-system.md +94 -0
- package/get-shit-done/references/sketch-tooling.md +45 -0
- package/get-shit-done/references/sketch-variant-patterns.md +81 -0
- package/get-shit-done/references/spidr-splitting.md +69 -0
- package/get-shit-done/references/tdd.md +330 -0
- package/get-shit-done/references/thinking-models-debug.md +44 -0
- package/get-shit-done/references/thinking-models-execution.md +50 -0
- package/get-shit-done/references/thinking-models-planning.md +62 -0
- package/get-shit-done/references/thinking-models-research.md +50 -0
- package/get-shit-done/references/thinking-models-verification.md +55 -0
- package/get-shit-done/references/thinking-partner.md +96 -0
- package/get-shit-done/references/ui-brand.md +160 -0
- package/get-shit-done/references/universal-anti-patterns.md +63 -0
- package/get-shit-done/references/user-profiling.md +681 -0
- package/get-shit-done/references/user-story-template.md +58 -0
- package/get-shit-done/references/verification-overrides.md +227 -0
- package/get-shit-done/references/verification-patterns.md +612 -0
- package/get-shit-done/references/verify-mvp-mode.md +85 -0
- package/get-shit-done/references/workstream-flag.md +111 -0
- package/get-shit-done/references/worktree-path-safety.md +89 -0
- package/get-shit-done/templates/AI-SPEC.md +246 -0
- package/get-shit-done/templates/DEBUG.md +169 -0
- package/get-shit-done/templates/README.md +77 -0
- package/get-shit-done/templates/SECURITY.md +61 -0
- package/get-shit-done/templates/UAT.md +265 -0
- package/get-shit-done/templates/UI-SPEC.md +100 -0
- package/get-shit-done/templates/VALIDATION.md +76 -0
- package/get-shit-done/templates/claude-md.md +145 -0
- package/get-shit-done/templates/codebase/architecture.md +255 -0
- package/get-shit-done/templates/codebase/concerns.md +310 -0
- package/get-shit-done/templates/codebase/conventions.md +307 -0
- package/get-shit-done/templates/codebase/integrations.md +280 -0
- package/get-shit-done/templates/codebase/stack.md +186 -0
- package/get-shit-done/templates/codebase/structure.md +285 -0
- package/get-shit-done/templates/codebase/testing.md +480 -0
- package/get-shit-done/templates/config.json +62 -0
- package/get-shit-done/templates/context.md +352 -0
- package/get-shit-done/templates/continue-here.md +78 -0
- package/get-shit-done/templates/copilot-instructions.md +7 -0
- package/get-shit-done/templates/debug-subagent-prompt.md +91 -0
- package/get-shit-done/templates/dev-preferences.md +21 -0
- package/get-shit-done/templates/discovery.md +146 -0
- package/get-shit-done/templates/discussion-log.md +63 -0
- package/get-shit-done/templates/milestone-archive.md +123 -0
- package/get-shit-done/templates/milestone.md +115 -0
- package/get-shit-done/templates/phase-prompt.md +610 -0
- package/get-shit-done/templates/planner-subagent-prompt.md +117 -0
- package/get-shit-done/templates/project.md +186 -0
- package/get-shit-done/templates/requirements.md +231 -0
- package/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
- package/get-shit-done/templates/research-project/FEATURES.md +147 -0
- package/get-shit-done/templates/research-project/PITFALLS.md +200 -0
- package/get-shit-done/templates/research-project/STACK.md +120 -0
- package/get-shit-done/templates/research-project/SUMMARY.md +170 -0
- package/get-shit-done/templates/research.md +592 -0
- package/get-shit-done/templates/retrospective.md +54 -0
- package/get-shit-done/templates/roadmap.md +202 -0
- package/get-shit-done/templates/spec.md +307 -0
- package/get-shit-done/templates/state.md +195 -0
- package/get-shit-done/templates/summary-complex.md +59 -0
- package/get-shit-done/templates/summary-minimal.md +41 -0
- package/get-shit-done/templates/summary-standard.md +48 -0
- package/get-shit-done/templates/summary.md +248 -0
- package/get-shit-done/templates/user-profile.md +146 -0
- package/get-shit-done/templates/user-setup.md +311 -0
- package/get-shit-done/templates/verification-report.md +322 -0
- package/get-shit-done/workflows/_runtime-launcher.snippet.sh +1 -0
- package/get-shit-done/workflows/add-backlog.md +91 -0
- package/get-shit-done/workflows/add-phase.md +113 -0
- package/get-shit-done/workflows/add-tests.md +355 -0
- package/get-shit-done/workflows/add-todo.md +161 -0
- package/get-shit-done/workflows/ai-integration-phase.md +295 -0
- package/get-shit-done/workflows/analyze-dependencies.md +96 -0
- package/get-shit-done/workflows/audit-fix.md +178 -0
- package/get-shit-done/workflows/audit-milestone.md +358 -0
- package/get-shit-done/workflows/audit-uat.md +110 -0
- package/get-shit-done/workflows/autonomous.md +795 -0
- package/get-shit-done/workflows/check-todos.md +180 -0
- package/get-shit-done/workflows/cleanup.md +155 -0
- package/get-shit-done/workflows/code-review-fix.md +502 -0
- package/get-shit-done/workflows/code-review.md +656 -0
- package/get-shit-done/workflows/complete-milestone.md +855 -0
- package/get-shit-done/workflows/debug.md +232 -0
- package/get-shit-done/workflows/diagnose-issues.md +241 -0
- package/get-shit-done/workflows/discovery-phase.md +291 -0
- package/get-shit-done/workflows/discuss-phase/modes/advisor.md +176 -0
- package/get-shit-done/workflows/discuss-phase/modes/all.md +28 -0
- package/get-shit-done/workflows/discuss-phase/modes/analyze.md +44 -0
- package/get-shit-done/workflows/discuss-phase/modes/auto.md +57 -0
- package/get-shit-done/workflows/discuss-phase/modes/batch.md +52 -0
- package/get-shit-done/workflows/discuss-phase/modes/chain.md +98 -0
- package/get-shit-done/workflows/discuss-phase/modes/default.md +141 -0
- package/get-shit-done/workflows/discuss-phase/modes/power.md +44 -0
- package/get-shit-done/workflows/discuss-phase/modes/text.md +55 -0
- package/get-shit-done/workflows/discuss-phase/templates/checkpoint.json +18 -0
- package/get-shit-done/workflows/discuss-phase/templates/context.md +136 -0
- package/get-shit-done/workflows/discuss-phase/templates/discussion-log.md +50 -0
- package/get-shit-done/workflows/discuss-phase-assumptions.md +675 -0
- package/get-shit-done/workflows/discuss-phase-power.md +291 -0
- package/get-shit-done/workflows/discuss-phase.md +499 -0
- package/get-shit-done/workflows/do.md +111 -0
- package/get-shit-done/workflows/docs-update.md +1162 -0
- package/get-shit-done/workflows/edit-phase.md +295 -0
- package/get-shit-done/workflows/eval-review.md +156 -0
- package/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md +82 -0
- package/get-shit-done/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
- package/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md +117 -0
- package/get-shit-done/workflows/execute-phase.md +1709 -0
- package/get-shit-done/workflows/execute-plan.md +526 -0
- package/get-shit-done/workflows/explore.md +144 -0
- package/get-shit-done/workflows/extract-learnings.md +243 -0
- package/get-shit-done/workflows/fast.md +124 -0
- package/get-shit-done/workflows/forensics.md +279 -0
- package/get-shit-done/workflows/graduation.md +196 -0
- package/get-shit-done/workflows/health.md +224 -0
- package/get-shit-done/workflows/help/modes/brief.md +22 -0
- package/get-shit-done/workflows/help/modes/default.md +50 -0
- package/get-shit-done/workflows/help/modes/full.md +784 -0
- package/get-shit-done/workflows/help/modes/topic.md +74 -0
- package/get-shit-done/workflows/help.md +24 -0
- package/get-shit-done/workflows/import.md +254 -0
- package/get-shit-done/workflows/inbox.md +387 -0
- package/get-shit-done/workflows/ingest-docs.md +339 -0
- package/get-shit-done/workflows/insert-phase.md +152 -0
- package/get-shit-done/workflows/list-phase-assumptions.md +178 -0
- package/get-shit-done/workflows/list-workspaces.md +57 -0
- package/get-shit-done/workflows/manager.md +393 -0
- package/get-shit-done/workflows/map-codebase.md +444 -0
- package/get-shit-done/workflows/milestone-summary.md +224 -0
- package/get-shit-done/workflows/mvp-phase.md +222 -0
- package/get-shit-done/workflows/new-milestone.md +635 -0
- package/get-shit-done/workflows/new-project.md +1555 -0
- package/get-shit-done/workflows/new-workspace.md +240 -0
- package/get-shit-done/workflows/next.md +299 -0
- package/get-shit-done/workflows/node-repair.md +92 -0
- package/get-shit-done/workflows/note.md +158 -0
- package/get-shit-done/workflows/pause-work.md +244 -0
- package/get-shit-done/workflows/plan-milestone-gaps.md +281 -0
- package/get-shit-done/workflows/plan-phase.md +1809 -0
- package/get-shit-done/workflows/plan-review-convergence.md +346 -0
- package/get-shit-done/workflows/plant-seed.md +230 -0
- package/get-shit-done/workflows/pr-branch.md +157 -0
- package/get-shit-done/workflows/profile-user.md +453 -0
- package/get-shit-done/workflows/progress.md +699 -0
- package/get-shit-done/workflows/quick.md +1039 -0
- package/get-shit-done/workflows/reapply-patches.md +426 -0
- package/get-shit-done/workflows/remove-phase.md +156 -0
- package/get-shit-done/workflows/remove-workspace.md +108 -0
- package/get-shit-done/workflows/resume-project.md +332 -0
- package/get-shit-done/workflows/review.md +623 -0
- package/get-shit-done/workflows/scan.md +105 -0
- package/get-shit-done/workflows/secure-phase.md +180 -0
- package/get-shit-done/workflows/session-report.md +146 -0
- package/get-shit-done/workflows/settings-advanced.md +620 -0
- package/get-shit-done/workflows/settings-integrations.md +312 -0
- package/get-shit-done/workflows/settings.md +552 -0
- package/get-shit-done/workflows/ship.md +356 -0
- package/get-shit-done/workflows/sketch-wrap-up.md +286 -0
- package/get-shit-done/workflows/sketch.md +361 -0
- package/get-shit-done/workflows/spec-phase.md +262 -0
- package/get-shit-done/workflows/spike-wrap-up.md +307 -0
- package/get-shit-done/workflows/spike.md +453 -0
- package/get-shit-done/workflows/stats.md +80 -0
- package/get-shit-done/workflows/sync-skills.md +182 -0
- package/get-shit-done/workflows/thread.md +222 -0
- package/get-shit-done/workflows/transition.md +694 -0
- package/get-shit-done/workflows/ui-phase.md +328 -0
- package/get-shit-done/workflows/ui-review.md +193 -0
- package/get-shit-done/workflows/ultraplan-phase.md +199 -0
- package/get-shit-done/workflows/undo.md +314 -0
- package/get-shit-done/workflows/update.md +443 -0
- package/get-shit-done/workflows/validate-phase.md +179 -0
- package/get-shit-done/workflows/verify-phase.md +544 -0
- package/get-shit-done/workflows/verify-work.md +781 -0
- package/hooks/dist/gsd-check-update-worker.js +95 -0
- package/hooks/dist/gsd-check-update.js +64 -0
- package/hooks/dist/gsd-context-monitor.js +195 -0
- package/hooks/dist/gsd-graphify-update.sh +158 -0
- package/hooks/dist/gsd-phase-boundary.sh +47 -0
- package/hooks/dist/gsd-prompt-guard.js +97 -0
- package/hooks/dist/gsd-read-guard.js +101 -0
- package/hooks/dist/gsd-read-injection-scanner.js +203 -0
- package/hooks/dist/gsd-session-state.sh +59 -0
- package/hooks/dist/gsd-statusline.js +548 -0
- package/hooks/dist/gsd-update-banner.js +134 -0
- package/hooks/dist/gsd-validate-commit.sh +57 -0
- package/hooks/dist/gsd-workflow-guard.js +166 -0
- package/hooks/dist/lib/git-cmd.js +150 -0
- package/hooks/dist/lib/gsd-graphify-rebuild.sh +65 -0
- package/hooks/gsd-check-update-worker.js +95 -0
- package/hooks/gsd-check-update.js +64 -0
- package/hooks/gsd-context-monitor.js +195 -0
- package/hooks/gsd-graphify-update.sh +158 -0
- package/hooks/gsd-phase-boundary.sh +47 -0
- package/hooks/gsd-prompt-guard.js +97 -0
- package/hooks/gsd-read-guard.js +101 -0
- package/hooks/gsd-read-injection-scanner.js +203 -0
- package/hooks/gsd-session-state.sh +59 -0
- package/hooks/gsd-statusline.js +548 -0
- package/hooks/gsd-update-banner.js +134 -0
- package/hooks/gsd-validate-commit.sh +57 -0
- package/hooks/gsd-workflow-guard.js +166 -0
- package/hooks/lib/git-cmd.js +150 -0
- package/hooks/lib/gsd-graphify-rebuild.sh +65 -0
- package/hooks/managed-hooks-registry.cjs +34 -0
- package/package.json +102 -0
- package/scripts/affected-tests-lib.cjs +541 -0
- package/scripts/audit-workflow-script-paths.cjs +73 -0
- package/scripts/base64-scan.sh +339 -0
- package/scripts/build-hooks.js +236 -0
- package/scripts/changeset/README.md +129 -0
- package/scripts/changeset/cli.cjs +392 -0
- package/scripts/changeset/github-release-notes.cjs +199 -0
- package/scripts/changeset/lint.cjs +110 -0
- package/scripts/changeset/new.cjs +137 -0
- package/scripts/changeset/parse.cjs +114 -0
- package/scripts/changeset/render.cjs +34 -0
- package/scripts/changeset/serialize.cjs +130 -0
- package/scripts/check-alias-drift.cjs +108 -0
- package/scripts/check-env.cjs +302 -0
- package/scripts/check-npm-integrity.cjs +209 -0
- package/scripts/ci-guard-runner.cjs +16 -0
- package/scripts/ci-prepare-test-scope.cjs +46 -0
- package/scripts/ci-rebase-check.cjs +85 -0
- package/scripts/ci-test-scope.cjs +302 -0
- package/scripts/command-contract-helpers.cjs +64 -0
- package/scripts/diff-touches-shipped-paths.cjs +147 -0
- package/scripts/fix-slash-commands.cjs +147 -0
- package/scripts/gen-inventory-manifest.cjs +109 -0
- package/scripts/generate-package-identity.cjs +104 -0
- package/scripts/lint-command-contract.cjs +108 -0
- package/scripts/lint-descriptions.cjs +83 -0
- package/scripts/lint-docs-required.cjs +222 -0
- package/scripts/lint-no-source-grep-extras.cjs +81 -0
- package/scripts/lint-no-source-grep.cjs +174 -0
- package/scripts/lint-package-identity-drift.cjs +141 -0
- package/scripts/lint-pr-check-project-dir.cjs +98 -0
- package/scripts/lint-shared-module-handsync.cjs +388 -0
- package/scripts/lint-shell-command-projection-drift.cjs +57 -0
- package/scripts/lint-skill-deps.cjs +180 -0
- package/scripts/lint-test-file-count.allowlist.json +36 -0
- package/scripts/lint-test-file-count.cjs +190 -0
- package/scripts/pr-template-policy.cjs +268 -0
- package/scripts/prompt-injection-scan.sh +203 -0
- package/scripts/release-tarball-smoke.cjs +627 -0
- package/scripts/run-affected-tests.cjs +6 -0
- package/scripts/run-cross-platform-tests.cjs +63 -0
- package/scripts/run-tests.cjs +282 -0
- package/scripts/secret-scan-lint.sh +231 -0
- package/scripts/secret-scan.sh +358 -0
- package/scripts/setup-branch-protection.sh +236 -0
- package/scripts/shared-module-handsync-allowlist.json +183 -0
- package/scripts/strip-prose-atrefs.cjs +106 -0
- package/scripts/sync-rulesets.sh +34 -0
- package/scripts/sync-runtime-launcher.cjs +402 -0
- package/scripts/test-failure-reasons.cjs +34 -0
- package/scripts/workflow-policy.cjs +450 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* command-contract-helpers.cjs (ADR-0002)
|
|
4
|
+
*
|
|
5
|
+
* Single source of truth for the commands/gsd/*.md contract constants and
|
|
6
|
+
* parsers shared by scripts/lint-command-contract.cjs and
|
|
7
|
+
* tests/command-contract.test.cjs.
|
|
8
|
+
*
|
|
9
|
+
* Keeping these in one place ensures the lint script and the test suite
|
|
10
|
+
* always agree on what constitutes a valid tool, a valid @-ref, and a valid
|
|
11
|
+
* frontmatter structure. A new canonical tool added here is automatically
|
|
12
|
+
* enforced by both consumers.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const CANONICAL_TOOLS = new Set([
|
|
16
|
+
'Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep',
|
|
17
|
+
'Task', 'Agent', 'Skill', 'SlashCommand',
|
|
18
|
+
'AskUserQuestion', 'WebFetch', 'WebSearch', 'TodoWrite',
|
|
19
|
+
'mcp__context7__resolve-library-id',
|
|
20
|
+
'mcp__context7__query-docs',
|
|
21
|
+
'mcp__context7__*',
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
function parseFrontmatter(content) {
|
|
25
|
+
// CRLF-tolerant split: Windows checkouts (autocrlf=true) leave a trailing
|
|
26
|
+
// \r on every line, making lines.indexOf('---', 1) return -1 (the value
|
|
27
|
+
// would be '---\r', not '---') → returns {} → every field appears missing.
|
|
28
|
+
const lines = content.split(/\r?\n/);
|
|
29
|
+
if (lines[0].trim() !== '---') return {};
|
|
30
|
+
const end = lines.indexOf('---', 1);
|
|
31
|
+
if (end === -1) return {};
|
|
32
|
+
const fm = {};
|
|
33
|
+
let key = null;
|
|
34
|
+
for (const line of lines.slice(1, end)) {
|
|
35
|
+
const kv = line.match(/^([a-zA-Z0-9_-]+):\s*(.*)/);
|
|
36
|
+
if (kv) { key = kv[1]; fm[key] = kv[2].trim(); }
|
|
37
|
+
else if (key && line.match(/^\s+-\s+/)) {
|
|
38
|
+
const val = line.replace(/^\s+-\s+/, '').trim();
|
|
39
|
+
fm[key] = fm[key] ? fm[key] + '\n' + val : val;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return fm;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function executionContextRefs(content) {
|
|
46
|
+
const refs = [];
|
|
47
|
+
const re = /<execution_context(?:_extended)?>([\s\S]*?)<\/execution_context(?:_extended)?>/g;
|
|
48
|
+
let m;
|
|
49
|
+
while ((m = re.exec(content)) !== null) {
|
|
50
|
+
for (const rawLine of m[1].split('\n')) {
|
|
51
|
+
const line = rawLine.trim();
|
|
52
|
+
if (!line.startsWith('@')) continue;
|
|
53
|
+
const token = line.split(/\s+/)[0];
|
|
54
|
+
const trailingProse = line.length > token.length;
|
|
55
|
+
const normalized = token
|
|
56
|
+
.replace(/^@(?:~|\$HOME)\//, '')
|
|
57
|
+
.replace(/^(?:\.claude\/)?(?:get-shit-done\/)?/, '');
|
|
58
|
+
refs.push({ token, normalized, trailingProse });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return refs;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { CANONICAL_TOOLS, parseFrontmatter, executionContextRefs };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Used by the release-sdk hotfix cherry-pick loop to decide whether a
|
|
4
|
+
* candidate commit can possibly change what ships in the npm package.
|
|
5
|
+
*
|
|
6
|
+
* Reads a newline-separated list of paths from stdin (typically the
|
|
7
|
+
* output of `git diff-tree --no-commit-id --name-only -r <SHA>`) and
|
|
8
|
+
* exits with one of three codes so the workflow can distinguish a
|
|
9
|
+
* legitimate "skip this commit" signal from a classifier failure.
|
|
10
|
+
*
|
|
11
|
+
* "Shipped" = the union of:
|
|
12
|
+
* - package.json (always included by `npm pack`, regardless of `files`)
|
|
13
|
+
* - every entry in package.json `files`, treated as either an exact
|
|
14
|
+
* file match or a directory prefix (matching `npm pack` semantics).
|
|
15
|
+
* - CI-gating test paths: `tests/<anything>` plus
|
|
16
|
+
* `sdk/src/<anything>/<name>.test.<ts|cjs|mjs|js>` and `.spec.` variants
|
|
17
|
+
* — these don't ship in the tarball, but they gate the hotfix-branch
|
|
18
|
+
* test job. A test fixture update that aligns with a cherry-picked
|
|
19
|
+
* production fix MUST be pickable or CI fails on the hotfix run.
|
|
20
|
+
* #3621 — root cause of the v1.42.3 hotfix red CI.
|
|
21
|
+
*
|
|
22
|
+
* `package-lock.json` is intentionally NOT considered shipped — `npm pack`
|
|
23
|
+
* excludes it from the tarball unless it's explicitly in `files`, and at
|
|
24
|
+
* the time of writing this repo's `files` whitelist does not include it.
|
|
25
|
+
*
|
|
26
|
+
* Exit codes (the workflow MUST treat these distinctly — bug #2983):
|
|
27
|
+
* 0 at least one path is shipped → cherry-pick is meaningful
|
|
28
|
+
* 1 no shipped paths → CI / test / docs / planning
|
|
29
|
+
* only; hotfix loop skips
|
|
30
|
+
* 2 classifier error → bad/missing package.json,
|
|
31
|
+
* I/O failure, or any
|
|
32
|
+
* uncaught exception. The
|
|
33
|
+
* workflow MUST fail-fast on
|
|
34
|
+
* this code rather than
|
|
35
|
+
* treating it as a skip.
|
|
36
|
+
*
|
|
37
|
+
* Why distinct codes: Node's default exit code for uncaught throws is 1,
|
|
38
|
+
* which would otherwise be indistinguishable from the legitimate "no
|
|
39
|
+
* shipped paths" result. CodeRabbit on PR #2981 / bug #2983.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
'use strict';
|
|
43
|
+
|
|
44
|
+
const fs = require('node:fs');
|
|
45
|
+
const path = require('node:path');
|
|
46
|
+
|
|
47
|
+
const EXIT_SHIPPED = 0;
|
|
48
|
+
const EXIT_NOT_SHIPPED = 1;
|
|
49
|
+
const EXIT_ERROR = 2;
|
|
50
|
+
|
|
51
|
+
function loadShipPrefixes(pkgPath) {
|
|
52
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
53
|
+
const files = Array.isArray(pkg.files) ? pkg.files : [];
|
|
54
|
+
return ['package.json', ...files];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// #3621: paths that gate hotfix-branch CI even though they don't appear
|
|
58
|
+
// in the npm tarball. When a cherry-picked production fix changes behavior
|
|
59
|
+
// that an existing test on the v1.42.2 base asserts against, the matching
|
|
60
|
+
// test fixture from `main` must also be cherry-picked or CI fails on the
|
|
61
|
+
// hotfix run (exactly what happened on v1.42.3 — production fix(3562) was
|
|
62
|
+
// picked, the bundled test-fixture correction in commit 08848df8 was not).
|
|
63
|
+
// Combined with the `test:` prefix being added to the candidate-loop regex
|
|
64
|
+
// in hotfix.yml, this lets `test(####):` fixture-alignment commits be
|
|
65
|
+
// cherry-picked alongside their production counterparts.
|
|
66
|
+
function isCiGating(diffPath) {
|
|
67
|
+
if (diffPath.startsWith('tests/')) return true;
|
|
68
|
+
// SDK vitest specs live next to source. Production source ships via
|
|
69
|
+
// sdk/dist/ (already in package.json `files`); the test files are what's
|
|
70
|
+
// missing from that surface.
|
|
71
|
+
if (diffPath.startsWith('sdk/src/') && /\.(test|spec)\.(ts|cjs|mjs|js)$/.test(diffPath)) return true;
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isShipped(diffPath, shipPrefixes) {
|
|
76
|
+
// Normalize Windows-style separators just in case (git always emits
|
|
77
|
+
// forward slashes, but a developer running this locally on a different
|
|
78
|
+
// tool's output shouldn't get a false negative).
|
|
79
|
+
const p = diffPath.replace(/\\/g, '/');
|
|
80
|
+
return shipPrefixes.some((s) => p === s || p.startsWith(s + '/'));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// #2980: commits that touch `.github/workflows/*` cannot be cherry-picked
|
|
84
|
+
// onto a hotfix branch because the default GITHUB_TOKEN lacks the
|
|
85
|
+
// `workflow` permission and the push step fails. Detect them upfront so a
|
|
86
|
+
// `test:`-eligible commit bundling a workflow edit still gets skipped.
|
|
87
|
+
function isPushBlocking(diffPath) {
|
|
88
|
+
return diffPath.replace(/\\/g, '/').startsWith('.github/workflows/');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function fail(message, err) {
|
|
92
|
+
process.stderr.write(`diff-touches-shipped-paths: ${message}\n`);
|
|
93
|
+
if (err && err.stack) process.stderr.write(`${err.stack}\n`);
|
|
94
|
+
process.exit(EXIT_ERROR);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function main() {
|
|
98
|
+
// Surface ANY uncaught failure as exit 2 (classifier error) rather
|
|
99
|
+
// than letting Node's default-1 shadow the legitimate
|
|
100
|
+
// "no shipped paths" result. Bug #2983.
|
|
101
|
+
process.on('uncaughtException', (err) => fail('uncaught exception', err));
|
|
102
|
+
process.on('unhandledRejection', (err) => fail('unhandled rejection', err));
|
|
103
|
+
|
|
104
|
+
let shipPrefixes;
|
|
105
|
+
try {
|
|
106
|
+
const pkgPath = path.resolve(process.cwd(), 'package.json');
|
|
107
|
+
shipPrefixes = loadShipPrefixes(pkgPath);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
return fail(`failed to read package.json from ${process.cwd()}`, err);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let buf = '';
|
|
113
|
+
process.stdin.setEncoding('utf8');
|
|
114
|
+
process.stdin.on('error', (err) => fail('stdin read error', err));
|
|
115
|
+
process.stdin.on('data', (chunk) => {
|
|
116
|
+
buf += chunk;
|
|
117
|
+
});
|
|
118
|
+
process.stdin.on('end', () => {
|
|
119
|
+
try {
|
|
120
|
+
const paths = buf.split('\n').map((s) => s.trim()).filter(Boolean);
|
|
121
|
+
// #2980 still wins over #3621: any commit touching .github/workflows/*
|
|
122
|
+
// is unpickable regardless of other content because the push step
|
|
123
|
+
// fails on workflow scope rejection. Check this first.
|
|
124
|
+
if (paths.some(isPushBlocking)) {
|
|
125
|
+
process.exit(EXIT_NOT_SHIPPED);
|
|
126
|
+
}
|
|
127
|
+
if (paths.some((p) => isShipped(p, shipPrefixes))) {
|
|
128
|
+
process.exit(EXIT_SHIPPED);
|
|
129
|
+
}
|
|
130
|
+
// #3621: a commit whose only relevant paths are CI-gating tests is
|
|
131
|
+
// still pickable — it can change whether the hotfix CI passes even
|
|
132
|
+
// though it doesn't change what the npm tarball ships.
|
|
133
|
+
if (paths.some(isCiGating)) {
|
|
134
|
+
process.exit(EXIT_SHIPPED);
|
|
135
|
+
}
|
|
136
|
+
process.exit(EXIT_NOT_SHIPPED);
|
|
137
|
+
} catch (err) {
|
|
138
|
+
fail('classification failed', err);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (require.main === module) {
|
|
144
|
+
main();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = { loadShipPrefixes, isShipped, isCiGating, isPushBlocking, EXIT_SHIPPED, EXIT_NOT_SHIPPED, EXIT_ERROR };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* One-shot script + library: bidirectional GSD slash-command namespace normalizer.
|
|
4
|
+
*
|
|
5
|
+
* - Default direction (transformContent): retired /gsd-<cmd> → /gsd:<cmd>
|
|
6
|
+
* (keeps monorepo sources, docs, and workflows in the active colon form).
|
|
7
|
+
* - Reverse direction (transformContentToHyphen): /gsd:<cmd> / gsd:<cmd> → gsd-<cmd>
|
|
8
|
+
* (used during skill installation for runtimes that register skills under the
|
|
9
|
+
* canonical hyphen form established in #2808).
|
|
10
|
+
*
|
|
11
|
+
* Both directions only rewrite known commands from `commands/gsd/*.md` (longest-first
|
|
12
|
+
* matching + word-boundary safety). Non-commands (gsd-sdk, gsd-tools, etc.) are
|
|
13
|
+
* intentionally left untouched.
|
|
14
|
+
*
|
|
15
|
+
* The transforms are pure and exported for use by the installer and tests.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('node:fs');
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
|
|
21
|
+
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
|
|
22
|
+
const SEARCH_DIRS = [
|
|
23
|
+
path.join(__dirname, '..', 'get-shit-done', 'bin', 'lib'),
|
|
24
|
+
path.join(__dirname, '..', 'get-shit-done', 'workflows'),
|
|
25
|
+
path.join(__dirname, '..', 'get-shit-done', 'references'),
|
|
26
|
+
path.join(__dirname, '..', 'get-shit-done', 'templates'),
|
|
27
|
+
path.join(__dirname, '..', 'get-shit-done', 'contexts'),
|
|
28
|
+
path.join(__dirname, '..', 'commands', 'gsd'),
|
|
29
|
+
path.join(__dirname, '..', 'agents'),
|
|
30
|
+
path.join(__dirname, '..', 'hooks'),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const TOP_LEVEL_FILES = [
|
|
34
|
+
path.join(__dirname, '..', '.clinerules'),
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const SKIP_DIRS = new Set(['node_modules', 'dist', '.turbo']);
|
|
38
|
+
const EXTENSIONS = new Set(['.md', '.cjs', '.js', '.ts', '.tsx']);
|
|
39
|
+
|
|
40
|
+
// Test files contain intentional fixture strings (e.g. inputs the sanitizer
|
|
41
|
+
// is expected to strip). Rewriting them changes test semantics.
|
|
42
|
+
function isTestFile(name) {
|
|
43
|
+
return /\.test\.(c?js|tsx?)$/.test(name);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildPattern(cmdNames) {
|
|
47
|
+
// Empty input would compile `/gsd-()(?=[^a-zA-Z0-9_-]|$)/g`, which the regex
|
|
48
|
+
// engine still matches at any `/gsd-` token followed by a non-word boundary
|
|
49
|
+
// (e.g. EOL, whitespace, punctuation) — rewriting it to a stray `/gsd:`.
|
|
50
|
+
// Short-circuit so the caller can no-op on a missing/empty registry rather
|
|
51
|
+
// than perform an unintended broad rewrite.
|
|
52
|
+
if (!Array.isArray(cmdNames) || cmdNames.length === 0) return null;
|
|
53
|
+
const sorted = [...cmdNames].sort((a, b) => b.length - a.length); // longest first to avoid partial matches
|
|
54
|
+
return new RegExp(`/gsd-(${sorted.join('|')})(?=[^a-zA-Z0-9_-]|$)`, 'g');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Pure transform: rewrite retired `/gsd-<cmd>` to `/gsd:<cmd>` for the given command names.
|
|
59
|
+
* Returns the rewritten string. Identifiers not in `cmdNames` (e.g. `/gsd-sdk`,
|
|
60
|
+
* `/gsd-tools`) are left untouched.
|
|
61
|
+
*/
|
|
62
|
+
function transformContent(src, cmdNames) {
|
|
63
|
+
const pattern = buildPattern(cmdNames);
|
|
64
|
+
if (!pattern) return src;
|
|
65
|
+
return src.replace(pattern, (_, cmd) => `/gsd:${cmd}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Build regex for the reverse direction (colon form → hyphen form).
|
|
70
|
+
* Matches both "gsd:cmd" and "/gsd:cmd" (the leading / is preserved automatically
|
|
71
|
+
* because it is not part of the match). Uses longest-first ordering plus
|
|
72
|
+
* bidirectional word-boundary safety (negative lookbehind on the left, lookahead
|
|
73
|
+
* on the right) so matches only occur at token boundaries.
|
|
74
|
+
*/
|
|
75
|
+
function buildColonPattern(cmdNames) {
|
|
76
|
+
if (!Array.isArray(cmdNames) || cmdNames.length === 0) return null;
|
|
77
|
+
const sorted = [...cmdNames].sort((a, b) => b.length - a.length);
|
|
78
|
+
return new RegExp(`(?<![a-zA-Z0-9_-])gsd:(${sorted.join('|')})(?=[^a-zA-Z0-9_-]|$)`, 'g');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Pure transform (reverse): rewrite `/gsd:<cmd>` / `gsd:<cmd>` to hyphen form
|
|
83
|
+
* for known GSD commands.
|
|
84
|
+
*
|
|
85
|
+
* Non-command identifiers (e.g. gsd-sdk, gsd-tools) are left untouched, matching
|
|
86
|
+
* the safety contract of the forward transform.
|
|
87
|
+
*/
|
|
88
|
+
function transformContentToHyphen(src, cmdNames) {
|
|
89
|
+
const pattern = buildColonPattern(cmdNames);
|
|
90
|
+
if (!pattern) return src;
|
|
91
|
+
return src.replace(pattern, (_, cmd) => `gsd-${cmd}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readCmdNames() {
|
|
95
|
+
return fs.readdirSync(COMMANDS_DIR)
|
|
96
|
+
.filter(f => f.endsWith('.md'))
|
|
97
|
+
.map(f => f.replace(/\.md$/, ''));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function processFile(file, cmdNames) {
|
|
101
|
+
const pattern = buildPattern(cmdNames);
|
|
102
|
+
if (!pattern) return;
|
|
103
|
+
let src;
|
|
104
|
+
try { src = fs.readFileSync(file, 'utf-8'); } catch { return; }
|
|
105
|
+
const replaced = transformContent(src, cmdNames);
|
|
106
|
+
if (replaced !== src) {
|
|
107
|
+
fs.writeFileSync(file, replaced, 'utf-8');
|
|
108
|
+
const count = (src.match(pattern) || []).length;
|
|
109
|
+
console.log(` ${count} replacements: ${path.relative(path.join(__dirname, '..'), file)}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function processDir(dir, cmdNames) {
|
|
114
|
+
const pattern = buildPattern(cmdNames);
|
|
115
|
+
if (!pattern) return;
|
|
116
|
+
let entries;
|
|
117
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
118
|
+
for (const e of entries) {
|
|
119
|
+
const full = path.join(dir, e.name);
|
|
120
|
+
if (e.isDirectory()) {
|
|
121
|
+
if (SKIP_DIRS.has(e.name)) continue;
|
|
122
|
+
processDir(full, cmdNames);
|
|
123
|
+
} else if (EXTENSIONS.has(path.extname(e.name)) && !isTestFile(e.name)) {
|
|
124
|
+
processFile(full, cmdNames);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (require.main === module) {
|
|
130
|
+
const cmdNames = readCmdNames();
|
|
131
|
+
for (const dir of SEARCH_DIRS) {
|
|
132
|
+
processDir(dir, cmdNames);
|
|
133
|
+
}
|
|
134
|
+
for (const file of TOP_LEVEL_FILES) {
|
|
135
|
+
processFile(file, cmdNames);
|
|
136
|
+
}
|
|
137
|
+
console.log('Done.');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = {
|
|
141
|
+
transformContent,
|
|
142
|
+
transformContentToHyphen,
|
|
143
|
+
buildPattern,
|
|
144
|
+
buildColonPattern,
|
|
145
|
+
readCmdNames,
|
|
146
|
+
SKIP_DIRS
|
|
147
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generates docs/INVENTORY-MANIFEST.json — a structural skeleton of every
|
|
6
|
+
* shipped surface derived entirely from the filesystem. Commit this file;
|
|
7
|
+
* CI re-runs the script and diffs. A non-empty diff means a surface shipped
|
|
8
|
+
* without an INVENTORY.md row.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node scripts/gen-inventory-manifest.cjs # print to stdout
|
|
12
|
+
* node scripts/gen-inventory-manifest.cjs --write # write docs/INVENTORY-MANIFEST.json
|
|
13
|
+
* node scripts/gen-inventory-manifest.cjs --check # exit 1 if committed manifest is stale
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('node:fs');
|
|
17
|
+
const path = require('node:path');
|
|
18
|
+
|
|
19
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
20
|
+
const MANIFEST_PATH = path.join(ROOT, 'docs', 'INVENTORY-MANIFEST.json');
|
|
21
|
+
|
|
22
|
+
const FAMILIES = [
|
|
23
|
+
{
|
|
24
|
+
name: 'agents',
|
|
25
|
+
dir: path.join(ROOT, 'agents'),
|
|
26
|
+
filter: (f) => /^gsd-.*\.md$/.test(f),
|
|
27
|
+
toName: (f) => f.replace(/\.md$/, ''),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'commands',
|
|
31
|
+
dir: path.join(ROOT, 'commands', 'gsd'),
|
|
32
|
+
filter: (f) => f.endsWith('.md'),
|
|
33
|
+
toName: (f) => '/gsd-' + f.replace(/\.md$/, ''),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'workflows',
|
|
37
|
+
dir: path.join(ROOT, 'get-shit-done', 'workflows'),
|
|
38
|
+
filter: (f) => f.endsWith('.md'),
|
|
39
|
+
toName: (f) => f,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'references',
|
|
43
|
+
dir: path.join(ROOT, 'get-shit-done', 'references'),
|
|
44
|
+
filter: (f) => f.endsWith('.md'),
|
|
45
|
+
toName: (f) => f,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'cli_modules',
|
|
49
|
+
dir: path.join(ROOT, 'get-shit-done', 'bin', 'lib'),
|
|
50
|
+
filter: (f) => f.endsWith('.cjs'),
|
|
51
|
+
toName: (f) => f,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'hooks',
|
|
55
|
+
dir: path.join(ROOT, 'hooks'),
|
|
56
|
+
filter: (f) => /\.(js|sh)$/.test(f),
|
|
57
|
+
toName: (f) => f,
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
function buildManifest() {
|
|
62
|
+
const manifest = { generated: new Date().toISOString().slice(0, 10), families: {} };
|
|
63
|
+
for (const { name, dir, filter, toName } of FAMILIES) {
|
|
64
|
+
manifest.families[name] = fs
|
|
65
|
+
.readdirSync(dir)
|
|
66
|
+
.filter((f) => fs.statSync(path.join(dir, f)).isFile() && filter(f))
|
|
67
|
+
.map(toName)
|
|
68
|
+
.sort();
|
|
69
|
+
}
|
|
70
|
+
return manifest;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const [, , flag] = process.argv;
|
|
74
|
+
|
|
75
|
+
if (flag === '--check') {
|
|
76
|
+
const committed = JSON.parse(fs.readFileSync(MANIFEST_PATH, 'utf8'));
|
|
77
|
+
const live = buildManifest();
|
|
78
|
+
// Strip the generated date for comparison
|
|
79
|
+
delete committed.generated;
|
|
80
|
+
delete live.generated;
|
|
81
|
+
const committedStr = JSON.stringify(committed, null, 2);
|
|
82
|
+
const liveStr = JSON.stringify(live, null, 2);
|
|
83
|
+
if (committedStr !== liveStr) {
|
|
84
|
+
process.stderr.write(
|
|
85
|
+
'docs/INVENTORY-MANIFEST.json is stale. Run:\n' +
|
|
86
|
+
' node scripts/gen-inventory-manifest.cjs --write\n' +
|
|
87
|
+
'then add a matching row in docs/INVENTORY.md for each new entry.\n\n',
|
|
88
|
+
);
|
|
89
|
+
// Show diff-friendly output
|
|
90
|
+
for (const family of Object.keys(live.families)) {
|
|
91
|
+
const liveSet = new Set(live.families[family]);
|
|
92
|
+
const committedSet = new Set((committed.families || {})[family] || []);
|
|
93
|
+
for (const name of liveSet) {
|
|
94
|
+
if (!committedSet.has(name)) process.stderr.write(' + ' + family + '/' + name + '\n');
|
|
95
|
+
}
|
|
96
|
+
for (const name of committedSet) {
|
|
97
|
+
if (!liveSet.has(name)) process.stderr.write(' - ' + family + '/' + name + '\n');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
process.stdout.write('docs/INVENTORY-MANIFEST.json is up to date.\n');
|
|
103
|
+
} else if (flag === '--write') {
|
|
104
|
+
const manifest = buildManifest();
|
|
105
|
+
fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2) + '\n');
|
|
106
|
+
process.stdout.write('Wrote ' + MANIFEST_PATH + '\n');
|
|
107
|
+
} else {
|
|
108
|
+
process.stdout.write(JSON.stringify(buildManifest(), null, 2) + '\n');
|
|
109
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Single source for GSD's published-package coordinates (issue #498).
|
|
6
|
+
*
|
|
7
|
+
* `deriveIdentity(pkg)` is the pure core: it turns a parsed package.json into
|
|
8
|
+
* the coordinate record every consumer needs. The generated runtime module
|
|
9
|
+
* `get-shit-done/bin/lib/package-identity.cjs` bakes those values at build
|
|
10
|
+
* time, because the installed tree carries only a synthetic
|
|
11
|
+
* `{"type":"commonjs"}` package.json (no `.name`) — so a runtime
|
|
12
|
+
* `require('package.json').name` resolves to `undefined` (the #378 bug this
|
|
13
|
+
* seam retires). Baking from package.json reconciles #378 (renames survive)
|
|
14
|
+
* with #2992 (the value is never an LLM runtime choice).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parse `owner/name` out of a package.json `repository.url`, stripping the
|
|
19
|
+
* `git+` prefix and `.git` suffix npm conventionally adds.
|
|
20
|
+
*/
|
|
21
|
+
function parseRepoSlug(repository) {
|
|
22
|
+
const url = typeof repository === 'string' ? repository : (repository && repository.url) || '';
|
|
23
|
+
const m = url.replace(/^git\+/, '').replace(/\.git$/, '').match(/github\.com[/:]([^/]+\/[^/]+)$/);
|
|
24
|
+
return m ? m[1] : '';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Pure: package.json object -> the package identity coordinates.
|
|
29
|
+
*/
|
|
30
|
+
function deriveIdentity(pkg = {}) {
|
|
31
|
+
const packageName = pkg.name || '';
|
|
32
|
+
const binName = pkg.bin ? Object.keys(pkg.bin)[0] || '' : '';
|
|
33
|
+
const repoSlug = parseRepoSlug(pkg.repository);
|
|
34
|
+
const repoUrl = repoSlug ? `https://github.com/${repoSlug}` : '';
|
|
35
|
+
const changelogRawUrl = repoSlug
|
|
36
|
+
? `https://raw.githubusercontent.com/${repoSlug}/main/CHANGELOG.md`
|
|
37
|
+
: '';
|
|
38
|
+
return { packageName, binName, repoSlug, repoUrl, changelogRawUrl };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Pure: format the `npx` fallback install command. Shape matches the literal
|
|
43
|
+
* the update workflow embeds: `npx -y --package=<pkg>@latest -- <bin>
|
|
44
|
+
* [--<runtime>] --<scope>`. The runtime flag is omitted when not supplied.
|
|
45
|
+
*
|
|
46
|
+
* This function is the canonical source — `render()` serializes it verbatim
|
|
47
|
+
* into the generated module, so the runtime copy can never drift from it.
|
|
48
|
+
*/
|
|
49
|
+
function formatManualInstall({ packageName, binName, scope, runtime } = {}) {
|
|
50
|
+
const runtimeFlag = runtime ? ` --${runtime}` : '';
|
|
51
|
+
return `npx -y --package=${packageName}@latest -- ${binName}${runtimeFlag} --${scope}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const GENERATED_HEADER =
|
|
55
|
+
'// @generated by scripts/generate-package-identity.cjs from package.json — DO NOT EDIT.\n' +
|
|
56
|
+
'// Single source for GSD package coordinates (issue #498). Regenerate with:\n' +
|
|
57
|
+
'// node scripts/generate-package-identity.cjs\n';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Render the generated runtime module text for a derived identity. Values are
|
|
61
|
+
* baked as literals; `formatManualInstall` is embedded by `.toString()` so the
|
|
62
|
+
* runtime command builder is byte-identical to the tested source above.
|
|
63
|
+
*/
|
|
64
|
+
function render(identity) {
|
|
65
|
+
const { packageName, binName, repoSlug, repoUrl, changelogRawUrl } = identity;
|
|
66
|
+
const j = (v) => JSON.stringify(v);
|
|
67
|
+
return (
|
|
68
|
+
GENERATED_HEADER +
|
|
69
|
+
"'use strict';\n\n" +
|
|
70
|
+
`const packageName = ${j(packageName)};\n` +
|
|
71
|
+
`const binName = ${j(binName)};\n` +
|
|
72
|
+
`const repoSlug = ${j(repoSlug)};\n` +
|
|
73
|
+
`const repoUrl = ${j(repoUrl)};\n` +
|
|
74
|
+
`const changelogRawUrl = ${j(changelogRawUrl)};\n\n` +
|
|
75
|
+
`${formatManualInstall.toString()}\n\n` +
|
|
76
|
+
'function manualInstallCommand(opts = {}) {\n' +
|
|
77
|
+
' return formatManualInstall({ packageName, binName, scope: opts.scope, runtime: opts.runtime });\n' +
|
|
78
|
+
'}\n\n' +
|
|
79
|
+
'module.exports = Object.freeze({\n' +
|
|
80
|
+
' packageName,\n' +
|
|
81
|
+
' // PACKAGE_NAME: back-compat alias for #516-era consumers. Baked here, so it\n' +
|
|
82
|
+
' // survives the installed tree’s synthetic package.json (fixes the #378 undefined).\n' +
|
|
83
|
+
' PACKAGE_NAME: packageName,\n' +
|
|
84
|
+
' binName,\n' +
|
|
85
|
+
' repoSlug,\n' +
|
|
86
|
+
' repoUrl,\n' +
|
|
87
|
+
' changelogRawUrl,\n' +
|
|
88
|
+
' manualInstallCommand,\n' +
|
|
89
|
+
'});\n'
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function main() {
|
|
94
|
+
const fs = require('node:fs');
|
|
95
|
+
const path = require('node:path');
|
|
96
|
+
const pkg = require(path.join(__dirname, '..', 'package.json'));
|
|
97
|
+
const out = path.join(__dirname, '..', 'get-shit-done', 'bin', 'lib', 'package-identity.cjs');
|
|
98
|
+
fs.writeFileSync(out, render(deriveIdentity(pkg)));
|
|
99
|
+
process.stdout.write(`wrote ${path.relative(path.join(__dirname, '..'), out)}\n`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (require.main === module) main();
|
|
103
|
+
|
|
104
|
+
module.exports = { deriveIdentity, parseRepoSlug, formatManualInstall, render, main };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* lint-command-contract.cjs (ADR-0002)
|
|
4
|
+
*
|
|
5
|
+
* Enforces the commands/gsd/*.md contract across all 65 command files:
|
|
6
|
+
*
|
|
7
|
+
* 1. name: present, non-empty, matches gsd: or gsd- prefix
|
|
8
|
+
* 2. description: present, non-empty
|
|
9
|
+
* 3. allowed-tools: block present, non-empty, all entries from CANONICAL_TOOLS
|
|
10
|
+
* 4. execution_context @-refs: every @-reference resolves to an existing file on disk
|
|
11
|
+
* 5. execution_context @-refs: each appears on its own line (no trailing prose)
|
|
12
|
+
*
|
|
13
|
+
* Exit 0 = clean. Exit 1 = violations (with diagnostics).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const ROOT = path.join(__dirname, '..');
|
|
22
|
+
const COMMANDS_DIR = path.join(ROOT, 'commands', 'gsd');
|
|
23
|
+
const GSD_ROOT = path.join(ROOT, 'get-shit-done');
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
CANONICAL_TOOLS,
|
|
27
|
+
parseFrontmatter,
|
|
28
|
+
executionContextRefs: extractExecutionContextRefs,
|
|
29
|
+
} = require('./command-contract-helpers.cjs');
|
|
30
|
+
|
|
31
|
+
// ─── check one file ───────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
function check(filePath) {
|
|
34
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
35
|
+
const rel = path.relative(ROOT, filePath);
|
|
36
|
+
const fm = parseFrontmatter(content);
|
|
37
|
+
const violations = [];
|
|
38
|
+
|
|
39
|
+
// 1. name: present + gsd: / gsd- prefix
|
|
40
|
+
if (!fm.name || !fm.name.trim()) {
|
|
41
|
+
violations.push('name: field missing or empty');
|
|
42
|
+
} else if (!/^gsd[:-]/.test(fm.name.trim())) {
|
|
43
|
+
violations.push(`name: must start with "gsd:" or "gsd-", got "${fm.name.trim()}"`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 2. description: present + non-empty
|
|
47
|
+
if (!fm.description || !fm.description.trim()) {
|
|
48
|
+
violations.push('description: field missing or empty');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 3. allowed-tools: present + non-empty + all entries canonical
|
|
52
|
+
if (!fm['allowed-tools'] || !fm['allowed-tools'].trim()) {
|
|
53
|
+
violations.push('allowed-tools: block missing or empty');
|
|
54
|
+
} else {
|
|
55
|
+
const tools = fm['allowed-tools'].split('\n').map(t => t.trim()).filter(Boolean);
|
|
56
|
+
for (const tool of tools) {
|
|
57
|
+
const valid =
|
|
58
|
+
CANONICAL_TOOLS.has(tool) ||
|
|
59
|
+
(tool.startsWith('mcp__context7__') && CANONICAL_TOOLS.has('mcp__context7__*'));
|
|
60
|
+
if (!valid) violations.push(`allowed-tools: unknown tool "${tool}"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 4+5. execution_context @-refs resolve + no trailing prose
|
|
65
|
+
const refs = extractExecutionContextRefs(content);
|
|
66
|
+
for (const { token, normalized, trailingProse } of refs) {
|
|
67
|
+
const absPath = path.join(GSD_ROOT, normalized);
|
|
68
|
+
if (!fs.existsSync(absPath)) {
|
|
69
|
+
violations.push(`execution_context: @-ref "${normalized}" does not exist on disk`);
|
|
70
|
+
}
|
|
71
|
+
if (trailingProse) {
|
|
72
|
+
violations.push(`execution_context: @-ref "${token}" has trailing prose on the same line`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (violations.length === 0) return null;
|
|
77
|
+
return { file: rel, violations };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─── run ─────────────────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
const commandFiles = fs
|
|
83
|
+
.readdirSync(COMMANDS_DIR)
|
|
84
|
+
.filter(f => f.endsWith('.md'))
|
|
85
|
+
.map(f => path.join(COMMANDS_DIR, f));
|
|
86
|
+
|
|
87
|
+
const results = commandFiles.map(check).filter(Boolean);
|
|
88
|
+
|
|
89
|
+
if (results.length === 0) {
|
|
90
|
+
console.log(
|
|
91
|
+
`ok lint-command-contract: ${commandFiles.length} command files checked, 0 violations`,
|
|
92
|
+
);
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const total = results.reduce((n, r) => n + r.violations.length, 0);
|
|
97
|
+
process.stderr.write(
|
|
98
|
+
`\nERROR lint-command-contract: ${total} violation(s) across ${results.length} file(s)\n\n`,
|
|
99
|
+
);
|
|
100
|
+
for (const r of results) {
|
|
101
|
+
process.stderr.write(` ${r.file}\n`);
|
|
102
|
+
for (const v of r.violations) {
|
|
103
|
+
process.stderr.write(` - ${v}\n`);
|
|
104
|
+
}
|
|
105
|
+
process.stderr.write('\n');
|
|
106
|
+
}
|
|
107
|
+
process.stderr.write('See docs/adr/0002-command-contract-validation-module.md for the contract spec.\n\n');
|
|
108
|
+
process.exit(1);
|