fix(#1857): test gates normalize to one-shot + bounded timeout (no watch-mode hang)
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>
This commit is contained in:
5
.changeset/1857-test-gate-watch-mode-timeout.md
Normal file
5
.changeset/1857-test-gate-watch-mode-timeout.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 2060
|
||||
---
|
||||
**Test gates can no longer hang forever on a watch-mode test runner.** vitest defaults to watch mode in an interactive terminal (exactly where `gsd-execute-phase` runs), so a resolved `npm test` / `pnpm test` that maps to vitest never exited and the orchestrator waited indefinitely until the user manually intervened. Every GSD test-command gate — the regression gate, the post-merge gate, the audit-fix gate, and the verify-phase gate — now routes the resolved command through a shared `normalize-test-command` helper that rewrites it to a one-shot form (direct vitest → `vitest run`; jest `--watch` → `--watchAll=false`; a package-manager `test` script backed by watch-vitest → `CI=true` prefix; already-one-shot commands are left unchanged). The three gates that previously hung or silently continued — the regression, post-merge, and audit-fix gates — additionally bound execution with a configurable `workflow.test_gate_timeout` (default 600s), aborting or surfacing the cause on timeout instead of hanging; the verify-phase gate was already bounded (a fixed 5-minute limit) and keeps it, now naming watch mode on timeout. The normalizer only rewrites a runner named as a standalone command token (so paths/targets like `run-vitest.js` are never mangled), is length-capped and linear-time on adversarial input, and only reads a regular-file `package.json`.
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -166,6 +166,7 @@ build/
|
||||
/gsd-core/bin/lib/core-utils.cjs
|
||||
/gsd-core/bin/lib/io.cjs
|
||||
/gsd-core/bin/lib/phase-id.cjs
|
||||
/gsd-core/bin/lib/normalize-test-command.cjs
|
||||
/gsd-core/bin/lib/config-loader.cjs
|
||||
/gsd-core/bin/lib/model-resolver.cjs
|
||||
/gsd-core/bin/lib/loop-resolver.cjs
|
||||
|
||||
@@ -55,6 +55,7 @@ GSD stores project settings in `.planning/config.json`. Created during `/gsd-new
|
||||
"cross_ai_execution": false,
|
||||
"cross_ai_command": null,
|
||||
"cross_ai_timeout": 300,
|
||||
"test_gate_timeout": 600,
|
||||
"security_enforcement": true,
|
||||
"security_asvs_level": 1,
|
||||
"security_block_on": "high",
|
||||
@@ -322,6 +323,7 @@ All workflow toggles follow the **absent = enabled** pattern. If a key is missin
|
||||
| `workflow.cross_ai_execution` | boolean | `false` | Delegate phase execution to an external AI CLI instead of spawning local executor agents. Useful for leveraging a different model's strengths for specific phases. Added in v1.36 |
|
||||
| `workflow.cross_ai_command` | string | (none) | Shell command template for cross-AI execution. Receives the phase prompt via stdin. Must produce SUMMARY.md-compatible output. Required when `cross_ai_execution` is `true`. Added in v1.36 |
|
||||
| `workflow.cross_ai_timeout` | number | `300` | Timeout in seconds for cross-AI execution commands. Prevents runaway external processes. Added in v1.36 |
|
||||
| `workflow.test_gate_timeout` | number | `600` | Wall-clock timeout (seconds) for a verification test gate; a watch-mode runner (vitest/jest) that never exits is aborted after this budget instead of hanging the orchestrator (#1857) |
|
||||
| `workflow.ai_integration_phase` | boolean | `true` | Enable the `/gsd-ai-integration-phase` command. When `false`, the command exits with a configuration gate message |
|
||||
| `workflow.auto_prune_state` | boolean | `false` | When `true`, automatically prune stale entries from STATE.md at phase boundaries instead of prompting |
|
||||
| `workflow.pattern_mapper` | boolean | `true` | Run the `gsd-pattern-mapper` agent between research and planning to map new files to existing codebase analogs |
|
||||
|
||||
@@ -373,6 +373,7 @@
|
||||
"model-catalog.cjs",
|
||||
"model-profiles.cjs",
|
||||
"model-resolver.cjs",
|
||||
"normalize-test-command.cjs",
|
||||
"onboard-projection.cjs",
|
||||
"package-identity.cjs",
|
||||
"package-legitimacy.cjs",
|
||||
|
||||
@@ -510,6 +510,7 @@ Full listing: `gsd-core/bin/lib/*.cjs`.
|
||||
| `surface.cjs` | Runtime surface module — manages the runtime enable/disable surface state independently of the install-time profile marker (ADR-0011 Phase 2) |
|
||||
| `task-command-router.cjs` | Thin CJS subcommand router adapter for `gsd-tools task` |
|
||||
| `template.cjs` | Template selection and filling with variable substitution |
|
||||
| `normalize-test-command.cjs` | Normalizes a resolved test command to a one-shot form so a watch-mode runner (vitest/jest) cannot hang a verification gate (#1857); shared by all four test-command gates (regression, post-merge, audit-fix, verify-phase) |
|
||||
| `uat.cjs` | UAT file parsing, verification debt tracking, audit-uat support |
|
||||
| `uat-predicate.cjs` | UAT-passed predicate — markdown-aware evaluation of HUMAN-UAT results; returns pass only when all required checks pass; ignores false-positive contexts (frontmatter, fenced code, blockquotes, HTML comments) |
|
||||
| `ui-safety-gate.cjs` | Shell-free word-boundary UI token detector (#3706, #3718); reads phase-section text from stdin, exits 0 (UI found) or 1 (no UI); also deployed to `gsd-core/bin/lib/` so the GSD installer ships it to `$RUNTIME_DIR` (#448) |
|
||||
|
||||
@@ -149,6 +149,7 @@ export default tseslint.config(
|
||||
'gsd-core/bin/lib/core-utils.cjs',
|
||||
'gsd-core/bin/lib/io.cjs',
|
||||
'gsd-core/bin/lib/phase-id.cjs',
|
||||
'gsd-core/bin/lib/normalize-test-command.cjs',
|
||||
'gsd-core/bin/lib/config-loader.cjs',
|
||||
'gsd-core/bin/lib/phase-locator.cjs',
|
||||
'gsd-core/bin/lib/roadmap-parser.cjs',
|
||||
|
||||
@@ -688,7 +688,7 @@ async function main() {
|
||||
// phase / roadmap / milestone / progress / etc.
|
||||
const TOP_LEVEL_USAGE = 'Usage: gsd-tools <command> [args] [--raw] [--pick <field>] [--cwd <path>] [--ws <name>] [--json-errors]\n' +
|
||||
'Commands: agent, agent-skills, assumption-delta, audit-open, audit-uat, check, check-commit, commit, commit-to-subrepo, pr-subrepo, ' +
|
||||
'config-ensure-section, config-get, config-new-project, config-path, config-set, migrate-config, ' +
|
||||
'config-ensure-section, config-get, config-new-project, config-path, config-set, migrate-config, normalize-test-command, ' +
|
||||
'current-timestamp, detect-custom-files, docs-init, drift-guard, effort, extract-messages, find-phase, ' +
|
||||
'from-gsd2, frontmatter, gap-analysis, generate-claude-md, generate-claude-profile, ' +
|
||||
'generate-dev-preferences, generate-slug, graphify, history-digest, init, intel, ' +
|
||||
@@ -1291,6 +1291,16 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
||||
break;
|
||||
}
|
||||
|
||||
case 'normalize-test-command': {
|
||||
// #1857: rewrite a resolved test command to a one-shot form so a
|
||||
// watch-mode runner (vitest/jest) cannot hang a verification gate. Shared
|
||||
// by the regression gate and the post-merge gate. args[1] is the raw
|
||||
// resolved command; --cwd (already parsed into `cwd`) locates package.json.
|
||||
const testCommandNormalizer = require('./lib/normalize-test-command.cjs');
|
||||
testCommandNormalizer.cmdNormalizeTestCommand(cwd, args[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'dispatch-should-flatten': {
|
||||
// #1708 / #853: typed query replacing the `RUNTIME === 'codex'` prose rule.
|
||||
//
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"workflow.cross_ai_command",
|
||||
"workflow.cross_ai_timeout",
|
||||
"workflow.subagent_timeout",
|
||||
"workflow.test_gate_timeout",
|
||||
"workflow.test_command",
|
||||
"workflow.build_command",
|
||||
"workflow.mvp_mode",
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"plan_bounce_passes": 2,
|
||||
"cross_ai_execution": false,
|
||||
"cross_ai_command": "",
|
||||
"cross_ai_timeout": 300
|
||||
"cross_ai_timeout": 300,
|
||||
"test_gate_timeout": 600
|
||||
},
|
||||
"ship": {
|
||||
"pr_body_sections": []
|
||||
|
||||
@@ -124,7 +124,15 @@ if [ -z "$AUDIT_TEST_CMD" ]; then
|
||||
AUDIT_TEST_CMD="true"
|
||||
fi
|
||||
fi
|
||||
eval "$AUDIT_TEST_CMD" 2>&1 | tail -20
|
||||
# #1857: normalize to one-shot (defeat vitest/jest watch mode) + bound with a
|
||||
# timeout so a watch-mode runner cannot hang the audit gate indefinitely.
|
||||
AUDIT_TEST_CMD=$(gsd_run query normalize-test-command "$AUDIT_TEST_CMD" --cwd . 2>/dev/null || echo "$AUDIT_TEST_CMD")
|
||||
TEST_GATE_TIMEOUT=$(gsd_run query config-get workflow.test_gate_timeout 2>/dev/null || echo "600")
|
||||
timeout "$TEST_GATE_TIMEOUT" bash -c "$AUDIT_TEST_CMD" 2>&1 | tail -20
|
||||
AUDIT_TEST_EXIT=${PIPESTATUS[0]}
|
||||
if [ "$AUDIT_TEST_EXIT" -eq 124 ]; then
|
||||
echo "✗ Audit test gate timed out after ${TEST_GATE_TIMEOUT}s — likely stuck in watch/dev mode (e.g. vitest without 'run'). Run tests one-shot (e.g. 'vitest run') or raise workflow.test_gate_timeout."
|
||||
fi
|
||||
```
|
||||
|
||||
**c. If tests pass** — commit atomically:
|
||||
|
||||
@@ -1289,31 +1289,7 @@ For each VERIFICATION.md found, look for test file references:
|
||||
|
||||
Collect all unique test file paths into `REGRESSION_FILES`.
|
||||
|
||||
**Step 3: Run regression tests (if any found)**
|
||||
|
||||
```bash
|
||||
# Resolve test command: project config > Makefile > language sniff
|
||||
REG_TEST_CMD=$(gsd_run query config-get workflow.test_command --default "" 2>/dev/null || true)
|
||||
if [ -z "$REG_TEST_CMD" ]; then
|
||||
if [ -f "Makefile" ] && grep -q "^test:" Makefile; then
|
||||
REG_TEST_CMD="make test"
|
||||
elif [ -f "Justfile" ] || [ -f "justfile" ]; then
|
||||
REG_TEST_CMD="just test"
|
||||
elif [ -f "package.json" ]; then
|
||||
REG_TEST_CMD="npm test"
|
||||
elif [ -f "Cargo.toml" ]; then
|
||||
REG_TEST_CMD="cargo test"
|
||||
elif [ -f "go.mod" ]; then
|
||||
REG_TEST_CMD="go test ./..."
|
||||
elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
|
||||
REG_TEST_CMD="python -m pytest ${REGRESSION_FILES} -q --tb=short"
|
||||
else
|
||||
REG_TEST_CMD="true"
|
||||
fi
|
||||
fi
|
||||
# Detect test runner and run prior phase tests
|
||||
eval "$REG_TEST_CMD" 2>&1
|
||||
```
|
||||
**Step 3: Run regression tests (if any found)** — Read and execute `gsd-core/workflows/execute-phase/steps/regression-gate.md`. It resolves the project test command, normalizes it to a one-shot form (defeating vitest/jest watch mode via the shared `normalize-test-command` helper), runs it under `workflow.test_gate_timeout`, and aborts on timeout with a watch-mode hint (#1857). On `REGRESSION GATE ABORTED` (exit 124), HALT — do not proceed to verification.
|
||||
|
||||
**Step 4: Report results**
|
||||
|
||||
|
||||
@@ -94,14 +94,18 @@ if [ -z "$TEST_CMD" ]; then
|
||||
echo "⚠ No test runner detected — skipping post-merge test gate"
|
||||
fi
|
||||
fi
|
||||
# Run test suite with 5-minute timeout
|
||||
# #1857: normalize to a one-shot form (defeat vitest/jest watch mode) via the
|
||||
# same shared normalize-test-command helper the regression gate uses, then bound
|
||||
# with the configured timeout so a watch-mode runner cannot hang the gate.
|
||||
TEST_CMD=$(gsd_run query normalize-test-command "$TEST_CMD" --cwd . 2>/dev/null || echo "$TEST_CMD")
|
||||
TEST_GATE_TIMEOUT=$(gsd_run query config-get workflow.test_gate_timeout 2>/dev/null || echo "600")
|
||||
TEST_EXIT=0
|
||||
timeout 300 bash -c "$TEST_CMD" 2>&1
|
||||
timeout "$TEST_GATE_TIMEOUT" bash -c "$TEST_CMD" 2>&1
|
||||
TEST_EXIT=$?
|
||||
if [ "${TEST_EXIT}" -eq 0 ]; then
|
||||
echo "✓ Post-merge test gate passed — no cross-plan conflicts"
|
||||
elif [ "${TEST_EXIT}" -eq 124 ]; then
|
||||
echo "⚠ Post-merge test gate timed out after 5 minutes"
|
||||
echo "⚠ POST-MERGE TEST GATE TIMED OUT after ${TEST_GATE_TIMEOUT}s — the runner did not exit, likely stuck in watch/dev mode (e.g. vitest without 'run'). Verify tests with a one-shot command (e.g. 'vitest run') or raise workflow.test_gate_timeout."
|
||||
else
|
||||
echo "✗ Post-merge test gate failed (exit code ${TEST_EXIT})"
|
||||
WAVE_FAILURE_COUNT=$((WAVE_FAILURE_COUNT + 1))
|
||||
@@ -110,7 +114,7 @@ fi
|
||||
|
||||
**If `TEST_EXIT` is 0 (pass):** `✓ Post-merge test gate: {N} tests passed — no cross-plan conflicts` → continue to orchestrator tracking update.
|
||||
|
||||
**If `TEST_EXIT` is 124 (timeout):** Log warning, treat as non-blocking, continue. Tests may need a longer budget or manual run.
|
||||
**If `TEST_EXIT` is 124 (timeout):** The runner did not exit within the budget — surface the printed message clearly (watch/dev mode is the likely cause; #1857). Treated as non-blocking (a genuinely long suite may just need a larger `workflow.test_gate_timeout`), but it is NEVER silently ignored — the watch-mode cause is named so the user can fix it (one-shot command / `workflow.test_command` / larger timeout).
|
||||
|
||||
**If `TEST_EXIT` is non-zero (test failure):** Increment `WAVE_FAILURE_COUNT` to track
|
||||
cumulative failures across waves. Subsequent waves should report:
|
||||
|
||||
42
gsd-core/workflows/execute-phase/steps/regression-gate.md
Normal file
42
gsd-core/workflows/execute-phase/steps/regression-gate.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Step: regression_gate_run
|
||||
|
||||
Run the resolved prior-phase test command one-shot, bounded by a timeout, so a
|
||||
watch-mode runner (vitest defaults to watch in a TTY; jest `--watch`) cannot
|
||||
hang this gate forever (#1857). Uses the shared `normalize-test-command` helper
|
||||
— the same one the post-merge gate uses — so the two gate paths cannot drift.
|
||||
|
||||
Expects `REGRESSION_FILES` (from the prior step) in scope for the pytest branch.
|
||||
|
||||
```bash
|
||||
_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}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; 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
|
||||
# Resolve test command: project config > Makefile > language sniff
|
||||
REG_TEST_CMD=$(gsd_run query config-get workflow.test_command --default "" 2>/dev/null || true)
|
||||
if [ -z "$REG_TEST_CMD" ]; then
|
||||
if [ -f "Makefile" ] && grep -q "^test:" Makefile; then
|
||||
REG_TEST_CMD="make test"
|
||||
elif [ -f "Justfile" ] || [ -f "justfile" ]; then
|
||||
REG_TEST_CMD="just test"
|
||||
elif [ -f "package.json" ]; then
|
||||
REG_TEST_CMD="npm test"
|
||||
elif [ -f "Cargo.toml" ]; then
|
||||
REG_TEST_CMD="cargo test"
|
||||
elif [ -f "go.mod" ]; then
|
||||
REG_TEST_CMD="go test ./..."
|
||||
elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
|
||||
REG_TEST_CMD="python -m pytest ${REGRESSION_FILES} -q --tb=short"
|
||||
else
|
||||
REG_TEST_CMD="true"
|
||||
fi
|
||||
fi
|
||||
# #1857: normalize to a one-shot form (defeat vitest/jest watch mode) and bound
|
||||
# with a timeout so a watch-mode runner cannot hang the gate indefinitely.
|
||||
REG_TEST_CMD=$(gsd_run query normalize-test-command "$REG_TEST_CMD" --cwd . 2>/dev/null || echo "$REG_TEST_CMD")
|
||||
TEST_GATE_TIMEOUT=$(gsd_run query config-get workflow.test_gate_timeout 2>/dev/null || echo "600")
|
||||
timeout "$TEST_GATE_TIMEOUT" bash -c "$REG_TEST_CMD" 2>&1
|
||||
REG_TEST_EXIT=$?
|
||||
if [ "$REG_TEST_EXIT" -eq 124 ]; then
|
||||
echo "✗ REGRESSION GATE ABORTED — test runner did not exit within ${TEST_GATE_TIMEOUT}s, likely stuck in watch/dev mode (e.g. vitest without 'run'). Run tests one-shot (e.g. 'vitest run'), set workflow.test_command, or raise workflow.test_gate_timeout."
|
||||
fi
|
||||
```
|
||||
|
||||
**On `REG_TEST_EXIT` 124 (`REGRESSION GATE ABORTED`):** HALT — do not proceed to verification. The runner did not exit within the budget (watch/dev mode is the likely cause). Surface the watch-mode cause and the recovery options; never silently continue.
|
||||
@@ -288,14 +288,15 @@ if [ -z "$TEST_CMD" ]; then
|
||||
echo "⚠ No test runner detected — skipping test suite"
|
||||
fi
|
||||
fi
|
||||
# Detect test runner and run all tests (timeout: 5 minutes)
|
||||
# Run all tests (timeout: 5 min). #1857: normalize to one-shot so watch mode exits.
|
||||
TEST_CMD=$(gsd_run query normalize-test-command "$TEST_CMD" --cwd . 2>/dev/null || echo "$TEST_CMD")
|
||||
TEST_EXIT=0
|
||||
timeout 300 bash -c "$TEST_CMD" 2>&1
|
||||
TEST_EXIT=$?
|
||||
if [ "${TEST_EXIT}" -eq 0 ]; then
|
||||
echo "✓ Test suite passed"
|
||||
elif [ "${TEST_EXIT}" -eq 124 ]; then
|
||||
echo "⚠ Test suite timed out after 5 minutes"
|
||||
echo "⚠ Test suite timed out after 5 minutes — likely watch/dev mode"
|
||||
else
|
||||
echo "✗ Test suite failed (exit code ${TEST_EXIT})"
|
||||
fi
|
||||
|
||||
198
src/normalize-test-command.cts
Normal file
198
src/normalize-test-command.cts
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Test-command normalizer (#1857).
|
||||
*
|
||||
* A GSD verification gate resolves a project's test command and runs it. When
|
||||
* that command is a watch/dev-mode runner (vitest defaults to WATCH in an
|
||||
* interactive TTY — which is exactly a user running `gsd-execute-phase` in their
|
||||
* terminal — and jest with `--watch`/`--watchAll`), the process never exits and
|
||||
* the orchestrator waits forever.
|
||||
*
|
||||
* `normalizeTestCommand` rewrites a resolved command to a best-effort one-shot
|
||||
* form so a gate cannot hang on watch mode. It is intentionally conservative:
|
||||
* - it NEVER double-adds flags (already-one-shot commands are returned verbatim),
|
||||
* - it only touches commands it positively recognises as a watch runner,
|
||||
* - anything it cannot classify is returned unchanged.
|
||||
* The gate's wall-clock `timeout` is the ultimate guarantee for anything this
|
||||
* best-effort pass cannot defeat (e.g. an explicit `--watch` baked into a
|
||||
* project's `test` script, which even `CI=1` cannot override per vitest docs).
|
||||
*
|
||||
* Bounded by design (#1857 security review): the input is length-capped, all
|
||||
* scanning is linear-time (no super-linear regex backtracking), and package.json
|
||||
* is only read when it is a regular file — so normalization itself can never
|
||||
* hang or take super-linear time on an adversarial `workflow.test_command`.
|
||||
*
|
||||
* Single source of truth: all four test-command gates (regression, post-merge,
|
||||
* audit-fix, verify-phase) route their resolved command through this helper so
|
||||
* the paths cannot drift.
|
||||
*
|
||||
* Leaf module — depends only on node:fs / node:path.
|
||||
*/
|
||||
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
// A resolved test command is never realistically this long; anything larger is
|
||||
// not a real runner invocation. We skip normalization above this bound (the
|
||||
// gate's own timeout still bounds the actual run) so no regex ever scans an
|
||||
// adversarial multi-KB string.
|
||||
const MAX_COMMAND_LENGTH = 4096;
|
||||
|
||||
// Markers proving a command is already one-shot / non-watch. If any is present
|
||||
// we return the command unchanged so we never double-add flags or fight an
|
||||
// explicit user choice.
|
||||
const ONE_SHOT_MARKERS: RegExp[] = [
|
||||
/(?:^|\s)vitest\s+run\b/, // vitest run …
|
||||
/(?:^|\s)--run\b/, // vitest --run
|
||||
/(?:^|\s)--no-watch\b/, // vitest --no-watch
|
||||
/(?:^|\s)--watchAll=false\b/, // jest --watchAll=false
|
||||
/(?:^|\s)--watch=false\b/,
|
||||
/(?:^|\s)--ci\b/, // jest --ci
|
||||
/^\s*CI=/, // already forced into CI/run mode via env
|
||||
];
|
||||
|
||||
/** True if the command already runs one-shot (so normalization is a no-op). */
|
||||
function isAlreadyOneShot(cmd: string): boolean {
|
||||
return ONE_SHOT_MARKERS.some((re) => re.test(cmd));
|
||||
}
|
||||
|
||||
// Match a runner as a standalone command TOKEN (whitespace-delimited), NOT as a
|
||||
// substring — so "vitest.config.js" / "jest-environment" / "node vitest-x.js"
|
||||
// are not treated as the runner and are never mangled.
|
||||
const VITEST_TOKEN = /(?:^|\s)vitest(?=\s|$)/;
|
||||
const JEST_TOKEN = /(?:^|\s)jest(?=\s|$)/;
|
||||
|
||||
/**
|
||||
* Linear-time detection of a package-manager `test` script invocation
|
||||
* (`npm test`, `pnpm run test`, `pnpm --dir app test`, `yarn test`, …). We split
|
||||
* on shell separators FIRST (linear), then test each bounded segment with simple
|
||||
* anchored regexes — no tempered-greedy scan, so no super-linear backtracking on
|
||||
* adversarial input.
|
||||
*/
|
||||
function isScriptInvocation(cmd: string): boolean {
|
||||
return cmd.split(/&&|\|\||;/).some((seg) => {
|
||||
const s = seg.trim();
|
||||
return /^(?:npm|pnpm|yarn|bun)\b/.test(s) && /\btest\b/.test(s);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the package.json directory for a command that may target a different
|
||||
* working dir via `--dir <p>` (pnpm), `-C <p>` (pnpm), or `--prefix <p>` (npm).
|
||||
*/
|
||||
function resolvePackageDir(cmd: string, cwd: string): string {
|
||||
const m = cmd.match(/(?:--dir|--prefix|-C)[=\s]+(\S+)/);
|
||||
if (m && m[1]) {
|
||||
const p = m[1].replace(/^['"]|['"]$/g, '');
|
||||
return path.isAbsolute(p) ? p : path.join(cwd, p);
|
||||
}
|
||||
return cwd;
|
||||
}
|
||||
|
||||
type WatchRunner = 'vitest' | 'jest' | null;
|
||||
|
||||
/**
|
||||
* Inspect package.json `scripts.test` for the given command's target dir and
|
||||
* report whether it resolves to a watch-by-default / explicitly-watching runner.
|
||||
* Only ever reads `scripts.test` as a STRING for classification — it is never
|
||||
* executed or spliced into the output.
|
||||
*/
|
||||
function scriptTestRunner(cmd: string, cwd: string): WatchRunner {
|
||||
try {
|
||||
const pkgPath = path.join(resolvePackageDir(cmd, cwd), 'package.json');
|
||||
// Only read a REGULAR file — never block on a FIFO/socket/dir named
|
||||
// "package.json" reachable via --dir (#1857 security review).
|
||||
let stat: fs.Stats;
|
||||
try {
|
||||
stat = fs.statSync(pkgPath);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
if (!stat.isFile()) return null;
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as {
|
||||
scripts?: Record<string, string>;
|
||||
};
|
||||
const testScript = pkg.scripts?.test ?? '';
|
||||
if (!testScript) return null;
|
||||
// vitest watches by default unless the script itself is already one-shot.
|
||||
if (VITEST_TOKEN.test(testScript) && !isAlreadyOneShot(testScript)) return 'vitest';
|
||||
// jest only watches when explicitly asked to.
|
||||
if (
|
||||
JEST_TOKEN.test(testScript) &&
|
||||
/(?:^|\s)--watch(?:All)?\b/.test(testScript) &&
|
||||
!/--watch(?:All)?=false\b/.test(testScript)
|
||||
) {
|
||||
return 'jest';
|
||||
}
|
||||
return null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Strip a bare/explicit-true `--watch` / `--watchAll` (never `=false`). */
|
||||
function stripWatchFlags(cmd: string): string {
|
||||
return cmd
|
||||
.replace(/(?:^|\s)--watch(?:All)?(?:=true)?(?=\s|$)/g, ' ')
|
||||
.replace(/\s{2,}/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a resolved test command to a best-effort one-shot form.
|
||||
*
|
||||
* @param rawCmd The resolved test command (e.g. from `config-get
|
||||
* workflow.test_command` or the gate's runner sniff).
|
||||
* @param cwd Directory used to locate package.json for script invocations.
|
||||
* @returns A one-shot command, or `rawCmd` unchanged when it is already
|
||||
* one-shot / not a recognised watch runner / too long to be a real runner.
|
||||
*/
|
||||
function normalizeTestCommand(rawCmd: string, cwd: string): string {
|
||||
const cmd = (rawCmd ?? '').trim();
|
||||
if (!cmd || cmd === 'true') return rawCmd;
|
||||
if (cmd.length > MAX_COMMAND_LENGTH) return rawCmd; // bound all downstream scanning
|
||||
if (isAlreadyOneShot(cmd)) return rawCmd;
|
||||
|
||||
const isScript = isScriptInvocation(cmd);
|
||||
|
||||
// 1. Direct vitest invocation (`vitest`, `npx vitest`, `pnpm exec vitest`, …):
|
||||
// force the explicit one-shot `run` command and drop any bare --watch.
|
||||
if (VITEST_TOKEN.test(cmd) && !isScript) {
|
||||
return stripWatchFlags(cmd).replace(/(^|\s)vitest(?=\s|$)/, '$1vitest run');
|
||||
}
|
||||
|
||||
// 2. Direct jest invocation with an explicit watch flag: make it one-shot.
|
||||
if (JEST_TOKEN.test(cmd) && !isScript) {
|
||||
if (/(?:^|\s)--watch(?:All)?\b/.test(cmd)) {
|
||||
return `${stripWatchFlags(cmd)} --watchAll=false`;
|
||||
}
|
||||
return rawCmd; // jest without --watch already runs once
|
||||
}
|
||||
|
||||
// 3. Package-manager `test` script invocation: the runner is inside
|
||||
// package.json. If it resolves to a watch runner, force CI/run mode via
|
||||
// the CI env — robust across --dir and pnpm/yarn `--` propagation quirks
|
||||
// (vitest & jest both switch to run/non-interactive mode when CI is set).
|
||||
if (isScript) {
|
||||
const runner = scriptTestRunner(cmd, cwd);
|
||||
if (runner === 'vitest' || runner === 'jest') {
|
||||
return `CI=true ${cmd}`;
|
||||
}
|
||||
return rawCmd;
|
||||
}
|
||||
|
||||
return rawCmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* CLI handler for `gsd-tools query normalize-test-command <raw-cmd>`: prints the
|
||||
* normalized one-shot command to stdout (the gates capture it via `$(…)`).
|
||||
*/
|
||||
function cmdNormalizeTestCommand(cwd: string, rawCmd: string | undefined): void {
|
||||
process.stdout.write(normalizeTestCommand(rawCmd ?? '', cwd));
|
||||
}
|
||||
|
||||
export = {
|
||||
normalizeTestCommand,
|
||||
cmdNormalizeTestCommand,
|
||||
isAlreadyOneShot,
|
||||
};
|
||||
@@ -97,6 +97,9 @@ const path = require('path');
|
||||
const EXECUTE_PHASE_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'execute-phase.md');
|
||||
const VERIFY_PHASE_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-phase.md');
|
||||
const AUDIT_FIX_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'audit-fix.md');
|
||||
// #1857: execute-phase's regression-gate test-command resolution was extracted
|
||||
// to this step file (execute-phase.md is size-frozen — phase-6 capstone).
|
||||
const REGRESSION_GATE_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'execute-phase', 'steps', 'regression-gate.md');
|
||||
|
||||
function assertMakefileCheckBeforeNpmTest(filePath, label) {
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
@@ -166,8 +169,8 @@ describe('bug-2396: Makefile test target must take priority over hardcoded comma
|
||||
assert.ok(fs.existsSync(AUDIT_FIX_PATH), 'audit-fix.md should exist');
|
||||
});
|
||||
|
||||
test('execute-phase.md: Makefile check precedes npm test (post-merge gate)', () => {
|
||||
assertMakefileCheckBeforeNpmTest(EXECUTE_PHASE_PATH, 'execute-phase.md');
|
||||
test('regression-gate step: Makefile check precedes npm test (#1857 — extracted from execute-phase.md)', () => {
|
||||
assertMakefileCheckBeforeNpmTest(REGRESSION_GATE_PATH, 'regression-gate.md');
|
||||
});
|
||||
|
||||
test('verify-phase.md: Makefile check precedes npm test', () => {
|
||||
@@ -178,8 +181,8 @@ describe('bug-2396: Makefile test target must take priority over hardcoded comma
|
||||
assertMakefileCheckBeforeNpmTest(AUDIT_FIX_PATH, 'audit-fix.md');
|
||||
});
|
||||
|
||||
test('execute-phase.md: workflow.test_command config checked first (within bash block)', () => {
|
||||
assertConfigGetBeforeMakefile(EXECUTE_PHASE_PATH, 'execute-phase.md');
|
||||
test('regression-gate step: workflow.test_command config checked first (within bash block) (#1857)', () => {
|
||||
assertConfigGetBeforeMakefile(REGRESSION_GATE_PATH, 'regression-gate.md');
|
||||
});
|
||||
|
||||
test('verify-phase.md: workflow.test_command config checked first (within bash block)', () => {
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "ea841e2865248e74",
|
||||
"gsd-core/bin/gsd-tools.cjs": "b518bc939b3e031e",
|
||||
"gsd-core/bin/gsd-tools.cjs": "e8ccbbe8cefc2e9a",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "8bc541aabc2e143c",
|
||||
@@ -162,7 +162,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "6c505bdf5af338c8",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
|
||||
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -200,7 +200,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "de1ac76acfcc0133",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "22f5466085c47c00",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "44e9b0a78eb79311",
|
||||
"gsd-core/workflows/audit-fix.md": "3ecffffe78021e0a",
|
||||
"gsd-core/workflows/audit-milestone.md": "77089ccd7b45c0f0",
|
||||
"gsd-core/workflows/audit-uat.md": "ea8ddd910ed16ba4",
|
||||
"gsd-core/workflows/autonomous.md": "603ce2019835f00e",
|
||||
@@ -231,10 +231,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "8e986e26d0e6e1a0",
|
||||
"gsd-core/workflows/edit-phase.md": "fc932e82ba1f585a",
|
||||
"gsd-core/workflows/eval-review.md": "eb4040eaa5b8497f",
|
||||
"gsd-core/workflows/execute-phase.md": "97453d3b8f49f27f",
|
||||
"gsd-core/workflows/execute-phase.md": "82beafd82b24210c",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "55d0706e80a2554a",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "687513ef1010180e",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "9b7107b31b60a3b9",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "e0fa99178ae544f0",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "907af77eafc3d97b",
|
||||
"gsd-core/workflows/explore.md": "934c00f9f216dbdb",
|
||||
@@ -306,7 +307,7 @@
|
||||
"gsd-core/workflows/undo.md": "6ab639d1fc7e0721",
|
||||
"gsd-core/workflows/update.md": "2c58df5e21c41c31",
|
||||
"gsd-core/workflows/validate-phase.md": "6c0ab739d15709fa",
|
||||
"gsd-core/workflows/verify-phase.md": "8070a098ab538b33",
|
||||
"gsd-core/workflows/verify-phase.md": "0eefbb6bb1b0bed6",
|
||||
"gsd-core/workflows/verify-work.md": "be699ed7920f61b0",
|
||||
"hooks/gsd-check-update-worker.js": "fa301e6366270d5f",
|
||||
"hooks/gsd-check-update.js": "4617a98bf529e4c3",
|
||||
|
||||
@@ -109,10 +109,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
|
||||
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -233,7 +233,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -271,7 +271,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "cc0efe270004c8fb",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
|
||||
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
|
||||
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
|
||||
"gsd-core/workflows/audit-milestone.md": "6866ce260980c21e",
|
||||
"gsd-core/workflows/audit-uat.md": "fcfbec501620b564",
|
||||
"gsd-core/workflows/autonomous.md": "7e5683728ef33707",
|
||||
@@ -302,10 +302,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "f35922d15b7061c9",
|
||||
"gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04",
|
||||
"gsd-core/workflows/eval-review.md": "f898936e2cfe4130",
|
||||
"gsd-core/workflows/execute-phase.md": "346e443b260e4f38",
|
||||
"gsd-core/workflows/execute-phase.md": "1b2d0b868f574e80",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "4e265392b3f2ba0e",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "2c412310dce31a0b",
|
||||
"gsd-core/workflows/explore.md": "6c04f2e658d93261",
|
||||
@@ -377,7 +378,7 @@
|
||||
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
|
||||
"gsd-core/workflows/update.md": "fd160e13f8b7e83c",
|
||||
"gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa",
|
||||
"gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c",
|
||||
"gsd-core/workflows/verify-phase.md": "22f18492581f1da5",
|
||||
"gsd-core/workflows/verify-work.md": "34e980a6950cd83c",
|
||||
"hooks/gsd-check-update-worker.js": "cc1ef5f840f9dfc9",
|
||||
"hooks/gsd-check-update.js": "7b3a7983d5f1f5d3",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/claude.json
vendored
15
tests/fixtures/golden-install-parity/claude.json
vendored
@@ -37,10 +37,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
|
||||
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -161,7 +161,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -199,7 +199,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "8488f10f56ac24ca",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "a898d99b8d844215",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
|
||||
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
|
||||
"gsd-core/workflows/audit-milestone.md": "23c1e35f449933b8",
|
||||
"gsd-core/workflows/audit-uat.md": "e11db0d74c2a7405",
|
||||
"gsd-core/workflows/autonomous.md": "722397c04272dfaa",
|
||||
@@ -230,10 +230,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "63082608d3ae92be",
|
||||
"gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a",
|
||||
"gsd-core/workflows/eval-review.md": "f59e8329dae1e528",
|
||||
"gsd-core/workflows/execute-phase.md": "4aa452149551956b",
|
||||
"gsd-core/workflows/execute-phase.md": "4aa35e8cb9d68cde",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "facb0e816d87a0c7",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "cce1a33fe9a0a32d",
|
||||
"gsd-core/workflows/explore.md": "b9eea1bac358c9ce",
|
||||
@@ -305,7 +306,7 @@
|
||||
"gsd-core/workflows/undo.md": "791e0bf96d9a057f",
|
||||
"gsd-core/workflows/update.md": "f9e7d8a760d0d3c8",
|
||||
"gsd-core/workflows/validate-phase.md": "2ac231dc541441c2",
|
||||
"gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a",
|
||||
"gsd-core/workflows/verify-phase.md": "e0957e153788a222",
|
||||
"gsd-core/workflows/verify-work.md": "efe57bdbbb3af03f",
|
||||
"hooks/gsd-check-update-worker.js": "a530efdb5fdc0da3",
|
||||
"hooks/gsd-check-update.js": "25cde66a12d6b886",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/cline.json
vendored
15
tests/fixtures/golden-install-parity/cline.json
vendored
@@ -41,10 +41,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "476aa24e8c4f03cf",
|
||||
"gsd-core/bin/gsd-tools.cjs": "3dce0048d7aed8f4",
|
||||
"gsd-core/bin/gsd-tools.cjs": "93273f4eda2750d2",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -165,7 +165,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "988307dc093216d1",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -203,7 +203,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "b71e80304fe484eb",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "5159c6bdf102f74b",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
|
||||
"gsd-core/workflows/audit-fix.md": "47c29d04bab02b27",
|
||||
"gsd-core/workflows/audit-fix.md": "9bb427cd3b4075d5",
|
||||
"gsd-core/workflows/audit-milestone.md": "2266710d0ae48932",
|
||||
"gsd-core/workflows/audit-uat.md": "1fb7b2ab9d587c8f",
|
||||
"gsd-core/workflows/autonomous.md": "cc5217b1b2238a4c",
|
||||
@@ -234,10 +234,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "39f288623a8f6f32",
|
||||
"gsd-core/workflows/edit-phase.md": "9c9fadc047c61d74",
|
||||
"gsd-core/workflows/eval-review.md": "3e1d7829ed2ed494",
|
||||
"gsd-core/workflows/execute-phase.md": "5c56112513a04340",
|
||||
"gsd-core/workflows/execute-phase.md": "ae12e044fb2f3b57",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "67ebc93f51968cb6",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "e3cb789a350dcadc",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "82e6cfe1e1b1ec0e",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "36b463d72d3e11c5",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "0c5551f99ee0a017",
|
||||
"gsd-core/workflows/explore.md": "e83af8ceae314cf9",
|
||||
@@ -309,7 +310,7 @@
|
||||
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
|
||||
"gsd-core/workflows/update.md": "165beec33490bd28",
|
||||
"gsd-core/workflows/validate-phase.md": "5b4ae14c87859bd2",
|
||||
"gsd-core/workflows/verify-phase.md": "20e90407e1e531fc",
|
||||
"gsd-core/workflows/verify-phase.md": "a4f918c92c927268",
|
||||
"gsd-core/workflows/verify-work.md": "6fa216623778c541",
|
||||
"scripts/changeset/README.md": "86ff89331dfd94b2",
|
||||
"scripts/changeset/cli.cjs": "68f92a344b199271",
|
||||
|
||||
@@ -109,10 +109,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
|
||||
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -233,7 +233,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -271,7 +271,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "cc0efe270004c8fb",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
|
||||
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
|
||||
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
|
||||
"gsd-core/workflows/audit-milestone.md": "6866ce260980c21e",
|
||||
"gsd-core/workflows/audit-uat.md": "fcfbec501620b564",
|
||||
"gsd-core/workflows/autonomous.md": "7e5683728ef33707",
|
||||
@@ -302,10 +302,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "f35922d15b7061c9",
|
||||
"gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04",
|
||||
"gsd-core/workflows/eval-review.md": "f898936e2cfe4130",
|
||||
"gsd-core/workflows/execute-phase.md": "2f9b53aac81a8f27",
|
||||
"gsd-core/workflows/execute-phase.md": "cf72b6db051f9189",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "4e265392b3f2ba0e",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "933d10547116794a",
|
||||
"gsd-core/workflows/explore.md": "6c04f2e658d93261",
|
||||
@@ -377,7 +378,7 @@
|
||||
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
|
||||
"gsd-core/workflows/update.md": "5ff1f77222977648",
|
||||
"gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa",
|
||||
"gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c",
|
||||
"gsd-core/workflows/verify-phase.md": "22f18492581f1da5",
|
||||
"gsd-core/workflows/verify-work.md": "34e980a6950cd83c",
|
||||
"hooks/gsd-check-update-worker.js": "bdc9324a2f080ddd",
|
||||
"hooks/gsd-check-update.js": "b7669f605631e506",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/codex.json
vendored
15
tests/fixtures/golden-install-parity/codex.json
vendored
@@ -73,10 +73,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
|
||||
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -197,7 +197,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "5b5dd37145241462",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
|
||||
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -235,7 +235,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "097e171f797737df",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "1dfa15d8f28c022d",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "f799abc00907377f",
|
||||
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
|
||||
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
|
||||
"gsd-core/workflows/audit-milestone.md": "46edd152d8b63bfc",
|
||||
"gsd-core/workflows/audit-uat.md": "2564078edb15b5e9",
|
||||
"gsd-core/workflows/autonomous.md": "92f08626d4aea668",
|
||||
@@ -266,10 +266,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "e255317df939e302",
|
||||
"gsd-core/workflows/edit-phase.md": "e592a4d85ce5380f",
|
||||
"gsd-core/workflows/eval-review.md": "63d0d0670b54c244",
|
||||
"gsd-core/workflows/execute-phase.md": "b6f4765843dc05f7",
|
||||
"gsd-core/workflows/execute-phase.md": "e62b664cf4db4d55",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "f4cacd27d37bac65",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "ac1f1d9ada00a91e",
|
||||
"gsd-core/workflows/explore.md": "2ef10d17c8864a04",
|
||||
@@ -341,7 +342,7 @@
|
||||
"gsd-core/workflows/undo.md": "5ff7d63b0a2f46d5",
|
||||
"gsd-core/workflows/update.md": "5c35c0ec0f462ea6",
|
||||
"gsd-core/workflows/validate-phase.md": "020201a41049679f",
|
||||
"gsd-core/workflows/verify-phase.md": "b9f70235e777aa81",
|
||||
"gsd-core/workflows/verify-phase.md": "2e12c3cb97a9122a",
|
||||
"gsd-core/workflows/verify-work.md": "69e27f6f419d0bba",
|
||||
"hooks/gsd-check-update.js": "ef48957eb6ac6a10",
|
||||
"hooks/gsd-context-monitor.js": "76fecaaa2babd6c1",
|
||||
|
||||
@@ -39,10 +39,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "ea841e2865248e74",
|
||||
"gsd-core/bin/gsd-tools.cjs": "b518bc939b3e031e",
|
||||
"gsd-core/bin/gsd-tools.cjs": "e8ccbbe8cefc2e9a",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "10226e9512dd44bf",
|
||||
@@ -163,7 +163,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "27318be7b7c984e1",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
|
||||
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -201,7 +201,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "10253591112b7d06",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "ef0c2474cee76b00",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "d25431af0ecf6355",
|
||||
"gsd-core/workflows/audit-fix.md": "9fdfe8a7fbcd1417",
|
||||
"gsd-core/workflows/audit-milestone.md": "19e03e6d34d96f38",
|
||||
"gsd-core/workflows/audit-uat.md": "5ea0e30548ed0933",
|
||||
"gsd-core/workflows/autonomous.md": "dd972ddde9663295",
|
||||
@@ -232,10 +232,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "9292cfa3c52c434e",
|
||||
"gsd-core/workflows/edit-phase.md": "8667c28b22b1599f",
|
||||
"gsd-core/workflows/eval-review.md": "81c8e72ba3862856",
|
||||
"gsd-core/workflows/execute-phase.md": "bc0ec0e19ce96269",
|
||||
"gsd-core/workflows/execute-phase.md": "6f7aa92705d3527e",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "63b712920f21a40f",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "15f872e83ad87196",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "1b73ab2fc47c9dbf",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "b26edeee455481a7",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "c5e9dae726db15cc",
|
||||
"gsd-core/workflows/explore.md": "5fd91a8510e1114b",
|
||||
@@ -307,7 +308,7 @@
|
||||
"gsd-core/workflows/undo.md": "ba1ef7aa80bef6bd",
|
||||
"gsd-core/workflows/update.md": "f444a7cfcd246cfb",
|
||||
"gsd-core/workflows/validate-phase.md": "2f705775a4b76d42",
|
||||
"gsd-core/workflows/verify-phase.md": "59d1046b3a2bc481",
|
||||
"gsd-core/workflows/verify-phase.md": "5c72780e34214e27",
|
||||
"gsd-core/workflows/verify-work.md": "58e9b1b16f773b53",
|
||||
"hooks/gsd-session.json": "0a462834f2a28fee",
|
||||
"scripts/changeset/README.md": "86ff89331dfd94b2",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/cursor.json
vendored
15
tests/fixtures/golden-install-parity/cursor.json
vendored
@@ -109,10 +109,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "2525f1ae8b086828",
|
||||
"gsd-core/bin/gsd-tools.cjs": "7fd5fbaf1bbd9db5",
|
||||
"gsd-core/bin/gsd-tools.cjs": "3fa86b509ea5c8fc",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -233,7 +233,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "762b16f9a6488474",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -271,7 +271,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "d483ebe8edcf193a",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "b79f320d59a68773",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
|
||||
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
|
||||
"gsd-core/workflows/audit-milestone.md": "23c1e35f449933b8",
|
||||
"gsd-core/workflows/audit-uat.md": "e11db0d74c2a7405",
|
||||
"gsd-core/workflows/autonomous.md": "4b20eda9a0b587ce",
|
||||
@@ -302,10 +302,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "e86d7d7e2e3dac6d",
|
||||
"gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a",
|
||||
"gsd-core/workflows/eval-review.md": "a86279dd98dd5c03",
|
||||
"gsd-core/workflows/execute-phase.md": "f9c628754cd74d0a",
|
||||
"gsd-core/workflows/execute-phase.md": "cf1b15f505b519d8",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "facb0e816d87a0c7",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "83dc1bf7f73735c0",
|
||||
"gsd-core/workflows/explore.md": "b9eea1bac358c9ce",
|
||||
@@ -377,7 +378,7 @@
|
||||
"gsd-core/workflows/undo.md": "18dec684fb1076f9",
|
||||
"gsd-core/workflows/update.md": "23e294ba707c3580",
|
||||
"gsd-core/workflows/validate-phase.md": "2df0c6e298a5f249",
|
||||
"gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a",
|
||||
"gsd-core/workflows/verify-phase.md": "e0957e153788a222",
|
||||
"gsd-core/workflows/verify-work.md": "145596b2542c457a",
|
||||
"hooks/gsd-cursor-post-tool.js": "019d503aee8b4a3f",
|
||||
"hooks/gsd-cursor-session-start.js": "c6e04ed597ea7020",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/hermes.json
vendored
15
tests/fixtures/golden-install-parity/hermes.json
vendored
@@ -38,10 +38,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "3a3409215044af9f",
|
||||
"gsd-core/bin/gsd-tools.cjs": "e666de93d4fd49fc",
|
||||
"gsd-core/bin/gsd-tools.cjs": "e979f092ce2b15ee",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -162,7 +162,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "6f968b6bb6e1982f",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -200,7 +200,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "5fe3ddc3227e0e22",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "ddab2912d025db65",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "cc6270e912471cc2",
|
||||
"gsd-core/workflows/audit-fix.md": "2eee4a0be82ef951",
|
||||
"gsd-core/workflows/audit-milestone.md": "806d346ee5bfe9f8",
|
||||
"gsd-core/workflows/audit-uat.md": "86d9131fccabf2ad",
|
||||
"gsd-core/workflows/autonomous.md": "dd572ca89862e5ec",
|
||||
@@ -231,10 +231,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "4d6c06e611d83b6d",
|
||||
"gsd-core/workflows/edit-phase.md": "7f27003f20e88fb8",
|
||||
"gsd-core/workflows/eval-review.md": "f510e5762212dc6f",
|
||||
"gsd-core/workflows/execute-phase.md": "c449a87fcca14433",
|
||||
"gsd-core/workflows/execute-phase.md": "f36c7b810285838c",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "ceb8758c22660c1a",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "3ab8bc8a07133068",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "c9ad17d6cc6dfe45",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "5a78d5dfea6a911a",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "4dbe9b6f0c976245",
|
||||
"gsd-core/workflows/explore.md": "48770d68e8b9c132",
|
||||
@@ -306,7 +307,7 @@
|
||||
"gsd-core/workflows/undo.md": "791e0bf96d9a057f",
|
||||
"gsd-core/workflows/update.md": "7499bb4cb2a3ce6f",
|
||||
"gsd-core/workflows/validate-phase.md": "75e8971d3981d06b",
|
||||
"gsd-core/workflows/verify-phase.md": "84e00bd685006870",
|
||||
"gsd-core/workflows/verify-phase.md": "5c8d1305b47fbef4",
|
||||
"gsd-core/workflows/verify-work.md": "e56e07475d5eb51e",
|
||||
"hooks/gsd-check-update-worker.js": "7989cc2bedd1138d",
|
||||
"hooks/gsd-check-update.js": "25f5ad726f76fc11",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/kilo.json
vendored
15
tests/fixtures/golden-install-parity/kilo.json
vendored
@@ -109,10 +109,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
|
||||
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -233,7 +233,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "5b5dd37145241462",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
|
||||
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -271,7 +271,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "5082510bf0449204",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "c85c6afdc64f0da6",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
|
||||
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
|
||||
"gsd-core/workflows/audit-milestone.md": "23c1e35f449933b8",
|
||||
"gsd-core/workflows/audit-uat.md": "e11db0d74c2a7405",
|
||||
"gsd-core/workflows/autonomous.md": "73f429f7472c9949",
|
||||
@@ -302,10 +302,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "79afaaf19fd527cc",
|
||||
"gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a",
|
||||
"gsd-core/workflows/eval-review.md": "926eda8bbee28b23",
|
||||
"gsd-core/workflows/execute-phase.md": "17cf87593b833b6d",
|
||||
"gsd-core/workflows/execute-phase.md": "ec448a1e25854abf",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "facb0e816d87a0c7",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "8dc89b35582407f7",
|
||||
"gsd-core/workflows/explore.md": "14242d36d4822df6",
|
||||
@@ -377,7 +378,7 @@
|
||||
"gsd-core/workflows/undo.md": "7cd2153f8b15e30d",
|
||||
"gsd-core/workflows/update.md": "07dc2fba78ad1865",
|
||||
"gsd-core/workflows/validate-phase.md": "557e3251e3b9349a",
|
||||
"gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a",
|
||||
"gsd-core/workflows/verify-phase.md": "e0957e153788a222",
|
||||
"gsd-core/workflows/verify-work.md": "b68ac37f6301a3b5",
|
||||
"hooks/gsd-check-update-worker.js": "c992bbad91d0e994",
|
||||
"hooks/gsd-check-update.js": "fdd77abe7ef26a2d",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/kimi.json
vendored
15
tests/fixtures/golden-install-parity/kimi.json
vendored
@@ -74,10 +74,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
|
||||
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -198,7 +198,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -236,7 +236,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "cc0efe270004c8fb",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
|
||||
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
|
||||
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
|
||||
"gsd-core/workflows/audit-milestone.md": "6866ce260980c21e",
|
||||
"gsd-core/workflows/audit-uat.md": "fcfbec501620b564",
|
||||
"gsd-core/workflows/autonomous.md": "7e5683728ef33707",
|
||||
@@ -267,10 +267,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "f35922d15b7061c9",
|
||||
"gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04",
|
||||
"gsd-core/workflows/eval-review.md": "f898936e2cfe4130",
|
||||
"gsd-core/workflows/execute-phase.md": "5d3377bc8ebbae58",
|
||||
"gsd-core/workflows/execute-phase.md": "91fe17be2d178f24",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "4e265392b3f2ba0e",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "c8502b7475d797a7",
|
||||
"gsd-core/workflows/explore.md": "6c04f2e658d93261",
|
||||
@@ -342,7 +343,7 @@
|
||||
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
|
||||
"gsd-core/workflows/update.md": "6718e0632bba26ca",
|
||||
"gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa",
|
||||
"gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c",
|
||||
"gsd-core/workflows/verify-phase.md": "22f18492581f1da5",
|
||||
"gsd-core/workflows/verify-work.md": "34e980a6950cd83c",
|
||||
"scripts/changeset/README.md": "86ff89331dfd94b2",
|
||||
"scripts/changeset/cli.cjs": "68f92a344b199271",
|
||||
|
||||
@@ -109,10 +109,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
|
||||
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -233,7 +233,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "bb76f9538f2bc4e0",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
|
||||
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -271,7 +271,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "72fcef9fd0cafda5",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "90e5f97018715b18",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "497a33eb4ee38d47",
|
||||
"gsd-core/workflows/audit-fix.md": "2871c5d0a4b671fa",
|
||||
"gsd-core/workflows/audit-milestone.md": "7aa0db364a4b67e2",
|
||||
"gsd-core/workflows/audit-uat.md": "c800099fab1e1c1b",
|
||||
"gsd-core/workflows/autonomous.md": "6cb0c014f5f56965",
|
||||
@@ -302,10 +302,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "850366c2ef8fb780",
|
||||
"gsd-core/workflows/edit-phase.md": "1876c855fb0a0a39",
|
||||
"gsd-core/workflows/eval-review.md": "5394694d29ad7543",
|
||||
"gsd-core/workflows/execute-phase.md": "ec2ef02d93b17a24",
|
||||
"gsd-core/workflows/execute-phase.md": "9026c312d564381f",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "1804215577f1ad35",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "647ec0d29a0d6365",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "baa2c401af10a80a",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "b86ca98268dd3705",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "e8de8ea661c1fe81",
|
||||
"gsd-core/workflows/explore.md": "7f5f9231cfd3089b",
|
||||
@@ -377,7 +378,7 @@
|
||||
"gsd-core/workflows/undo.md": "0bba5e7f6196c894",
|
||||
"gsd-core/workflows/update.md": "71b6cd852f38b4bc",
|
||||
"gsd-core/workflows/validate-phase.md": "abcdbc1b56780565",
|
||||
"gsd-core/workflows/verify-phase.md": "5bd04b040cd071dd",
|
||||
"gsd-core/workflows/verify-phase.md": "126be1d026900102",
|
||||
"gsd-core/workflows/verify-work.md": "f0d205568abfaf74",
|
||||
"hooks/gsd-check-update-worker.js": "385fb7c67810baf6",
|
||||
"hooks/gsd-check-update.js": "4549451414ffa7d7",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/qwen.json
vendored
15
tests/fixtures/golden-install-parity/qwen.json
vendored
@@ -38,10 +38,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "6e98d76e955e35a2",
|
||||
"gsd-core/bin/gsd-tools.cjs": "1caaaac4e81c7105",
|
||||
"gsd-core/bin/gsd-tools.cjs": "0341a6cf54b9acbe",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -162,7 +162,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "fe32daf7235d2a93",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -200,7 +200,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "5e037b444e657557",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "afdc7c15f03a95fc",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "da62236c7b3161a0",
|
||||
"gsd-core/workflows/audit-fix.md": "aaa1b74e001322b6",
|
||||
"gsd-core/workflows/audit-milestone.md": "b7617cf590d92a56",
|
||||
"gsd-core/workflows/audit-uat.md": "97d441d07e7972b3",
|
||||
"gsd-core/workflows/autonomous.md": "3014ff90115f0daf",
|
||||
@@ -231,10 +231,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "45d2f0d173c84e07",
|
||||
"gsd-core/workflows/edit-phase.md": "0fb5e0123cfc6f36",
|
||||
"gsd-core/workflows/eval-review.md": "6dee8a1e40ececd4",
|
||||
"gsd-core/workflows/execute-phase.md": "6bb6f3c6a33c4233",
|
||||
"gsd-core/workflows/execute-phase.md": "60deeb0a791c3cd5",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "36af8d91e4ae8b9c",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "5c30e38cdc265e20",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "98db1ba4c39cd784",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "56fc78db4de210df",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "503b0ced0731dc38",
|
||||
"gsd-core/workflows/explore.md": "e1a83a8982532e5b",
|
||||
@@ -306,7 +307,7 @@
|
||||
"gsd-core/workflows/undo.md": "791e0bf96d9a057f",
|
||||
"gsd-core/workflows/update.md": "b34cb866152d4de3",
|
||||
"gsd-core/workflows/validate-phase.md": "e989cbaa4228564c",
|
||||
"gsd-core/workflows/verify-phase.md": "a8679ba1d84145c5",
|
||||
"gsd-core/workflows/verify-phase.md": "0dc52b9e629a5f5a",
|
||||
"gsd-core/workflows/verify-work.md": "b5afb65fdf311301",
|
||||
"hooks/gsd-check-update-worker.js": "4bb354044e0dff91",
|
||||
"hooks/gsd-check-update.js": "d2065cb3e725a42a",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/trae.json
vendored
15
tests/fixtures/golden-install-parity/trae.json
vendored
@@ -38,10 +38,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "de4627dff103d527",
|
||||
"gsd-core/bin/gsd-tools.cjs": "172d8fce13b74b2d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "75bf5691ded4927b",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -162,7 +162,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "c9c5df7a8911bca9",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -200,7 +200,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "0fe07cbd29ec252b",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "d469eb120e52de0f",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "ac71c1179444fdc3",
|
||||
"gsd-core/workflows/audit-fix.md": "76607add3257cb37",
|
||||
"gsd-core/workflows/audit-milestone.md": "a379eda51d821bce",
|
||||
"gsd-core/workflows/audit-uat.md": "6e768b1c208a787a",
|
||||
"gsd-core/workflows/autonomous.md": "c482645c5d1ead46",
|
||||
@@ -231,10 +231,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "f13571f08e083356",
|
||||
"gsd-core/workflows/edit-phase.md": "7facd0faa33c8cad",
|
||||
"gsd-core/workflows/eval-review.md": "37d545d4f0db4927",
|
||||
"gsd-core/workflows/execute-phase.md": "0f90fb13e63cf2b2",
|
||||
"gsd-core/workflows/execute-phase.md": "aa5abb8c77a00153",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "c985a30317a1aa6b",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "1e0cc4675bcf1496",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "0a9e915170c7121c",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "4b00ef3484a84954",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "4910f75bab2040ab",
|
||||
"gsd-core/workflows/explore.md": "8a5437aa0c239c38",
|
||||
@@ -306,7 +307,7 @@
|
||||
"gsd-core/workflows/undo.md": "59b8baa54efc4110",
|
||||
"gsd-core/workflows/update.md": "1f935251fca1f276",
|
||||
"gsd-core/workflows/validate-phase.md": "1c0ebe56d96a14d1",
|
||||
"gsd-core/workflows/verify-phase.md": "53cbdce394dcdac0",
|
||||
"gsd-core/workflows/verify-phase.md": "a151ed36eb51813b",
|
||||
"gsd-core/workflows/verify-work.md": "d3a0970205acc6a5",
|
||||
"scripts/changeset/README.md": "86ff89331dfd94b2",
|
||||
"scripts/changeset/cli.cjs": "68f92a344b199271",
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "5636ca0b726871b2",
|
||||
"gsd-core/bin/gsd-tools.cjs": "d4fb7a7431f2b7d2",
|
||||
"gsd-core/bin/gsd-tools.cjs": "dd746ae946645155",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -162,7 +162,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "f7e0345b72e84e6e",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -200,7 +200,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "cab0d8215579fbdd",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "8948988717506320",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
|
||||
"gsd-core/workflows/audit-fix.md": "babe6812b86cec8f",
|
||||
"gsd-core/workflows/audit-fix.md": "aa052e15623d759d",
|
||||
"gsd-core/workflows/audit-milestone.md": "ac2238ea6c11ae9e",
|
||||
"gsd-core/workflows/audit-uat.md": "d496e39402e160de",
|
||||
"gsd-core/workflows/autonomous.md": "fe7bb7c978f305a2",
|
||||
@@ -231,10 +231,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "70f73cc8c27e0ca0",
|
||||
"gsd-core/workflows/edit-phase.md": "c0ae7d0063f3e789",
|
||||
"gsd-core/workflows/eval-review.md": "b28be79ef29f16fd",
|
||||
"gsd-core/workflows/execute-phase.md": "7cf72d7c95491ece",
|
||||
"gsd-core/workflows/execute-phase.md": "1dac1bdda0696dc0",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "47ae5482f8e64100",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "0f9ccd7edea1d6a9",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "15bca39a75c664be",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "02324a66cb42fae3",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "c8567fb4438b4404",
|
||||
"gsd-core/workflows/explore.md": "04e461ff8159a24e",
|
||||
@@ -306,7 +307,7 @@
|
||||
"gsd-core/workflows/undo.md": "18dec684fb1076f9",
|
||||
"gsd-core/workflows/update.md": "79aaf4b8f1f83045",
|
||||
"gsd-core/workflows/validate-phase.md": "2db47bf5547d7b9d",
|
||||
"gsd-core/workflows/verify-phase.md": "ea7f8a705b297e27",
|
||||
"gsd-core/workflows/verify-phase.md": "f961cdb3ef03ff05",
|
||||
"gsd-core/workflows/verify-work.md": "5ad63a5edfb6acac",
|
||||
"scripts/changeset/README.md": "86ff89331dfd94b2",
|
||||
"scripts/changeset/cli.cjs": "68f92a344b199271",
|
||||
|
||||
15
tests/fixtures/golden-install-parity/zcode.json
vendored
15
tests/fixtures/golden-install-parity/zcode.json
vendored
@@ -109,10 +109,10 @@
|
||||
"gsd-core/VERSION": "ef0deccd81a6723c",
|
||||
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
|
||||
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
|
||||
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
|
||||
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
|
||||
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
|
||||
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
|
||||
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
|
||||
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
|
||||
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
|
||||
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
|
||||
@@ -233,7 +233,7 @@
|
||||
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
|
||||
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
|
||||
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
|
||||
"gsd-core/templates/config.json": "1473dff11272d3c4",
|
||||
"gsd-core/templates/config.json": "a4b783ef759a0f37",
|
||||
"gsd-core/templates/context.md": "69b01e7909ea3f66",
|
||||
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
|
||||
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
|
||||
@@ -271,7 +271,7 @@
|
||||
"gsd-core/workflows/add-todo.md": "cc0efe270004c8fb",
|
||||
"gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f",
|
||||
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
|
||||
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
|
||||
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
|
||||
"gsd-core/workflows/audit-milestone.md": "6866ce260980c21e",
|
||||
"gsd-core/workflows/audit-uat.md": "fcfbec501620b564",
|
||||
"gsd-core/workflows/autonomous.md": "7e5683728ef33707",
|
||||
@@ -302,10 +302,11 @@
|
||||
"gsd-core/workflows/docs-update.md": "f35922d15b7061c9",
|
||||
"gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04",
|
||||
"gsd-core/workflows/eval-review.md": "f898936e2cfe4130",
|
||||
"gsd-core/workflows/execute-phase.md": "49f793a605e4665e",
|
||||
"gsd-core/workflows/execute-phase.md": "bb4f1120804c5a90",
|
||||
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "4e265392b3f2ba0e",
|
||||
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
|
||||
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
|
||||
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
|
||||
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
|
||||
"gsd-core/workflows/execute-plan.md": "ed874410972d32b7",
|
||||
"gsd-core/workflows/explore.md": "6c04f2e658d93261",
|
||||
@@ -377,7 +378,7 @@
|
||||
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
|
||||
"gsd-core/workflows/update.md": "dc580dee13f881a6",
|
||||
"gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa",
|
||||
"gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c",
|
||||
"gsd-core/workflows/verify-phase.md": "22f18492581f1da5",
|
||||
"gsd-core/workflows/verify-work.md": "34e980a6950cd83c",
|
||||
"hooks/gsd-check-update-worker.js": "6660bcf03ed849a0",
|
||||
"hooks/gsd-check-update.js": "901ea3bd75fd5bbc",
|
||||
|
||||
158
tests/normalize-test-command.test.cjs
Normal file
158
tests/normalize-test-command.test.cjs
Normal file
@@ -0,0 +1,158 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Regression tests for the test-command normalizer (#1857).
|
||||
*
|
||||
* A GSD test gate must not hang forever on a watch-mode runner. The normalizer
|
||||
* rewrites a resolved test command to a best-effort one-shot form; the gate's
|
||||
* wall-clock timeout is the ultimate guarantee (asserted separately as workflow
|
||||
* content). These tests cover the two normalization acceptance criteria:
|
||||
* (a) an already-one-shot command is invoked UNCHANGED (never double-flagged),
|
||||
* (b) a watch-mode command is normalized to a one-shot form.
|
||||
*/
|
||||
|
||||
const { test, describe, beforeEach, afterEach } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
|
||||
const { cleanup } = require('./helpers.cjs');
|
||||
|
||||
const normalizer = require('../gsd-core/bin/lib/normalize-test-command.cjs');
|
||||
const { normalizeTestCommand, isAlreadyOneShot } = normalizer;
|
||||
|
||||
function tmpProject(testScript) {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1857-'));
|
||||
fs.writeFileSync(
|
||||
path.join(dir, 'package.json'),
|
||||
JSON.stringify({ scripts: { test: testScript } }),
|
||||
);
|
||||
return dir;
|
||||
}
|
||||
|
||||
describe('normalizeTestCommand: direct vitest (watch by default) → one-shot (#1857)', () => {
|
||||
test('bare vitest gains "run"', () => {
|
||||
assert.strictEqual(normalizeTestCommand('vitest', '/tmp'), 'vitest run');
|
||||
});
|
||||
test('npx vitest with flags gains "run" and keeps flags', () => {
|
||||
assert.strictEqual(normalizeTestCommand('npx vitest --coverage', '/tmp'), 'npx vitest run --coverage');
|
||||
});
|
||||
test('vitest --watch is stripped and made one-shot', () => {
|
||||
assert.strictEqual(normalizeTestCommand('vitest --watch', '/tmp'), 'vitest run');
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeTestCommand: already one-shot is a no-op (#1857)', () => {
|
||||
for (const cmd of ['vitest run', 'vitest --run', 'npx vitest run -t foo', 'jest --watchAll=false']) {
|
||||
test(`"${cmd}" is recognised one-shot and returned unchanged`, () => {
|
||||
assert.strictEqual(normalizeTestCommand(cmd, '/tmp'), cmd);
|
||||
assert.ok(isAlreadyOneShot(cmd), `"${cmd}" should be recognised as one-shot`);
|
||||
});
|
||||
}
|
||||
// jest is one-shot by default (no --watch); --runInBand doesn't disable watch,
|
||||
// so it isn't a one-shot MARKER — but a jest command without a watch flag is
|
||||
// still returned unchanged via the jest branch.
|
||||
for (const cmd of ['jest', 'jest --runInBand']) {
|
||||
test(`"${cmd}" (jest, no watch flag) is returned unchanged`, () => {
|
||||
assert.strictEqual(normalizeTestCommand(cmd, '/tmp'), cmd);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('normalizeTestCommand: direct jest with watch flag → one-shot (#1857)', () => {
|
||||
test('jest --watch → --watchAll=false', () => {
|
||||
assert.strictEqual(normalizeTestCommand('jest --watch', '/tmp'), 'jest --watchAll=false');
|
||||
});
|
||||
test('jest --watchAll → --watchAll=false', () => {
|
||||
assert.strictEqual(normalizeTestCommand('jest --watchAll', '/tmp'), 'jest --watchAll=false');
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeTestCommand: package-manager script invocation inspects package.json (#1857)', () => {
|
||||
let vitestDir; let vitestRunDir; let jestDir;
|
||||
beforeEach(() => {
|
||||
vitestDir = tmpProject('vitest'); // watches by default
|
||||
vitestRunDir = tmpProject('vitest run'); // already one-shot
|
||||
jestDir = tmpProject('jest'); // one-shot by default
|
||||
});
|
||||
afterEach(() => {
|
||||
for (const d of [vitestDir, vitestRunDir, jestDir]) {
|
||||
cleanup(d);
|
||||
}
|
||||
});
|
||||
|
||||
test('npm test whose script is watch-vitest → CI=true prefix', () => {
|
||||
assert.strictEqual(normalizeTestCommand('npm test', vitestDir), 'CI=true npm test');
|
||||
});
|
||||
test('pnpm test whose script is watch-vitest → CI=true prefix', () => {
|
||||
assert.strictEqual(normalizeTestCommand('pnpm test', vitestDir), 'CI=true pnpm test');
|
||||
});
|
||||
test('npm test whose script is already "vitest run" → unchanged', () => {
|
||||
assert.strictEqual(normalizeTestCommand('npm test', vitestRunDir), 'npm test');
|
||||
});
|
||||
test('npm test whose script is jest (one-shot) → unchanged', () => {
|
||||
assert.strictEqual(normalizeTestCommand('npm test', jestDir), 'npm test');
|
||||
});
|
||||
|
||||
test('pnpm --dir <app> test inspects the target package.json (#1857 comment 5)', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1857-root-'));
|
||||
try {
|
||||
fs.mkdirSync(path.join(root, 'app'));
|
||||
fs.writeFileSync(path.join(root, 'app', 'package.json'), JSON.stringify({ scripts: { test: 'vitest' } }));
|
||||
assert.strictEqual(normalizeTestCommand('pnpm --dir app test', root), 'CI=true pnpm --dir app test');
|
||||
// An explicit --run the user already passed is respected (no-op); the
|
||||
// gate timeout backstops a project that still watches despite --run.
|
||||
assert.strictEqual(normalizeTestCommand('pnpm --dir app test -- --run', root), 'pnpm --dir app test -- --run');
|
||||
} finally {
|
||||
cleanup(root);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeTestCommand: non-JS / unknown runners are untouched (#1857)', () => {
|
||||
for (const cmd of ['cargo test', 'go test ./...', 'make test', 'python -m pytest -q', 'true', '']) {
|
||||
test(`"${cmd}" is returned unchanged`, () => {
|
||||
assert.strictEqual(normalizeTestCommand(cmd, '/tmp'), cmd);
|
||||
});
|
||||
}
|
||||
test('npm test with no package.json is left unchanged (cannot classify)', () => {
|
||||
const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1857-empty-'));
|
||||
try {
|
||||
assert.strictEqual(normalizeTestCommand('npm test', empty), 'npm test');
|
||||
} finally {
|
||||
cleanup(empty);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeTestCommand: security hardening (#1857 review)', () => {
|
||||
// "vitest"/"jest" as a token that isn't the invoked binary must NOT be mangled.
|
||||
for (const cmd of ['make test-vitest', 'node ./scripts/run-vitest.js', './bin/vitest-wrapper.sh', 'cat vitest.config.js', 'node jest-runner.js']) {
|
||||
test(`"${cmd}" is not mangled (word-token, not substring)`, () => {
|
||||
assert.strictEqual(normalizeTestCommand(cmd, '/tmp'), cmd);
|
||||
});
|
||||
}
|
||||
|
||||
test('an oversized command is returned unchanged and in linear time (no ReDoS)', () => {
|
||||
// The blow-up input from the review: a long "npm " run with no `test` token.
|
||||
const huge = 'npm '.repeat(200000); // ~800 KB
|
||||
const start = Date.now();
|
||||
const out = normalizeTestCommand(huge, '/tmp');
|
||||
const elapsedMs = Date.now() - start;
|
||||
assert.strictEqual(out, huge, 'oversized input must be returned unchanged');
|
||||
assert.ok(elapsedMs < 250, `normalization must be fast even on adversarial input (took ${elapsedMs}ms)`);
|
||||
});
|
||||
|
||||
test('a package.json that is not a regular file is ignored (no FIFO hang)', () => {
|
||||
// resolvePackageDir would point here; a non-regular "package.json" must be skipped.
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1857-notfile-'));
|
||||
try {
|
||||
fs.mkdirSync(path.join(dir, 'package.json')); // a DIRECTORY named package.json
|
||||
// Classified as "cannot determine runner" → command returned unchanged.
|
||||
assert.strictEqual(normalizeTestCommand('npm test', dir), 'npm test');
|
||||
} finally {
|
||||
cleanup(dir);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -122,9 +122,9 @@ const ALLOWLIST = {
|
||||
'review.md': ['time_sizing'],
|
||||
// Fast uses "under 2 minutes wall time" as operational constraint
|
||||
'fast.md': ['time_sizing'],
|
||||
// Execute-phase uses "timeout: 5 minutes" for test runner
|
||||
// Execute-phase uses a configurable test-gate timeout (workflow.test_gate_timeout, #1857)
|
||||
'execute-phase.md': ['time_sizing'],
|
||||
// Verify-phase uses "timeout: 5 minutes" for test runner
|
||||
// Verify-phase uses a configurable test-gate timeout (workflow.test_gate_timeout, #1857)
|
||||
'verify-phase.md': ['time_sizing'],
|
||||
// Map-codebase documents subagent_timeout
|
||||
'map-codebase.md': ['time_sizing'],
|
||||
|
||||
93
tests/test-gate-watch-mode.test.cjs
Normal file
93
tests/test-gate-watch-mode.test.cjs
Normal file
@@ -0,0 +1,93 @@
|
||||
// allow-test-rule: source-text-is-the-product #1857
|
||||
// Workflow .md files — their text IS the deployed contract the orchestrator runs.
|
||||
|
||||
/**
|
||||
* #1857: a GSD test gate must not hang forever on a watch-mode runner.
|
||||
*
|
||||
* Three gates were UNBOUNDED or silently-continued and are the core fix. They must:
|
||||
* - route the resolved command through the shared `normalize-test-command`
|
||||
* helper (defeats vitest/jest watch mode), so the paths cannot drift,
|
||||
* - bound execution with `timeout` using the `workflow.test_gate_timeout`
|
||||
* budget, and
|
||||
* - surface a timeout (exit 124) with a watch-mode hint — the regression gate
|
||||
* ABORTS, the others surface clearly (never silently ignored).
|
||||
*
|
||||
* verify-phase's gate was ALREADY bounded (a fixed `timeout 300`, not a hang), so
|
||||
* it only needs the normalizer (so a watch runner exits fast) and keeps its own
|
||||
* fixed 5-minute bound — asserted separately below.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { test, describe } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const REGRESSION_GATE = path.join(ROOT, 'gsd-core', 'workflows', 'execute-phase', 'steps', 'regression-gate.md');
|
||||
const POST_MERGE_GATE = path.join(ROOT, 'gsd-core', 'workflows', 'execute-phase', 'steps', 'post-merge-gate.md');
|
||||
const AUDIT_FIX = path.join(ROOT, 'gsd-core', 'workflows', 'audit-fix.md');
|
||||
const VERIFY_PHASE = path.join(ROOT, 'gsd-core', 'workflows', 'verify-phase.md');
|
||||
const EXECUTE_PHASE = path.join(ROOT, 'gsd-core', 'workflows', 'execute-phase.md');
|
||||
|
||||
function read(p) { return fs.readFileSync(p, 'utf-8'); }
|
||||
|
||||
// The three gates that were unbounded/silently-continued: full normalize + configured timeout.
|
||||
const FULL_GATES = [
|
||||
['regression gate', REGRESSION_GATE],
|
||||
['post-merge gate', POST_MERGE_GATE],
|
||||
['audit-fix gate', AUDIT_FIX],
|
||||
];
|
||||
|
||||
describe('#1857: test gates normalize to one-shot and bound with a timeout', () => {
|
||||
for (const [label, file] of FULL_GATES) {
|
||||
describe(label, () => {
|
||||
test('routes the resolved command through the shared normalize-test-command helper', () => {
|
||||
const c = read(file);
|
||||
assert.match(c, /normalize-test-command/, `${label} must call the shared normalize-test-command helper`);
|
||||
});
|
||||
test('bounds execution with a timeout using the workflow.test_gate_timeout budget', () => {
|
||||
const c = read(file);
|
||||
assert.match(c, /workflow\.test_gate_timeout/, `${label} must read workflow.test_gate_timeout`);
|
||||
assert.match(c, /timeout "\$TEST_GATE_TIMEOUT"/, `${label} must wrap the test command in a timeout with the configured budget`);
|
||||
});
|
||||
test('surfaces a timeout (exit 124) with a watch-mode hint — never a silent hang', () => {
|
||||
const c = read(file);
|
||||
assert.match(c, /-eq 124/, `${label} must handle the timeout exit code (124)`);
|
||||
assert.match(c, /watch\/dev mode/, `${label} must name watch/dev mode as the likely cause on timeout`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// verify-phase is already bounded (fixed `timeout 300`, not a hang); it only
|
||||
// needs the normalizer so a watch runner exits fast, and names watch mode on 124.
|
||||
describe('verify-phase gate (already bounded — normalize-only)', () => {
|
||||
test('routes the resolved command through the shared normalize-test-command helper', () => {
|
||||
assert.match(read(VERIFY_PHASE), /normalize-test-command/, 'verify-phase must call the shared normalize-test-command helper');
|
||||
});
|
||||
test('surfaces its fixed timeout (exit 124) naming watch/dev mode', () => {
|
||||
const c = read(VERIFY_PHASE);
|
||||
assert.match(c, /-eq 124/, 'verify-phase must handle the timeout exit code (124)');
|
||||
assert.match(c, /watch\/dev mode/, 'verify-phase must name watch/dev mode as the likely cause on timeout');
|
||||
});
|
||||
});
|
||||
|
||||
test('the regression gate ABORTS (halts) on a watch-mode timeout', () => {
|
||||
const c = read(REGRESSION_GATE);
|
||||
assert.match(c, /REGRESSION GATE ABORTED/, 'regression gate must abort (not continue) on timeout');
|
||||
});
|
||||
|
||||
test('execute-phase.md delegates the regression gate to the extracted step (size-frozen file stays lean)', () => {
|
||||
const c = read(EXECUTE_PHASE);
|
||||
assert.match(c, /steps\/regression-gate\.md/, 'execute-phase.md must reference the extracted regression-gate step');
|
||||
});
|
||||
|
||||
test('the gates share ONE normalizer — the helper is a single source of truth', () => {
|
||||
// The behaviour lives in src/normalize-test-command.cts; every gate invokes it
|
||||
// by the same verb name, so a change to watch-defeat logic touches one place.
|
||||
for (const file of [REGRESSION_GATE, POST_MERGE_GATE, AUDIT_FIX, VERIFY_PHASE]) {
|
||||
assert.match(read(file), /gsd_run query normalize-test-command/);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@
|
||||
"add-todo.md": 8996,
|
||||
"ai-integration-phase.md": 14805,
|
||||
"analyze-dependencies.md": 3887,
|
||||
"audit-fix.md": 11032,
|
||||
"audit-fix.md": 11717,
|
||||
"audit-milestone.md": 17681,
|
||||
"audit-uat.md": 7469,
|
||||
"autonomous.md": 42474,
|
||||
@@ -24,7 +24,7 @@
|
||||
"docs-update.md": 55706,
|
||||
"edit-phase.md": 12927,
|
||||
"eval-review.md": 9967,
|
||||
"execute-phase.md": 93528,
|
||||
"execute-phase.md": 93132,
|
||||
"execute-plan.md": 32655,
|
||||
"explore.md": 10541,
|
||||
"extract-learnings.md": 12893,
|
||||
@@ -88,6 +88,6 @@
|
||||
"undo.md": 10431,
|
||||
"update.md": 20914,
|
||||
"validate-phase.md": 10789,
|
||||
"verify-phase.md": 40772,
|
||||
"verify-phase.md": 40923,
|
||||
"verify-work.md": 38267
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user