@opengsd/gsd-core 1.2.0 → 1.3.0
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/README.ja-JP.md +46 -791
- package/README.ko-KR.md +44 -780
- package/README.md +42 -218
- package/README.pt-BR.md +47 -414
- package/README.zh-CN.md +46 -763
- package/agents/gsd-ai-researcher.md +2 -2
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +8 -8
- package/agents/gsd-doc-writer.md +7 -6
- package/agents/gsd-domain-researcher.md +15 -2
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-eval-planner.md +2 -2
- package/agents/gsd-executor.md +21 -8
- package/agents/gsd-framework-selector.md +1 -1
- package/agents/gsd-intel-updater.md +4 -4
- package/agents/gsd-phase-researcher.md +19 -6
- package/agents/gsd-plan-checker.md +3 -3
- package/agents/gsd-planner.md +36 -23
- package/agents/gsd-project-researcher.md +13 -0
- package/agents/gsd-research-synthesizer.md +6 -2
- package/agents/gsd-roadmapper.md +6 -6
- package/agents/gsd-ui-researcher.md +16 -3
- package/agents/gsd-user-profiler.md +2 -2
- package/agents/gsd-verifier.md +8 -8
- package/assets/gsd-logo-2000-transparent.png +0 -0
- package/assets/gsd-logo-2000-transparent.svg +17 -0
- package/assets/gsd-logo-2000.png +0 -0
- package/assets/gsd-logo-2000.svg +21 -0
- package/assets/terminal.svg +68 -0
- package/bin/install.js +255 -103
- package/commands/gsd/add-tests.md +1 -1
- package/commands/gsd/ai-integration-phase.md +3 -3
- package/commands/gsd/audit-fix.md +1 -1
- package/commands/gsd/audit-milestone.md +1 -1
- package/commands/gsd/audit-uat.md +1 -1
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +6 -6
- package/commands/gsd/cleanup.md +1 -1
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/complete-milestone.md +2 -2
- package/commands/gsd/config.md +3 -3
- package/commands/gsd/debug.md +1 -1
- package/commands/gsd/discuss-phase.md +5 -4
- package/commands/gsd/docs-update.md +1 -1
- package/commands/gsd/eval-review.md +2 -2
- package/commands/gsd/execute-phase.md +2 -2
- package/commands/gsd/explore.md +1 -1
- package/commands/gsd/extract-learnings.md +2 -2
- package/commands/gsd/fast.md +1 -1
- package/commands/gsd/forensics.md +1 -1
- package/commands/gsd/graphify.md +9 -9
- package/commands/gsd/health.md +1 -1
- package/commands/gsd/help.md +2 -2
- package/commands/gsd/import.md +5 -5
- package/commands/gsd/inbox.md +1 -1
- package/commands/gsd/ingest-docs.md +4 -4
- package/commands/gsd/manager.md +3 -3
- package/commands/gsd/map-codebase.md +1 -1
- package/commands/gsd/milestone-summary.md +1 -1
- package/commands/gsd/mvp-phase.md +4 -4
- package/commands/gsd/new-milestone.md +5 -5
- package/commands/gsd/new-project.md +5 -5
- package/commands/gsd/pause-work.md +2 -2
- package/commands/gsd/phase.md +4 -4
- package/commands/gsd/plan-phase.md +2 -2
- package/commands/gsd/plan-review-convergence.md +4 -4
- package/commands/gsd/pr-branch.md +1 -1
- package/commands/gsd/profile-user.md +2 -2
- package/commands/gsd/progress.md +4 -4
- package/commands/gsd/quick.md +1 -1
- package/commands/gsd/resume-work.md +1 -1
- package/commands/gsd/review.md +3 -2
- package/commands/gsd/secure-phase.md +1 -1
- package/commands/gsd/settings.md +1 -1
- package/commands/gsd/ship.md +2 -2
- package/commands/gsd/sketch.md +7 -7
- package/commands/gsd/spec-phase.md +2 -2
- package/commands/gsd/spike.md +3 -3
- package/commands/gsd/stats.md +1 -1
- package/commands/gsd/surface.md +4 -4
- package/commands/gsd/thread.md +1 -1
- package/commands/gsd/ui-phase.md +2 -2
- package/commands/gsd/ui-review.md +2 -2
- package/commands/gsd/ultraplan-phase.md +2 -2
- package/commands/gsd/undo.md +3 -3
- package/commands/gsd/update.md +3 -3
- package/commands/gsd/validate-phase.md +1 -1
- package/commands/gsd/verify-work.md +2 -2
- package/commands/gsd/workspace.md +4 -4
- package/{get-shit-done → gsd-core}/bin/check-latest-version.cjs +1 -1
- package/{get-shit-done → gsd-core}/bin/gsd-tools.cjs +50 -4
- package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
- package/gsd-core/bin/lib/adr-parser.cjs +399 -0
- package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
- package/gsd-core/bin/lib/artifacts.cjs +51 -0
- package/gsd-core/bin/lib/audit.cjs +743 -0
- package/gsd-core/bin/lib/check-command-router.cjs +342 -0
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
- package/gsd-core/bin/lib/clock.cjs +95 -0
- package/gsd-core/bin/lib/clusters.cjs +128 -0
- package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
- package/gsd-core/bin/lib/command-aliases.cjs +809 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
- package/gsd-core/bin/lib/commands.cjs +1202 -0
- package/gsd-core/bin/lib/config-schema.cjs +29 -0
- package/gsd-core/bin/lib/config-types.cjs +19 -0
- package/gsd-core/bin/lib/config.cjs +714 -0
- package/{get-shit-done → gsd-core}/bin/lib/configuration.cjs +76 -85
- package/gsd-core/bin/lib/context-utilization.cjs +48 -0
- package/gsd-core/bin/lib/core.cjs +2007 -0
- package/{get-shit-done → gsd-core}/bin/lib/decisions.cjs +9 -7
- package/gsd-core/bin/lib/docs.cjs +252 -0
- package/gsd-core/bin/lib/drift.cjs +364 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
- package/gsd-core/bin/lib/frontmatter.cjs +442 -0
- package/gsd-core/bin/lib/gap-checker.cjs +257 -0
- package/gsd-core/bin/lib/graphify.cjs +496 -0
- package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
- package/gsd-core/bin/lib/init-command-router.cjs +62 -0
- package/gsd-core/bin/lib/init.cjs +1799 -0
- package/gsd-core/bin/lib/install-profiles.cjs +526 -0
- package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +347 -0
- package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
- package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
- package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
- package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +784 -0
- package/gsd-core/bin/lib/intel.cjs +607 -0
- package/gsd-core/bin/lib/learnings.cjs +270 -0
- package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
- package/gsd-core/bin/lib/milestone.cjs +373 -0
- package/gsd-core/bin/lib/model-catalog.cjs +154 -0
- package/gsd-core/bin/lib/model-profiles.cjs +24 -0
- package/gsd-core/bin/lib/observability/event.cjs +51 -0
- package/gsd-core/bin/lib/observability/logger.cjs +146 -0
- package/{get-shit-done → gsd-core}/bin/lib/observability/redaction.cjs +19 -21
- package/{get-shit-done → gsd-core}/bin/lib/package-identity.cjs +5 -1
- package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
- package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
- package/gsd-core/bin/lib/phase.cjs +1307 -0
- package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
- package/{get-shit-done → gsd-core}/bin/lib/plan-scan.cjs +18 -24
- package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
- package/gsd-core/bin/lib/profile-output.cjs +1120 -0
- package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
- package/gsd-core/bin/lib/project-root.cjs +119 -0
- package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +491 -0
- package/gsd-core/bin/lib/roadmap.cjs +600 -0
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +254 -0
- package/gsd-core/bin/lib/runtime-homes.cjs +169 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
- package/{get-shit-done → gsd-core}/bin/lib/schema-detect.cjs +20 -26
- package/gsd-core/bin/lib/secrets.cjs +34 -0
- package/gsd-core/bin/lib/security.cjs +407 -0
- package/gsd-core/bin/lib/semver-compare.cjs +42 -0
- package/gsd-core/bin/lib/shell-command-projection.cjs +524 -0
- package/gsd-core/bin/lib/state-command-router.cjs +160 -0
- package/{get-shit-done → gsd-core}/bin/lib/state-document.cjs +78 -82
- package/gsd-core/bin/lib/state.cjs +2010 -0
- package/gsd-core/bin/lib/surface.cjs +406 -0
- package/gsd-core/bin/lib/task-command-router.cjs +85 -0
- package/gsd-core/bin/lib/template.cjs +237 -0
- package/gsd-core/bin/lib/uat.cjs +297 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
- package/gsd-core/bin/lib/update-context.cjs +218 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
- package/gsd-core/bin/lib/validate.cjs +112 -0
- package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
- package/gsd-core/bin/lib/verify.cjs +1451 -0
- package/{get-shit-done → gsd-core}/bin/lib/workstream-inventory-builder.cjs +19 -12
- package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
- package/{get-shit-done → gsd-core}/bin/lib/workstream-name-policy.cjs +28 -31
- package/gsd-core/bin/lib/workstream.cjs +380 -0
- package/gsd-core/bin/lib/worktree-safety.cjs +912 -0
- package/{get-shit-done → gsd-core}/bin/shared/config-defaults.manifest.json +1 -0
- package/{get-shit-done → gsd-core}/bin/shared/config-schema.manifest.json +17 -1
- package/{get-shit-done → gsd-core}/bin/shared/model-catalog.json +27 -0
- package/{get-shit-done → gsd-core}/references/artifact-types.md +1 -1
- package/{get-shit-done → gsd-core}/references/checkpoints.md +1 -1
- package/{get-shit-done → gsd-core}/references/few-shot-examples/plan-checker.md +2 -2
- package/{get-shit-done → gsd-core}/references/few-shot-examples/verifier.md +12 -12
- package/{get-shit-done → gsd-core}/references/model-profile-resolution.md +1 -1
- package/{get-shit-done → gsd-core}/references/mvp-concepts.md +1 -1
- package/{get-shit-done → gsd-core}/references/planner-graphify-auto-update.md +2 -2
- package/{get-shit-done → gsd-core}/references/planner-human-verify-mode.md +1 -1
- package/{get-shit-done → gsd-core}/references/planner-mvp-mode.md +1 -1
- package/{get-shit-done → gsd-core}/references/ui-brand.md +4 -2
- package/{get-shit-done → gsd-core}/references/verification-patterns.md +1 -1
- package/gsd-core/references/worktree-branch-check.md +38 -0
- package/{get-shit-done → gsd-core}/references/worktree-path-safety.md +4 -26
- package/{get-shit-done → gsd-core}/templates/README.md +2 -2
- package/{get-shit-done → gsd-core}/templates/codebase/structure.md +10 -10
- package/{get-shit-done → gsd-core}/templates/copilot-instructions.md +1 -1
- package/{get-shit-done → gsd-core}/templates/phase-prompt.md +10 -10
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
- package/{get-shit-done → gsd-core}/workflows/add-backlog.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/add-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/add-tests.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/add-todo.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/ai-integration-phase.md +4 -4
- package/{get-shit-done → gsd-core}/workflows/audit-fix.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/audit-milestone.md +3 -1
- package/{get-shit-done → gsd-core}/workflows/audit-uat.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/autonomous.md +10 -8
- package/{get-shit-done → gsd-core}/workflows/check-todos.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/cleanup.md +44 -4
- package/{get-shit-done → gsd-core}/workflows/code-review-fix.md +4 -4
- package/{get-shit-done → gsd-core}/workflows/code-review.md +6 -4
- package/{get-shit-done → gsd-core}/workflows/complete-milestone.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/debug.md +7 -2
- package/{get-shit-done → gsd-core}/workflows/diagnose-issues.md +6 -2
- package/{get-shit-done → gsd-core}/workflows/discovery-phase.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/advisor.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/auto.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/chain.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/power.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/discuss-phase-assumptions.md +4 -4
- package/{get-shit-done → gsd-core}/workflows/discuss-phase.md +6 -6
- package/{get-shit-done → gsd-core}/workflows/do.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/docs-update.md +19 -5
- package/{get-shit-done → gsd-core}/workflows/edit-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/eval-review.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/codebase-drift-gate.md +16 -3
- package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/post-merge-gate.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/execute-phase.md +89 -57
- package/{get-shit-done → gsd-core}/workflows/execute-plan.md +8 -8
- package/{get-shit-done → gsd-core}/workflows/explore.md +5 -3
- package/{get-shit-done → gsd-core}/workflows/extract-learnings.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/forensics.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/graduation.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/health.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/help/modes/default.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/help/modes/full.md +6 -6
- package/{get-shit-done → gsd-core}/workflows/import.md +3 -1
- package/{get-shit-done → gsd-core}/workflows/ingest-docs.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/insert-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/list-workspaces.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/manager.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/map-codebase.md +3 -1
- package/{get-shit-done → gsd-core}/workflows/milestone-summary.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/mvp-phase.md +7 -7
- package/{get-shit-done → gsd-core}/workflows/new-milestone.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/new-project.md +8 -8
- package/{get-shit-done → gsd-core}/workflows/new-workspace.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/next.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/pause-work.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/plan-milestone-gaps.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/plan-phase.md +29 -28
- package/{get-shit-done → gsd-core}/workflows/plan-review-convergence.md +10 -10
- package/{get-shit-done → gsd-core}/workflows/plant-seed.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/profile-user.md +11 -11
- package/{get-shit-done → gsd-core}/workflows/progress.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/quick.md +7 -29
- package/{get-shit-done → gsd-core}/workflows/reapply-patches.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/remove-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/remove-workspace.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/resume-project.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/review.md +110 -2
- package/{get-shit-done → gsd-core}/workflows/scan.md +3 -1
- package/{get-shit-done → gsd-core}/workflows/secure-phase.md +5 -3
- package/{get-shit-done → gsd-core}/workflows/settings-advanced.md +196 -6
- package/{get-shit-done → gsd-core}/workflows/settings-integrations.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/settings.md +16 -2
- package/{get-shit-done → gsd-core}/workflows/ship.md +56 -4
- package/{get-shit-done → gsd-core}/workflows/sketch-wrap-up.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/sketch.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/spec-phase.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/spike-wrap-up.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/spike.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/stats.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/sync-skills.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/thread.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/transition.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/ui-phase.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/ui-review.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/ultraplan-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/undo.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/update.md +41 -16
- package/{get-shit-done → gsd-core}/workflows/validate-phase.md +5 -3
- package/{get-shit-done → gsd-core}/workflows/verify-phase.md +4 -4
- package/{get-shit-done → gsd-core}/workflows/verify-work.md +7 -7
- package/hooks/dist/gsd-check-update-worker.js +16 -3
- package/hooks/dist/gsd-check-update.js +7 -5
- package/hooks/dist/gsd-context-monitor.js +2 -2
- package/hooks/dist/gsd-statusline.js +39 -21
- package/hooks/dist/gsd-update-banner.js +6 -2
- package/hooks/dist/gsd-worktree-path-guard.js +169 -0
- package/hooks/dist/managed-hooks-registry.cjs +35 -0
- package/hooks/gsd-check-update-worker.js +16 -3
- package/hooks/gsd-check-update.js +7 -5
- package/hooks/gsd-context-monitor.js +2 -2
- package/hooks/gsd-statusline.js +39 -21
- package/hooks/gsd-update-banner.js +6 -2
- package/hooks/gsd-worktree-path-guard.js +169 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +17 -11
- package/scripts/affected-tests-lib.cjs +1 -1
- package/scripts/base64-scan.sh +12 -0
- package/scripts/build-hooks.js +5 -1
- package/scripts/changeset/cli.cjs +2 -2
- package/scripts/changeset/github-release-notes.cjs +1 -1
- package/scripts/changeset/lint.cjs +1 -1
- package/scripts/check-alias-drift.cjs +8 -8
- package/scripts/check-env.cjs +5 -1
- package/scripts/ci-test-scope.cjs +34 -9
- package/scripts/command-contract-helpers.cjs +1 -1
- package/scripts/fix-slash-commands.cjs +5 -5
- package/scripts/gen-inventory-manifest.cjs +3 -3
- package/scripts/generate-package-identity.cjs +28 -7
- package/scripts/lib/allowlist-ratchet.cjs +136 -0
- package/scripts/lint-command-contract.cjs +1 -1
- package/scripts/lint-legacy-dir-name.cjs +156 -0
- package/scripts/lint-package-identity-drift.cjs +8 -8
- package/scripts/lint-pr-check-project-dir.cjs +0 -1
- package/scripts/lint-shell-command-projection-drift.cjs +1 -1
- package/scripts/lint-skill-deps.cjs +1 -1
- package/scripts/lint-test-file-count.allowlist.json +129 -32
- package/scripts/lint-test-file-count.cjs +85 -30
- package/scripts/mutation-matrix.cjs +219 -0
- package/scripts/prompt-injection-scan.sh +5 -1
- package/scripts/release-notes/format-github-release-notes.cjs +256 -0
- package/scripts/release-tarball-smoke.cjs +9 -9
- package/scripts/run-tests.cjs +34 -2
- package/scripts/strip-prose-atrefs.cjs +2 -2
- package/scripts/sync-runtime-launcher.cjs +2 -2
- package/scripts/verify-npm-publish.cjs +252 -0
- package/get-shit-done/bin/lib/active-workstream-store.cjs +0 -302
- package/get-shit-done/bin/lib/adr-parser.cjs +0 -394
- package/get-shit-done/bin/lib/agent-command-router.cjs +0 -65
- package/get-shit-done/bin/lib/artifacts.cjs +0 -53
- package/get-shit-done/bin/lib/audit.cjs +0 -755
- package/get-shit-done/bin/lib/check-command-router.cjs +0 -333
- package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +0 -118
- package/get-shit-done/bin/lib/clock.cjs +0 -96
- package/get-shit-done/bin/lib/clusters.cjs +0 -135
- package/get-shit-done/bin/lib/code-review-flags.cjs +0 -74
- package/get-shit-done/bin/lib/command-aliases.cjs +0 -815
- package/get-shit-done/bin/lib/command-arg-projection.cjs +0 -62
- package/get-shit-done/bin/lib/command-routing-hub.cjs +0 -388
- package/get-shit-done/bin/lib/commands.cjs +0 -1188
- package/get-shit-done/bin/lib/config-schema.cjs +0 -31
- package/get-shit-done/bin/lib/config.cjs +0 -728
- package/get-shit-done/bin/lib/context-utilization.cjs +0 -47
- package/get-shit-done/bin/lib/core.cjs +0 -2121
- package/get-shit-done/bin/lib/docs.cjs +0 -270
- package/get-shit-done/bin/lib/drift.cjs +0 -388
- package/get-shit-done/bin/lib/fallow-runner.cjs +0 -109
- package/get-shit-done/bin/lib/frontmatter.cjs +0 -389
- package/get-shit-done/bin/lib/gap-checker.cjs +0 -205
- package/get-shit-done/bin/lib/graphify.cjs +0 -592
- package/get-shit-done/bin/lib/gsd2-import.cjs +0 -514
- package/get-shit-done/bin/lib/init-command-router.cjs +0 -58
- package/get-shit-done/bin/lib/init.cjs +0 -2112
- package/get-shit-done/bin/lib/install-profiles.cjs +0 -603
- package/get-shit-done/bin/lib/installer-migration-authoring.cjs +0 -117
- package/get-shit-done/bin/lib/installer-migration-report.cjs +0 -354
- package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +0 -220
- package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +0 -41
- package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +0 -80
- package/get-shit-done/bin/lib/installer-migrations.cjs +0 -778
- package/get-shit-done/bin/lib/intel.cjs +0 -708
- package/get-shit-done/bin/lib/learnings.cjs +0 -421
- package/get-shit-done/bin/lib/milestone.cjs +0 -314
- package/get-shit-done/bin/lib/model-catalog.cjs +0 -212
- package/get-shit-done/bin/lib/model-profiles.cjs +0 -31
- package/get-shit-done/bin/lib/observability/event.cjs +0 -82
- package/get-shit-done/bin/lib/observability/logger.cjs +0 -174
- package/get-shit-done/bin/lib/phase-command-router.cjs +0 -191
- package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -80
- package/get-shit-done/bin/lib/phase.cjs +0 -1607
- package/get-shit-done/bin/lib/phases-command-router.cjs +0 -39
- package/get-shit-done/bin/lib/planning-workspace.cjs +0 -238
- package/get-shit-done/bin/lib/profile-output.cjs +0 -1141
- package/get-shit-done/bin/lib/profile-pipeline.cjs +0 -539
- package/get-shit-done/bin/lib/project-root.cjs +0 -112
- package/get-shit-done/bin/lib/prompt-budget.cjs +0 -399
- package/get-shit-done/bin/lib/review-reviewer-selection.cjs +0 -125
- package/get-shit-done/bin/lib/roadmap-command-router.cjs +0 -28
- package/get-shit-done/bin/lib/roadmap.cjs +0 -650
- package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +0 -301
- package/get-shit-done/bin/lib/runtime-homes.cjs +0 -222
- package/get-shit-done/bin/lib/runtime-name-policy.cjs +0 -83
- package/get-shit-done/bin/lib/runtime-slash.cjs +0 -112
- package/get-shit-done/bin/lib/secrets.cjs +0 -32
- package/get-shit-done/bin/lib/security.cjs +0 -600
- package/get-shit-done/bin/lib/semver-compare.cjs +0 -35
- package/get-shit-done/bin/lib/shell-command-projection.cjs +0 -500
- package/get-shit-done/bin/lib/state-command-router.cjs +0 -252
- package/get-shit-done/bin/lib/state.cjs +0 -2038
- package/get-shit-done/bin/lib/surface.cjs +0 -470
- package/get-shit-done/bin/lib/task-command-router.cjs +0 -81
- package/get-shit-done/bin/lib/template.cjs +0 -228
- package/get-shit-done/bin/lib/uat.cjs +0 -289
- package/get-shit-done/bin/lib/update-context.cjs +0 -209
- package/get-shit-done/bin/lib/validate-command-router.cjs +0 -83
- package/get-shit-done/bin/lib/validate.cjs +0 -92
- package/get-shit-done/bin/lib/verify-command-router.cjs +0 -40
- package/get-shit-done/bin/lib/verify.cjs +0 -1511
- package/get-shit-done/bin/lib/workstream-inventory.cjs +0 -146
- package/get-shit-done/bin/lib/workstream.cjs +0 -389
- package/get-shit-done/bin/lib/worktree-safety.cjs +0 -985
- package/get-shit-done/workflows/_runtime-launcher.snippet.sh +0 -1
- package/scripts/lint-no-source-grep-extras.cjs +0 -81
- package/scripts/lint-no-source-grep.cjs +0 -174
- package/scripts/lint-shared-module-handsync.cjs +0 -388
- package/scripts/shared-module-handsync-allowlist.json +0 -183
- /package/{get-shit-done → gsd-core}/bin/shared/runtime-aliases.manifest.json +0 -0
- /package/{get-shit-done → gsd-core}/bin/verify-reapply-patches.cjs +0 -0
- /package/{get-shit-done → gsd-core}/contexts/dev.md +0 -0
- /package/{get-shit-done → gsd-core}/contexts/research.md +0 -0
- /package/{get-shit-done → gsd-core}/contexts/review.md +0 -0
- /package/{get-shit-done → gsd-core}/references/agent-contracts.md +0 -0
- /package/{get-shit-done → gsd-core}/references/ai-evals.md +0 -0
- /package/{get-shit-done → gsd-core}/references/ai-frameworks.md +0 -0
- /package/{get-shit-done → gsd-core}/references/autonomous-smart-discuss.md +0 -0
- /package/{get-shit-done → gsd-core}/references/common-bug-patterns.md +0 -0
- /package/{get-shit-done → gsd-core}/references/context-budget.md +0 -0
- /package/{get-shit-done → gsd-core}/references/continuation-format.md +0 -0
- /package/{get-shit-done → gsd-core}/references/debugger-philosophy.md +0 -0
- /package/{get-shit-done → gsd-core}/references/decimal-phase-calculation.md +0 -0
- /package/{get-shit-done → gsd-core}/references/doc-conflict-engine.md +0 -0
- /package/{get-shit-done → gsd-core}/references/domain-probes.md +0 -0
- /package/{get-shit-done → gsd-core}/references/execute-mvp-tdd.md +0 -0
- /package/{get-shit-done → gsd-core}/references/executor-examples.md +0 -0
- /package/{get-shit-done → gsd-core}/references/gate-prompts.md +0 -0
- /package/{get-shit-done → gsd-core}/references/gates.md +0 -0
- /package/{get-shit-done → gsd-core}/references/git-integration.md +0 -0
- /package/{get-shit-done → gsd-core}/references/git-planning-commit.md +0 -0
- /package/{get-shit-done → gsd-core}/references/ios-scaffold.md +0 -0
- /package/{get-shit-done → gsd-core}/references/mandatory-initial-read.md +0 -0
- /package/{get-shit-done → gsd-core}/references/model-profiles.md +0 -0
- /package/{get-shit-done → gsd-core}/references/phase-argument-parsing.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-antipatterns.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-chunked.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-gap-closure.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-interface-context.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-reviews.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-revision.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-source-audit.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planning-config.md +0 -0
- /package/{get-shit-done → gsd-core}/references/project-skills-discovery.md +0 -0
- /package/{get-shit-done → gsd-core}/references/questioning.md +0 -0
- /package/{get-shit-done → gsd-core}/references/revision-loop.md +0 -0
- /package/{get-shit-done → gsd-core}/references/scout-codebase.md +0 -0
- /package/{get-shit-done → gsd-core}/references/skeleton-template.md +0 -0
- /package/{get-shit-done → gsd-core}/references/sketch-interactivity.md +0 -0
- /package/{get-shit-done → gsd-core}/references/sketch-theme-system.md +0 -0
- /package/{get-shit-done → gsd-core}/references/sketch-tooling.md +0 -0
- /package/{get-shit-done → gsd-core}/references/sketch-variant-patterns.md +0 -0
- /package/{get-shit-done → gsd-core}/references/spidr-splitting.md +0 -0
- /package/{get-shit-done → gsd-core}/references/tdd.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-debug.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-execution.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-planning.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-research.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-verification.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-partner.md +0 -0
- /package/{get-shit-done → gsd-core}/references/universal-anti-patterns.md +0 -0
- /package/{get-shit-done → gsd-core}/references/user-profiling.md +0 -0
- /package/{get-shit-done → gsd-core}/references/user-story-template.md +0 -0
- /package/{get-shit-done → gsd-core}/references/verification-overrides.md +0 -0
- /package/{get-shit-done → gsd-core}/references/verify-mvp-mode.md +0 -0
- /package/{get-shit-done → gsd-core}/references/workstream-flag.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/AI-SPEC.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/DEBUG.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/SECURITY.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/UAT.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/UI-SPEC.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/VALIDATION.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/claude-md.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/architecture.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/concerns.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/conventions.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/integrations.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/stack.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/testing.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/config.json +0 -0
- /package/{get-shit-done → gsd-core}/templates/context.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/continue-here.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/debug-subagent-prompt.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/dev-preferences.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/discovery.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/discussion-log.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/milestone-archive.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/milestone.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/planner-subagent-prompt.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/project.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/requirements.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/ARCHITECTURE.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/FEATURES.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/PITFALLS.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/STACK.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/SUMMARY.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/retrospective.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/roadmap.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/spec.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/state.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/summary-complex.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/summary-minimal.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/summary-standard.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/summary.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/user-profile.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/user-setup.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/verification-report.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/analyze-dependencies.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/all.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/analyze.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/batch.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/default.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/text.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/checkpoint.json +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/context.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/discussion-log.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase-power.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/fast.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/help/modes/brief.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/help/modes/topic.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/help.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/inbox.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/list-phase-assumptions.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/node-repair.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/note.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/pr-branch.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/session-report.md +0 -0
|
@@ -2,24 +2,27 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* lint-test-file-count.cjs — max 2 test files per production module.
|
|
4
4
|
*
|
|
5
|
-
* Scans sdk/src/query/, sdk/src/,
|
|
5
|
+
* Scans sdk/src/query/, sdk/src/, gsd-core/bin/lib/, bin/ for production
|
|
6
6
|
* modules, then counts matching test files in tests/ and sdk/src (recursive). Cap is 2
|
|
7
|
-
* (primary + one integration). Over-limit clusters must be in the allowlist
|
|
8
|
-
*
|
|
7
|
+
* (primary + one integration). Over-limit clusters must be in the allowlist with the
|
|
8
|
+
* EXACT set of test filenames grandfathered (identity ratchet via allowlist-ratchet.cjs).
|
|
9
|
+
* Adding a new test file to a capped module is a novel offender; removing one requires
|
|
10
|
+
* pruning the allowlist entry (stale). --json emits structured output.
|
|
9
11
|
*
|
|
10
12
|
* Verdicts: OK_UNDER_LIMIT | OK_IN_ALLOWLIST | FAIL_EXCEEDS_LIMIT |
|
|
11
|
-
*
|
|
13
|
+
* FAIL_NOVEL_FILES | FAIL_STALE_ALLOWLIST
|
|
12
14
|
*/
|
|
13
15
|
'use strict';
|
|
14
16
|
|
|
15
17
|
const fs = require('fs');
|
|
16
18
|
const path = require('path');
|
|
19
|
+
const { assertWithinAllowlist } = require('./lib/allowlist-ratchet.cjs');
|
|
17
20
|
|
|
18
21
|
const ROOT = path.join(__dirname, '..');
|
|
19
22
|
const PROD_DIRS = [
|
|
20
23
|
path.join(ROOT, 'sdk', 'src', 'query'),
|
|
21
24
|
path.join(ROOT, 'sdk', 'src'),
|
|
22
|
-
path.join(ROOT, '
|
|
25
|
+
path.join(ROOT, 'gsd-core', 'bin', 'lib'),
|
|
23
26
|
path.join(ROOT, 'bin'),
|
|
24
27
|
];
|
|
25
28
|
const TEST_DIRS = [
|
|
@@ -30,11 +33,11 @@ const ALLOWLIST_PATH = path.join(__dirname, 'lint-test-file-count.allowlist.json
|
|
|
30
33
|
const MAX_FILES = 2;
|
|
31
34
|
|
|
32
35
|
const Verdict = Object.freeze({
|
|
33
|
-
OK_UNDER_LIMIT:
|
|
34
|
-
OK_IN_ALLOWLIST:
|
|
35
|
-
FAIL_EXCEEDS_LIMIT:
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
OK_UNDER_LIMIT: 'OK_UNDER_LIMIT',
|
|
37
|
+
OK_IN_ALLOWLIST: 'OK_IN_ALLOWLIST',
|
|
38
|
+
FAIL_EXCEEDS_LIMIT: 'FAIL_EXCEEDS_LIMIT',
|
|
39
|
+
FAIL_NOVEL_FILES: 'FAIL_NOVEL_FILES',
|
|
40
|
+
FAIL_STALE_ALLOWLIST: 'FAIL_STALE_ALLOWLIST',
|
|
38
41
|
});
|
|
39
42
|
|
|
40
43
|
function isTestFile(name) {
|
|
@@ -120,17 +123,62 @@ function loadAllowlist() {
|
|
|
120
123
|
catch (_) { return {}; }
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Evaluate one module's test files against the allowlist.
|
|
128
|
+
*
|
|
129
|
+
* For modules under the default cap (≤ MAX_FILES): simple count check.
|
|
130
|
+
* For modules with an allowlist entry: identity check via assertWithinAllowlist.
|
|
131
|
+
* - count now ≤ MAX_FILES → FAIL_STALE_ALLOWLIST (all known files are stale; prune entry)
|
|
132
|
+
* - novel files (in current but not in known) → FAIL_NOVEL_FILES
|
|
133
|
+
* - stale files (in known but not in current) → FAIL_STALE_ALLOWLIST
|
|
134
|
+
* - exact match → OK_IN_ALLOWLIST
|
|
135
|
+
* For modules over the cap with no allowlist entry: FAIL_EXCEEDS_LIMIT.
|
|
136
|
+
*
|
|
137
|
+
* Returns { verdict, prefix, count, knownFiles, novel, stale, files }
|
|
138
|
+
*/
|
|
123
139
|
function evaluateLint({ prefix, testFiles, allowlist }) {
|
|
124
140
|
const count = testFiles.length;
|
|
125
141
|
const entry = allowlist[prefix];
|
|
126
|
-
const
|
|
142
|
+
const currentNames = testFiles.map(f => path.basename(f));
|
|
143
|
+
|
|
127
144
|
if (entry !== undefined) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
145
|
+
const knownFiles = Array.isArray(entry.files) ? entry.files : [];
|
|
146
|
+
// If the module is now at or under the default cap, the entire allowlist entry is
|
|
147
|
+
// stale and must be removed — this is a ratchet-DOWN failure, not a hint.
|
|
148
|
+
// All known files are stale (the whole entry can go).
|
|
149
|
+
if (count <= MAX_FILES) {
|
|
150
|
+
return {
|
|
151
|
+
verdict: Verdict.FAIL_STALE_ALLOWLIST,
|
|
152
|
+
prefix, count,
|
|
153
|
+
knownFiles,
|
|
154
|
+
novel: [],
|
|
155
|
+
stale: knownFiles.slice().sort(),
|
|
156
|
+
files: testFiles,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// Identity check via assertWithinAllowlist
|
|
160
|
+
const messages = [];
|
|
161
|
+
const { novel, stale } = assertWithinAllowlist({
|
|
162
|
+
label: prefix,
|
|
163
|
+
current: currentNames,
|
|
164
|
+
known: knownFiles,
|
|
165
|
+
fail: (msg) => messages.push(msg),
|
|
166
|
+
pruneHint: 'scripts/lint-test-file-count.allowlist.json',
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (novel.length > 0) {
|
|
170
|
+
return { verdict: Verdict.FAIL_NOVEL_FILES, prefix, count, knownFiles, novel, stale, files: testFiles };
|
|
171
|
+
}
|
|
172
|
+
if (stale.length > 0) {
|
|
173
|
+
return { verdict: Verdict.FAIL_STALE_ALLOWLIST, prefix, count, knownFiles, novel, stale, files: testFiles };
|
|
174
|
+
}
|
|
175
|
+
return { verdict: Verdict.OK_IN_ALLOWLIST, prefix, count, knownFiles, novel: [], stale: [], files: testFiles };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (count <= MAX_FILES) {
|
|
179
|
+
return { verdict: Verdict.OK_UNDER_LIMIT, prefix, count, knownFiles: null, novel: [], stale: [], files: testFiles };
|
|
131
180
|
}
|
|
132
|
-
|
|
133
|
-
return { verdict: Verdict.FAIL_EXCEEDS_LIMIT, prefix, count, ceiling: null, files: testFiles };
|
|
181
|
+
return { verdict: Verdict.FAIL_EXCEEDS_LIMIT, prefix, count, knownFiles: null, novel: [], stale: [], files: testFiles };
|
|
134
182
|
}
|
|
135
183
|
|
|
136
184
|
function run() {
|
|
@@ -147,35 +195,42 @@ function run() {
|
|
|
147
195
|
}
|
|
148
196
|
|
|
149
197
|
const failures = results.filter(r =>
|
|
150
|
-
r.verdict === Verdict.FAIL_EXCEEDS_LIMIT ||
|
|
151
|
-
|
|
198
|
+
r.verdict === Verdict.FAIL_EXCEEDS_LIMIT ||
|
|
199
|
+
r.verdict === Verdict.FAIL_NOVEL_FILES ||
|
|
200
|
+
r.verdict === Verdict.FAIL_STALE_ALLOWLIST);
|
|
152
201
|
|
|
153
202
|
if (jsonMode) {
|
|
154
|
-
console.log(JSON.stringify({ ok: failures.length === 0, results, failures, hints }, null, 2));
|
|
203
|
+
console.log(JSON.stringify({ ok: failures.length === 0, results, failures, hints: [] }, null, 2));
|
|
155
204
|
process.exit(failures.length > 0 ? 1 : 0);
|
|
156
205
|
}
|
|
157
206
|
|
|
158
207
|
if (failures.length === 0) {
|
|
159
208
|
const inAllowlist = results.filter(r => r.verdict === Verdict.OK_IN_ALLOWLIST).length;
|
|
160
209
|
console.log(`ok lint-test-file-count: ${results.length} module(s) checked, 0 failures` +
|
|
161
|
-
(inAllowlist > 0 ? `, ${inAllowlist} allowlisted` : '')
|
|
162
|
-
(hints.length > 0 ? `, ${hints.length} hint(s)` : ''));
|
|
163
|
-
for (const h of hints) {
|
|
164
|
-
console.log(` hint: "${h.prefix}" is allowlisted at ${h.ceiling} but now has ${h.count} — remove from allowlist`);
|
|
165
|
-
}
|
|
210
|
+
(inAllowlist > 0 ? `, ${inAllowlist} allowlisted` : ''));
|
|
166
211
|
process.exit(0);
|
|
167
212
|
}
|
|
168
213
|
|
|
169
214
|
process.stderr.write(`\nERROR lint-test-file-count: ${failures.length} module(s) exceed the test-file limit\n\n`);
|
|
170
215
|
for (const f of failures) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
216
|
+
if (f.verdict === Verdict.FAIL_EXCEEDS_LIMIT) {
|
|
217
|
+
process.stderr.write(` ${f.prefix}: ${f.count} files (limit ${MAX_FILES}) — not in allowlist\n`);
|
|
218
|
+
for (const tf of f.files) process.stderr.write(` ${path.relative(ROOT, tf)}\n`);
|
|
219
|
+
} else if (f.verdict === Verdict.FAIL_NOVEL_FILES) {
|
|
220
|
+
process.stderr.write(` ${f.prefix}: ${f.novel.length} NEW test file(s) not in allowlist\n`);
|
|
221
|
+
for (const n of f.novel) process.stderr.write(` + ${n}\n`);
|
|
222
|
+
} else if (f.verdict === Verdict.FAIL_STALE_ALLOWLIST) {
|
|
223
|
+
if (f.count <= MAX_FILES) {
|
|
224
|
+
const staleList = f.stale.join(', ');
|
|
225
|
+
process.stderr.write(` "${f.prefix}": now at ${f.count} file(s) (≤ ${MAX_FILES}) — remove its entry from the allowlist (stale: ${staleList})\n`);
|
|
226
|
+
} else {
|
|
227
|
+
process.stderr.write(` ${f.prefix}: ${f.stale.length} allowlisted file(s) no longer present — prune allowlist\n`);
|
|
228
|
+
for (const s of f.stale) process.stderr.write(` - ${s}\n`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
176
231
|
}
|
|
177
232
|
process.stderr.write('\nFix: consolidate test files per module (one primary + one integration).\n');
|
|
178
|
-
process.stderr.write('Or
|
|
233
|
+
process.stderr.write('Or update scripts/lint-test-file-count.allowlist.json with PR justification.\n\n');
|
|
179
234
|
process.exit(1);
|
|
180
235
|
}
|
|
181
236
|
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* scripts/mutation-matrix.cjs
|
|
6
|
+
*
|
|
7
|
+
* Single source of truth for the ADR-457 Stryker mutation gate dynamic matrix.
|
|
8
|
+
*
|
|
9
|
+
* Computes which covered modules changed vs a base ref and emits a GitHub
|
|
10
|
+
* Actions matrix JSON so CI can run one Stryker shard per changed module in
|
|
11
|
+
* parallel rather than a single serial run over all modules.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node scripts/mutation-matrix.cjs --base origin/next
|
|
15
|
+
* printf 'src/config-schema.cts\n' | node scripts/mutation-matrix.cjs
|
|
16
|
+
* node scripts/mutation-matrix.cjs --base origin/next --print
|
|
17
|
+
*
|
|
18
|
+
* Output (stdout, default): JSON object
|
|
19
|
+
* {
|
|
20
|
+
* "has_work": "true"|"false",
|
|
21
|
+
* "matrix": {
|
|
22
|
+
* "include": [
|
|
23
|
+
* { "name": "<module>", "mutate": "gsd-core/bin/lib/<module>.cjs", "tests": "<space-joined test files>" },
|
|
24
|
+
* ...
|
|
25
|
+
* ]
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* Exit codes: 0 always (empty matrix is not an error, has_work "false").
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const { execFileSync } = require('child_process');
|
|
33
|
+
const { readFileSync } = require('fs');
|
|
34
|
+
|
|
35
|
+
// ── Single source of truth: covered modules ───────────────────────────────────
|
|
36
|
+
// Each entry: { cjs: '<built artifact>', tests: ['tests/...', ...] }
|
|
37
|
+
// A module is "covered" iff its tests are wired into the Stryker command runner
|
|
38
|
+
// (stryker.config.mjs commandRunner.command). Mutating an uncovered module can
|
|
39
|
+
// only ever produce survived mutants — so we scope strictly to these 6.
|
|
40
|
+
const COVERED = {
|
|
41
|
+
'context-utilization': {
|
|
42
|
+
cjs: 'gsd-core/bin/lib/context-utilization.cjs',
|
|
43
|
+
tests: [
|
|
44
|
+
'tests/context-utilization.property.test.cjs',
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
'prompt-budget': {
|
|
48
|
+
cjs: 'gsd-core/bin/lib/prompt-budget.cjs',
|
|
49
|
+
tests: [
|
|
50
|
+
'tests/prompt-budget.property.test.cjs',
|
|
51
|
+
'tests/prompt-budget.unit.test.cjs',
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
frontmatter: {
|
|
55
|
+
cjs: 'gsd-core/bin/lib/frontmatter.cjs',
|
|
56
|
+
tests: [
|
|
57
|
+
'tests/frontmatter.property.test.cjs',
|
|
58
|
+
'tests/frontmatter.unit.test.cjs',
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
'adr-parser': {
|
|
62
|
+
cjs: 'gsd-core/bin/lib/adr-parser.cjs',
|
|
63
|
+
tests: [
|
|
64
|
+
'tests/adr-parser.property.test.cjs',
|
|
65
|
+
'tests/adr-parser.test.cjs',
|
|
66
|
+
'tests/adr-parser.unit.test.cjs',
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
'config-schema': {
|
|
70
|
+
cjs: 'gsd-core/bin/lib/config-schema.cjs',
|
|
71
|
+
tests: [
|
|
72
|
+
'tests/config-schema.property.test.cjs',
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
'active-workstream-store': {
|
|
76
|
+
cjs: 'gsd-core/bin/lib/active-workstream-store.cjs',
|
|
77
|
+
tests: [
|
|
78
|
+
'tests/active-workstream-store.test.cjs',
|
|
79
|
+
'tests/active-workstream-store.unit.test.cjs',
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// ── Files that, when changed, invalidate ALL modules ─────────────────────────
|
|
85
|
+
// Changes to the Stryker config, this script itself, or any covered test file
|
|
86
|
+
// affect all mutation scores and must force a full re-run.
|
|
87
|
+
const GLOBAL_TRIGGERS = new Set([
|
|
88
|
+
'stryker.config.mjs',
|
|
89
|
+
'scripts/mutation-matrix.cjs',
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
// Also flag all test files that belong to any covered module as global triggers.
|
|
93
|
+
for (const mod of Object.values(COVERED)) {
|
|
94
|
+
for (const t of mod.tests) {
|
|
95
|
+
GLOBAL_TRIGGERS.add(t);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── Argument parsing ──────────────────────────────────────────────────────────
|
|
100
|
+
function parseArgs(argv) {
|
|
101
|
+
const out = { base: null, print: false };
|
|
102
|
+
for (let i = 0; i < argv.length; i++) {
|
|
103
|
+
const arg = argv[i];
|
|
104
|
+
if (arg === '--base') {
|
|
105
|
+
out.base = argv[++i];
|
|
106
|
+
if (!out.base || out.base.startsWith('--')) {
|
|
107
|
+
throw new Error('--base requires a value');
|
|
108
|
+
}
|
|
109
|
+
} else if (arg.startsWith('--base=')) {
|
|
110
|
+
out.base = arg.slice('--base='.length);
|
|
111
|
+
if (!out.base) throw new Error('--base requires a value');
|
|
112
|
+
} else if (arg === '--print') {
|
|
113
|
+
out.print = true;
|
|
114
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
115
|
+
console.log([
|
|
116
|
+
'Usage:',
|
|
117
|
+
' node scripts/mutation-matrix.cjs --base <ref> [--print]',
|
|
118
|
+
' printf "src/foo.cts\\n" | node scripts/mutation-matrix.cjs [--print]',
|
|
119
|
+
'',
|
|
120
|
+
'Options:',
|
|
121
|
+
' --base <ref> Git ref to diff against (default: origin/${GITHUB_BASE_REF:-next})',
|
|
122
|
+
' --print Human-readable output instead of JSON',
|
|
123
|
+
].join('\n'));
|
|
124
|
+
process.exit(0);
|
|
125
|
+
} else {
|
|
126
|
+
throw new Error(`unknown argument: ${arg}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ── Changed-file resolution ───────────────────────────────────────────────────
|
|
133
|
+
function resolveChangedFiles(args) {
|
|
134
|
+
// When --base is provided, always use git diff (regardless of stdin).
|
|
135
|
+
// When --base is absent AND stdin is not a TTY (isTTY is falsy / undefined),
|
|
136
|
+
// read a newline-delimited file list from stdin.
|
|
137
|
+
if (!args.base && process.stdin.isTTY !== true) {
|
|
138
|
+
const raw = readFileSync(process.stdin.fd, 'utf8');
|
|
139
|
+
return raw.split('\n').map(l => l.trim()).filter(Boolean);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Otherwise (--base given, or stdin is a real TTY), diff against the base ref.
|
|
143
|
+
const defaultBase = `origin/${process.env.GITHUB_BASE_REF || 'next'}`;
|
|
144
|
+
const base = args.base || defaultBase;
|
|
145
|
+
const stdout = execFileSync('git', ['diff', '--name-only', `${base}...HEAD`], {
|
|
146
|
+
encoding: 'utf8',
|
|
147
|
+
});
|
|
148
|
+
return stdout.split('\n').map(l => l.trim()).filter(Boolean);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ── Module classification ─────────────────────────────────────────────────────
|
|
152
|
+
function computeMatrix(changedFiles) {
|
|
153
|
+
// Check for global triggers first — if any hit, include every covered module.
|
|
154
|
+
const allModuleNames = Object.keys(COVERED);
|
|
155
|
+
for (const f of changedFiles) {
|
|
156
|
+
if (GLOBAL_TRIGGERS.has(f)) {
|
|
157
|
+
return allModuleNames;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Otherwise find which modules have their src/*.cts changed.
|
|
162
|
+
const changed = new Set();
|
|
163
|
+
for (const f of changedFiles) {
|
|
164
|
+
// Match src/<module>.cts (top-level src/, not nested)
|
|
165
|
+
const m = f.match(/^src\/([^/]+)\.cts$/);
|
|
166
|
+
if (m && COVERED[m[1]]) {
|
|
167
|
+
changed.add(m[1]);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return [...changed];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ── Output formatting ─────────────────────────────────────────────────────────
|
|
174
|
+
function buildResult(moduleNames) {
|
|
175
|
+
const include = moduleNames.map(name => ({
|
|
176
|
+
name,
|
|
177
|
+
mutate: COVERED[name].cjs,
|
|
178
|
+
tests: COVERED[name].tests.join(' '),
|
|
179
|
+
}));
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
has_work: include.length > 0 ? 'true' : 'false',
|
|
183
|
+
matrix: { include },
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function printHuman(result, changedFiles) {
|
|
188
|
+
console.log(`Changed files (${changedFiles.length}):`);
|
|
189
|
+
for (const f of changedFiles) console.log(` ${f}`);
|
|
190
|
+
console.log('');
|
|
191
|
+
console.log(`has_work: ${result.has_work}`);
|
|
192
|
+
console.log(`Shards (${result.matrix.include.length}):`);
|
|
193
|
+
for (const shard of result.matrix.include) {
|
|
194
|
+
console.log(` [${shard.name}]`);
|
|
195
|
+
console.log(` mutate: ${shard.mutate}`);
|
|
196
|
+
console.log(` tests: ${shard.tests}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
201
|
+
function main() {
|
|
202
|
+
try {
|
|
203
|
+
const args = parseArgs(process.argv.slice(2));
|
|
204
|
+
const changedFiles = resolveChangedFiles(args);
|
|
205
|
+
const moduleNames = computeMatrix(changedFiles);
|
|
206
|
+
const result = buildResult(moduleNames);
|
|
207
|
+
|
|
208
|
+
if (args.print) {
|
|
209
|
+
printHuman(result, changedFiles);
|
|
210
|
+
} else {
|
|
211
|
+
console.log(JSON.stringify(result, null, 2));
|
|
212
|
+
}
|
|
213
|
+
} catch (err) {
|
|
214
|
+
console.error(`mutation-matrix: ${err.message}`);
|
|
215
|
+
process.exit(2);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
main();
|
|
@@ -73,13 +73,17 @@ ALLOWLIST=(
|
|
|
73
73
|
'tests/security.test.cjs'
|
|
74
74
|
'tests/prompt-injection-scan.test.cjs'
|
|
75
75
|
'tests/verify.test.cjs'
|
|
76
|
-
'
|
|
76
|
+
'gsd-core/bin/lib/security.cjs'
|
|
77
77
|
'hooks/gsd-prompt-guard.js'
|
|
78
78
|
'hooks/gsd-read-injection-scanner.js'
|
|
79
79
|
'tests/read-injection-scanner.test.cjs'
|
|
80
80
|
'tests/security-prompt-injection.test.cjs'
|
|
81
81
|
'tests/fixtures/adversarial/security/'
|
|
82
82
|
'SECURITY.md'
|
|
83
|
+
# These files contain intentional injection examples / security-model prose
|
|
84
|
+
# and are not attack vectors — they explain/demonstrate injection patterns.
|
|
85
|
+
'TEST-EXAMPLES.md'
|
|
86
|
+
'docs/explanation/security-model.md'
|
|
83
87
|
)
|
|
84
88
|
|
|
85
89
|
is_allowlisted() {
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const { execFileSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Classify a What's-Changed bullet line into 'Feature', 'Fix', or 'Enhancement'.
|
|
10
|
+
* @param {string} bulletLine - Full bullet line including the leading `* ` or `- ` marker.
|
|
11
|
+
* @returns {'Feature'|'Fix'|'Enhancement'}
|
|
12
|
+
*/
|
|
13
|
+
function classifyTitle(bulletLine) {
|
|
14
|
+
// Strip leading `* ` or `- ` marker
|
|
15
|
+
const withoutMarker = bulletLine.replace(/^[*-]\s+/, '');
|
|
16
|
+
|
|
17
|
+
// Extract title = text before ` by @`
|
|
18
|
+
const byIdx = withoutMarker.indexOf(' by @');
|
|
19
|
+
const title = (byIdx !== -1 ? withoutMarker.slice(0, byIdx) : withoutMarker).trim();
|
|
20
|
+
|
|
21
|
+
if (/^feat(?:ure)?\s*(?:\(|!|:)/i.test(title)) return 'Feature';
|
|
22
|
+
if (/^fix\s*(?:\(|!|:)/i.test(title)) return 'Fix';
|
|
23
|
+
return 'Enhancement';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reformat GitHub's auto-generated release notes into the repo's hand-curated format.
|
|
28
|
+
*
|
|
29
|
+
* @param {object} opts
|
|
30
|
+
* @param {string} opts.generatedBody - The raw GitHub-generated release body.
|
|
31
|
+
* @param {string} opts.version - Version string (e.g. "1.3.0-rc.1"), no leading "v".
|
|
32
|
+
* @param {boolean} opts.prerelease - Whether this is a pre-release.
|
|
33
|
+
* @param {string} opts.packageName - npm package name (e.g. "@opengsd/gsd-core").
|
|
34
|
+
* @returns {string} Formatted release body (no trailing newline).
|
|
35
|
+
*/
|
|
36
|
+
function formatReleaseNotes({ generatedBody, version, prerelease, packageName }) {
|
|
37
|
+
const lines = generatedBody.split('\n');
|
|
38
|
+
|
|
39
|
+
const featureBullets = [];
|
|
40
|
+
const fixBullets = [];
|
|
41
|
+
const enhancementBullets = [];
|
|
42
|
+
const newContributorBullets = [];
|
|
43
|
+
let fullChangelogLine = null;
|
|
44
|
+
|
|
45
|
+
let inWhatsChanged = false;
|
|
46
|
+
let inNewContributors = false;
|
|
47
|
+
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const trimmed = line.trim();
|
|
50
|
+
|
|
51
|
+
// Detect section headings
|
|
52
|
+
if (trimmed === '## What\'s Changed') {
|
|
53
|
+
inWhatsChanged = true;
|
|
54
|
+
inNewContributors = false;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (trimmed === '## New Contributors') {
|
|
59
|
+
inWhatsChanged = false;
|
|
60
|
+
inNewContributors = true;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Full changelog line ends the What's Changed section
|
|
65
|
+
if (trimmed.startsWith('**Full Changelog**:')) {
|
|
66
|
+
inWhatsChanged = false;
|
|
67
|
+
inNewContributors = false;
|
|
68
|
+
fullChangelogLine = trimmed;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Any other `##` heading ends current section
|
|
73
|
+
if (trimmed.startsWith('## ')) {
|
|
74
|
+
inWhatsChanged = false;
|
|
75
|
+
inNewContributors = false;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Collect bullets
|
|
80
|
+
if (inWhatsChanged && (trimmed.startsWith('* ') || trimmed.startsWith('- '))) {
|
|
81
|
+
const category = classifyTitle(trimmed);
|
|
82
|
+
if (category === 'Feature') featureBullets.push(trimmed);
|
|
83
|
+
else if (category === 'Fix') fixBullets.push(trimmed);
|
|
84
|
+
else enhancementBullets.push(trimmed);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (inNewContributors && (trimmed.startsWith('* ') || trimmed.startsWith('- '))) {
|
|
89
|
+
newContributorBullets.push(trimmed);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Build Install block
|
|
95
|
+
let installBlock;
|
|
96
|
+
if (prerelease) {
|
|
97
|
+
installBlock = [
|
|
98
|
+
'## Install',
|
|
99
|
+
'',
|
|
100
|
+
'This pre-release is published to npm under the `next` dist-tag.',
|
|
101
|
+
'',
|
|
102
|
+
'```bash',
|
|
103
|
+
`npm i ${packageName}@${version}`,
|
|
104
|
+
'# or',
|
|
105
|
+
`npm i ${packageName}@next`,
|
|
106
|
+
'```',
|
|
107
|
+
].join('\n');
|
|
108
|
+
} else {
|
|
109
|
+
installBlock = [
|
|
110
|
+
'## Install',
|
|
111
|
+
'',
|
|
112
|
+
'```bash',
|
|
113
|
+
`npm i ${packageName}@${version}`,
|
|
114
|
+
'# or',
|
|
115
|
+
`npm i ${packageName}@latest`,
|
|
116
|
+
'```',
|
|
117
|
+
].join('\n');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Assemble groups (omit empty ones)
|
|
121
|
+
const groups = [];
|
|
122
|
+
|
|
123
|
+
// Group A: Install
|
|
124
|
+
groups.push(installBlock);
|
|
125
|
+
|
|
126
|
+
// Group B: What's Changed heading
|
|
127
|
+
groups.push('## What\'s Changed');
|
|
128
|
+
|
|
129
|
+
// Group C: Features
|
|
130
|
+
if (featureBullets.length > 0) {
|
|
131
|
+
groups.push('### Feature\n' + featureBullets.join('\n'));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Group D: Enhancements
|
|
135
|
+
if (enhancementBullets.length > 0) {
|
|
136
|
+
groups.push('### Enhancement\n' + enhancementBullets.join('\n'));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Group E: Fixes
|
|
140
|
+
if (fixBullets.length > 0) {
|
|
141
|
+
groups.push('### Fix\n' + fixBullets.join('\n'));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Group F: New Contributors
|
|
145
|
+
if (newContributorBullets.length > 0) {
|
|
146
|
+
groups.push('## New Contributors\n' + newContributorBullets.join('\n'));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Group G: Full Changelog
|
|
150
|
+
if (fullChangelogLine) {
|
|
151
|
+
groups.push(fullChangelogLine);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return groups.join('\n\n');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// CLI entry point
|
|
158
|
+
if (require.main === module) {
|
|
159
|
+
try {
|
|
160
|
+
const argv = process.argv.slice(2);
|
|
161
|
+
|
|
162
|
+
let tag = null;
|
|
163
|
+
let repo = null;
|
|
164
|
+
let packageName = null;
|
|
165
|
+
let prerelease = null;
|
|
166
|
+
let useStdin = false;
|
|
167
|
+
let doApply = false;
|
|
168
|
+
|
|
169
|
+
for (let i = 0; i < argv.length; i++) {
|
|
170
|
+
const arg = argv[i];
|
|
171
|
+
if (arg === '--tag') {
|
|
172
|
+
tag = argv[++i];
|
|
173
|
+
} else if (arg === '--repo') {
|
|
174
|
+
repo = argv[++i];
|
|
175
|
+
} else if (arg === '--package') {
|
|
176
|
+
packageName = argv[++i];
|
|
177
|
+
} else if (arg === '--prerelease') {
|
|
178
|
+
prerelease = true;
|
|
179
|
+
} else if (arg === '--latest') {
|
|
180
|
+
prerelease = false;
|
|
181
|
+
} else if (arg === '--stdin') {
|
|
182
|
+
useStdin = true;
|
|
183
|
+
} else if (arg === '--apply') {
|
|
184
|
+
doApply = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Derive version from tag
|
|
189
|
+
const version = tag ? tag.replace(/^v/, '') : null;
|
|
190
|
+
|
|
191
|
+
// Resolve package name if not provided
|
|
192
|
+
if (!packageName) {
|
|
193
|
+
const repoRoot = path.resolve(__dirname, '..', '..');
|
|
194
|
+
const pkgJson = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'));
|
|
195
|
+
packageName = pkgJson.name;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let generatedBody;
|
|
199
|
+
|
|
200
|
+
if (useStdin) {
|
|
201
|
+
// Read from stdin
|
|
202
|
+
if (!version) {
|
|
203
|
+
throw new Error('--stdin mode requires --tag or --version to derive version');
|
|
204
|
+
}
|
|
205
|
+
if (prerelease === null) {
|
|
206
|
+
throw new Error('--stdin mode requires --prerelease or --latest');
|
|
207
|
+
}
|
|
208
|
+
generatedBody = fs.readFileSync('/dev/stdin', 'utf8');
|
|
209
|
+
} else {
|
|
210
|
+
// Fetch from gh
|
|
211
|
+
if (!tag) {
|
|
212
|
+
throw new Error('--tag <tag> is required');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const ghArgs = ['release', 'view', tag, '--json', 'body', '-q', '.body'];
|
|
216
|
+
if (repo) ghArgs.push('--repo', repo);
|
|
217
|
+
|
|
218
|
+
generatedBody = execFileSync('gh', ghArgs, { encoding: 'utf8' });
|
|
219
|
+
|
|
220
|
+
// Determine prerelease if not forced
|
|
221
|
+
if (prerelease === null) {
|
|
222
|
+
try {
|
|
223
|
+
const ghPreArgs = ['release', 'view', tag, '--json', 'isPrerelease', '-q', '.isPrerelease'];
|
|
224
|
+
if (repo) ghPreArgs.push('--repo', repo);
|
|
225
|
+
const result = execFileSync('gh', ghPreArgs, { encoding: 'utf8' }).trim();
|
|
226
|
+
prerelease = result === 'true';
|
|
227
|
+
} catch (_e) {
|
|
228
|
+
// Final fallback: check if tag contains `-` after version digits
|
|
229
|
+
prerelease = /-/.test(version);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const formatted = formatReleaseNotes({ generatedBody, version, prerelease, packageName });
|
|
235
|
+
|
|
236
|
+
if (doApply) {
|
|
237
|
+
const tmpFile = path.join(os.tmpdir(), `release-notes-${Date.now()}.md`);
|
|
238
|
+
fs.writeFileSync(tmpFile, formatted, 'utf8');
|
|
239
|
+
try {
|
|
240
|
+
const ghArgs = ['release', 'edit', tag, '--notes-file', tmpFile];
|
|
241
|
+
if (repo) ghArgs.push('--repo', repo);
|
|
242
|
+
execFileSync('gh', ghArgs, { encoding: 'utf8' });
|
|
243
|
+
process.stderr.write(`Release notes updated for ${tag}\n`);
|
|
244
|
+
} finally {
|
|
245
|
+
fs.unlinkSync(tmpFile);
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
process.stdout.write(formatted + '\n');
|
|
249
|
+
}
|
|
250
|
+
} catch (err) {
|
|
251
|
+
process.stderr.write((err.message || String(err)) + '\n');
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = { formatReleaseNotes, classifyTitle };
|