@opengsd/gsd-core 1.15.0 → 1.17.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 +1 -2
- package/.opencode/plugins/gsd-core.js +336 -6
- package/.opencode/plugins/gsd-statusline/tui.tsx +55 -0
- package/GEMINI.md +1 -1
- package/agents/gsd-code-fixer.compact.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +7 -1
- package/agents/gsd-debug-session-manager.md +7 -1
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +4 -4
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +7 -2
- package/agents/gsd-planner.md +3 -3
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +42 -51
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +31 -9
- package/bin/gsd-mcp-server.js +3 -1
- package/bin/install.js +487 -290
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +5 -0
- package/commands/gsd/capture.md +8 -4
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +5 -1
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +5 -1
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +6 -1
- package/commands/gsd/quick-batch.md +20 -8
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +5 -1
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +159 -58
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/adr-parser.cjs +37 -5
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +78 -44
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +249 -117
- package/gsd-core/bin/lib/capability-validator.cjs +18 -1
- package/gsd-core/bin/lib/capability-writer.cjs +2 -1
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +201 -178
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config.cjs +43 -12
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +413 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +142 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +81 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/graphify.cjs +3 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/init.cjs +194 -108
- package/gsd-core/bin/lib/install-engine.cjs +30 -35
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/install-shadow-report.cjs +12 -0
- package/gsd-core/bin/lib/installer-migrations/011-opencode-mcp-no-prompts.cjs +99 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +54 -1
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/jsonc-edit.cjs +418 -0
- package/gsd-core/bin/lib/loop-host-contract.cjs +2 -1
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/mcp-server.cjs +5 -1
- package/gsd-core/bin/lib/milestone.cjs +19 -1
- package/gsd-core/bin/lib/model-resolver.cjs +18 -18
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/opencode-mcp-entry.cjs +39 -0
- package/gsd-core/bin/lib/opencode-version.cjs +486 -0
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- package/gsd-core/bin/lib/phase-id.cjs +1 -1
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +301 -80
- package/gsd-core/bin/lib/plan-document.cjs +93 -19
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +273 -40
- package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +13 -9
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
- package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
- package/gsd-core/bin/lib/roadmap.cjs +169 -72
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +186 -161
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +365 -594
- package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
- package/gsd-core/bin/lib/runtime-slash.cjs +60 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
- package/gsd-core/bin/lib/smart-entry.cjs +111 -56
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state-transition.cjs +67 -9
- package/gsd-core/bin/lib/state.cjs +668 -171
- package/gsd-core/bin/lib/surface.cjs +2 -1
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
- package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
- package/gsd-core/bin/lib/uat.cjs +424 -7
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
- package/gsd-core/bin/lib/update-context.cjs +18 -1
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1265 -324
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +286 -567
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/execute-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +7 -1
- package/gsd-core/references/offer-next.md +1 -1
- package/gsd-core/references/planning-config.md +1 -1
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +10 -4
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +8 -7
- package/gsd-core/workflows/add-tests.md +3 -2
- package/gsd-core/workflows/add-todo.md +4 -3
- package/gsd-core/workflows/ai-integration-phase.md +3 -2
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous.md +28 -18
- package/gsd-core/workflows/check-todos.md +6 -5
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +5 -4
- package/gsd-core/workflows/code-review.md +100 -91
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +12 -7
- package/gsd-core/workflows/debug.md +30 -5
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +1 -1
- package/gsd-core/workflows/docs-update.md +4 -3
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +5 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase.md +81 -171
- package/gsd-core/workflows/execute-plan.md +13 -19
- package/gsd-core/workflows/explore.md +2 -2
- package/gsd-core/workflows/extract-learnings.md +3 -2
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +3 -2
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +5 -3
- package/gsd-core/workflows/map-codebase.md +4 -3
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +10 -10
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +1 -1
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/pause-work.md +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
- package/gsd-core/workflows/plan-phase.md +27 -18
- package/gsd-core/workflows/plan-review-convergence.md +1 -1
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +1 -1
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +42 -31
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +17 -12
- package/gsd-core/workflows/review.md +3 -2
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +11 -12
- package/gsd-core/workflows/settings-advanced.md +1 -1
- package/gsd-core/workflows/settings-integrations.md +1 -1
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +12 -12
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +1 -1
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +1 -1
- package/gsd-core/workflows/thread.md +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +5 -4
- package/gsd-core/workflows/ui-review.md +4 -3
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/validate-phase.md +10 -12
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +68 -59
- package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +34 -20
- package/hooks/dist/gsd-context-monitor.js +45 -13
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +263 -16
- package/hooks/dist/gsd-statusline.js +336 -29
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +8 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +34 -20
- package/hooks/gsd-context-monitor.js +45 -13
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +263 -16
- package/hooks/gsd-statusline.js +336 -29
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +21 -4
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +12 -8
- package/scripts/docs-guard-registry.cjs +6 -0
- package/scripts/gen-capability-registry.cjs +7 -1
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +14 -2
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +24 -2
- package/scripts/lib/ndjson-reporter.cjs +28 -3
- package/scripts/lib/platform-conformance-tier.generated.cjs +44 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +29 -0
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-test-file-count.allowlist.json +11 -1
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
- package/scripts/mutation-matrix.cjs +53 -6
- package/scripts/release-tarball-smoke.cjs +14 -7
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +5 -0
- package/skills/gsd-capture/SKILL.md +8 -4
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +5 -1
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +6 -1
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +20 -8
- package/skills/gsd-review/SKILL.md +5 -1
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gsd-core",
|
|
3
3
|
"displayName": "GSD Core",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.17.0",
|
|
5
5
|
"description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "open-gsd",
|
|
@@ -18,6 +18,5 @@
|
|
|
18
18
|
"claude-code",
|
|
19
19
|
"gsd"
|
|
20
20
|
],
|
|
21
|
-
"commands": "./commands/gsd/",
|
|
22
21
|
"skills": "./skills/"
|
|
23
22
|
}
|
|
@@ -146,6 +146,11 @@ const TOOL_NAME_MAP = {
|
|
|
146
146
|
websearch: "WebSearch",
|
|
147
147
|
task: "Task",
|
|
148
148
|
subagent: "Task",
|
|
149
|
+
// >>> gsd:opencode-v2
|
|
150
|
+
// OpenCode 2.x tool ids (ADR-5331 E4): `shell` replaces `bash`, `patch` replaces `apply_patch`.
|
|
151
|
+
shell: "Bash",
|
|
152
|
+
patch: "MultiEdit",
|
|
153
|
+
// <<< gsd:opencode-v2
|
|
149
154
|
};
|
|
150
155
|
|
|
151
156
|
function mapToolName(tool) {
|
|
@@ -207,6 +212,50 @@ function mapToolInput(args) {
|
|
|
207
212
|
*/
|
|
208
213
|
const warnedMissingHooks = new Set();
|
|
209
214
|
|
|
215
|
+
// A hook this adapter kills on timeout has no exit status, so runHook below
|
|
216
|
+
// reports it as exit 0 — an ALLOW. For a guard that blocks, a bound shorter
|
|
217
|
+
// than the guard's own worst case therefore silently disables the gate. The
|
|
218
|
+
// two guards that probe git (worktree path, workflow force-add) run up to
|
|
219
|
+
// BLOCKING_GUARD_MAX_SEQUENTIAL_PROBES sequential probes of
|
|
220
|
+
// BLOCKING_GUARD_PROBE_TIMEOUT_MS each (hooks/lib/git-probe.js, #5180), so
|
|
221
|
+
// their bound is that product plus a margin for node start/kill/reap. Read
|
|
222
|
+
// from the staged hooks/lib so it can never drift from the guards' own budget;
|
|
223
|
+
// the fallback is used only when that lib is missing from a partial install,
|
|
224
|
+
// and is sized for the same worst case.
|
|
225
|
+
const GIT_PROBING_GUARDS = new Set([
|
|
226
|
+
"gsd-worktree-path-guard.js",
|
|
227
|
+
"gsd-workflow-guard.js",
|
|
228
|
+
]);
|
|
229
|
+
const GIT_PROBING_GUARD_MARGIN_MS = 5000;
|
|
230
|
+
const GIT_PROBING_GUARD_FALLBACK_TIMEOUT_MS = 20000;
|
|
231
|
+
|
|
232
|
+
function gitProbingGuardTimeoutMs() {
|
|
233
|
+
try {
|
|
234
|
+
const probe = require(path.join(HOOKS_DIR, "lib", "git-probe.js"));
|
|
235
|
+
const worstCaseMs =
|
|
236
|
+
probe.BLOCKING_GUARD_MAX_SEQUENTIAL_PROBES *
|
|
237
|
+
probe.BLOCKING_GUARD_PROBE_TIMEOUT_MS;
|
|
238
|
+
if (Number.isFinite(worstCaseMs) && worstCaseMs > 0) {
|
|
239
|
+
return worstCaseMs + GIT_PROBING_GUARD_MARGIN_MS;
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
// hooks/lib/git-probe.js unavailable — use the fallback below.
|
|
243
|
+
}
|
|
244
|
+
return GIT_PROBING_GUARD_FALLBACK_TIMEOUT_MS;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Hooks are Node scripts. `process.execPath` is only a JS runtime when the host is Node or Bun
|
|
248
|
+
// itself; inside OpenCode's single-file binary (1.x and 2.x) spawning it with a .js path boots
|
|
249
|
+
// OpenCode instead and exits 0, silently disabling every guard (#4849). So: an explicit
|
|
250
|
+
// GSD_HOOK_RUNTIME wins, then a Node/Bun host's own executable, else `node` from PATH.
|
|
251
|
+
let warnedMissingRuntime = false;
|
|
252
|
+
function hookRuntime() {
|
|
253
|
+
const fromEnv = process.env.GSD_HOOK_RUNTIME;
|
|
254
|
+
if (typeof fromEnv === "string" && fromEnv.length > 0) return fromEnv;
|
|
255
|
+
const base = path.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
|
|
256
|
+
return base === "node" || base === "bun" ? process.execPath : "node";
|
|
257
|
+
}
|
|
258
|
+
|
|
210
259
|
function runHook(hookFile, payload, opts = {}) {
|
|
211
260
|
const hookPath = path.join(HOOKS_DIR, hookFile);
|
|
212
261
|
if (!fs.existsSync(hookPath)) {
|
|
@@ -224,10 +273,12 @@ function runHook(hookFile, payload, opts = {}) {
|
|
|
224
273
|
}
|
|
225
274
|
return { stdout: "", exitCode: 0, timedOut: false };
|
|
226
275
|
}
|
|
227
|
-
const timeout =
|
|
276
|
+
const timeout =
|
|
277
|
+
opts.timeout ??
|
|
278
|
+
(GIT_PROBING_GUARDS.has(hookFile) ? gitProbingGuardTimeoutMs() : 8000);
|
|
228
279
|
let result;
|
|
229
280
|
try {
|
|
230
|
-
result = spawnSync(
|
|
281
|
+
result = spawnSync(hookRuntime(), [hookPath], {
|
|
231
282
|
input: JSON.stringify(payload),
|
|
232
283
|
encoding: "utf8",
|
|
233
284
|
timeout,
|
|
@@ -239,6 +290,15 @@ function runHook(hookFile, payload, opts = {}) {
|
|
|
239
290
|
return { stdout: "", exitCode: 0, timedOut: false };
|
|
240
291
|
}
|
|
241
292
|
|
|
293
|
+
if (result.error && !warnedMissingRuntime) {
|
|
294
|
+
// The runtime could not be started: the guard did not run. Fail open (adapter contract) but
|
|
295
|
+
// never silently (#4849).
|
|
296
|
+
warnedMissingRuntime = true;
|
|
297
|
+
console.error(
|
|
298
|
+
`[gsd-core] cannot start hook runtime '${hookRuntime()}' (${result.error.code || result.error.message}) — ` +
|
|
299
|
+
"GSD hooks are NOT enforced. Install Node.js or set GSD_HOOK_RUNTIME to a node/bun executable.",
|
|
300
|
+
);
|
|
301
|
+
}
|
|
242
302
|
const stdout = (result.stdout || "").trim();
|
|
243
303
|
const exitCode = result.status == null ? 0 : result.status;
|
|
244
304
|
return { stdout, exitCode, timedOut: result.signal === "SIGTERM" };
|
|
@@ -324,18 +384,134 @@ function handleHookResult(hookResult, output) {
|
|
|
324
384
|
}
|
|
325
385
|
// Best-effort visibility when metadata isn't surfaced to the model
|
|
326
386
|
console.error(advisory);
|
|
387
|
+
// >>> gsd:opencode-parity
|
|
388
|
+
deliverAdvisory(advisory, output);
|
|
389
|
+
// <<< gsd:opencode-parity
|
|
327
390
|
}
|
|
328
391
|
}
|
|
392
|
+
// >>> gsd:opencode-parity (ADR-5331 Phase 3; OpenCode-only — the Kilo mirror omits this block)
|
|
393
|
+
// The four opt-in community hooks are bash scripts. Their gates (hooks.community, graphify.*) are
|
|
394
|
+
// re-checked here in-process so a project that has not opted in never pays a bash spawn per tool call.
|
|
395
|
+
function readProjectConfig(cwd) {
|
|
396
|
+
try {
|
|
397
|
+
return JSON.parse(fs.readFileSync(path.join(cwd, ".planning", "config.json"), "utf8"));
|
|
398
|
+
} catch {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function communityHooksEnabled(cwd) {
|
|
404
|
+
const config = readProjectConfig(cwd);
|
|
405
|
+
return !!config && config.hooks && config.hooks.community === true;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function graphifyAutoUpdateEnabled(cwd) {
|
|
409
|
+
const config = readProjectConfig(cwd);
|
|
410
|
+
return !!config && !process.env.CI && !!config.graphify &&
|
|
411
|
+
config.graphify.enabled === true && config.graphify.auto_update === true;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Run a GSD `.sh` hook under bash with the hook payload on stdin. Fails open: a missing script or no
|
|
416
|
+
* bash on PATH (a Windows host without Git Bash) is the same as the hook not being installed.
|
|
417
|
+
*/
|
|
418
|
+
function runShellHook(hookFile, payload, opts = {}) {
|
|
419
|
+
const hookPath = path.join(HOOKS_DIR, hookFile);
|
|
420
|
+
if (!fs.existsSync(hookPath)) return { stdout: "", exitCode: 0, timedOut: false };
|
|
421
|
+
let result;
|
|
422
|
+
try {
|
|
423
|
+
result = spawnSync(process.env.GSD_HOOK_SHELL || "bash", [hookPath], {
|
|
424
|
+
input: JSON.stringify(payload),
|
|
425
|
+
encoding: "utf8",
|
|
426
|
+
timeout: opts.timeout ?? 15000,
|
|
427
|
+
cwd: opts.cwd || currentCwd,
|
|
428
|
+
windowsHide: true,
|
|
429
|
+
});
|
|
430
|
+
} catch {
|
|
431
|
+
return { stdout: "", exitCode: 0, timedOut: false };
|
|
432
|
+
}
|
|
433
|
+
if (result.error) return { stdout: "", exitCode: 0, timedOut: false };
|
|
434
|
+
return {
|
|
435
|
+
stdout: (result.stdout || "").trim(),
|
|
436
|
+
exitCode: result.status == null ? 0 : result.status,
|
|
437
|
+
timedOut: result.signal === "SIGTERM",
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// The SessionStart orientation text, produced once per session and handed to the model with its next request.
|
|
442
|
+
let pendingSessionContext = null;
|
|
443
|
+
|
|
444
|
+
// Advisories (read-before-edit, injection findings, phase-boundary, context warnings) were logged to stderr
|
|
445
|
+
// only — OpenCode does not show a plugin's stderr or metadata to the model. They are appended to the tool's
|
|
446
|
+
// own output instead, which is the one channel the model reads on both generations. An advisory raised before
|
|
447
|
+
// the tool runs waits here for that tool's result.
|
|
448
|
+
const pendingAdvisories = [];
|
|
449
|
+
function deliverAdvisory(text, output) {
|
|
450
|
+
if (output && typeof output.output === "string") {
|
|
451
|
+
output.output += "\n\n[GSD advisory] " + text;
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (!pendingAdvisories.includes(text) && pendingAdvisories.length < 5) pendingAdvisories.push(text);
|
|
455
|
+
}
|
|
456
|
+
function flushPendingAdvisories(output) {
|
|
457
|
+
if (!output || typeof output.output !== "string") return;
|
|
458
|
+
while (pendingAdvisories.length > 0) output.output += "\n\n[GSD advisory] " + pendingAdvisories.shift();
|
|
459
|
+
}
|
|
460
|
+
// <<< gsd:opencode-parity
|
|
329
461
|
|
|
330
462
|
// ---------------------------------------------------------------------------
|
|
331
463
|
// Frontmatter helpers (for config registration)
|
|
332
464
|
// ---------------------------------------------------------------------------
|
|
333
465
|
|
|
466
|
+
// A self-contained copy of `locateFrontmatterFence` (src/frontmatter-fence.cts, the
|
|
467
|
+
// one frontmatter fence owner). Kept here, not required from the built
|
|
468
|
+
// gsd-core/bin/lib/frontmatter-fence.cjs, because this plugin must load in every
|
|
469
|
+
// layout it is copied to — including a package/git-spec tree, which may carry no
|
|
470
|
+
// built bin/lib. Found while implementing #5105: tests/frontmatter-fence.test.cjs
|
|
471
|
+
// ("kept frontmatter fence copies agree with the owner") pins this copy to the owner
|
|
472
|
+
// over a fixture corpus and a property test, and
|
|
473
|
+
// scripts/lint-frontmatter-fence-drift.cjs allowlists exactly this function.
|
|
474
|
+
function locateFrontmatterFence(text) {
|
|
475
|
+
if (typeof text !== "string") {
|
|
476
|
+
throw new TypeError(`locateFrontmatterFence: expected a string, got ${typeof text}`);
|
|
477
|
+
}
|
|
478
|
+
const closingFenceLine = /^---[ \t]*$/;
|
|
479
|
+
const lenientClosingFenceLine = /^-{4,}[ \t]*$/;
|
|
480
|
+
const bom = text.charCodeAt(0) === 0xfeff ? text.slice(0, 1) : "";
|
|
481
|
+
const start = bom.length;
|
|
482
|
+
let eol;
|
|
483
|
+
if (text.startsWith("---\r\n", start)) eol = "\r\n";
|
|
484
|
+
else if (text.startsWith("---\n", start)) eol = "\n";
|
|
485
|
+
else return null;
|
|
486
|
+
const openEnd = start + 3 + eol.length;
|
|
487
|
+
const closedAt = (lineStart, lineEnd) => {
|
|
488
|
+
let bodyEnd = openEnd;
|
|
489
|
+
if (lineStart > openEnd) {
|
|
490
|
+
bodyEnd = lineStart - 1;
|
|
491
|
+
if (bodyEnd > openEnd && text[bodyEnd - 1] === "\r") bodyEnd -= 1;
|
|
492
|
+
}
|
|
493
|
+
return { bom, eol, openEnd, closed: true, closingStart: lineStart, closingFenceEnd: lineEnd, bodyEnd };
|
|
494
|
+
};
|
|
495
|
+
let lenient = null;
|
|
496
|
+
let lineStart = openEnd;
|
|
497
|
+
while (lineStart <= text.length) {
|
|
498
|
+
const newline = text.indexOf("\n", lineStart);
|
|
499
|
+
const lineEnd = newline === -1 ? text.length : newline > lineStart && text[newline - 1] === "\r" ? newline - 1 : newline;
|
|
500
|
+
const line = text.slice(lineStart, lineEnd);
|
|
501
|
+
if (closingFenceLine.test(line)) return closedAt(lineStart, lineEnd);
|
|
502
|
+
if (lenient === null && lenientClosingFenceLine.test(line)) lenient = [lineStart, lineEnd];
|
|
503
|
+
if (newline === -1) break;
|
|
504
|
+
lineStart = newline + 1;
|
|
505
|
+
}
|
|
506
|
+
if (lenient !== null) return closedAt(lenient[0], lenient[1]);
|
|
507
|
+
return { bom, eol, openEnd, closed: false, closingStart: -1, closingFenceEnd: -1, bodyEnd: text.length };
|
|
508
|
+
}
|
|
509
|
+
|
|
334
510
|
function parseFrontmatter(content) {
|
|
335
|
-
const
|
|
336
|
-
if (!
|
|
511
|
+
const fence = locateFrontmatterFence(content);
|
|
512
|
+
if (!fence || !fence.closed) return { frontmatter: {}, body: content };
|
|
337
513
|
const fm = {};
|
|
338
|
-
for (const line of
|
|
514
|
+
for (const line of content.slice(fence.openEnd, fence.bodyEnd).split(/\r?\n/)) {
|
|
339
515
|
const i = line.indexOf(":");
|
|
340
516
|
if (i > 0) {
|
|
341
517
|
let v = line.slice(i + 1).trim();
|
|
@@ -343,7 +519,8 @@ function parseFrontmatter(content) {
|
|
|
343
519
|
fm[line.slice(0, i).trim()] = v;
|
|
344
520
|
}
|
|
345
521
|
}
|
|
346
|
-
|
|
522
|
+
// The body is everything past the closing fence line and its line ending.
|
|
523
|
+
return { frontmatter: fm, body: content.slice(fence.closingFenceEnd).replace(/^\r?\n/, "") };
|
|
347
524
|
}
|
|
348
525
|
|
|
349
526
|
// Rewrite @~/.claude/ includes to point at the repo root.
|
|
@@ -588,6 +765,13 @@ const GsdCorePlugin = async ({ directory } = {}) => {
|
|
|
588
765
|
const r = runHook("gsd-secret-read-guard.js", prePayload());
|
|
589
766
|
handleHookResult(r, output);
|
|
590
767
|
}
|
|
768
|
+
// >>> gsd:opencode-parity
|
|
769
|
+
// 7. gsd-validate-commit.sh — Conventional Commits gate (opt-in: hooks.community)
|
|
770
|
+
if (claudeTool === "Bash" && communityHooksEnabled(cwd)) {
|
|
771
|
+
const r = runShellHook("gsd-validate-commit.sh", prePayload());
|
|
772
|
+
handleHookResult(r, output);
|
|
773
|
+
}
|
|
774
|
+
// <<< gsd:opencode-parity
|
|
591
775
|
},
|
|
592
776
|
|
|
593
777
|
// ── tool.execute.after — PostToolUse hooks ─────────────────────────
|
|
@@ -611,6 +795,25 @@ const GsdCorePlugin = async ({ directory } = {}) => {
|
|
|
611
795
|
: String(output.output);
|
|
612
796
|
output.output = rewriteContent(content);
|
|
613
797
|
}
|
|
798
|
+
// >>> gsd:opencode-parity
|
|
799
|
+
flushPendingAdvisories(output);
|
|
800
|
+
// gsd-phase-boundary.sh — reminder when .planning/ files change outside the workflow (opt-in)
|
|
801
|
+
// gsd-graphify-update.sh — rebuild the knowledge graph after a HEAD-advancing git op (opt-in)
|
|
802
|
+
{
|
|
803
|
+
const postPayload = {
|
|
804
|
+
hook_event_name: "PostToolUse",
|
|
805
|
+
tool_name: claudeTool,
|
|
806
|
+
tool_input: toolInput,
|
|
807
|
+
cwd,
|
|
808
|
+
};
|
|
809
|
+
if ((claudeTool === "Write" || claudeTool === "Edit") && communityHooksEnabled(cwd)) {
|
|
810
|
+
handleHookResult(runShellHook("gsd-phase-boundary.sh", postPayload), output);
|
|
811
|
+
}
|
|
812
|
+
if (claudeTool === "Bash" && graphifyAutoUpdateEnabled(cwd)) {
|
|
813
|
+
handleHookResult(runShellHook("gsd-graphify-update.sh", postPayload, { timeout: 8000 }), output);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
// <<< gsd:opencode-parity
|
|
614
817
|
|
|
615
818
|
// gsd-read-injection-scanner.js — scan Read/WebFetch/WebSearch results
|
|
616
819
|
if (
|
|
@@ -648,6 +851,16 @@ const GsdCorePlugin = async ({ directory } = {}) => {
|
|
|
648
851
|
handleHookResult(r, output);
|
|
649
852
|
}
|
|
650
853
|
},
|
|
854
|
+
// >>> gsd:opencode-parity
|
|
855
|
+
// ── experimental.chat.system.transform — SessionStart orientation (gsd-session-state.sh) ──
|
|
856
|
+
"experimental.chat.system.transform": async (_input, output) => {
|
|
857
|
+
if (!pendingSessionContext) return;
|
|
858
|
+
const text = pendingSessionContext;
|
|
859
|
+
pendingSessionContext = null;
|
|
860
|
+
output.system = output.system || [];
|
|
861
|
+
output.system.push(text);
|
|
862
|
+
},
|
|
863
|
+
// <<< gsd:opencode-parity
|
|
651
864
|
|
|
652
865
|
// ── experimental.session.compacting — PreCompact ───────────────────
|
|
653
866
|
"experimental.session.compacting": async (_input, output) => {
|
|
@@ -691,6 +904,23 @@ const GsdCorePlugin = async ({ directory } = {}) => {
|
|
|
691
904
|
session_id: currentSessionId,
|
|
692
905
|
cwd: currentCwd,
|
|
693
906
|
});
|
|
907
|
+
// >>> gsd:opencode-parity
|
|
908
|
+
// gsd-session-state.sh — project state orientation for the session (opt-in: hooks.community)
|
|
909
|
+
if (communityHooksEnabled(currentCwd)) {
|
|
910
|
+
const r = runShellHook("gsd-session-state.sh", {
|
|
911
|
+
hook_event_name: "SessionStart",
|
|
912
|
+
session_id: currentSessionId,
|
|
913
|
+
cwd: currentCwd,
|
|
914
|
+
});
|
|
915
|
+
try {
|
|
916
|
+
const parsed = JSON.parse(r.stdout);
|
|
917
|
+
const text = parsed && parsed.hookSpecificOutput && parsed.hookSpecificOutput.additionalContext;
|
|
918
|
+
pendingSessionContext = typeof text === "string" && text ? text : null;
|
|
919
|
+
} catch {
|
|
920
|
+
pendingSessionContext = null;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
// <<< gsd:opencode-parity
|
|
694
924
|
return;
|
|
695
925
|
}
|
|
696
926
|
|
|
@@ -777,6 +1007,7 @@ GsdCorePlugin._internals = {
|
|
|
777
1007
|
IS_PACKAGE_TREE,
|
|
778
1008
|
mapToolName,
|
|
779
1009
|
mapToolInput,
|
|
1010
|
+
locateFrontmatterFence,
|
|
780
1011
|
parseFrontmatter,
|
|
781
1012
|
rewriteContent,
|
|
782
1013
|
isGsdManagedFile,
|
|
@@ -784,7 +1015,106 @@ GsdCorePlugin._internals = {
|
|
|
784
1015
|
GsdCorePlugin,
|
|
785
1016
|
};
|
|
786
1017
|
|
|
1018
|
+
// >>> gsd:opencode-v2 (ADR-5331 D2; OpenCode 2.x entrypoint — the Kilo mirror omits this block)
|
|
1019
|
+
// OpenCode 2.x calls `setup(ctx)` with a `ctx` exposing `ctx.tool.hook(...)`; 1.x loads `server`
|
|
1020
|
+
// and never calls `setup` with such a ctx. `setup` therefore returns at once unless it is
|
|
1021
|
+
// handed a 2.x ctx. The 1.x hook handlers are reused through thin adapters so both generations
|
|
1022
|
+
// run the same guards.
|
|
1023
|
+
function v2ResultText(result) {
|
|
1024
|
+
const first = result && Array.isArray(result.content) ? result.content[0] : null;
|
|
1025
|
+
return first && typeof first.text === "string" ? first.text : null;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
async function setupV2(ctx) {
|
|
1029
|
+
if (!(ctx && ctx.tool && typeof ctx.tool.hook === "function")) return undefined;
|
|
1030
|
+
const hooks = await GsdCorePlugin({ directory: ctx.directory });
|
|
1031
|
+
// A thrown error in a 2.x before-hook blocks the tool (verified on 2.0.27), as in 1.x.
|
|
1032
|
+
await ctx.tool.hook("execute.before", async (e) => {
|
|
1033
|
+
await hooks["tool.execute.before"]({ tool: e.tool }, { args: e.input || {} });
|
|
1034
|
+
});
|
|
1035
|
+
await ctx.tool.hook("execute.after", async (e) => {
|
|
1036
|
+
if (e.status !== "completed") return;
|
|
1037
|
+
const text = v2ResultText(e.result);
|
|
1038
|
+
const out = { output: text, metadata: {} };
|
|
1039
|
+
await hooks["tool.execute.after"]({ tool: e.tool, args: e.input || {} }, out);
|
|
1040
|
+
if (text !== null && typeof out.output === "string" && out.output !== text) {
|
|
1041
|
+
e.result.content[0].text = out.output;
|
|
1042
|
+
}
|
|
1043
|
+
// 2.x emits no file.edited event (observed on 2.0.27), so derive it from the edit tools: the
|
|
1044
|
+
// only consumer is the .planning/config.json reload hook.
|
|
1045
|
+
const claudeTool = mapToolName(e.tool);
|
|
1046
|
+
if (claudeTool === "Write" || claudeTool === "Edit" || claudeTool === "MultiEdit") {
|
|
1047
|
+
const edited = mapToolInput(e.input || {}).file_path;
|
|
1048
|
+
if (typeof edited === "string" && edited.endsWith("config.json")) {
|
|
1049
|
+
await hooks.event({
|
|
1050
|
+
event: { type: "file.edited", properties: { file: edited, cwd: path.dirname(path.dirname(edited)) } },
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
if (ctx.session && typeof ctx.session.hook === "function") {
|
|
1056
|
+
// 2.x compaction event: { sessionID, system: [{ type: "text", text }], messages, … }; items added
|
|
1057
|
+
// to `system` reach the summarizer (observed on 2.0.27).
|
|
1058
|
+
// gsd:opencode-parity: SessionStart orientation reaches the model through the 2.x context hook.
|
|
1059
|
+
await ctx.session.hook("context", async (e) => {
|
|
1060
|
+
if (!e || !Array.isArray(e.system)) return;
|
|
1061
|
+
const out = { system: [] };
|
|
1062
|
+
await hooks["experimental.chat.system.transform"]({}, out);
|
|
1063
|
+
for (const line of out.system) e.system.push({ type: "text", text: String(line) });
|
|
1064
|
+
});
|
|
1065
|
+
await ctx.session.hook("compaction", async (e) => {
|
|
1066
|
+
if (!e || !Array.isArray(e.system)) return;
|
|
1067
|
+
const out = { context: [] };
|
|
1068
|
+
await hooks["experimental.session.compacting"]({}, out);
|
|
1069
|
+
for (const line of out.context) e.system.push({ type: "text", text: String(line) });
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
if (ctx.shell && typeof ctx.shell.hook === "function") {
|
|
1073
|
+
await ctx.shell.hook("create.before", async (e) => {
|
|
1074
|
+
if (e && e.env && typeof e.env === "object") e.env.GSD_DIR = GSD_CORE;
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
let stop = null;
|
|
1078
|
+
const seenSessions = new Set();
|
|
1079
|
+
if (ctx.event && typeof ctx.event.subscribe === "function") {
|
|
1080
|
+
const ac = new AbortController();
|
|
1081
|
+
stop = () => ac.abort();
|
|
1082
|
+
(async () => {
|
|
1083
|
+
for await (const ev of ctx.event.subscribe({ signal: ac.signal })) {
|
|
1084
|
+
// 2.0.27 shape (observed): { type, location: { directory }, data: { sessionID, … } }.
|
|
1085
|
+
const d = (ev && ev.data) || {};
|
|
1086
|
+
const dir = (ev && ev.location && ev.location.directory) || (d.location && d.location.directory);
|
|
1087
|
+
try {
|
|
1088
|
+
// A 2.x `run` never emits `session.created` (observed on 2.0.27: the first event of a session is
|
|
1089
|
+
// `session.inbox.enqueued`). The first event that names a session is its SessionStart.
|
|
1090
|
+
if (ev.type !== "session.created" && typeof d.sessionID === "string" && !seenSessions.has(d.sessionID)) {
|
|
1091
|
+
seenSessions.add(d.sessionID);
|
|
1092
|
+
await hooks.event({
|
|
1093
|
+
event: { type: "session.created", properties: { info: { id: d.sessionID, directory: dir } }, sessionID: d.sessionID },
|
|
1094
|
+
});
|
|
1095
|
+
} else if (ev.type === "session.created" && typeof d.sessionID === "string") {
|
|
1096
|
+
seenSessions.add(d.sessionID);
|
|
1097
|
+
}
|
|
1098
|
+
await hooks.event({
|
|
1099
|
+
event: {
|
|
1100
|
+
type: ev.type,
|
|
1101
|
+
properties: { info: { id: d.sessionID, directory: dir }, file: d.file, cwd: dir },
|
|
1102
|
+
sessionID: d.sessionID,
|
|
1103
|
+
},
|
|
1104
|
+
});
|
|
1105
|
+
} catch {
|
|
1106
|
+
// one bad event must not end the subscription
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
})().catch(() => {});
|
|
1110
|
+
}
|
|
1111
|
+
return stop || undefined;
|
|
1112
|
+
}
|
|
1113
|
+
// <<< gsd:opencode-v2
|
|
787
1114
|
const gsdCorePluginExport = { server: GsdCorePlugin };
|
|
1115
|
+
// >>> gsd:opencode-v2
|
|
1116
|
+
Object.defineProperty(gsdCorePluginExport, "setup", { value: setupV2, enumerable: false });
|
|
1117
|
+
// <<< gsd:opencode-v2
|
|
788
1118
|
Object.defineProperty(gsdCorePluginExport, "id", {
|
|
789
1119
|
value: "gsd-core",
|
|
790
1120
|
enumerable: false,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// GSD statusline and update banner for the OpenCode 2.x terminal client (ADR-5331 Phase 3).
|
|
2
|
+
//
|
|
3
|
+
// A CLI plugin (https://opencode.ai/v2/docs/build/plugins/cli): OpenCode 2.x loads `tui.tsx` from a
|
|
4
|
+
// directory under plugins/ and renders the slots registered here. The line itself comes from GSD's own
|
|
5
|
+
// hooks/gsd-statusline.js — the script Claude Code runs — so state, progress, git and update-available
|
|
6
|
+
// output stay one implementation. OpenCode 1.x never loads this directory (it scans plugins/*.js|ts only).
|
|
7
|
+
import { Plugin } from "@opencode/plugin/tui"
|
|
8
|
+
import { execFile } from "node:child_process"
|
|
9
|
+
import { existsSync } from "node:fs"
|
|
10
|
+
import path from "node:path"
|
|
11
|
+
import { fileURLToPath } from "node:url"
|
|
12
|
+
|
|
13
|
+
const REFRESH_MS = 10_000
|
|
14
|
+
// Strip terminal colour codes: the host styles its own footer.
|
|
15
|
+
const ANSI = /\u001b\[[0-9;?]*[ -/]*[@-~]/g
|
|
16
|
+
|
|
17
|
+
function hooksDir() {
|
|
18
|
+
// <config>/plugins/gsd-statusline/tui.tsx → <config>/hooks
|
|
19
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "hooks")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function runtime() {
|
|
23
|
+
return process.env.GSD_HOOK_RUNTIME || "node"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function render(directory: string, model: string, done: (line: string) => void) {
|
|
27
|
+
const script = path.join(hooksDir(), "gsd-statusline.js")
|
|
28
|
+
// Only inside a GSD project, and only when the script is installed.
|
|
29
|
+
if (!existsSync(script) || !existsSync(path.join(directory, ".planning"))) return done("")
|
|
30
|
+
const child = execFile(runtime(), [script], { cwd: directory, timeout: 4000, windowsHide: true }, (error, stdout) => {
|
|
31
|
+
done(error ? "" : String(stdout).replace(ANSI, "").split("\n")[0].trim())
|
|
32
|
+
})
|
|
33
|
+
child.stdin?.end(JSON.stringify({ model: { display_name: model }, workspace: { current_dir: directory } }))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default Plugin.define({
|
|
37
|
+
id: "gsd.statusline",
|
|
38
|
+
setup(context) {
|
|
39
|
+
const directory = context.location?.directory ?? context.data.location.default().directory
|
|
40
|
+
const [state, update] = context.storage.memory("line", { initial: { text: "" } })
|
|
41
|
+
const refresh = () => {
|
|
42
|
+
const selected = context.ui.model.current()
|
|
43
|
+
render(directory, selected?.modelID || "OpenCode", (text) => update((draft: { text: string }) => { draft.text = text }))
|
|
44
|
+
}
|
|
45
|
+
refresh()
|
|
46
|
+
const timer = setInterval(refresh, REFRESH_MS)
|
|
47
|
+
const stopHome = context.ui.slot({ append: "home.footer.status", render: () => <text>{state.text}</text> })
|
|
48
|
+
const stopPrompt = context.ui.slot({ append: "prompt.footer.status", render: () => <text>{state.text}</text> })
|
|
49
|
+
return () => {
|
|
50
|
+
clearInterval(timer)
|
|
51
|
+
stopHome?.()
|
|
52
|
+
stopPrompt?.()
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
})
|
package/GEMINI.md
CHANGED
|
@@ -25,7 +25,7 @@ files rather than in the conversation.
|
|
|
25
25
|
> run the dedicated installer:
|
|
26
26
|
>
|
|
27
27
|
> ```bash
|
|
28
|
-
> npx gsd-core --antigravity --global
|
|
28
|
+
> npx @opengsd/gsd-core@latest --antigravity --global
|
|
29
29
|
> ```
|
|
30
30
|
>
|
|
31
31
|
> The commands below are available only once that installer has run.
|
|
@@ -287,7 +287,7 @@ For each finding in sorted order:
|
|
|
287
287
|
**f. Commit atomically.** If verification passed, use `gsd_run query commit` (message first, then every staged file path):
|
|
288
288
|
|
|
289
289
|
```bash
|
|
290
|
-
_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() {
|
|
290
|
+
_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
|
|
291
291
|
gsd_run query commit \
|
|
292
292
|
"fix({padded_phase}): {finding_id} {short_description}" \
|
|
293
293
|
--files \
|
package/agents/gsd-code-fixer.md
CHANGED
|
@@ -532,7 +532,7 @@ For each finding in sorted order:
|
|
|
532
532
|
|
|
533
533
|
Use `gsd_run query commit` with conventional format (message first, then every staged file path):
|
|
534
534
|
```bash
|
|
535
|
-
_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() {
|
|
535
|
+
_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
|
|
536
536
|
gsd_run query commit \
|
|
537
537
|
"fix({padded_phase}): {finding_id} {short_description}" \
|
|
538
538
|
--files \
|
|
@@ -84,12 +84,14 @@ files:
|
|
|
84
84
|
```
|
|
85
85
|
Present and non-empty → use directly, skip fallback below.
|
|
86
86
|
|
|
87
|
-
**Fallback (safety net only, when invoked directly without workflow context — `/gsd:code-review` always passes `files`):** if `files` absent/empty,
|
|
87
|
+
**Fallback (safety net only, when invoked directly without workflow context — `/gsd:code-review` always passes `files`):** if `files` absent/empty, ask the evaluation-scope resolver (#5164) for the phase named by `phase_dir`; otherwise **fail closed**: "Cannot determine review scope. Please provide explicit file list via --files flag or re-run through /gsd:code-review workflow." Do NOT invent a heuristic (e.g. HEAD~5) or a `base..HEAD` range — silent mis-scoping is worse than failing loudly.
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
Resolver call (phase number = the leading digits of the `phase_dir` basename; add `--since "$diff_base"` when `diff_base` is provided):
|
|
90
90
|
```bash
|
|
91
|
-
git
|
|
91
|
+
_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
|
|
92
|
+
gsd_run check evaluation-scope --phase "<phase number>" --raw
|
|
92
93
|
```
|
|
94
|
+
Use its `files`. A `status` of `unresolvable` (exit 69, JSON still printed), or empty `files`, is the fail-closed case above; `degraded` is usable but say so in REVIEW.md.
|
|
93
95
|
|
|
94
96
|
**4. Parse structural findings when present:** `<structural_findings>...</structural_findings>` → parse JSON, cache as `STRUCTURAL_FINDINGS`. Include in `## Structural Findings (fallow)` section of REVIEW.md during `write_review` (verbatim if small; concise summary if large). Optional block — absence means no structural pre-pass.
|
|
95
97
|
|
|
@@ -127,16 +127,18 @@ Parse each `- path` line under `files:` into the REVIEW_FILES array. If `files`
|
|
|
127
127
|
|
|
128
128
|
This fallback runs ONLY when invoked directly without workflow context. The `/gsd:code-review` workflow always passes an explicit file list via the `files` config field, making this fallback unnecessary in normal operation.
|
|
129
129
|
|
|
130
|
-
If `files` is absent or empty,
|
|
131
|
-
1.
|
|
132
|
-
2.
|
|
130
|
+
If `files` is absent or empty, ask the evaluation-scope resolver (#5164, ADR-5057 §4) for the phase named by `phase_dir`:
|
|
131
|
+
1. The phase number is the leading digits of the `phase_dir` basename; add `--since "$diff_base"` when `diff_base` is provided in config
|
|
132
|
+
2. If the resolver reports `status: unresolvable` (it exits 69 and still prints its JSON), or returns no `files`, **fail closed** with error: "Cannot determine review scope. Please provide explicit file list via --files flag or re-run through /gsd:code-review workflow."
|
|
133
133
|
|
|
134
|
-
Do NOT invent a heuristic (e.g., HEAD~5) — silent mis-scoping is worse than failing loudly.
|
|
134
|
+
Do NOT invent a heuristic (e.g., HEAD~5) or a `base..HEAD` range — silent mis-scoping is worse than failing loudly.
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
Run:
|
|
137
137
|
```bash
|
|
138
|
-
git
|
|
138
|
+
_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
|
|
139
|
+
gsd_run check evaluation-scope --phase "<phase number>" --raw
|
|
139
140
|
```
|
|
141
|
+
Use its `files` (the union of the phase's own commits' file sets, planning artifacts and lockfiles excluded). A `degraded` status is usable, but say so in REVIEW.md. A `status` of `unresolvable` (exit `69`, JSON still printed) means the scope could not be resolved: an empty `files` then is not a clean review — fail loudly as above.
|
|
140
142
|
|
|
141
143
|
**4. Parse structural findings when present:** If prompt includes:
|
|
142
144
|
```xml
|