A GSD verification gate resolves a project's test command and runs it. vitest defaults to WATCH mode in an interactive TTY — exactly where a user runs `gsd-execute-phase` — so a resolved `npm test`/`pnpm test` backed by vitest never exited and the orchestrator waited indefinitely. Recovery needed the user to manually prompt "something blocking?". Fix — one shared helper + a bounded, surfacing timeout on the test-command gates: - New pure module src/normalize-test-command.cts + `gsd-tools query normalize-test-command` verb: rewrites a resolved command to a best-effort one-shot form (direct vitest → `vitest run`; jest `--watch` → `--watchAll=false`; a package-manager `test` script whose package.json runner is watch-vitest → `CI=true` prefix; handles `--dir`; already-one-shot commands unchanged — never double-flagged). Named `normalize-test-command` (not `test-*`) so the file does not match node --test's default `test-*` discovery glob. - The three gates that HUNG or silently-continued route through that ONE helper and bound execution with `timeout $(config-get workflow.test_gate_timeout)` (new config key, default 600s): the regression gate (extracted to execute-phase/steps/regression-gate.md since execute-phase.md is size-frozen — it shrank 93528→93132; ABORTS on exit 124), the post-merge gate, and the audit-fix gate (previously an UNBOUNDED `eval`). All name watch/dev mode on 124. - verify-phase's gate was ALREADY bounded (a fixed `timeout 300`, not a hang), so it only gains the normalizer (so a watch runner exits fast) + a watch-mode hint on 124, staying under its frozen 40960-byte tier cap. Security hardening (review): the normalizer only rewrites a runner named as a standalone command TOKEN (so `run-vitest.js`/`make test-vitest`/paths are never mangled), is length-capped and uses only linear-time split-based scanning (no super-linear backtracking on an adversarial `workflow.test_command`), and reads package.json only when it is a regular file (never blocks on a FIFO via `--dir`). Config key `workflow.test_gate_timeout` (seconds, default 600) registered in the schema manifest + templates/config.json + docs/CONFIGURATION.md (mirrors workflow.cross_ai_timeout). New module registered in .gitignore, eslint ignores, inventory manifest/index. All 16 golden-install-parity fixtures + workflow size baseline regenerated for the changed shipped files; bin/lib is excluded from the parity manifest. Tests: tests/normalize-test-command.test.cjs (normalizer units incl. security hardening) and tests/test-gate-watch-mode.test.cjs (the three core gates route through the shared helper + configured timeout + exit-124 watch-mode hint; verify-phase asserted as normalize-only/already-bounded). tests/execute-phase-active-flags.test.cjs repointed at the extracted step; tests/planner-language-regression.test.cjs allowlist comment updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
64 lines
1.4 KiB
JSON
64 lines
1.4 KiB
JSON
{
|
|
"mode": "interactive",
|
|
"granularity": "standard",
|
|
"workflow": {
|
|
"research": true,
|
|
"plan_check": true,
|
|
"verifier": true,
|
|
"auto_advance": false,
|
|
"nyquist_validation": true,
|
|
"security_enforcement": true,
|
|
"security_asvs_level": 1,
|
|
"security_block_on": "high",
|
|
"discuss_mode": "discuss",
|
|
"research_before_questions": false,
|
|
"code_review_command": null,
|
|
"plan_bounce": false,
|
|
"plan_bounce_script": null,
|
|
"plan_bounce_passes": 2,
|
|
"cross_ai_execution": false,
|
|
"cross_ai_command": "",
|
|
"cross_ai_timeout": 300,
|
|
"test_gate_timeout": 600
|
|
},
|
|
"ship": {
|
|
"pr_body_sections": []
|
|
},
|
|
"planning": {
|
|
"commit_docs": true,
|
|
"search_gitignored": false,
|
|
"sub_repos": []
|
|
},
|
|
"git": {
|
|
"create_tag": true
|
|
},
|
|
"parallelization": {
|
|
"enabled": true,
|
|
"plan_level": true,
|
|
"task_level": false,
|
|
"skip_checkpoints": true,
|
|
"max_concurrent_agents": 3,
|
|
"min_plans_for_parallel": 2
|
|
},
|
|
"gates": {
|
|
"confirm_project": true,
|
|
"confirm_phases": true,
|
|
"confirm_roadmap": true,
|
|
"confirm_breakdown": true,
|
|
"confirm_plan": true,
|
|
"execute_next_plan": true,
|
|
"issues_review": true,
|
|
"confirm_transition": true
|
|
},
|
|
"safety": {
|
|
"always_confirm_destructive": true,
|
|
"always_confirm_external_services": true
|
|
},
|
|
"hooks": {
|
|
"context_warnings": true
|
|
},
|
|
"project_code": null,
|
|
"agent_skills": {},
|
|
"claude_md_path": "./.claude/CLAUDE.md"
|
|
}
|