@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,130 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Markdown serializer + parser for the changelog IR. The two are inverses
|
|
5
|
+
* over the well-formed subset; tests assert via round-trip (parse(serialize(ir)))
|
|
6
|
+
* rather than by inspecting serialized text — see CONTRIBUTING.md
|
|
7
|
+
* "Prohibited: Raw Text Matching on Test Outputs".
|
|
8
|
+
*
|
|
9
|
+
* Serialized form (Keep a Changelog):
|
|
10
|
+
*
|
|
11
|
+
* ## [1.42.0] - 2026-05-01
|
|
12
|
+
*
|
|
13
|
+
* ### Fixed
|
|
14
|
+
*
|
|
15
|
+
* - body of the bullet (#NNNN)
|
|
16
|
+
*
|
|
17
|
+
* <priorChangelog appended verbatim>
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function serializeChangelog(ir) {
|
|
21
|
+
const lines = [];
|
|
22
|
+
const { version, date } = ir.releaseHeader;
|
|
23
|
+
lines.push(`## [${version}] - ${date}`);
|
|
24
|
+
lines.push('');
|
|
25
|
+
for (const section of ir.sections) {
|
|
26
|
+
lines.push(`### ${section.type}`);
|
|
27
|
+
lines.push('');
|
|
28
|
+
for (const b of section.bullets) {
|
|
29
|
+
lines.push(`- ${b.body} (#${b.pr})`);
|
|
30
|
+
}
|
|
31
|
+
lines.push('');
|
|
32
|
+
}
|
|
33
|
+
let out = lines.join('\n');
|
|
34
|
+
if (ir.priorChangelog) {
|
|
35
|
+
out += '\n' + ir.priorChangelog;
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Inverse parser: extracts the structured releases from a CHANGELOG.md
|
|
42
|
+
* text. Returns { releases: [{ version, date, sections: [{ type, bullets:
|
|
43
|
+
* [{ pr, body }] }] }] }. Tolerates the actual repo's CHANGELOG dialect.
|
|
44
|
+
*
|
|
45
|
+
* Multi-line bullets are supported: a bullet opens on a line starting with
|
|
46
|
+
* `- ` and continues on lines starting with two or more spaces (or a tab).
|
|
47
|
+
* The `(#NNNN)` PR trailer may appear on any continuation line. Single-line
|
|
48
|
+
* bullets (entire entry on one `- ` line) are still handled as before.
|
|
49
|
+
*
|
|
50
|
+
* Fix for #3496: the previous implementation only matched single-line bullets
|
|
51
|
+
* whose `(#NNNN)` suffix was on the same line as the opening `- `. Long
|
|
52
|
+
* bullets — which wrap onto indented continuation lines — returned 0 entries
|
|
53
|
+
* for their section even when the markdown was well-formed.
|
|
54
|
+
*/
|
|
55
|
+
function parseChangelog(text) {
|
|
56
|
+
const releases = [];
|
|
57
|
+
const lines = text.split(/\r?\n/);
|
|
58
|
+
let cur = null;
|
|
59
|
+
let curSection = null;
|
|
60
|
+
// Accumulates lines belonging to the current in-flight bullet (may span
|
|
61
|
+
// multiple lines). Flushed when a new block-level element is encountered.
|
|
62
|
+
let bulletLines = null;
|
|
63
|
+
|
|
64
|
+
function flushBullet() {
|
|
65
|
+
if (bulletLines === null || !curSection) return;
|
|
66
|
+
const joined = bulletLines.join(' ').trim();
|
|
67
|
+
// Locate the (# pr) trailer anywhere in the joined text. The trailer is
|
|
68
|
+
// expected to be at the very end, but we tolerate trailing whitespace.
|
|
69
|
+
const trailMatch = joined.match(/^(.*?)\s*\(#(\d+)\)\s*$/);
|
|
70
|
+
if (trailMatch) {
|
|
71
|
+
curSection.bullets.push({ body: trailMatch[1].trim(), pr: Number(trailMatch[2]) });
|
|
72
|
+
} else {
|
|
73
|
+
// Bullet has no PR trailer — preserve it with pr: null so callers
|
|
74
|
+
// (e.g. cmdExtract) do not silently drop authored content.
|
|
75
|
+
curSection.bullets.push({ body: joined, pr: null });
|
|
76
|
+
}
|
|
77
|
+
bulletLines = null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (const line of lines) {
|
|
81
|
+
// F3: match linked headers: ## [1.42.1](url) - 2026-05-15
|
|
82
|
+
// The (?:\([^)]*\))? group skips an optional (url) after the closing ]
|
|
83
|
+
// before looking for the optional date suffix.
|
|
84
|
+
// F6: strip a leading `v` from the captured version so `## [v1.0.0]`
|
|
85
|
+
// parses as version "1.0.0" instead of "v1.0.0".
|
|
86
|
+
const releaseMatch = line.match(/^##\s+\[([^\]]+)\](?:\([^)]*\))?\s*(?:-\s*(\S+))?/);
|
|
87
|
+
if (releaseMatch) {
|
|
88
|
+
flushBullet();
|
|
89
|
+
const rawVersion = releaseMatch[1];
|
|
90
|
+
const version = rawVersion.replace(/^v/, '');
|
|
91
|
+
cur = { version, date: releaseMatch[2] || null, sections: [] };
|
|
92
|
+
curSection = null;
|
|
93
|
+
releases.push(cur);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (!cur) continue;
|
|
97
|
+
const sectionMatch = line.match(/^###\s+(.+?)\s*$/);
|
|
98
|
+
if (sectionMatch) {
|
|
99
|
+
flushBullet();
|
|
100
|
+
curSection = { type: sectionMatch[1], bullets: [] };
|
|
101
|
+
cur.sections.push(curSection);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (!curSection) continue;
|
|
105
|
+
|
|
106
|
+
// New bullet: line begins with `- ` (after optional leading spaces that
|
|
107
|
+
// would indicate a nested list — we only handle top-level bullets here).
|
|
108
|
+
if (/^-\s+/.test(line)) {
|
|
109
|
+
flushBullet();
|
|
110
|
+
bulletLines = [line.replace(/^-\s+/, '')];
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Continuation line: any indentation (F7: relaxed from /^[ \t]{2}/ so that
|
|
115
|
+
// 1-space-indented continuations also fold) BUT NOT a nested bullet marker
|
|
116
|
+
// (F4: ` - nested item` terminates the current bullet rather than folding).
|
|
117
|
+
if (bulletLines !== null && /^\s+/.test(line) && !/^\s+-\s/.test(line)) {
|
|
118
|
+
bulletLines.push(line.trim());
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Any other line (blank, heading, nested bullet, etc.) terminates a pending bullet.
|
|
123
|
+
flushBullet();
|
|
124
|
+
}
|
|
125
|
+
flushBullet();
|
|
126
|
+
|
|
127
|
+
return { releases };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = { serializeChangelog, parseChangelog };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
7
|
+
const aliasesPath = path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'command-aliases.cjs');
|
|
8
|
+
|
|
9
|
+
function fail(message) {
|
|
10
|
+
process.stderr.write(`${message}\n`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function ensureArray(value, name) {
|
|
15
|
+
if (!Array.isArray(value)) {
|
|
16
|
+
fail(`check:alias-drift: expected ${name} to be an array`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function assertNoDuplicates(values, label) {
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
for (const value of values) {
|
|
23
|
+
if (seen.has(value)) {
|
|
24
|
+
fail(`check:alias-drift: duplicate ${label} value "${value}"`);
|
|
25
|
+
}
|
|
26
|
+
seen.add(value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!fs.existsSync(aliasesPath)) {
|
|
31
|
+
fail(`check:alias-drift: missing ${path.relative(ROOT, aliasesPath)}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const aliases = require(aliasesPath);
|
|
35
|
+
|
|
36
|
+
const families = [
|
|
37
|
+
{
|
|
38
|
+
commandAliases: 'STATE_COMMAND_ALIASES',
|
|
39
|
+
subcommands: 'STATE_SUBCOMMANDS',
|
|
40
|
+
routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'state-command-router.cjs'),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
commandAliases: 'VERIFY_COMMAND_ALIASES',
|
|
44
|
+
subcommands: 'VERIFY_SUBCOMMANDS',
|
|
45
|
+
routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'verify-command-router.cjs'),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
commandAliases: 'INIT_COMMAND_ALIASES',
|
|
49
|
+
subcommands: 'INIT_SUBCOMMANDS',
|
|
50
|
+
routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'init-command-router.cjs'),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
commandAliases: 'PHASE_COMMAND_ALIASES',
|
|
54
|
+
subcommands: 'PHASE_SUBCOMMANDS',
|
|
55
|
+
routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'phase-command-router.cjs'),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
commandAliases: 'PHASES_COMMAND_ALIASES',
|
|
59
|
+
subcommands: 'PHASES_SUBCOMMANDS',
|
|
60
|
+
routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'phases-command-router.cjs'),
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
commandAliases: 'VALIDATE_COMMAND_ALIASES',
|
|
64
|
+
subcommands: 'VALIDATE_SUBCOMMANDS',
|
|
65
|
+
routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'validate-command-router.cjs'),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
commandAliases: 'ROADMAP_COMMAND_ALIASES',
|
|
69
|
+
subcommands: 'ROADMAP_SUBCOMMANDS',
|
|
70
|
+
routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'roadmap-command-router.cjs'),
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
for (const family of families) {
|
|
75
|
+
const commandAliases = aliases[family.commandAliases];
|
|
76
|
+
const subcommands = aliases[family.subcommands];
|
|
77
|
+
|
|
78
|
+
ensureArray(commandAliases, family.commandAliases);
|
|
79
|
+
ensureArray(subcommands, family.subcommands);
|
|
80
|
+
|
|
81
|
+
const derivedSubcommands = commandAliases.map((entry) => entry && entry.subcommand);
|
|
82
|
+
assertNoDuplicates(derivedSubcommands, `${family.commandAliases}.subcommand`);
|
|
83
|
+
|
|
84
|
+
if (derivedSubcommands.length !== subcommands.length) {
|
|
85
|
+
fail(
|
|
86
|
+
`check:alias-drift: ${family.subcommands} length ${subcommands.length} does not match ` +
|
|
87
|
+
`${family.commandAliases} length ${derivedSubcommands.length}`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (let i = 0; i < derivedSubcommands.length; i++) {
|
|
92
|
+
if (derivedSubcommands[i] !== subcommands[i]) {
|
|
93
|
+
fail(
|
|
94
|
+
`check:alias-drift: ${family.subcommands}[${i}] = "${subcommands[i]}" ` +
|
|
95
|
+
`does not match ${family.commandAliases}[${i}].subcommand = "${derivedSubcommands[i]}"`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const routerSource = fs.readFileSync(family.routerPath, 'utf8');
|
|
101
|
+
if (!routerSource.includes(family.subcommands)) {
|
|
102
|
+
fail(
|
|
103
|
+
`check:alias-drift: ${path.relative(ROOT, family.routerPath)} does not reference ${family.subcommands}`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
process.stdout.write('check:alias-drift ok\n');
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
// scripts/check-env.cjs — Environment parity validator for contributors (issue #117).
|
|
4
|
+
//
|
|
5
|
+
// Node.js port of scripts/check-env.sh. Behaviorally identical output and
|
|
6
|
+
// exit codes; shell-agnostic so it runs on Windows, macOS, and Linux.
|
|
7
|
+
//
|
|
8
|
+
// Checks that the developer's environment matches project requirements before
|
|
9
|
+
// running tests or audits. Designed to catch mismatches early rather than
|
|
10
|
+
// through cryptic test failures.
|
|
11
|
+
//
|
|
12
|
+
// Exit codes:
|
|
13
|
+
// 0 All checks passed
|
|
14
|
+
// 1 One or more checks failed
|
|
15
|
+
// 2 Tool error (missing required tool, corrupt package.json, etc.)
|
|
16
|
+
//
|
|
17
|
+
// Usage:
|
|
18
|
+
// node scripts/check-env.cjs # Human-readable report
|
|
19
|
+
// node scripts/check-env.cjs --json # Structured JSON report
|
|
20
|
+
// node scripts/check-env.cjs --help # This message
|
|
21
|
+
//
|
|
22
|
+
// Sources:
|
|
23
|
+
// npm engines: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines
|
|
24
|
+
// Reproducible builds: https://reproducible-builds.org/docs/source-tree/
|
|
25
|
+
// npm ci docs: https://docs.npmjs.com/cli/v10/commands/npm-ci
|
|
26
|
+
// gsd-test-runner: https://github.com/open-gsd/gsd-test-runner
|
|
27
|
+
|
|
28
|
+
const fs = require('fs');
|
|
29
|
+
const path = require('path');
|
|
30
|
+
const { execFileSync, spawnSync } = require('child_process');
|
|
31
|
+
|
|
32
|
+
// On Windows, npm ships as npm.cmd (a batch wrapper); spawnSync without
|
|
33
|
+
// shell:true requires the exact filename including extension.
|
|
34
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Argument parsing
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
let jsonMode = false;
|
|
40
|
+
|
|
41
|
+
for (const arg of process.argv.slice(2)) {
|
|
42
|
+
if (arg === '--json') {
|
|
43
|
+
jsonMode = true;
|
|
44
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
45
|
+
process.stdout.write(
|
|
46
|
+
'scripts/check-env.cjs — Environment parity validator for contributors (issue #117).\n' +
|
|
47
|
+
'\n' +
|
|
48
|
+
'Checks that the developer\'s environment matches project requirements before\n' +
|
|
49
|
+
'running tests or audits. Designed to catch mismatches early rather than\n' +
|
|
50
|
+
'through cryptic test failures.\n' +
|
|
51
|
+
'\n' +
|
|
52
|
+
'Exit codes:\n' +
|
|
53
|
+
' 0 All checks passed\n' +
|
|
54
|
+
' 1 One or more checks failed\n' +
|
|
55
|
+
' 2 Tool error (missing required tool, corrupt package.json, etc.)\n' +
|
|
56
|
+
'\n' +
|
|
57
|
+
'Usage:\n' +
|
|
58
|
+
' node scripts/check-env.cjs # Human-readable report\n' +
|
|
59
|
+
' node scripts/check-env.cjs --json # Structured JSON report\n' +
|
|
60
|
+
' node scripts/check-env.cjs --help # This message\n'
|
|
61
|
+
);
|
|
62
|
+
process.exit(0);
|
|
63
|
+
} else {
|
|
64
|
+
process.stderr.write(`Unknown option: ${arg}\n`);
|
|
65
|
+
process.exit(2);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Locate the project root (directory containing package.json)
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
const PROJECT_ROOT = process.cwd();
|
|
73
|
+
const PACKAGE_JSON = path.join(PROJECT_ROOT, 'package.json');
|
|
74
|
+
|
|
75
|
+
if (!fs.existsSync(PACKAGE_JSON)) {
|
|
76
|
+
process.stderr.write(`ERROR: package.json not found in ${PROJECT_ROOT}\n`);
|
|
77
|
+
process.exit(2);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Helpers
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
/** @type {Array<{name: string, status: 'pass'|'fail'|'skip', message: string}>} */
|
|
85
|
+
const checks = [];
|
|
86
|
+
|
|
87
|
+
function addCheck(name, status, message) {
|
|
88
|
+
checks.push({ name, status, message });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Semver comparison: does `version` satisfy `constraint`?
|
|
93
|
+
* Constraint forms: >=X.Y.Z, >X.Y.Z, <=X.Y.Z, <X.Y.Z, =X.Y.Z, X.Y.Z
|
|
94
|
+
* Returns true if satisfied, false otherwise.
|
|
95
|
+
*/
|
|
96
|
+
function satisfiesConstraint(version, constraint) {
|
|
97
|
+
// Strip leading 'v' and pre-release/build suffixes
|
|
98
|
+
version = version.replace(/^v/, '').replace(/-.*$/, '').replace(/\+.*$/, '');
|
|
99
|
+
|
|
100
|
+
let op, reqVer;
|
|
101
|
+
const opMatch = constraint.match(/^(>=|>|<=|<|=)(.+)$/);
|
|
102
|
+
if (opMatch) {
|
|
103
|
+
op = opMatch[1];
|
|
104
|
+
reqVer = opMatch[2];
|
|
105
|
+
} else {
|
|
106
|
+
op = '=';
|
|
107
|
+
reqVer = constraint;
|
|
108
|
+
}
|
|
109
|
+
reqVer = reqVer.replace(/^v/, '').replace(/-.*$/, '').replace(/\+.*$/, '');
|
|
110
|
+
|
|
111
|
+
function parseTuple(v) {
|
|
112
|
+
const parts = (v + '.0.0').split('.');
|
|
113
|
+
return [
|
|
114
|
+
parseInt(parts[0], 10) || 0,
|
|
115
|
+
parseInt(parts[1], 10) || 0,
|
|
116
|
+
parseInt(parts[2], 10) || 0,
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const [vMaj, vMin, vPat] = parseTuple(version);
|
|
121
|
+
const [rMaj, rMin, rPat] = parseTuple(reqVer);
|
|
122
|
+
|
|
123
|
+
const vNum = vMaj * 1_000_000 + vMin * 1_000 + vPat;
|
|
124
|
+
const rNum = rMaj * 1_000_000 + rMin * 1_000 + rPat;
|
|
125
|
+
|
|
126
|
+
switch (op) {
|
|
127
|
+
case '>=': return vNum >= rNum;
|
|
128
|
+
case '>': return vNum > rNum;
|
|
129
|
+
case '<=': return vNum <= rNum;
|
|
130
|
+
case '<': return vNum < rNum;
|
|
131
|
+
case '=': return vNum === rNum;
|
|
132
|
+
default: return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Read a field from package.json using dot-notation (e.g. 'engines.node').
|
|
138
|
+
* Returns the string value or empty string if absent.
|
|
139
|
+
* Uses './package.json' so Node resolves relative to CWD on all platforms.
|
|
140
|
+
*/
|
|
141
|
+
function pkgField(fieldPath) {
|
|
142
|
+
try {
|
|
143
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PROJECT_ROOT, 'package.json'), 'utf8'));
|
|
144
|
+
let val = pkg;
|
|
145
|
+
for (const key of fieldPath.split('.')) {
|
|
146
|
+
if (val == null || typeof val !== 'object') return '';
|
|
147
|
+
val = val[key];
|
|
148
|
+
}
|
|
149
|
+
return val != null ? String(val) : '';
|
|
150
|
+
} catch {
|
|
151
|
+
return '';
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Check 1: Node version vs engines.node
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
const enginesNode = pkgField('engines.node');
|
|
159
|
+
let currentNode = '';
|
|
160
|
+
try {
|
|
161
|
+
currentNode = process.version.replace(/^v/, '');
|
|
162
|
+
} catch { /* ignore */ }
|
|
163
|
+
|
|
164
|
+
if (!currentNode) {
|
|
165
|
+
addCheck('node-version', 'fail', 'node binary not found on PATH');
|
|
166
|
+
} else if (!enginesNode) {
|
|
167
|
+
addCheck('node-version', 'fail', 'engines.node missing from package.json — add it (see D2 in docs/contributing/bootstrap.md)');
|
|
168
|
+
} else {
|
|
169
|
+
if (satisfiesConstraint(currentNode, enginesNode)) {
|
|
170
|
+
addCheck('node-version', 'pass', `Node ${currentNode} satisfies ${enginesNode}`);
|
|
171
|
+
} else {
|
|
172
|
+
addCheck('node-version', 'fail', `Node ${currentNode} does NOT satisfy engines.node ${enginesNode}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// Check 2: npm version vs engines.npm (skip if field absent)
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
const enginesNpm = pkgField('engines.npm');
|
|
180
|
+
let currentNpm = '';
|
|
181
|
+
try {
|
|
182
|
+
const res = spawnSync(npmCmd, ['--version'], { encoding: 'utf8', timeout: 10_000, shell: process.platform === 'win32' });
|
|
183
|
+
if (res.status === 0 && res.stdout) {
|
|
184
|
+
currentNpm = res.stdout.trim();
|
|
185
|
+
}
|
|
186
|
+
} catch { /* ignore */ }
|
|
187
|
+
|
|
188
|
+
if (!enginesNpm) {
|
|
189
|
+
addCheck('npm-version', 'skip', 'engines.npm not set in package.json — skipping');
|
|
190
|
+
} else if (!currentNpm) {
|
|
191
|
+
addCheck('npm-version', 'fail', 'npm binary not found on PATH');
|
|
192
|
+
} else {
|
|
193
|
+
if (satisfiesConstraint(currentNpm, enginesNpm)) {
|
|
194
|
+
addCheck('npm-version', 'pass', `npm ${currentNpm} satisfies ${enginesNpm}`);
|
|
195
|
+
} else {
|
|
196
|
+
addCheck('npm-version', 'fail', `npm ${currentNpm} does NOT satisfy engines.npm ${enginesNpm}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// Check 3: Lockfile presence
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
const LOCKFILE = path.join(PROJECT_ROOT, 'package-lock.json');
|
|
204
|
+
if (fs.existsSync(LOCKFILE)) {
|
|
205
|
+
addCheck('lockfile-present', 'pass', 'package-lock.json exists');
|
|
206
|
+
} else {
|
|
207
|
+
addCheck('lockfile-present', 'fail', "package-lock.json missing — run 'npm install' to generate it");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// Check 4: Lockfile sync (npm ci --dry-run)
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
if (fs.existsSync(LOCKFILE)) {
|
|
214
|
+
try {
|
|
215
|
+
const res = spawnSync(npmCmd, ['ci', '--dry-run'], {
|
|
216
|
+
cwd: PROJECT_ROOT,
|
|
217
|
+
encoding: 'utf8',
|
|
218
|
+
shell: process.platform === 'win32',
|
|
219
|
+
});
|
|
220
|
+
if (res.status === 0) {
|
|
221
|
+
addCheck('lockfile-sync', 'pass', 'package-lock.json is in sync with package.json');
|
|
222
|
+
} else {
|
|
223
|
+
addCheck('lockfile-sync', 'fail', "package-lock.json is out of sync — run 'npm ci' to restore");
|
|
224
|
+
}
|
|
225
|
+
} catch {
|
|
226
|
+
addCheck('lockfile-sync', 'fail', "package-lock.json is out of sync — run 'npm ci' to restore");
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
addCheck('lockfile-sync', 'skip', 'skipped — lockfile missing');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
// Check 5: Version manager pin vs active Node
|
|
234
|
+
// Looks for .nvmrc, .node-version, or .tool-versions at project root.
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
const NVMRC = path.join(PROJECT_ROOT, '.nvmrc');
|
|
237
|
+
const NODE_VERSION_FILE = path.join(PROJECT_ROOT, '.node-version');
|
|
238
|
+
const TOOL_VERSIONS = path.join(PROJECT_ROOT, '.tool-versions');
|
|
239
|
+
|
|
240
|
+
let pinnedMajor = '';
|
|
241
|
+
let pinSource = '';
|
|
242
|
+
|
|
243
|
+
if (fs.existsSync(NVMRC)) {
|
|
244
|
+
const content = fs.readFileSync(NVMRC, 'utf8').split('\n')[0].trim().replace(/^v/, '');
|
|
245
|
+
pinnedMajor = content.split('.')[0];
|
|
246
|
+
pinSource = '.nvmrc';
|
|
247
|
+
} else if (fs.existsSync(NODE_VERSION_FILE)) {
|
|
248
|
+
const content = fs.readFileSync(NODE_VERSION_FILE, 'utf8').split('\n')[0].trim().replace(/^v/, '');
|
|
249
|
+
pinnedMajor = content.split('.')[0];
|
|
250
|
+
pinSource = '.node-version';
|
|
251
|
+
} else if (fs.existsSync(TOOL_VERSIONS)) {
|
|
252
|
+
const lines = fs.readFileSync(TOOL_VERSIONS, 'utf8').split('\n');
|
|
253
|
+
const nodeLine = lines.find(l => /^nodejs\s+/.test(l));
|
|
254
|
+
if (nodeLine) {
|
|
255
|
+
const ver = nodeLine.split(/\s+/)[1] || '';
|
|
256
|
+
pinnedMajor = ver.replace(/^v/, '').split('.')[0];
|
|
257
|
+
pinSource = '.tool-versions';
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (!pinnedMajor) {
|
|
262
|
+
addCheck('version-manager-pin', 'skip', 'no .nvmrc, .node-version, or .tool-versions found — skipping');
|
|
263
|
+
} else if (process.env.CI === 'true') {
|
|
264
|
+
addCheck('version-manager-pin', 'skip', 'CI=true — version-manager pin check skipped (matrix tests multiple Node majors)');
|
|
265
|
+
} else {
|
|
266
|
+
const activeMajor = process.version.replace(/^v/, '').split('.')[0];
|
|
267
|
+
if (activeMajor === pinnedMajor) {
|
|
268
|
+
addCheck('version-manager-pin', 'pass', `Active Node major (${activeMajor}) matches ${pinSource} pin (${pinnedMajor})`);
|
|
269
|
+
} else {
|
|
270
|
+
addCheck('version-manager-pin', 'fail', `Active Node major (${activeMajor}) does NOT match ${pinSource} pin (${pinnedMajor}) — run 'nvm use' or equivalent`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
// Output
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
const overallPass = checks.every(c => c.status !== 'fail');
|
|
278
|
+
|
|
279
|
+
if (jsonMode) {
|
|
280
|
+
// Structured JSON: {pass: bool, checks: [{name, status, message}]}
|
|
281
|
+
const out = {
|
|
282
|
+
pass: overallPass,
|
|
283
|
+
checks: checks.map(c => ({ name: c.name, status: c.status, message: c.message })),
|
|
284
|
+
};
|
|
285
|
+
process.stdout.write(JSON.stringify(out, null, 2) + '\n');
|
|
286
|
+
} else {
|
|
287
|
+
// Human-readable report
|
|
288
|
+
process.stdout.write('=== Environment Check ===\n');
|
|
289
|
+
for (const { name, status, message } of checks) {
|
|
290
|
+
const icon = status === 'pass' ? '[PASS]' : status === 'fail' ? '[FAIL]' : '[SKIP]';
|
|
291
|
+
const namePadded = name.padEnd(25);
|
|
292
|
+
process.stdout.write(` ${icon} ${namePadded} ${message}\n`);
|
|
293
|
+
}
|
|
294
|
+
process.stdout.write('\n');
|
|
295
|
+
if (overallPass) {
|
|
296
|
+
process.stdout.write('Result: ALL CHECKS PASSED\n');
|
|
297
|
+
} else {
|
|
298
|
+
process.stdout.write('Result: ONE OR MORE CHECKS FAILED — see above\n');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
process.exit(overallPass ? 0 : 1);
|