@opengsd/gsd-core 1.18.0 → 1.20.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -1
- package/.opencode/plugins/gsd-core.js +2 -3
- package/agents/gsd-code-fixer.compact.md +7 -7
- package/agents/gsd-code-fixer.md +13 -7
- package/agents/gsd-code-reviewer.compact.md +49 -8
- package/agents/gsd-code-reviewer.md +53 -14
- package/agents/gsd-executor.md +8 -4
- package/agents/gsd-verifier.md +1 -1
- package/bin/install.js +422 -103
- package/commands/gsd/update.md +5 -2
- package/gsd-core/bin/gsd-tools.cjs +179 -30
- package/gsd-core/bin/lib/agent-install-check.cjs +29 -3
- package/gsd-core/bin/lib/args-terminator.cjs +114 -0
- package/gsd-core/bin/lib/broken-windows.cjs +59 -1
- package/gsd-core/bin/lib/capability-lifecycle.cjs +1 -12
- package/gsd-core/bin/lib/capability-lock.cjs +13 -2
- package/gsd-core/bin/lib/capability-registry.cjs +376 -103
- package/gsd-core/bin/lib/capability-state.cjs +14 -8
- package/gsd-core/bin/lib/capability-validator.cjs +32 -0
- package/gsd-core/bin/lib/commands.cjs +27 -17
- package/gsd-core/bin/lib/config-loader.cjs +13 -3
- package/gsd-core/bin/lib/config.cjs +256 -58
- package/gsd-core/bin/lib/core-utils.cjs +45 -0
- package/gsd-core/bin/lib/decision-coverage-support.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +21 -3
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +2 -2
- package/gsd-core/bin/lib/gate-context-drift.cjs +9 -4
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +6 -1
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +6 -1
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +134 -13
- package/gsd-core/bin/lib/gate-phase-context.cjs +7 -8
- package/gsd-core/bin/lib/gate-schema-drift.cjs +1 -1
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +63 -22
- package/gsd-core/bin/lib/gate-ui-safety.cjs +23 -5
- package/gsd-core/bin/lib/git-info-exclude.cjs +52 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +31 -12
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +9 -7
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +3 -3
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +4 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +52 -1
- package/gsd-core/bin/lib/host-integration.cjs +13 -6
- package/gsd-core/bin/lib/init.cjs +245 -68
- package/gsd-core/bin/lib/install-engine.cjs +246 -32
- package/gsd-core/bin/lib/install-profiles.cjs +9 -4
- package/gsd-core/bin/lib/installer-migration-report.cjs +2 -0
- package/gsd-core/bin/lib/io.cjs +6 -0
- package/gsd-core/bin/lib/markdown-line-diff.cjs +147 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +147 -1
- package/gsd-core/bin/lib/markdown-table.cjs +23 -0
- package/gsd-core/bin/lib/mcp-server.cjs +8 -5
- package/gsd-core/bin/lib/milestone-lock.cjs +8 -1
- package/gsd-core/bin/lib/milestone-release-map.cjs +244 -0
- package/gsd-core/bin/lib/milestone-release-tags.cjs +440 -0
- package/gsd-core/bin/lib/milestone.cjs +61 -51
- package/gsd-core/bin/lib/model-catalog.cjs +8 -0
- package/gsd-core/bin/lib/normalize-test-command.cjs +67 -0
- package/gsd-core/bin/lib/phase-entry-grammar.cjs +119 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +2 -0
- package/gsd-core/bin/lib/phase-id.cjs +629 -38
- package/gsd-core/bin/lib/phase-lifecycle.cjs +12 -44
- package/gsd-core/bin/lib/phase-locator.cjs +328 -19
- package/gsd-core/bin/lib/phase.cjs +3066 -653
- package/gsd-core/bin/lib/planning-document.cjs +26 -5
- package/gsd-core/bin/lib/planning-inspect.cjs +27 -35
- package/gsd-core/bin/lib/planning-snapshot.cjs +15 -8
- package/gsd-core/bin/lib/planning-workspace.cjs +21 -3
- package/gsd-core/bin/lib/pristine-baseline.cjs +11 -3
- package/gsd-core/bin/lib/read-only-git-env.cjs +79 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +2 -2
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +57 -2
- package/gsd-core/bin/lib/review-lane-invocation.cjs +125 -18
- package/gsd-core/bin/lib/review-lane-runner.cjs +33 -4
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +11 -9
- package/gsd-core/bin/lib/roadmap-parser.cjs +735 -137
- package/gsd-core/bin/lib/roadmap-progress.cjs +136 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +47 -7
- package/gsd-core/bin/lib/roadmap.cjs +383 -123
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +381 -14
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +8 -4
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +60 -16
- package/gsd-core/bin/lib/shell-command-projection.cjs +151 -19
- package/gsd-core/bin/lib/smart-entry.cjs +35 -11
- package/gsd-core/bin/lib/state-contract.cjs +39 -15
- package/gsd-core/bin/lib/state-document.cjs +344 -27
- package/gsd-core/bin/lib/state-transition.cjs +156 -32
- package/gsd-core/bin/lib/state.cjs +527 -186
- package/gsd-core/bin/lib/surface.cjs +9 -0
- package/gsd-core/bin/lib/task-command-router.cjs +5 -25
- package/gsd-core/bin/lib/task-content-resolution.cjs +46 -1
- package/gsd-core/bin/lib/template.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +3 -2
- package/gsd-core/bin/lib/vendor/re2js.cjs +863 -577
- package/gsd-core/bin/lib/vendor/re2js.d.cts +284 -219
- package/gsd-core/bin/lib/verification.cjs +96 -9
- package/gsd-core/bin/lib/verify.cjs +4 -2
- package/gsd-core/bin/lib/workstream-inventory.cjs +26 -20
- package/gsd-core/bin/lib/worktree-safety.cjs +22 -1
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +411 -10
- package/gsd-core/references/cicd-review-patterns.md +45 -0
- package/gsd-core/references/git-integration.md +11 -0
- package/gsd-core/references/loop-hook-dispatch.md +13 -6
- package/gsd-core/references/necessity-review.md +48 -0
- package/gsd-core/references/planning-config.md +2 -0
- package/gsd-core/references/tdd.md +2 -2
- package/gsd-core/templates/DEBUG.md +16 -0
- package/gsd-core/templates/config.json +2 -1
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/audit-fix.md +2 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +10 -1
- package/gsd-core/workflows/code-review-fix.md +46 -5
- package/gsd-core/workflows/code-review.md +64 -7
- package/gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md +145 -0
- package/gsd-core/workflows/complete-milestone/steps/release-map.md +80 -0
- package/gsd-core/workflows/complete-milestone.md +37 -150
- package/gsd-core/workflows/diagnose-issues.md +29 -5
- package/gsd-core/workflows/discuss-phase/modes/power.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +33 -2
- package/gsd-core/workflows/discuss-phase-power.md +19 -2
- package/gsd-core/workflows/discuss-phase.md +6 -10
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +13 -7
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +7 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +11 -2
- package/gsd-core/workflows/execute-phase.md +10 -6
- package/gsd-core/workflows/execute-plan.md +1 -1
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +2 -2
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +13 -9
- package/gsd-core/workflows/plan-phase.md +14 -14
- package/gsd-core/workflows/pr-branch.md +2 -0
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +8 -1
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +2 -1
- package/gsd-core/workflows/quick.md +1 -1
- package/gsd-core/workflows/reapply-patches.md +104 -0
- package/gsd-core/workflows/review.md +70 -154
- package/gsd-core/workflows/section-manifest.json +5 -0
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/settings-advanced.md +57 -9
- package/gsd-core/workflows/settings.md +1 -0
- package/gsd-core/workflows/ship.md +15 -4
- package/gsd-core/workflows/spec-phase.md +3 -6
- package/gsd-core/workflows/verify-work.md +4 -3
- package/hooks/dist/gsd-agent-isolation-guard.js +11 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
- package/hooks/dist/gsd-graphify-update.sh +6 -0
- package/hooks/dist/gsd-path-export.js +95 -0
- package/hooks/dist/gsd-secret-read-guard.js +172 -39
- package/hooks/dist/gsd-statusline.js +37 -3
- package/hooks/dist/gsd-windsurf-pre-write.js +29 -2
- package/hooks/dist/gsd-workflow-guard.js +3 -2
- package/hooks/dist/gsd-worktree-path-guard.js +29 -2
- package/hooks/dist/lib/git-probe.js +16 -0
- package/hooks/dist/lib/isolation-sentinel.js +44 -0
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-agent-isolation-guard.js +11 -1
- package/hooks/gsd-cursor-subagent-start.js +6 -2
- package/hooks/gsd-graphify-update.sh +6 -0
- package/hooks/gsd-path-export.js +95 -0
- package/hooks/gsd-secret-read-guard.js +172 -39
- package/hooks/gsd-statusline.js +37 -3
- package/hooks/gsd-windsurf-pre-write.js +29 -2
- package/hooks/gsd-workflow-guard.js +3 -2
- package/hooks/gsd-worktree-path-guard.js +29 -2
- package/hooks/hooks.json +1 -0
- package/hooks/lib/git-probe.js +16 -0
- package/hooks/lib/isolation-sentinel.js +44 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +15 -8
- package/pi/gsd.cjs +1047 -10
- package/pi/package-agents/gsd-advisor-researcher.md +113 -0
- package/pi/package-agents/gsd-ai-researcher.md +111 -0
- package/pi/package-agents/gsd-assumptions-analyzer.md +110 -0
- package/pi/package-agents/gsd-code-fixer.md +774 -0
- package/pi/package-agents/gsd-code-reviewer.md +441 -0
- package/pi/package-agents/gsd-codebase-mapper.md +850 -0
- package/pi/package-agents/gsd-debug-session-manager.md +416 -0
- package/pi/package-agents/gsd-debugger.md +1274 -0
- package/pi/package-agents/gsd-doc-classifier.md +269 -0
- package/pi/package-agents/gsd-doc-synthesizer.md +259 -0
- package/pi/package-agents/gsd-doc-verifier.md +212 -0
- package/pi/package-agents/gsd-doc-writer.md +626 -0
- package/pi/package-agents/gsd-dom-verifier.md +164 -0
- package/pi/package-agents/gsd-domain-researcher.md +144 -0
- package/pi/package-agents/gsd-eval-auditor.md +185 -0
- package/pi/package-agents/gsd-eval-planner.md +149 -0
- package/pi/package-agents/gsd-executor.md +898 -0
- package/pi/package-agents/gsd-framework-selector.md +159 -0
- package/pi/package-agents/gsd-integration-checker.md +476 -0
- package/pi/package-agents/gsd-intel-updater.md +338 -0
- package/pi/package-agents/gsd-mempalace-curator.md +49 -0
- package/pi/package-agents/gsd-nyquist-auditor.md +200 -0
- package/pi/package-agents/gsd-pattern-mapper.md +340 -0
- package/pi/package-agents/gsd-phase-researcher.md +897 -0
- package/pi/package-agents/gsd-plan-checker.md +1077 -0
- package/pi/package-agents/gsd-planner.md +1003 -0
- package/pi/package-agents/gsd-project-researcher.md +611 -0
- package/pi/package-agents/gsd-research-synthesizer.md +259 -0
- package/pi/package-agents/gsd-roadmapper.md +779 -0
- package/pi/package-agents/gsd-security-auditor.md +171 -0
- package/pi/package-agents/gsd-ui-auditor.md +581 -0
- package/pi/package-agents/gsd-ui-checker.md +417 -0
- package/pi/package-agents/gsd-ui-researcher.md +469 -0
- package/pi/package-agents/gsd-user-profiler.md +174 -0
- package/pi/package-agents/gsd-verifier.md +963 -0
- package/pi/package-agents/manifest.json +39 -0
- package/pi/package-skills/gsd-add-tests/SKILL.md +39 -0
- package/pi/package-skills/gsd-ai-integration-phase/SKILL.md +36 -0
- package/pi/package-skills/gsd-audit-fix/SKILL.md +34 -0
- package/pi/package-skills/gsd-audit-milestone/SKILL.md +40 -0
- package/pi/package-skills/gsd-audit-uat/SKILL.md +26 -0
- package/pi/package-skills/gsd-autonomous/SKILL.md +52 -0
- package/pi/package-skills/gsd-capture/SKILL.md +68 -0
- package/pi/package-skills/gsd-cleanup/SKILL.md +25 -0
- package/pi/package-skills/gsd-code-review/SKILL.md +71 -0
- package/pi/package-skills/gsd-complete-milestone/SKILL.md +147 -0
- package/pi/package-skills/gsd-config/SKILL.md +60 -0
- package/pi/package-skills/gsd-debug/SKILL.md +64 -0
- package/pi/package-skills/gsd-discuss-phase/SKILL.md +74 -0
- package/pi/package-skills/gsd-docs-update/SKILL.md +50 -0
- package/pi/package-skills/gsd-eval-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-execute-phase/SKILL.md +62 -0
- package/pi/package-skills/gsd-explore/SKILL.md +26 -0
- package/pi/package-skills/gsd-extract-learnings/SKILL.md +25 -0
- package/pi/package-skills/gsd-fast/SKILL.md +33 -0
- package/pi/package-skills/gsd-forensics/SKILL.md +59 -0
- package/pi/package-skills/gsd-graphify/SKILL.md +210 -0
- package/pi/package-skills/gsd-health/SKILL.md +36 -0
- package/pi/package-skills/gsd-help/SKILL.md +37 -0
- package/pi/package-skills/gsd-import/SKILL.md +46 -0
- package/pi/package-skills/gsd-inbox/SKILL.md +42 -0
- package/pi/package-skills/gsd-ingest-docs/SKILL.md +43 -0
- package/pi/package-skills/gsd-manager/SKILL.md +46 -0
- package/pi/package-skills/gsd-map-codebase/SKILL.md +85 -0
- package/pi/package-skills/gsd-mempalace-capture/SKILL.md +111 -0
- package/pi/package-skills/gsd-mempalace-recall/SKILL.md +111 -0
- package/pi/package-skills/gsd-milestone-summary/SKILL.md +54 -0
- package/pi/package-skills/gsd-mvp-phase/SKILL.md +45 -0
- package/pi/package-skills/gsd-new-milestone/SKILL.md +49 -0
- package/pi/package-skills/gsd-new-project/SKILL.md +49 -0
- package/pi/package-skills/gsd-next/SKILL.md +34 -0
- package/pi/package-skills/gsd-ns-context/SKILL.md +31 -0
- package/pi/package-skills/gsd-ns-ideate/SKILL.md +30 -0
- package/pi/package-skills/gsd-ns-manage/SKILL.md +42 -0
- package/pi/package-skills/gsd-ns-project/SKILL.md +34 -0
- package/pi/package-skills/gsd-ns-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-ns-workflow/SKILL.md +44 -0
- package/pi/package-skills/gsd-onboard/SKILL.md +46 -0
- package/pi/package-skills/gsd-pause-work/SKILL.md +48 -0
- package/pi/package-skills/gsd-phase/SKILL.md +61 -0
- package/pi/package-skills/gsd-plan-phase/SKILL.md +62 -0
- package/pi/package-skills/gsd-plan-review-convergence/SKILL.md +63 -0
- package/pi/package-skills/gsd-pr-branch/SKILL.md +31 -0
- package/pi/package-skills/gsd-profile-user/SKILL.md +48 -0
- package/pi/package-skills/gsd-progress/SKILL.md +51 -0
- package/pi/package-skills/gsd-quick/SKILL.md +179 -0
- package/pi/package-skills/gsd-quick-batch/SKILL.md +114 -0
- package/pi/package-skills/gsd-resume-work/SKILL.md +31 -0
- package/pi/package-skills/gsd-review/SKILL.md +50 -0
- package/pi/package-skills/gsd-review-backlog/SKILL.md +65 -0
- package/pi/package-skills/gsd-secure-phase/SKILL.md +37 -0
- package/pi/package-skills/gsd-settings/SKILL.md +30 -0
- package/pi/package-skills/gsd-ship/SKILL.md +27 -0
- package/pi/package-skills/gsd-sketch/SKILL.md +56 -0
- package/pi/package-skills/gsd-spec-phase/SKILL.md +63 -0
- package/pi/package-skills/gsd-spike/SKILL.md +53 -0
- package/pi/package-skills/gsd-stats/SKILL.md +22 -0
- package/pi/package-skills/gsd-surface/SKILL.md +177 -0
- package/pi/package-skills/gsd-thread/SKILL.md +29 -0
- package/pi/package-skills/gsd-ui-phase/SKILL.md +35 -0
- package/pi/package-skills/gsd-ui-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-ultraplan-phase/SKILL.md +38 -0
- package/pi/package-skills/gsd-undo/SKILL.md +38 -0
- package/pi/package-skills/gsd-update/SKILL.md +54 -0
- package/pi/package-skills/gsd-validate-phase/SKILL.md +37 -0
- package/pi/package-skills/gsd-verify-work/SKILL.md +41 -0
- package/pi/package-skills/gsd-workspace/SKILL.md +57 -0
- package/pi/package-skills/gsd-workstreams/SKILL.md +73 -0
- package/scripts/build-hooks.js +4 -0
- package/scripts/ci-next-health.cjs +246 -23
- package/scripts/command-contract-helpers.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +22 -7
- package/scripts/gen-features.cjs +14 -2
- package/scripts/gen-health-docs.cjs +13 -1
- package/scripts/gen-pi-package-skills.cjs +217 -0
- package/scripts/lib/drift-scan.cjs +27 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +17 -1
- package/scripts/lib/platform-conformance-tier.generated.cjs +37 -1
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +3 -3
- package/scripts/lint-phase-enumeration-drift.cjs +8 -4
- package/scripts/lint-retired-runtime-name.cjs +5 -0
- package/scripts/lint-roadmap-progress-drift.cjs +421 -0
- package/scripts/mutation-matrix.cjs +23 -1
- package/scripts/npm-audit-baseline.cjs +41 -7
- package/scripts/reviewed-or-maintainer-policy.cjs +181 -0
- package/scripts/select-docs-guards.cjs +1 -1
- package/scripts/self-test-report-policy.cjs +350 -0
- package/scripts/sync-next-version.cjs +38 -6
- package/skills/gsd-update/SKILL.md +5 -2
- package/vscode/package.json +1 -1
- package/scripts/diagnose-validate-commit-in-tier.cjs +0 -270
- package/scripts/diagnose-validate-commit-phases.cjs +0 -348
- package/scripts/xtrace-phase-timing.cjs +0 -205
|
@@ -35,6 +35,7 @@ Configuration options for `.planning/` directory behavior.
|
|
|
35
35
|
| `git.base_branch` | `null` (auto-detect) | Target branch for PRs and merges (e.g. `"master"`, `"develop"`). When `null`, auto-detects from `git symbolic-ref refs/remotes/origin/HEAD`, falling back to `"main"`. |
|
|
36
36
|
| `git.protected_branches` | (none) | Optional array of non-empty strings naming additional shared branches that should trigger protected-branch warnings |
|
|
37
37
|
| `git.create_tag` | `true` | Create git tags on milestone completion |
|
|
38
|
+
| `git.repo_tagging` | `"single"` | Milestone tagging mode: `"single"` (existing behavior) or `"per_repo"` (record one release per configured repository; each tag is pushed only after a per-repository confirmation) |
|
|
38
39
|
| `git.phase_branch_template` | `"gsd/phase-{phase}-{slug}"` | Branch template for phase strategy |
|
|
39
40
|
| `git.milestone_branch_template` | `"gsd/{milestone}-{slug}"` | Branch template for milestone strategy |
|
|
40
41
|
| `git.quick_branch_template` | `null` | Optional branch template for quick-task runs |
|
|
@@ -340,6 +341,7 @@ Set via `git.*` namespace (e.g., `"git": { "branching_strategy": "phase" }`).
|
|
|
340
341
|
| `git.base_branch` | string\|null | `null` (auto-detect) | Any branch name | Target branch for PRs and merges; auto-detects from `origin/HEAD` when `null` |
|
|
341
342
|
| `git.protected_branches` | array of non-empty strings | (none) | Non-empty branch names | Optional protected names added to the resolved base branch for execute-phase and ship warnings |
|
|
342
343
|
| `git.create_tag` | boolean | `true` | `true`, `false` | Create git tags on milestone completion |
|
|
344
|
+
| `git.repo_tagging` | string | `"single"` | `"single"`, `"per_repo"` | Milestone tagging mode; `"per_repo"` opts a multi-repo project into per-repository release records |
|
|
343
345
|
| `git.phase_branch_template` | string | `"gsd/phase-{phase}-{slug}"` | Template with `{phase}`, `{slug}` | Branch naming template for `phase` strategy |
|
|
344
346
|
| `git.milestone_branch_template` | string | `"gsd/{milestone}-{slug}"` | Template with `{milestone}`, `{slug}` | Branch naming template for `milestone` strategy |
|
|
345
347
|
| `git.quick_branch_template` | string\|null | `null` | Template with `{slug}` | Optional branch template for quick-task runs |
|
|
@@ -316,7 +316,7 @@ git log --oneline -E --grep="^feat\((0*${PHASE_N})-(0*${PLAN_N})\):" | head -1
|
|
|
316
316
|
git log --oneline -E --grep="^refactor\((0*${PHASE_N})-(0*${PLAN_N})\):" | head -1
|
|
317
317
|
```
|
|
318
318
|
|
|
319
|
-
If RED or GREEN gate commits are missing, add a `## TDD Gate Compliance` section to SUMMARY.md with the violation details.
|
|
319
|
+
If RED or GREEN gate commits are missing, or no GREEN commit follows a RED commit (#5275), add a `## TDD Gate Compliance` section to SUMMARY.md with the violation details.
|
|
320
320
|
</gate_enforcement>
|
|
321
321
|
|
|
322
322
|
<end_of_phase_review>
|
|
@@ -342,7 +342,7 @@ TDD Plans: {count} | Gate violations: {count}
|
|
|
342
342
|
|
|
343
343
|
### What the Review Checks
|
|
344
344
|
|
|
345
|
-
1. **Gate sequence:** Each TDD plan has RED → GREEN commits in order. A plan is scored on its own `test(<plan>):` / `feat(<plan>):` commits, with one exception (#4867): a RED-only probe plan is satisfied by a `feat(...)` commit under a plan that declares it in `depends_on`, directly or through a chain. That is the gap-closure shape (probe plan, then the fix plan that depends on it). The plan's own RED is still required, a plan nothing depends on is scored alone, and the report names the plan that supplied the GREEN (`Plan {id} GREEN is supplied by dependent plan {id}.`).
|
|
345
|
+
1. **Gate sequence:** Each TDD plan has RED → GREEN commits in order (#5275). Order is commit ancestry, not log position or commit date: a GREEN counts only when it descends from a RED commit of the plan, so a history merged from worktree branches is judged by what each commit descends from. A plan with both commit kinds but no GREEN after a RED fails with `reason: green_before_red` and the line `Plan {id} GREEN precedes RED: no feat(...) commit descends from a test(...) commit.`, distinct from the `missing` row for a plan without a RED or GREEN commit. If git cannot answer the ancestry question, the GREEN keeps its credit rather than becoming a violation. A plan is scored on its own `test(<plan>):` / `feat(<plan>):` commits, with one exception (#4867): a RED-only probe plan is satisfied by a `feat(...)` commit under a plan that declares it in `depends_on`, directly or through a chain. That is the gap-closure shape (probe plan, then the fix plan that depends on it). The plan's own RED is still required, a plan nothing depends on is scored alone, and the report names the plan that supplied the GREEN (`Plan {id} GREEN is supplied by dependent plan {id}.`).
|
|
346
346
|
2. **Test quality:** RED phase tests fail for the right reason (not import errors or syntax)
|
|
347
347
|
3. **Minimal GREEN:** Implementation is minimal — no premature optimization in GREEN phase
|
|
348
348
|
4. **Refactor discipline:** If REFACTOR commit exists, tests still pass
|
|
@@ -25,6 +25,17 @@ bug_class: null <!-- assigned at Phase 1.75 — bohrbug|heisenbug-mandelbug|con
|
|
|
25
25
|
reasoning_checkpoint: null <!-- populated before every fix attempt — see structured_returns -->
|
|
26
26
|
tdd_checkpoint: null <!-- populated when tdd_mode is active after root cause confirmed -->
|
|
27
27
|
|
|
28
|
+
## Session Loop
|
|
29
|
+
<!-- Read and written only by the checkpoint loop that drives gsd-debugger (on Pi, the top-level session); gsd-debugger never edits it. OVERWRITE on each dispatch and each wait -->
|
|
30
|
+
|
|
31
|
+
goal: find_and_fix | find_root_cause_only
|
|
32
|
+
tdd_mode: false
|
|
33
|
+
tdd_phase: none | green
|
|
34
|
+
resume_count: 0
|
|
35
|
+
awaiting: none | [header of the return whose question is open]
|
|
36
|
+
question: none | [checkpoint type and the full question text shown to the user]
|
|
37
|
+
last_next_action: [next_action seen before the last re-dispatch]
|
|
38
|
+
|
|
28
39
|
## Symptoms
|
|
29
40
|
<!-- Written during gathering, then immutable -->
|
|
30
41
|
|
|
@@ -78,6 +89,11 @@ files_changed: []
|
|
|
78
89
|
- `reasoning_checkpoint`: OVERWRITE before every fix_and_verify — seven-field structured reasoning record (hypothesis, confirming_evidence, falsification_test, fix_rationale, blind_spots, candidate_causes, and_gate) — see `gsd-debugger.md` Structured Reasoning Checkpoint
|
|
79
90
|
- `tdd_checkpoint`: OVERWRITE during TDD red/green phases — test file, name, status, failure output
|
|
80
91
|
|
|
92
|
+
**Session Loop:**
|
|
93
|
+
- Owned by the checkpoint loop that drives `gsd-debugger`; on Pi that loop is the top-level session, which holds no state in memory between turns (#5638)
|
|
94
|
+
- OVERWRITE on each dispatch and each wait; the debugger never edits it and `## Current Focus` rewrites never touch it
|
|
95
|
+
- Fields: goal, tdd_mode, tdd_phase, resume_count, awaiting, question, last_next_action
|
|
96
|
+
|
|
81
97
|
**Symptoms:**
|
|
82
98
|
- Written during initial gathering phase
|
|
83
99
|
- IMMUTABLE after gathering complete
|
|
@@ -16,7 +16,7 @@ covered_files: # #4155 — see agents/gsd-verifier.md's "Create VERIFICATION.md"
|
|
|
16
16
|
- .planning/phases/XX-name/{phase_num}-{plan}-PLAN.md
|
|
17
17
|
- .planning/phases/XX-name/{phase_num}-{plan}-SUMMARY.md
|
|
18
18
|
- src/{changed-file}.cts
|
|
19
|
-
covered_digest: "
|
|
19
|
+
covered_digest: "v4:sha256:{digest from verification.fingerprint}"
|
|
20
20
|
behavior_unverified: 0 # Count of ⚠️ PRESENT_BEHAVIOR_UNVERIFIED truths (present + wired, behavior not exercised)
|
|
21
21
|
behavior_unverified_items: # Only if behavior_unverified > 0 — the truths above as structured items; emitted regardless of overall status
|
|
22
22
|
- truth: "Observable truth whose state transition or cancellation/cleanup/ordering invariant no test exercises"
|
|
@@ -128,7 +128,8 @@ if [ -z "$AUDIT_TEST_CMD" ]; then
|
|
|
128
128
|
elif [ -f "Justfile" ] || [ -f "justfile" ]; then
|
|
129
129
|
AUDIT_TEST_CMD="just test"
|
|
130
130
|
elif [ -f "package.json" ]; then
|
|
131
|
-
AUDIT_TEST_CMD
|
|
131
|
+
AUDIT_TEST_CMD=$(gsd_run query resolve-package-manager test --cwd . 2>/dev/null || echo "npm test")
|
|
132
|
+
[ -n "$AUDIT_TEST_CMD" ] || AUDIT_TEST_CMD="npm test"
|
|
132
133
|
elif [ -f "Cargo.toml" ]; then
|
|
133
134
|
AUDIT_TEST_CMD="cargo test"
|
|
134
135
|
elif [ -f "go.mod" ]; then
|
|
@@ -2,8 +2,17 @@ When `FALLOW_ENABLED=true`:
|
|
|
2
2
|
|
|
3
3
|
1) Resolve binary via `node_modules/.bin/fallow` first, then PATH.
|
|
4
4
|
```bash
|
|
5
|
+
# gsd-resolve-lib begin fallow-runner.cjs (#5640): load helpers from the installed runtime, not the cwd
|
|
6
|
+
_gsd_lib_probe="fallow-runner.cjs"
|
|
7
|
+
_gsd_rt="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
|
8
|
+
GSD_LIB_DIR=""
|
|
9
|
+
_gsd_pick() { for _gsd_d; do if [ -n "$_gsd_d" ] && [ -f "$_gsd_d/$_gsd_lib_probe" ]; then GSD_LIB_DIR="$_gsd_d"; return 0; fi; done; return 1; }
|
|
10
|
+
_gsd_pick "${GSD_TOOLS:+${GSD_TOOLS%/*}/lib}" "$_gsd_rt/gsd-core/bin/lib" "$_gsd_rt/.claude/gsd-core/bin/lib" "$_gsd_rt/.codex/gsd-core/bin/lib" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib" || true
|
|
11
|
+
if [ -z "$GSD_LIB_DIR" ]; then echo "ERROR: fallow-runner.cjs not found in the GSD runtime. Looked in: ${GSD_TOOLS:+${GSD_TOOLS%/*}/lib, }${_gsd_rt}/gsd-core/bin/lib (and its .claude and .codex forms), ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib, ${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib. Reinstall: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
|
|
12
|
+
export GSD_LIB_DIR
|
|
13
|
+
# gsd-resolve-lib end
|
|
5
14
|
FALLOW_BIN=$(FALLOW_CWD="$(pwd)" node -e "
|
|
6
|
-
const { resolveFallowBinary } = require('
|
|
15
|
+
const { resolveFallowBinary } = require(require('path').join(process.env.GSD_LIB_DIR, 'fallow-runner.cjs'));
|
|
7
16
|
const resolved = resolveFallowBinary({ cwd: process.env.FALLOW_CWD });
|
|
8
17
|
if (resolved) process.stdout.write(resolved);
|
|
9
18
|
")
|
|
@@ -270,7 +270,32 @@ if [ "$AUTO_MODE" = "true" ]; then
|
|
|
270
270
|
# It is re-derived there from the final REVIEW.md's status, which is exactly the condition the
|
|
271
271
|
# `break` below fires on. A variable set here and read nowhere would just be a decoy.
|
|
272
272
|
|
|
273
|
-
|
|
273
|
+
# #4100: the loop used to stop only on a re-review returning `status: clean`. A review whose
|
|
274
|
+
# remaining findings are all OUTSIDE the fix scope (Info, or necessity findings without --all)
|
|
275
|
+
# never reaches clean, so the loop re-spawned the fixer with nothing to fix until the cap and then
|
|
276
|
+
# printed the degradation warning over a run with no work left. The fixer is the scope authority:
|
|
277
|
+
# its REVIEW-FIX.md `findings_in_scope` is read strictly — only a frontmatter value of 0 proves
|
|
278
|
+
# zero scope; a missing report or an unusable value keeps the old behaviour.
|
|
279
|
+
_gsd_fix_scope_empty() {
|
|
280
|
+
[ -f "$1" ] || return 1
|
|
281
|
+
_gsd_n=$(FIX_REPORT_PATH="$1" node -e "
|
|
282
|
+
const fs = require('fs');
|
|
283
|
+
try {
|
|
284
|
+
const content = fs.readFileSync(process.env.FIX_REPORT_PATH, 'utf-8');
|
|
285
|
+
const m = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
286
|
+
const v = m && m[1].match(/^findings_in_scope:[ \t]*([0-9]+)[ \t]*$/m);
|
|
287
|
+
process.stdout.write(v ? String(Number(v[1])) : '');
|
|
288
|
+
} catch (e) {}
|
|
289
|
+
" 2>/dev/null || true)
|
|
290
|
+
[ "$_gsd_n" = "0" ]
|
|
291
|
+
}
|
|
292
|
+
NO_SCOPE_LEFT=false
|
|
293
|
+
if _gsd_fix_scope_empty "${FIX_REPORT_PATH}"; then
|
|
294
|
+
NO_SCOPE_LEFT=true
|
|
295
|
+
echo "No findings in fix scope (${FIX_SCOPE}) — skipping the re-review loop. Out-of-scope findings remain in ${REVIEW_PATH}."
|
|
296
|
+
fi
|
|
297
|
+
|
|
298
|
+
while [ "$NO_SCOPE_LEFT" = false ] && [ $ITERATION -lt $MAX_ITERATIONS ]; do
|
|
274
299
|
ITERATION=$((ITERATION + 1))
|
|
275
300
|
|
|
276
301
|
echo ""
|
|
@@ -361,6 +386,12 @@ ${AGENT_SKILLS_FIXER}")
|
|
|
361
386
|
echo "Warning: Iteration ${ITERATION} fixer failed to produce fix report. Stopping auto-loop."
|
|
362
387
|
break
|
|
363
388
|
fi
|
|
389
|
+
if _gsd_fix_scope_empty "${FIX_REPORT_PATH}"; then
|
|
390
|
+
NO_SCOPE_LEFT=true
|
|
391
|
+
echo ""
|
|
392
|
+
echo "✓ No in-scope findings remain after iteration ${ITERATION} (scope: ${FIX_SCOPE}). Out-of-scope findings remain in ${REVIEW_PATH}."
|
|
393
|
+
break
|
|
394
|
+
fi
|
|
364
395
|
done
|
|
365
396
|
|
|
366
397
|
# After loop completes. The iteration COUNTER alone does not distinguish degradation from success:
|
|
@@ -369,7 +400,7 @@ ${AGENT_SKILLS_FIXER}")
|
|
|
369
400
|
# every finding was fixed — telling the operator the opposite of what happened, on the one path
|
|
370
401
|
# where the cap and convergence coincide. Convergence is re-derived from the review the loop left
|
|
371
402
|
# behind, the same signal cleanup_iteration_backups reads, so the two cannot disagree.
|
|
372
|
-
if [ $ITERATION -ge $MAX_ITERATIONS ]; then
|
|
403
|
+
if [ "$NO_SCOPE_LEFT" = false ] && [ $ITERATION -ge $MAX_ITERATIONS ]; then
|
|
373
404
|
LOOP_END_STATUS=$(REVIEW_PATH="${REVIEW_PATH}" node -e "
|
|
374
405
|
const fs = require('fs');
|
|
375
406
|
try {
|
|
@@ -491,8 +522,9 @@ which is the one distinction #3829 exists to make.
|
|
|
491
522
|
Convergence is re-derived here rather than carried. Shell state does not survive the loop's fence, so
|
|
492
523
|
a flag set there would be gone by this step — and once nothing in the loop consumed it, keeping it
|
|
493
524
|
would have left a variable set in one place and read in none. The loop breaks on exactly one
|
|
494
|
-
condition, a re-review returning clean, and that leaves `REVIEW.md` at
|
|
495
|
-
review's status IS the converged case.
|
|
525
|
+
condition that counts as convergence, a re-review returning clean, and that leaves `REVIEW.md` at
|
|
526
|
+
`status: clean`: the final review's status IS the converged case. Its other stop, nothing left in
|
|
527
|
+
fix scope (#4100), leaves out-of-scope findings in a non-clean review, so the backups are kept. Hitting `MAX_ITERATIONS` leaves the last re-review non-clean,
|
|
496
528
|
and the backups are kept.
|
|
497
529
|
|
|
498
530
|
```bash
|
|
@@ -586,7 +618,16 @@ echo ""
|
|
|
586
618
|
|
|
587
619
|
If status is "all_fixed":
|
|
588
620
|
```bash
|
|
589
|
-
if [ "$
|
|
621
|
+
if [ "${FINDINGS_IN_SCOPE:-}" = "0" ]; then
|
|
622
|
+
# #4100: a vacuous all_fixed (nothing was in scope) must not claim the review is resolved.
|
|
623
|
+
echo "○ No findings were in fix scope (${FIX_SCOPE}). Out-of-scope findings (Info, and necessity unless --all) remain in ${REVIEW_PATH}."
|
|
624
|
+
echo ""
|
|
625
|
+
if [ "${FIX_SCOPE}" != "all" ]; then
|
|
626
|
+
echo "Next step:"
|
|
627
|
+
echo " /gsd:code-review ${PHASE_NUMBER} --fix --all — Include them in the fix scope"
|
|
628
|
+
echo ""
|
|
629
|
+
fi
|
|
630
|
+
elif [ "$FIX_STATUS" = "all_fixed" ]; then
|
|
590
631
|
echo "✓ All issues resolved."
|
|
591
632
|
echo ""
|
|
592
633
|
echo "Full report: ${FIX_REPORT_PATH}"
|
|
@@ -32,8 +32,20 @@ PHASE_ARG="${1}"
|
|
|
32
32
|
# logic (e.g., --all and --auto imply --fix). Resolved BEFORE the init call below so
|
|
33
33
|
# the section-manifest gate forwards the RESOLVED (post-implication) fix decision, not
|
|
34
34
|
# just a literal --fix token check.
|
|
35
|
+
# gsd-resolve-lib begin code-review-flags.cjs (#5640): load helpers from the installed runtime, not the cwd
|
|
36
|
+
_gsd_lib_probe="code-review-flags.cjs"
|
|
37
|
+
_gsd_rt="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
|
38
|
+
_gsd_gr="$(command -v gsd_run 2>/dev/null || true)"
|
|
39
|
+
case "$_gsd_gr" in /*) ;; *) _gsd_gr="" ;; esac # a gsd_run shell function prints its bare name: not a path
|
|
40
|
+
[ -n "$_gsd_gr" ] && _gsd_gr="$(dirname "$(node -p "require('fs').realpathSync(process.argv[1])" "$_gsd_gr" 2>/dev/null || echo "$_gsd_gr")")/lib"
|
|
41
|
+
GSD_LIB_DIR=""
|
|
42
|
+
_gsd_pick() { for _gsd_d; do if [ -n "$_gsd_d" ] && [ -f "$_gsd_d/$_gsd_lib_probe" ]; then GSD_LIB_DIR="$_gsd_d"; return 0; fi; done; return 1; }
|
|
43
|
+
_gsd_pick "${GSD_TOOLS:+${GSD_TOOLS%/*}/lib}" "$_gsd_rt/gsd-core/bin/lib" "$_gsd_rt/.claude/gsd-core/bin/lib" "$_gsd_rt/.codex/gsd-core/bin/lib" "$_gsd_gr" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib" || true
|
|
44
|
+
if [ -z "$GSD_LIB_DIR" ]; then echo "ERROR: code-review-flags.cjs not found in the GSD runtime. Looked in: ${GSD_TOOLS:+${GSD_TOOLS%/*}/lib, }${_gsd_rt}/gsd-core/bin/lib (and its .claude and .codex forms), ${_gsd_gr:-next to gsd_run (not on PATH)}, ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib, ${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib. Reinstall: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
|
|
45
|
+
export GSD_LIB_DIR
|
|
46
|
+
# gsd-resolve-lib end
|
|
35
47
|
FLAGS_JSON=$(node -e "
|
|
36
|
-
const { parseCodeReviewFlags } = require('
|
|
48
|
+
const { parseCodeReviewFlags } = require(require('path').join(process.env.GSD_LIB_DIR, 'code-review-flags.cjs'));
|
|
37
49
|
const flags = parseCodeReviewFlags(process.argv.slice(1));
|
|
38
50
|
process.stdout.write(JSON.stringify(flags));
|
|
39
51
|
" -- "$@" 2>/dev/null)
|
|
@@ -125,12 +137,25 @@ If FILES_OVERRIDE is set (from --files flag):
|
|
|
125
137
|
```bash
|
|
126
138
|
if [ -n "$FILES_OVERRIDE" ]; then
|
|
127
139
|
REVIEW_FILES=()
|
|
128
|
-
|
|
140
|
+
# #5519: compare the repository root and each resolved path in ONE form. On Windows Git Bash,
|
|
141
|
+
# `git rev-parse --show-toplevel` (a native program) reports a mixed path (C:/Users/..) while
|
|
142
|
+
# GNU `realpath` reports an MSYS POSIX path (/c/Users/..); the two never share a prefix, so
|
|
143
|
+
# every entry looked "outside". `cygpath -m` exists exactly where the forms differ and maps both
|
|
144
|
+
# to the mixed form; elsewhere the value passes through unchanged.
|
|
145
|
+
_gsd_norm_path() {
|
|
146
|
+
if command -v cygpath >/dev/null 2>&1; then cygpath -m "$1"; else printf '%s' "$1"; fi
|
|
147
|
+
}
|
|
148
|
+
REPO_ROOT=$(_gsd_norm_path "$(git rev-parse --show-toplevel 2>/dev/null)")
|
|
129
149
|
|
|
130
150
|
for file_path in "${FILES_ARRAY[@]}"; do
|
|
131
|
-
# Security: validate path is within repository (prevent path traversal)
|
|
132
|
-
|
|
133
|
-
|
|
151
|
+
# Security: validate path is within repository (prevent path traversal). Compare on a path
|
|
152
|
+
# boundary: the root itself or anything under "<root>/" — a sibling such as "<root>-other"
|
|
153
|
+
# shares the prefix but is not inside.
|
|
154
|
+
ABS_PATH=$(_gsd_norm_path "$(realpath -m "${file_path}" 2>/dev/null || echo "${file_path}")")
|
|
155
|
+
# Fail closed on two shapes that cannot be trusted: an empty root (git failed, so nothing can be
|
|
156
|
+
# "inside" it) and a path that still holds ".." segments (a resolved path never does, so it was
|
|
157
|
+
# not resolved — no GNU realpath).
|
|
158
|
+
if [ -z "$REPO_ROOT" ] || [[ "$ABS_PATH" == */../* || "$ABS_PATH" == */.. ]] || [[ "$ABS_PATH" != "$REPO_ROOT" && "$ABS_PATH" != "$REPO_ROOT"/* ]]; then
|
|
134
159
|
echo "Error: File path outside repository, skipping: ${file_path}"
|
|
135
160
|
continue
|
|
136
161
|
fi
|
|
@@ -437,8 +462,20 @@ DEPTH_PAYLOAD=$(printf '%s\n' "${REVIEW_FILES[@]}" | FLAG_DEPTH="$DEPTH_OVERRIDE
|
|
|
437
462
|
}));
|
|
438
463
|
")
|
|
439
464
|
|
|
465
|
+
# gsd-resolve-lib begin code-review-depth.cjs (#5640): load helpers from the installed runtime, not the cwd
|
|
466
|
+
_gsd_lib_probe="code-review-depth.cjs"
|
|
467
|
+
_gsd_rt="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
|
468
|
+
_gsd_gr="$(command -v gsd_run 2>/dev/null || true)"
|
|
469
|
+
case "$_gsd_gr" in /*) ;; *) _gsd_gr="" ;; esac # a gsd_run shell function prints its bare name: not a path
|
|
470
|
+
[ -n "$_gsd_gr" ] && _gsd_gr="$(dirname "$(node -p "require('fs').realpathSync(process.argv[1])" "$_gsd_gr" 2>/dev/null || echo "$_gsd_gr")")/lib"
|
|
471
|
+
GSD_LIB_DIR=""
|
|
472
|
+
_gsd_pick() { for _gsd_d; do if [ -n "$_gsd_d" ] && [ -f "$_gsd_d/$_gsd_lib_probe" ]; then GSD_LIB_DIR="$_gsd_d"; return 0; fi; done; return 1; }
|
|
473
|
+
_gsd_pick "${GSD_TOOLS:+${GSD_TOOLS%/*}/lib}" "$_gsd_rt/gsd-core/bin/lib" "$_gsd_rt/.claude/gsd-core/bin/lib" "$_gsd_rt/.codex/gsd-core/bin/lib" "$_gsd_gr" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib" || true
|
|
474
|
+
if [ -z "$GSD_LIB_DIR" ]; then echo "ERROR: code-review-depth.cjs not found in the GSD runtime. Looked in: ${GSD_TOOLS:+${GSD_TOOLS%/*}/lib, }${_gsd_rt}/gsd-core/bin/lib (and its .claude and .codex forms), ${_gsd_gr:-next to gsd_run (not on PATH)}, ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib, ${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib. Reinstall: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
|
|
475
|
+
export GSD_LIB_DIR
|
|
476
|
+
# gsd-resolve-lib end
|
|
440
477
|
DEPTH_JSON=$(echo "$DEPTH_PAYLOAD" | node -e "
|
|
441
|
-
const { resolveCodeReviewDepth } = require('
|
|
478
|
+
const { resolveCodeReviewDepth } = require(require('path').join(process.env.GSD_LIB_DIR, 'code-review-depth.cjs'));
|
|
442
479
|
const input = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf-8'));
|
|
443
480
|
process.stdout.write(JSON.stringify(resolveCodeReviewDepth(input)));
|
|
444
481
|
")
|
|
@@ -737,9 +774,21 @@ if [ -n "$FALLOW_JSON_PATH" ] && [ -f "$FALLOW_JSON_PATH" ]; then
|
|
|
737
774
|
# Normalize fallow's raw report into the compact {summary, findings[]} contract
|
|
738
775
|
# the reviewer consumes (real fallow schema -> normalized findings).
|
|
739
776
|
FALLOW_NORMALIZED_PATH="${PHASE_DIR}/FALLOW-normalized.json"
|
|
777
|
+
# gsd-resolve-lib begin fallow-runner.cjs (#5640): load helpers from the installed runtime, not the cwd
|
|
778
|
+
_gsd_lib_probe="fallow-runner.cjs"
|
|
779
|
+
_gsd_rt="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
|
780
|
+
_gsd_gr="$(command -v gsd_run 2>/dev/null || true)"
|
|
781
|
+
case "$_gsd_gr" in /*) ;; *) _gsd_gr="" ;; esac # a gsd_run shell function prints its bare name: not a path
|
|
782
|
+
[ -n "$_gsd_gr" ] && _gsd_gr="$(dirname "$(node -p "require('fs').realpathSync(process.argv[1])" "$_gsd_gr" 2>/dev/null || echo "$_gsd_gr")")/lib"
|
|
783
|
+
GSD_LIB_DIR=""
|
|
784
|
+
_gsd_pick() { for _gsd_d; do if [ -n "$_gsd_d" ] && [ -f "$_gsd_d/$_gsd_lib_probe" ]; then GSD_LIB_DIR="$_gsd_d"; return 0; fi; done; return 1; }
|
|
785
|
+
_gsd_pick "${GSD_TOOLS:+${GSD_TOOLS%/*}/lib}" "$_gsd_rt/gsd-core/bin/lib" "$_gsd_rt/.claude/gsd-core/bin/lib" "$_gsd_rt/.codex/gsd-core/bin/lib" "$_gsd_gr" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib" || true
|
|
786
|
+
if [ -z "$GSD_LIB_DIR" ]; then echo "ERROR: fallow-runner.cjs not found in the GSD runtime (looked in ${_gsd_rt}/gsd-core/bin/lib (and its .claude and .codex forms), ${_gsd_gr:-next to gsd_run (not on PATH)}, ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib, ${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib); continuing without it." >&2; fi
|
|
787
|
+
export GSD_LIB_DIR
|
|
788
|
+
# gsd-resolve-lib end
|
|
740
789
|
FALLOW_SRC="$FALLOW_JSON_PATH" FALLOW_OUT="$FALLOW_NORMALIZED_PATH" node -e "
|
|
741
790
|
const fs = require('fs');
|
|
742
|
-
const { normalizeFallowReportFile } = require('
|
|
791
|
+
const { normalizeFallowReportFile } = require(require('path').join(process.env.GSD_LIB_DIR, 'fallow-runner.cjs'));
|
|
743
792
|
const n = normalizeFallowReportFile(process.env.FALLOW_SRC);
|
|
744
793
|
fs.writeFileSync(process.env.FALLOW_OUT, JSON.stringify(n, null, 2));
|
|
745
794
|
" 2>/dev/null && FALLOW_EMBED_PATH="$FALLOW_NORMALIZED_PATH" || FALLOW_EMBED_PATH="$FALLOW_JSON_PATH"
|
|
@@ -883,6 +932,8 @@ CRITICAL=$(echo "$FRONTMATTER" | grep -E "^[[:space:]]*(critical|blocker):" | he
|
|
|
883
932
|
WARNING=$(echo "$FRONTMATTER" | grep "warning:" | head -1 | cut -d: -f2 | xargs)
|
|
884
933
|
INFO=$(echo "$FRONTMATTER" | grep "info:" | head -1 | cut -d: -f2 | xargs)
|
|
885
934
|
TOTAL=$(echo "$FRONTMATTER" | grep "total:" | head -1 | cut -d: -f2 | xargs)
|
|
935
|
+
# #4100: necessity is a SUBSET of warning+info, never part of total. Absent at quick depth.
|
|
936
|
+
NECESSITY=$(echo "$FRONTMATTER" | grep -E "^[[:space:]]*necessity:" | head -1 | cut -d: -f2 | sed 's/#.*//' | xargs)
|
|
886
937
|
```
|
|
887
938
|
|
|
888
939
|
Display inline summary to user:
|
|
@@ -901,6 +952,7 @@ Display inline summary to user:
|
|
|
901
952
|
Critical: ${CRITICAL}
|
|
902
953
|
Warning: ${WARNING}
|
|
903
954
|
Info: ${INFO}
|
|
955
|
+
Necessity: ${NECESSITY:-not assessed} (of the above; skipped by --fix unless --all)
|
|
904
956
|
|
|
905
957
|
---
|
|
906
958
|
Total: ${TOTAL}
|
|
@@ -943,6 +995,11 @@ grep -A 3 "^### CR-\|^### BL-\|^### WR-" "${REVIEW_PATH}" | head -n 12
|
|
|
943
995
|
**Windows:** This workflow uses bash features (arrays, process substitution). On Windows, it requires
|
|
944
996
|
Git Bash or WSL. Native PowerShell is not supported. The CI matrix (Ubuntu/macOS/Windows)
|
|
945
997
|
runs under Git Bash on Windows runners, which provides bash compatibility.
|
|
998
|
+
The `--files` containment check compares the repository root with each resolved path, and Git Bash
|
|
999
|
+
reports them in different forms (`git rev-parse` returns `C:/Users/...`, GNU `realpath` returns
|
|
1000
|
+
`/c/Users/...`), so both are normalized with `cygpath -m` (shipped with Git Bash) before the
|
|
1001
|
+
comparison. Relative paths and absolute paths in either form are accepted when they are inside the
|
|
1002
|
+
repository (#5519).
|
|
946
1003
|
|
|
947
1004
|
**macOS:** macOS ships with bash 3.2 (GPL licensing). This workflow does NOT use `mapfile` (bash 4+
|
|
948
1005
|
only) — all array construction uses portable `while IFS= read -r` loops compatible with bash 3.2.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<step name="evolve_project_full_review">
|
|
2
|
+
|
|
3
|
+
Full PROJECT.md evolution review at milestone completion.
|
|
4
|
+
|
|
5
|
+
Read all phase summaries:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
_SUMMARIES=( .planning/phases/*-*/*-SUMMARY.md )
|
|
9
|
+
if [ -e "${_SUMMARIES[0]}" ]; then cat "${_SUMMARIES[@]}"; fi
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Full review checklist:**
|
|
13
|
+
|
|
14
|
+
1. **"What This Is" accuracy:**
|
|
15
|
+
- Compare current description to what was built
|
|
16
|
+
- Update if product has meaningfully changed
|
|
17
|
+
|
|
18
|
+
2. **Core Value check:**
|
|
19
|
+
- Still the right priority? Did shipping reveal a different core value?
|
|
20
|
+
- Update if the ONE thing has shifted
|
|
21
|
+
|
|
22
|
+
3. **Business Context check (only if the section is present):**
|
|
23
|
+
- Skip entirely if PROJECT.md has no `## Business Context` section
|
|
24
|
+
- Customer, revenue model, and success metric still accurate after shipping?
|
|
25
|
+
- Update any field that drifted; refresh the linked strategy doc reference if it moved
|
|
26
|
+
|
|
27
|
+
4. **Requirements audit:**
|
|
28
|
+
|
|
29
|
+
**Validated section:**
|
|
30
|
+
- All Active requirements shipped this milestone → Move to Validated
|
|
31
|
+
- Format: `- ✓ [Requirement] — v[X.Y]`
|
|
32
|
+
|
|
33
|
+
**Active section:**
|
|
34
|
+
- Remove requirements moved to Validated
|
|
35
|
+
- Add new requirements for next milestone
|
|
36
|
+
- Keep unaddressed requirements
|
|
37
|
+
|
|
38
|
+
**Out of Scope audit:**
|
|
39
|
+
- Review each item — reasoning still valid?
|
|
40
|
+
- Remove irrelevant items
|
|
41
|
+
- Add requirements invalidated during milestone
|
|
42
|
+
|
|
43
|
+
5. **Context update:**
|
|
44
|
+
- Current codebase state (LOC, tech stack)
|
|
45
|
+
- User feedback themes (if any)
|
|
46
|
+
- Known issues or technical debt
|
|
47
|
+
|
|
48
|
+
6. **Key Decisions audit:**
|
|
49
|
+
- Extract all decisions from milestone phase summaries
|
|
50
|
+
- Add to Key Decisions table with outcomes
|
|
51
|
+
- Mark ✓ Good, ⚠️ Revisit, or — Pending
|
|
52
|
+
|
|
53
|
+
7. **Constraints check:**
|
|
54
|
+
- Any constraints changed during development? Update as needed
|
|
55
|
+
|
|
56
|
+
Update PROJECT.md inline. Update "Last updated" footer:
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
---
|
|
60
|
+
*Last updated: [date] after v[X.Y] milestone*
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Example full evolution (v1.0 → v1.1 prep):**
|
|
64
|
+
|
|
65
|
+
Before:
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
## What This Is
|
|
69
|
+
|
|
70
|
+
A real-time collaborative whiteboard for remote teams.
|
|
71
|
+
|
|
72
|
+
## Core Value
|
|
73
|
+
|
|
74
|
+
Real-time sync that feels instant.
|
|
75
|
+
|
|
76
|
+
## Requirements
|
|
77
|
+
|
|
78
|
+
### Validated
|
|
79
|
+
|
|
80
|
+
(None yet — ship to validate)
|
|
81
|
+
|
|
82
|
+
### Active
|
|
83
|
+
|
|
84
|
+
- [ ] Canvas drawing tools
|
|
85
|
+
- [ ] Real-time sync < 500ms
|
|
86
|
+
- [ ] User authentication
|
|
87
|
+
- [ ] Export to PNG
|
|
88
|
+
|
|
89
|
+
### Out of Scope
|
|
90
|
+
|
|
91
|
+
- Mobile app — web-first approach
|
|
92
|
+
- Video chat — use external tools
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
After v1.0:
|
|
96
|
+
|
|
97
|
+
```markdown
|
|
98
|
+
## What This Is
|
|
99
|
+
|
|
100
|
+
A real-time collaborative whiteboard for remote teams with instant sync and drawing tools.
|
|
101
|
+
|
|
102
|
+
## Core Value
|
|
103
|
+
|
|
104
|
+
Real-time sync that feels instant.
|
|
105
|
+
|
|
106
|
+
## Requirements
|
|
107
|
+
|
|
108
|
+
### Validated
|
|
109
|
+
|
|
110
|
+
- ✓ Canvas drawing tools — v1.0
|
|
111
|
+
- ✓ Real-time sync < 500ms — v1.0 (achieved 200ms avg)
|
|
112
|
+
- ✓ User authentication — v1.0
|
|
113
|
+
|
|
114
|
+
### Active
|
|
115
|
+
|
|
116
|
+
- [ ] Export to PNG
|
|
117
|
+
- [ ] Undo/redo history
|
|
118
|
+
- [ ] Shape tools (rectangles, circles)
|
|
119
|
+
|
|
120
|
+
### Out of Scope
|
|
121
|
+
|
|
122
|
+
- Mobile app — web-first approach, PWA works well
|
|
123
|
+
- Video chat — use external tools
|
|
124
|
+
- Offline mode — real-time is core value
|
|
125
|
+
|
|
126
|
+
## Context
|
|
127
|
+
|
|
128
|
+
Shipped v1.0 with 2,400 LOC TypeScript.
|
|
129
|
+
Tech stack: Next.js, Supabase, Canvas API.
|
|
130
|
+
Initial user testing showed demand for shape tools.
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Step complete when:**
|
|
134
|
+
|
|
135
|
+
- [ ] "What This Is" reviewed and updated if needed
|
|
136
|
+
- [ ] Core Value verified as still correct
|
|
137
|
+
- [ ] Business Context checked (or confirmed absent)
|
|
138
|
+
- [ ] All shipped requirements moved to Validated
|
|
139
|
+
- [ ] New requirements added to Active for next milestone
|
|
140
|
+
- [ ] Out of Scope reasoning audited
|
|
141
|
+
- [ ] Context updated with current state
|
|
142
|
+
- [ ] All milestone decisions added to Key Decisions
|
|
143
|
+
- [ ] "Last updated" footer reflects milestone completion
|
|
144
|
+
|
|
145
|
+
</step>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<step name="release_map">
|
|
2
|
+
|
|
3
|
+
Per-repository release mapping (#3628, ADR-3628). Runs only when the init JSON has `repo_tagging` set to `per_repo` AND a non-empty `sub_repos` list. A GSD milestone version names planned work; each repository has its own release version, so no `v[X.Y]` tag is created in the current directory on this path.
|
|
4
|
+
|
|
5
|
+
This file is read twice: Part 1 from `archive_milestone`, Part 2 from `push_release_tags`.
|
|
6
|
+
|
|
7
|
+
Text mode: when `TEXT_MODE` is active, replace every `AskUserQuestion` with a numbered plain-text list.
|
|
8
|
+
|
|
9
|
+
Working directory for the two JSON files: `RELEASE_MAP_DIR="${TMPDIR:-/tmp}/gsd-release-map-v[X.Y]"`, created with `mkdir -p "$RELEASE_MAP_DIR"`; the map file is `"$RELEASE_MAP_DIR/release-map.json"`. Shell state does not persist between commands, so re-derive these paths in every command that uses them. Write both JSON files with the Write tool; never build them with `echo`, a heredoc or any shell interpolation of the answers.
|
|
10
|
+
|
|
11
|
+
## Part 1 — Collect, preflight, confirm, tag (runs inside `archive_milestone`, before `milestone complete`)
|
|
12
|
+
|
|
13
|
+
1. **Collect one entry per repository in `sub_repos`.** For each repository ask for:
|
|
14
|
+
- `status`: `released`, `deployed`, or `unreleased`.
|
|
15
|
+
- `release`: the repository's release version. When a tag is created it becomes the tag name, so it must match `^[A-Za-z0-9][A-Za-z0-9._+-]{0,199}$`; re-ask on a mismatch, never alter or skip it. Leave it empty for an `unreleased` repository and never invent one.
|
|
16
|
+
- `reference`: a commit SHA or pull request reference (free text).
|
|
17
|
+
- `environment`: free text, for example `production`, `npm`, `development`.
|
|
18
|
+
- tag choice: `create` (create an annotated tag named `release`; requires a non-empty `release`) or `skip` (record the repository, create nothing). An `unreleased` repository defaults to `skip`.
|
|
19
|
+
|
|
20
|
+
Every text field is limited to 200 characters and a map to 256 entries; re-ask when a value is longer. If `git_create_tag` from init is `false`, do not ask the tag choice: every entry is recorded with a `tag` of `none`, no `tags.json` is built, and steps 3, 5 and 6 are skipped (the tag verb and the tag-state update); step 4 asks "Record this release map?" instead. Part 2 does not run.
|
|
21
|
+
|
|
22
|
+
2. **Build `release-map.json`** (array of `{ "repo", "release", "reference", "environment", "status", "tag" }`) with provisional tag states: `created` for a `create` entry, `skipped` for a `skip` entry, `none` when tagging is disabled. When tags are requested, also build `tags.json` in the same directory: `{ "repo": "<repo>", "tag": "<release>", "ref": "<ref>" }` for each `create` entry and `{ "repo": "<repo>", "skip": true }` for each `skip` entry. `ref` is the entry's `reference`, lowercased, only when it matches `^[0-9a-f]{7,40}$`; any other reference text (for example `PR #412`) is recorded but the tag is placed on the repository's current `HEAD`.
|
|
23
|
+
|
|
24
|
+
3. **Validate everything before anything is written:**
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; _gsd_id_ok() { case "$("$1" runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') return 0;; *) return 1;; esac; }; _gsd_homes() { set -- "${CLAUDE_CONFIG_DIR:-$HOME/.claude}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}" "$HOME/.gemini/antigravity-ide" "$HOME/.gemini/antigravity-cli" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}" "${CLINE_CONFIG_DIR:-$HOME/.cline}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}" "${CODEX_HOME:-$HOME/.codex}" "${COPILOT_CONFIG_DIR:-${COPILOT_HOME:-$HOME/.copilot}}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}" "${HERMES_HOME:-$HOME/.hermes}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}" "${KIMI_CONFIG_DIR:-$HOME/.config/agents}" "$HOME/.agents" "${KIMI_CODE_HOME:-$HOME/.kimi-code}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}" "${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}" "${TRAE_CONFIG_DIR:-$HOME/.trae}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}" "${ZCODE_CONFIG_DIR:-$HOME/.zcode}" "${GROK_AGENTS_HOME:-$HOME/.agents}"; for _h; do _gsd_at "$_h/gsd-core/bin/${_GSD_SHIM_NAME}" && return 0; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif _gsd_homes; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; [ -n "$_G" ] && _gsd_id_ok "$_G"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and no identity-proving gsd_run is on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; _gsd_id_ok gsd_run && GSD_IDENTITY_STATUS=ok; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
28
|
+
gsd_run query milestone release-tags --map "$RELEASE_MAP_DIR/tags.json" --dry-run
|
|
29
|
+
gsd_run query milestone.complete "v[X.Y]" --dry-run --release-map "$RELEASE_MAP_DIR/release-map.json"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If the first reports `ok: false`, show each error with its repository and `reason`; a `tag_conflict` means the tag already exists at a different commit and is never overwritten. If the second fails, it lists every release map problem. Let the user correct the entries or abort, and repeat. Do not continue while either check fails.
|
|
33
|
+
|
|
34
|
+
4. **One consolidated confirmation.** Show a single table and ask once (AskUserQuestion: "Create these tags? Nothing is pushed." — Create / Edit / Cancel). Include the commit each tag will be placed on (`commit`, shortened, from the dry-run result) and say so when the tag lands on the repository's current `HEAD` rather than a given SHA or when the result reports `detached_head`:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
Milestone v[X.Y] — [Name]
|
|
38
|
+
|
|
39
|
+
Repository Release Reference Environment Tag Commit
|
|
40
|
+
dashboard v5.78.0 PR #412 production create HEAD (a1b2c3d)
|
|
41
|
+
composers unreleased abc1234 development skip —
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
On Cancel, stop: nothing has been written and `milestone complete` is not called.
|
|
45
|
+
|
|
46
|
+
5. **Create the tags:**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
gsd_run query milestone release-tags --map "$RELEASE_MAP_DIR/tags.json"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If the command exits non-zero, report every repository's status and the `created` list (`repo:tag` pairs already written). Stop before `milestone complete`; running the same command again is safe, it retries only what failed and reports tags already written as `already_tagged`. Tags are placed on commits that already exist in each repository, so merge or squash a repository's release branch before running this flow if the tag must sit on the merged commit.
|
|
53
|
+
|
|
54
|
+
6. **Record the outcome in the map.** Rewrite `release-map.json` so each `create` entry's `tag` is that repository's `status` from the result (`created` or `already_tagged`); leave `skipped` and `none` as they are. Valid `status` values are `released`, `deployed`, `unreleased`; valid `tag` values are `created`, `already_tagged`, `skipped`, `none`.
|
|
55
|
+
|
|
56
|
+
7. **Archive the map with the milestone** by adding `--release-map "$RELEASE_MAP_DIR/release-map.json"` to every `milestone complete` call in `archive_milestone`. The map is stored as recorded, whether or not any tag was created.
|
|
57
|
+
|
|
58
|
+
## Part 2 — Push confirmation (runs after the archive, in place of the single-repository push prompt)
|
|
59
|
+
|
|
60
|
+
Nothing is pushed by default. For each repository whose entry has `tag` of `created` or `already_tagged`, one at a time. Take `REPO`, `REMOTE` and `TAG` only from the validated release map and the repository's own `git remote` list, and write them into the commands below as single-quoted literals.
|
|
61
|
+
|
|
62
|
+
Choose the remote: `origin` when `git -C "$REPO" remote` lists it; when there are several remotes and none is `origin`, show the list and ask which one; when there is none, report that and move on. Then show where the push would go (the push URL, with any embedded credentials removed before it is shown):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git -C "$REPO" remote get-url --push "$REMOTE"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Ask a separate question naming the repository, the tag, the remote and that URL:
|
|
69
|
+
|
|
70
|
+
`Push tag <tag> from <repo> to remote <remote> (<url>)? (y/n)`
|
|
71
|
+
|
|
72
|
+
Only on `y`, push that one tag, with `GIT_TERMINAL_PROMPT=0` exported:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git -C "$REPO" push -- "$REMOTE" "refs/tags/$TAG"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
A decline, a failed push, or a push that does not finish is reported for that repository only; continue with the next repository. Never push branches, never push several tags in one command, and never push without the answer for that repository.
|
|
79
|
+
|
|
80
|
+
</step>
|