@opengsd/gsd-core 1.3.1 → 1.4.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/gsd-advisor-researcher.md +1 -20
- package/agents/gsd-ai-researcher.md +1 -20
- package/agents/gsd-domain-researcher.md +1 -20
- package/agents/gsd-executor.md +1 -1
- package/agents/gsd-phase-researcher.md +92 -166
- package/agents/gsd-planner.md +9 -36
- package/agents/gsd-project-researcher.md +62 -141
- package/agents/gsd-ui-researcher.md +2 -21
- package/agents/gsd-verifier.md +8 -2
- package/bin/install.js +85 -4
- package/commands/gsd/graphify.md +11 -6
- package/commands/gsd/import.md +6 -2
- package/commands/gsd/plan-phase.md +2 -2
- package/gsd-core/bin/check-latest-version.cjs +3 -2
- package/gsd-core/bin/gsd-tools.cjs +238 -32
- package/gsd-core/bin/lib/check-command-router.cjs +1 -0
- package/gsd-core/bin/lib/cli-exit.cjs +42 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +1 -1
- package/gsd-core/bin/lib/commands.cjs +5 -4
- package/gsd-core/bin/lib/config.cjs +28 -4
- package/gsd-core/bin/lib/core.cjs +72 -28
- package/gsd-core/bin/lib/graphify.cjs +2 -2
- package/gsd-core/bin/lib/init-command-router.cjs +2 -2
- package/gsd-core/bin/lib/init.cjs +19 -3
- package/gsd-core/bin/lib/intel.cjs +3 -20
- package/gsd-core/bin/lib/package-legitimacy.cjs +368 -0
- package/gsd-core/bin/lib/phase.cjs +3 -3
- package/gsd-core/bin/lib/research-provider.cjs +137 -0
- package/gsd-core/bin/lib/research-store.cjs +167 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +4 -19
- package/gsd-core/bin/lib/security.cjs +73 -0
- package/gsd-core/bin/lib/shell-command-projection.cjs +3 -0
- package/gsd-core/bin/lib/validate.cjs +2 -2
- package/gsd-core/bin/lib/verification-command-router.cjs +31 -0
- package/gsd-core/bin/lib/verification.cjs +193 -0
- package/gsd-core/bin/lib/verify.cjs +2 -2
- package/gsd-core/bin/lib/workstream-inventory.cjs +1 -1
- package/gsd-core/bin/lib/worktree-base-ref.cjs +325 -0
- package/gsd-core/bin/lib/worktree-safety.cjs +31 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -1
- package/gsd-core/bin/verify-reapply-patches.cjs +8 -11
- package/gsd-core/references/planner-load-graph-context.md +36 -0
- package/gsd-core/references/planning-config.md +3 -1
- package/gsd-core/references/research-documentation-lookup.md +29 -0
- package/gsd-core/references/research-philosophy.md +29 -0
- package/gsd-core/references/research-verification-protocol.md +27 -0
- package/gsd-core/workflows/execute-phase.md +19 -8
- package/gsd-core/workflows/help/modes/full.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -2
- package/gsd-core/workflows/plan-phase.md +14 -10
- package/gsd-core/workflows/plan-review-convergence.md +3 -3
- package/gsd-core/workflows/review.md +22 -5
- package/gsd-core/workflows/ship.md +5 -8
- package/gsd-core/workflows/spec-phase.md +2 -1
- package/gsd-core/workflows/update.md +2 -1
- package/hooks/dist/gsd-context-monitor.js +1 -1
- package/hooks/dist/gsd-workflow-guard.js +1 -0
- package/hooks/dist/gsd-worktree-path-guard.js +1 -1
- package/hooks/gsd-context-monitor.js +1 -1
- package/hooks/gsd-workflow-guard.js +1 -0
- package/hooks/gsd-worktree-path-guard.js +1 -1
- package/package.json +4 -1
- package/scripts/affected-tests-lib.cjs +3 -2
- package/scripts/changeset/cli.cjs +183 -28
- package/scripts/changeset/lint.cjs +5 -4
- package/scripts/changeset/new.cjs +4 -4
- package/scripts/check-alias-drift.cjs +77 -71
- package/scripts/check-env.cjs +185 -179
- package/scripts/check-npm-integrity.cjs +115 -109
- package/scripts/ci-guard-runner.cjs +11 -5
- package/scripts/ci-prepare-test-scope.cjs +27 -22
- package/scripts/ci-rebase-check.cjs +46 -45
- package/scripts/ci-test-scope.cjs +6 -4
- package/scripts/diff-touches-shipped-paths.cjs +52 -44
- package/scripts/gen-inventory-manifest.cjs +38 -32
- package/scripts/gen-research-agents.cjs +276 -0
- package/scripts/lib/cli-exit.cjs +56 -0
- package/scripts/lint-command-contract.cjs +28 -22
- package/scripts/lint-descriptions.cjs +32 -28
- package/scripts/lint-docs-required.cjs +4 -4
- package/scripts/lint-legacy-dir-name.cjs +56 -52
- package/scripts/lint-pr-check-project-dir.cjs +3 -1
- package/scripts/lint-shell-command-projection-drift.cjs +27 -22
- package/scripts/lint-skill-deps.cjs +31 -26
- package/scripts/lint-test-file-count.allowlist.json +1 -0
- package/scripts/lint-test-file-count.cjs +5 -4
- package/scripts/mutation-matrix.cjs +6 -3
- package/scripts/prompt-injection-scan.sh +1 -1
- package/scripts/release-notes/format-github-release-notes.cjs +8 -3
- package/scripts/release-tarball-smoke.cjs +6 -4
- package/scripts/research-profiles.cjs +149 -0
- package/scripts/run-affected-tests.cjs +2 -1
- package/scripts/run-cross-platform-tests.cjs +11 -7
- package/scripts/run-tests.cjs +8 -7
- package/scripts/strip-prose-atrefs.cjs +1 -1
- package/scripts/sync-runtime-launcher.cjs +0 -3
- package/scripts/verify-npm-publish.cjs +14 -26
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Planner — Load Graph Context
|
|
2
|
+
|
|
3
|
+
> Loaded by `gsd-planner` at the `load_graph_context` step.
|
|
4
|
+
|
|
5
|
+
Check for knowledge graph:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
ls .planning/graphs/graph.json 2>/dev/null
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
If graph.json exists, check freshness:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
_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 command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/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
|
|
15
|
+
gsd_run graphify status
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If the status response has `stale: true`, note for later: "Graph is {age_hours}h old -- treat semantic relationships as approximate." Include this annotation inline with any graph context injected below.
|
|
19
|
+
|
|
20
|
+
Query the graph for phase-relevant dependency context (single query per D-06):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
gsd_run graphify query "<phase-goal-keyword>" --budget 2000
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Use the keyword that best captures the phase goal. Examples:
|
|
27
|
+
- Phase "User Authentication" -> query term "auth"
|
|
28
|
+
- Phase "Payment Integration" -> query term "payment"
|
|
29
|
+
- Phase "Database Migration" -> query term "migration"
|
|
30
|
+
|
|
31
|
+
If the query returns nodes and edges, incorporate as dependency context for planning:
|
|
32
|
+
- Which modules/files are semantically related to this phase's domain
|
|
33
|
+
- Which subsystems may be affected by changes in this phase
|
|
34
|
+
- Cross-document relationships that inform task ordering and wave structure
|
|
35
|
+
|
|
36
|
+
If no results or graph.json absent, continue without graph context.
|
|
@@ -34,7 +34,7 @@ Configuration options for `.planning/` directory behavior.
|
|
|
34
34
|
| `git.phase_branch_template` | `"gsd/phase-{phase}-{slug}"` | Branch template for phase strategy |
|
|
35
35
|
| `git.milestone_branch_template` | `"gsd/{milestone}-{slug}"` | Branch template for milestone strategy |
|
|
36
36
|
| `git.quick_branch_template` | `null` | Optional branch template for quick-task runs |
|
|
37
|
-
| `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. |
|
|
37
|
+
| `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. Note: if your branch is ahead of `origin/HEAD` (a diverged milestone or feature branch), GSD auto-degrades to sequential and prints a warning; set `worktree.baseRef:"head"` in `.claude/settings.local.json` to restore parallel execution. See the branch-divergence note below. |
|
|
38
38
|
| `workflow.subagent_timeout` | `300000` | Timeout in milliseconds for parallel subagent tasks (e.g. codebase mapping). Increase for large codebases or slower models. Default: 300000 (5 minutes). |
|
|
39
39
|
| `workflow.inline_plan_threshold` | `2` | Plans with this many tasks or fewer execute inline (Pattern C) instead of spawning a subagent. Avoids ~14K token spawn overhead for small plans. Set to `0` to always spawn subagents. |
|
|
40
40
|
| `manager.flags.discuss` | `""` | Flags passed to `/gsd:discuss-phase` when dispatched from manager (e.g. `"--auto --analyze"`) |
|
|
@@ -385,6 +385,8 @@ Several config fields affect each other or trigger special behavior:
|
|
|
385
385
|
|
|
386
386
|
8. **`sub_repos` auto-sync** -- On every config load, GSD scans for child directories with `.git` and updates the `sub_repos` array if the filesystem has changed. Legacy `multiRepo: true` is automatically migrated to a detected `sub_repos` array.
|
|
387
387
|
|
|
388
|
+
9. **`workflow.use_worktrees` and branch divergence** -- When `use_worktrees` is `true` (default), executor worktrees are forked from `origin/HEAD` by the Claude Code harness. If your current branch has commits that `origin/HEAD` does not (for example an unmerged milestone or feature branch), GSD automatically degrades to sequential execution for that run and prints a one-line `⚠ Worktree base mismatch` warning. To restore parallel execution permanently, set `worktree.baseRef:"head"` in `.claude/settings.local.json` (run `node gsd-tools.cjs worktree set-baseref`). This makes the harness fork worktrees from the live HEAD instead of `origin/HEAD`. Both fresh installs and upgrades of GSD Core set this automatically (no-clobber) when `use_worktrees` is enabled; you can also run the command manually at any time. Setting `workflow.use_worktrees: false` is the alternative if worktrees are not needed at all.
|
|
389
|
+
|
|
388
390
|
---
|
|
389
391
|
|
|
390
392
|
## Example Configurations
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
When you need library or framework documentation, check in this order:
|
|
2
|
+
|
|
3
|
+
1. If Context7 MCP tools (`mcp__context7__*`) are available in your environment, use them:
|
|
4
|
+
- Resolve library ID: `mcp__context7__resolve-library-id` with `libraryName`
|
|
5
|
+
- Fetch docs: `mcp__context7__get-library-docs` with `context7CompatibleLibraryId` and `topic`
|
|
6
|
+
|
|
7
|
+
2. If Context7 MCP is not available (upstream bug anthropics/claude-code#13898 strips MCP
|
|
8
|
+
tools from agents with a `tools:` frontmatter restriction), use the CLI fallback via Bash:
|
|
9
|
+
|
|
10
|
+
Step 1 — Resolve library ID:
|
|
11
|
+
```bash
|
|
12
|
+
if command -v ctx7 &>/dev/null; then
|
|
13
|
+
ctx7 library <name> "<query>"
|
|
14
|
+
else
|
|
15
|
+
echo "ctx7 not found — install with: npm install -g ctx7 (verify at npmjs.com/package/ctx7 first)"
|
|
16
|
+
fi
|
|
17
|
+
```
|
|
18
|
+
Step 2 — Fetch documentation:
|
|
19
|
+
```bash
|
|
20
|
+
if command -v ctx7 &>/dev/null; then
|
|
21
|
+
ctx7 docs <libraryId> "<query>"
|
|
22
|
+
else
|
|
23
|
+
echo "ctx7 not found — install with: npm install -g ctx7 (verify at npmjs.com/package/ctx7 first)"
|
|
24
|
+
fi
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Do not skip documentation lookups because MCP tools are unavailable — the CLI fallback
|
|
28
|
+
works via Bash and produces equivalent output. Do NOT use `npx --yes` to auto-download
|
|
29
|
+
ctx7 — this silently executes unverified packages from the registry.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
## Claude's Training as Hypothesis
|
|
2
|
+
|
|
3
|
+
Training data is 6-18 months stale. Treat pre-existing knowledge as hypothesis, not fact.
|
|
4
|
+
|
|
5
|
+
**The trap:** Claude "knows" things confidently, but knowledge may be outdated, incomplete, or wrong.
|
|
6
|
+
|
|
7
|
+
**The discipline:**
|
|
8
|
+
1. **Verify before asserting** — don't state library capabilities without checking Context7 or official docs
|
|
9
|
+
2. **Date your knowledge** — "As of my training" is a warning flag
|
|
10
|
+
3. **Prefer current sources** — Context7 and official docs trump training data
|
|
11
|
+
4. **Flag uncertainty** — LOW confidence when only training data supports a claim
|
|
12
|
+
|
|
13
|
+
## Honest Reporting
|
|
14
|
+
|
|
15
|
+
Research value comes from accuracy, not completeness theater.
|
|
16
|
+
|
|
17
|
+
**Report honestly:**
|
|
18
|
+
- "I couldn't find X" is valuable (now we know to investigate differently)
|
|
19
|
+
- "This is LOW confidence" is valuable (flags for validation)
|
|
20
|
+
- "Sources contradict" is valuable (surfaces real ambiguity)
|
|
21
|
+
|
|
22
|
+
**Avoid:** Padding findings, stating unverified claims as facts, hiding uncertainty behind confident language.
|
|
23
|
+
|
|
24
|
+
## Research is Investigation, Not Confirmation
|
|
25
|
+
|
|
26
|
+
**Bad research:** Start with hypothesis, find evidence to support it
|
|
27
|
+
**Good research:** Gather evidence, form conclusions from evidence
|
|
28
|
+
|
|
29
|
+
When researching "best library for X": find what the ecosystem actually uses, document tradeoffs honestly, let evidence drive recommendation.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## Known Pitfalls
|
|
2
|
+
|
|
3
|
+
### Configuration Scope Blindness
|
|
4
|
+
**Trap:** Assuming global configuration means no project-scoping exists
|
|
5
|
+
**Prevention:** Verify ALL configuration scopes (global, project, local, workspace)
|
|
6
|
+
|
|
7
|
+
### Deprecated Features
|
|
8
|
+
**Trap:** Finding old documentation and concluding feature doesn't exist
|
|
9
|
+
**Prevention:** Check current official docs, review changelog, verify version numbers and dates
|
|
10
|
+
|
|
11
|
+
### Negative Claims Without Evidence
|
|
12
|
+
**Trap:** Making definitive "X is not possible" statements without official verification
|
|
13
|
+
**Prevention:** For any negative claim — is it verified by official docs? Have you checked recent updates? Are you confusing "didn't find it" with "doesn't exist"?
|
|
14
|
+
|
|
15
|
+
### Single Source Reliance
|
|
16
|
+
**Trap:** Relying on a single source for critical claims
|
|
17
|
+
**Prevention:** Require multiple sources: official docs (primary), release notes (currency), additional source (verification)
|
|
18
|
+
|
|
19
|
+
## Pre-Submission Checklist
|
|
20
|
+
|
|
21
|
+
- [ ] All research domains in this agent's scope investigated (e.g. stack, features, architecture, patterns, pitfalls — whichever apply)
|
|
22
|
+
- [ ] Negative claims verified with official docs
|
|
23
|
+
- [ ] Multiple sources cross-referenced for critical claims
|
|
24
|
+
- [ ] URLs provided for authoritative sources
|
|
25
|
+
- [ ] Publication dates checked (prefer recent/current)
|
|
26
|
+
- [ ] Confidence levels assigned honestly
|
|
27
|
+
- [ ] "What might I have missed?" review completed
|
|
@@ -92,6 +92,16 @@ if [ "$RUNTIME" = "codex" ] && [ "$USE_WORKTREES" != "false" ]; then
|
|
|
92
92
|
fi
|
|
93
93
|
# Sweep orphaned locked worktrees from prior crashed sessions before spawning executors (#3707).
|
|
94
94
|
[ "$USE_WORKTREES" != "false" ] && gsd_run query worktree.reap-orphans 2>/dev/null || true
|
|
95
|
+
# Auto-degrade to sequential if HEAD has diverged from the worktree fork base (#683).
|
|
96
|
+
# Only applies to Claude Code (isolation="worktree" is Claude-Code-specific).
|
|
97
|
+
if [ "$RUNTIME" = "claude" ] && [ "$USE_WORKTREES" != "false" ]; then
|
|
98
|
+
_SHOULD_DEGRADE=$(gsd_run query worktree.base-check --pick shouldDegrade 2>/dev/null || true)
|
|
99
|
+
if [ "$_SHOULD_DEGRADE" = "true" ]; then
|
|
100
|
+
_DEGRADE_MSG=$(gsd_run query worktree.base-check --pick message 2>/dev/null || true)
|
|
101
|
+
[ -n "$_DEGRADE_MSG" ] && printf '%s\n' "$_DEGRADE_MSG" >&2
|
|
102
|
+
USE_WORKTREES=false
|
|
103
|
+
fi
|
|
104
|
+
fi
|
|
95
105
|
```
|
|
96
106
|
Codex maps subagents to `spawn_agent`, which has no direct Codex mapping for Claude Code's `isolation="worktree"` parameter. Failing closed prevents main-checkout edits while the workflow believes agents are isolated.
|
|
97
107
|
|
|
@@ -111,6 +121,8 @@ fi
|
|
|
111
121
|
|
|
112
122
|
When `USE_WORKTREES` (project-level) is `false`, all executor agents run without `isolation="worktree"` — they execute sequentially on the main working tree instead of in parallel worktrees. The per-plan decision below has no effect when worktrees are project-disabled.
|
|
113
123
|
|
|
124
|
+
`USE_WORKTREES` is also automatically set to `false` for the duration of a run when `worktree base-check` detects that the orchestrator HEAD has diverged from the worktree fork base (the #683 condition — e.g. an unmerged milestone or feature branch). This check runs only when `RUNTIME=claude` because `isolation="worktree"` is a Claude Code-specific feature; other runtimes do not use it. The auto-degrade prints a one-line warning to stderr and falls through to the sequential path so executors do not hit the exit-42 worktree-branch-check halt. To restore parallel worktree execution, set `worktree.baseRef:"head"` in `.claude/settings.local.json` (or run `gsd-tools worktree set-baseref`) — this makes the fork base track the live HEAD instead of a fixed remote ref. The `worktree-branch-check` exit-42 guard inside each executor remains in place as a backstop.
|
|
125
|
+
|
|
114
126
|
Read context window size for adaptive prompt enrichment:
|
|
115
127
|
|
|
116
128
|
```bash
|
|
@@ -188,7 +200,7 @@ if [ "$MVP_MODE" = "true" ] && [ "$TDD_MODE" = "true" ]; then
|
|
|
188
200
|
fi
|
|
189
201
|
fi
|
|
190
202
|
```
|
|
191
|
-
Pure doc-only / config-only / test-only tasks return `is_behavior_adding=false` and are exempt.
|
|
203
|
+
Pure doc-only / config-only / test-only tasks return `is_behavior_adding=false` and are exempt. When the gate trips, Read `~/.claude/gsd-core/references/execute-mvp-tdd.md` for the exact halt report format.
|
|
192
204
|
</step>
|
|
193
205
|
|
|
194
206
|
<step name="check_blocking_antipatterns" priority="first">
|
|
@@ -1413,16 +1425,15 @@ ${VERIFIER_SKILLS}",
|
|
|
1413
1425
|
|
|
1414
1426
|
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
|
|
1415
1427
|
|
|
1416
|
-
Read status:
|
|
1428
|
+
Read status via the canonical query (scoped to frontmatter, covers missing/unknown cases):
|
|
1417
1429
|
```bash
|
|
1418
|
-
|
|
1430
|
+
VERIFICATION=$(gsd_run query verification.status "$PHASE_DIR" 2>/dev/null)
|
|
1431
|
+
STATUS=$(printf '%s' "$VERIFICATION" | jq -r '.status' 2>/dev/null || echo "")
|
|
1432
|
+
NEXT_ACTION=$(printf '%s' "$VERIFICATION" | jq -r '.next_action' 2>/dev/null || echo "")
|
|
1433
|
+
NEXT_COMMAND=$(printf '%s' "$VERIFICATION" | jq -r '.next_command' 2>/dev/null || echo "")
|
|
1419
1434
|
```
|
|
1420
1435
|
|
|
1421
|
-
|
|
1422
|
-
|--------|--------|
|
|
1423
|
-
| `passed` | → update_roadmap |
|
|
1424
|
-
| `human_needed` | Persist and present human testing items; keep phase pending until verification reruns as `passed` |
|
|
1425
|
-
| `gaps_found` | Present gap summary, offer `/gsd:plan-phase {phase} --gaps ${GSD_WS}` |
|
|
1436
|
+
Route on `$STATUS`: if `passed`, proceed to update_roadmap. Otherwise keep the phase pending — present `$NEXT_ACTION` to the user and, when `$NEXT_COMMAND` is non-empty, show it as the next command to run. The query covers all cases including missing files (`missing`) and unexpected values (`unknown`), so no per-status arm needs to be listed here.
|
|
1426
1437
|
|
|
1427
1438
|
**If human_needed:**
|
|
1428
1439
|
|
|
@@ -86,7 +86,7 @@ Create detailed execution plan for a specific phase.
|
|
|
86
86
|
|
|
87
87
|
- `--skip-research` — bypass the research subagent
|
|
88
88
|
- `--research-phase <N>` — research-only mode. Spawns the research agent for phase `<N>`, writes `RESEARCH.md`, then exits before the planner runs. Useful for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops. Replaces the deleted `gsd-research-phase` standalone command (#3042).
|
|
89
|
-
- Modifiers: `--research` forces refresh (re-spawn researcher
|
|
89
|
+
- Modifiers: `--research` forces refresh (re-spawn researcher). `--view` prints existing `RESEARCH.md` to stdout without spawning. With neither, auto-uses an existing `RESEARCH.md` (one-line notice, then clean exit).
|
|
90
90
|
- `--gaps` — focus only on closing gaps from a prior plan-check
|
|
91
91
|
- `--skip-verify` — skip the post-plan verifier loop
|
|
92
92
|
- `--ingest <path-or-glob>` — pre-ingest external ADRs/PRDs/SPECs before planning (see *PRD Express Path* below)
|
|
@@ -100,7 +100,7 @@ Create detailed execution plan for a specific phase.
|
|
|
100
100
|
- Multiple plans per phase supported (XX-01, XX-02, etc.)
|
|
101
101
|
|
|
102
102
|
Usage: `/gsd:plan-phase 1`
|
|
103
|
-
Usage: `/gsd:plan-phase --research-phase 2` — research only on phase 2 (
|
|
103
|
+
Usage: `/gsd:plan-phase --research-phase 2` — research only on phase 2 (auto-uses existing `RESEARCH.md`, no prompt)
|
|
104
104
|
Usage: `/gsd:plan-phase --research-phase 2 --view` — print existing `RESEARCH.md`, no spawn
|
|
105
105
|
Usage: `/gsd:plan-phase --research-phase 2 --research` — force-refresh, no prompt
|
|
106
106
|
Result: Creates `.planning/phases/01-foundation/01-01-PLAN.md`
|
|
@@ -52,7 +52,8 @@ If `PATH_NOT_FOUND` or `MANIFEST_NOT_FOUND`: display error and exit.
|
|
|
52
52
|
Run the init query:
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
|
|
55
|
+
_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 command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/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
|
|
56
|
+
INIT=$(gsd_run init ingest-docs)
|
|
56
57
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
57
58
|
```
|
|
58
59
|
|
|
@@ -295,7 +296,7 @@ Preview the merge diff to the user and gate via approve-revise-abort before writ
|
|
|
295
296
|
Commit the ingest results:
|
|
296
297
|
|
|
297
298
|
```bash
|
|
298
|
-
|
|
299
|
+
gsd_run commit \
|
|
299
300
|
"docs: ingest {N} docs from {SCAN_PATH} (#2387)" --files \
|
|
300
301
|
.planning/PROJECT.md \
|
|
301
302
|
.planning/REQUIREMENTS.md \
|
|
@@ -32,7 +32,8 @@ Load all context in one call (paths only to minimize orchestrator context):
|
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
_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 command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/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
|
|
35
|
-
|
|
35
|
+
GRAN_PARAM=""; if [[ "$ARGUMENTS" =~ (^|[[:space:]])--granularity[[:space:]]+([^[:space:]-][^[:space:]]*) ]]; then GRAN_PARAM="--granularity ${BASH_REMATCH[2]}"; fi
|
|
36
|
+
INIT=$(gsd_run query init.plan-phase "$PHASE" $GRAN_PARAM)
|
|
36
37
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
37
38
|
AGENT_SKILLS_RESEARCHER=$(gsd_run query agent-skills gsd-phase-researcher)
|
|
38
39
|
AGENT_SKILLS_PLANNER=$(gsd_run query agent-skills gsd-planner)
|
|
@@ -46,7 +47,7 @@ When `TDD_MODE` is `true`, the planner agent is instructed to apply `type: tdd`
|
|
|
46
47
|
|
|
47
48
|
When `CONTEXT_WINDOW >= 500000`, the planner prompt includes the 3 most recent prior phase CONTEXT.md and SUMMARY.md files PLUS any phases explicitly listed in the current phase's `Depends on:` field in ROADMAP.md. Explicit dependencies always load regardless of recency (e.g., Phase 7 declaring `Depends on: Phase 2` always sees Phase 2's context). Bounded recency keeps the planner's context budget focused on recent work.
|
|
48
49
|
|
|
49
|
-
Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_enabled`, `plan_checker_enabled`, `nyquist_validation_enabled`, `commit_docs`, `text_mode`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_reviews`, `has_plans`, `plan_count`, `phase_status` (#3569), `planning_exists`, `roadmap_exists`, `phase_req_ids`, `response_language`.
|
|
50
|
+
Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_enabled`, `plan_checker_enabled`, `nyquist_validation_enabled`, `commit_docs`, `text_mode`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_reviews`, `has_plans`, `plan_count`, `phase_status` (#3569), `planning_exists`, `roadmap_exists`, `phase_req_ids`, `response_language`, `granularity`.
|
|
50
51
|
|
|
51
52
|
**If `response_language` is set:** Include `response_language: {value}` in all spawned subagent prompts so any user-facing output stays in the configured language.
|
|
52
53
|
|
|
@@ -99,7 +100,7 @@ The gate fires only on `Complete`. `Executed` and `Needs Review` are not gated
|
|
|
99
100
|
|
|
100
101
|
## 2. Parse and Normalize Arguments
|
|
101
102
|
|
|
102
|
-
Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--research-phase <N>`, `--gaps`, `--skip-verify`, `--skip-ui`, `--prd <filepath>`, `--ingest <path-or-glob>`, `--ingest-format <auto|nygard|madr|narrative>`, `--reviews`, `--text`, `--bounce`, `--skip-bounce`, `--chunked`, `--mvp`, `--tdd`, `--force` (override closed-phase gate, see §1.5)).
|
|
103
|
+
Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--research-phase <N>`, `--gaps`, `--skip-verify`, `--skip-ui`, `--prd <filepath>`, `--ingest <path-or-glob>`, `--ingest-format <auto|nygard|madr|narrative>`, `--reviews`, `--text`, `--bounce`, `--skip-bounce`, `--chunked`, `--mvp`, `--tdd`, `--granularity <coarse|standard|fine>`, `--force` (override closed-phase gate, see §1.5)).
|
|
103
104
|
|
|
104
105
|
**`--research-phase <N>` — research-only mode (#3042 + #3044).** When this flag is present, parse `<N>` as the phase number (overrides any positional phase argument), set `RESEARCH_ONLY=true`, and treat the rest of this workflow as a research-dispatch only — the planner spawn (step 8), plan-checker, verification, gaps, bounce, and post-planning-gaps blocks all skip on `RESEARCH_ONLY`. Use this for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops. Replaces the deleted `/gsd-research-phase` command.
|
|
105
106
|
|
|
@@ -120,6 +121,8 @@ if $RESEARCH_ONLY && [[ "$ARGUMENTS" =~ (^|[[:space:]])--view([[:space:]]|$) ]];
|
|
|
120
121
|
fi
|
|
121
122
|
```
|
|
122
123
|
|
|
124
|
+
**`--granularity <coarse|standard|fine>` — CLI override (#703).** When present, this value is the resolved granularity passed to the planner — it wins over any per-phase `granularities.<type>` config, top-level `granularity` config, or project defaults. The init JSON always includes a `granularity` field reflecting the resolved value; read it from there. Invalid values (anything other than `coarse`, `standard`, `fine`) cause an error at the CLI boundary.
|
|
125
|
+
|
|
123
126
|
Set `TEXT_MODE=true` if `--text` is present in $ARGUMENTS OR `text_mode` from init JSON is `true`. When `TEXT_MODE` is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for Claude Code remote sessions (`/rc` mode) where TUI menus don't work through the Claude App.
|
|
124
127
|
|
|
125
128
|
**MVP_MODE resolution.** Resolve `MVP_MODE` once via the centralized `phase.mvp-mode` query verb. Precedence (first hit wins): CLI flag → ROADMAP.md `**Mode:** mvp` → `workflow.mvp_mode` config → false. The verb is the single source of truth — do not re-implement the chain.
|
|
@@ -143,7 +146,7 @@ fi
|
|
|
143
146
|
```
|
|
144
147
|
|
|
145
148
|
When `WALKING_SKELETON=true`:
|
|
146
|
-
- Planner is instructed to produce `SKELETON.md` in the phase directory alongside `PLAN.md`. The template lives at
|
|
149
|
+
- Planner is instructed to produce `SKELETON.md` in the phase directory alongside `PLAN.md`. The template lives at `~/.claude/gsd-core/references/skeleton-template.md` — the planner reads it when producing SKELETON.md (lazy; not loaded on non-skeleton runs).
|
|
147
150
|
- The plan must scaffold project + routing + one real DB read/write + one real UI interaction + dev deployment — the thinnest possible end-to-end working slice.
|
|
148
151
|
|
|
149
152
|
**Interaction with `--prd <filepath>`.** `--mvp` and `--prd` compose. The PRD express path (Step 3.5) creates `CONTEXT.md` from the PRD file and continues to research; the Walking Skeleton gate fires independently from the conditions above. When both are active on Phase 1 of a new project, the planner receives `WALKING_SKELETON=true` and PRD-derived context simultaneously — the PRD informs *what the skeleton should prove*. No precedence is needed; the two signals are orthogonal. See [`references/mvp-concepts.md`](../references/mvp-concepts.md) for the broader interaction map.
|
|
@@ -417,15 +420,15 @@ Pass `ai_spec_path` and `framework_line` to planner in step 7 so it can referenc
|
|
|
417
420
|
|
|
418
421
|
**Skip if:** `--gaps` flag or `--skip-research` flag or `--reviews` flag.
|
|
419
422
|
|
|
420
|
-
### 5.0. Research-Only Modifiers (`--view`, `--research
|
|
423
|
+
### 5.0. Research-Only Modifiers (`--view`, `--research`)
|
|
421
424
|
|
|
422
425
|
**Skip if:** `RESEARCH_ONLY` is `false`.
|
|
423
426
|
|
|
424
427
|
Three branches in research-only mode (`--research-phase <N>`):
|
|
425
428
|
|
|
426
|
-
1. **`--view
|
|
429
|
+
1. **`--view`**: print `RESEARCH.md` to stdout, no spawn, exit. If `RESEARCH.md` is missing, error with: `--view requires an existing RESEARCH.md; drop --view to spawn the researcher.`
|
|
427
430
|
2. **`--research`** (force-refresh): re-spawn researcher unconditionally — fall through to "Spawn gsd-phase-researcher" below.
|
|
428
|
-
3. **Neither flag AND `has_research=true`:**
|
|
431
|
+
3. **Neither flag AND `has_research=true`:** auto-use the existing research and exit cleanly — do not prompt, do not re-spawn. Emit `RESEARCH.md already exists for Phase ${PHASE}, using it. To force-refresh, re-invoke with --research; to print, re-invoke with --view. Path: ${research_path}` then exit. The explicit-flag escape hatches cover any deviation; this matches §5.1's promptless auto-use of existing research, removing the §5.0/§5.1 inconsistency (#159).
|
|
429
432
|
|
|
430
433
|
```bash
|
|
431
434
|
if [[ "$VIEW_ONLY" == "true" ]]; then
|
|
@@ -933,12 +936,13 @@ Each TDD plan gets one feature with RED/GREEN/REFACTOR gate sequence.
|
|
|
933
936
|
</tdd_mode_active>
|
|
934
937
|
` : ''}
|
|
935
938
|
|
|
936
|
-
**MVP_MODE:** ${MVP_MODE} (when true, follow vertical-slice rules from
|
|
937
|
-
**WALKING_SKELETON:** ${WALKING_SKELETON} (when true, the first deliverable must be a Walking Skeleton — produce SKELETON.md alongside PLAN.md.)
|
|
939
|
+
**MVP_MODE:** ${MVP_MODE} (when true, follow vertical-slice rules from `~/.claude/gsd-core/references/planner-mvp-mode.md`; when false, ignore MVP guidance entirely.)
|
|
940
|
+
**WALKING_SKELETON:** ${WALKING_SKELETON} (when true, the first deliverable must be a Walking Skeleton — Read the template at `~/.claude/gsd-core/references/skeleton-template.md` and produce SKELETON.md alongside PLAN.md.)
|
|
941
|
+
**Granularity:** {granularity}
|
|
938
942
|
|
|
939
943
|
${MVP_MODE === 'true' ? `
|
|
940
944
|
<mvp_mode_active>
|
|
941
|
-
**MVP Mode is ENABLED.**
|
|
945
|
+
**MVP Mode is ENABLED.** Read `~/.claude/gsd-core/references/planner-mvp-mode.md` now and follow its vertical-slice planning rules. Each plan must deliver a complete vertical slice — thin end-to-end functionality rather than horizontal layers.
|
|
942
946
|
</mvp_mode_active>
|
|
943
947
|
` : ''}
|
|
944
948
|
</planning_context>
|
|
@@ -63,7 +63,7 @@ Then re-run: /gsd:plan-review-convergence {PHASE}
|
|
|
63
63
|
## 2. Initialize
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
|
-
INIT=$(
|
|
66
|
+
INIT=$(gsd_run init plan-phase "$PHASE")
|
|
67
67
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
68
68
|
```
|
|
69
69
|
|
|
@@ -76,7 +76,7 @@ Set `TEXT_MODE=true` if `--text` is present in $ARGUMENTS OR `text_mode` from in
|
|
|
76
76
|
## 3. Validate Phase + Pre-flight Gate
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
PHASE_INFO=$(
|
|
79
|
+
PHASE_INFO=$(gsd_run roadmap get-phase "${PHASE}")
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
**If `found` is false:** Error with available phases. Exit.
|
|
@@ -230,7 +230,7 @@ fi
|
|
|
230
230
|
**If HIGH_COUNT == 0 (converged):**
|
|
231
231
|
|
|
232
232
|
```bash
|
|
233
|
-
|
|
233
|
+
gsd_run state planned-phase --phase "${PHASE}" --name "${phase_name}" --plans "${PLAN_COUNT}"
|
|
234
234
|
```
|
|
235
235
|
|
|
236
236
|
Display:
|
|
@@ -22,7 +22,7 @@ command -v codex >/dev/null 2>&1 && echo "codex:available" || echo "codex:missin
|
|
|
22
22
|
command -v coderabbit >/dev/null 2>&1 && echo "coderabbit:available" || echo "coderabbit:missing"
|
|
23
23
|
command -v opencode >/dev/null 2>&1 && echo "opencode:available" || echo "opencode:missing"
|
|
24
24
|
command -v qwen >/dev/null 2>&1 && echo "qwen:available" || echo "qwen:missing"
|
|
25
|
-
command -v cursor >/dev/null 2>&1 && echo "cursor:available" || echo "cursor:missing"
|
|
25
|
+
command -v cursor-agent >/dev/null 2>&1 && echo "cursor:available" || echo "cursor:missing"
|
|
26
26
|
command -v agy >/dev/null 2>&1 && echo "antigravity:available" || echo "antigravity:missing"
|
|
27
27
|
|
|
28
28
|
# Check local model servers (OpenAI-compatible HTTP API — no CLI binary required)
|
|
@@ -284,9 +284,15 @@ fi
|
|
|
284
284
|
|
|
285
285
|
**Cursor:**
|
|
286
286
|
```bash
|
|
287
|
-
|
|
287
|
+
# cursor-agent is a SEPARATE binary from the `cursor` IDE launcher; print mode (-p) takes the
|
|
288
|
+
# prompt as an ARGUMENT, not stdin. A full review prompt can exceed the OS argument limit, so
|
|
289
|
+
# reference the prompt file by path rather than inlining it. Capture stderr so a failure is
|
|
290
|
+
# diagnosable instead of a silent empty result.
|
|
291
|
+
CURSOR_PROMPT_ARG="Read the file at /tmp/gsd-review-prompt-{phase}.md in full and carry out the review request it contains. Output only the resulting markdown review. Do not edit any files."
|
|
292
|
+
cursor-agent -p --mode ask --trust --output-format text "$CURSOR_PROMPT_ARG" 2>/tmp/gsd-review-cursor-{phase}.err > /tmp/gsd-review-cursor-{phase}.md
|
|
288
293
|
if [ ! -s /tmp/gsd-review-cursor-{phase}.md ]; then
|
|
289
|
-
echo "Cursor review failed or returned empty output." > /tmp/gsd-review-cursor-{phase}.md
|
|
294
|
+
echo "Cursor review failed or returned empty output. stderr:" > /tmp/gsd-review-cursor-{phase}.md
|
|
295
|
+
cat /tmp/gsd-review-cursor-{phase}.err >> /tmp/gsd-review-cursor-{phase}.md
|
|
290
296
|
fi
|
|
291
297
|
```
|
|
292
298
|
|
|
@@ -350,8 +356,19 @@ if [ -f "$_AGY_CACHE" ]; then
|
|
|
350
356
|
fi
|
|
351
357
|
fi
|
|
352
358
|
|
|
353
|
-
# Step 1 — primary invocation: stdout works on macOS, Linux, and WSL
|
|
354
|
-
agy -
|
|
359
|
+
# Step 1 — primary invocation: stdout works on macOS, Linux, and WSL.
|
|
360
|
+
# Bound the run with agy's OWN `--print-timeout` (issue #687). On a large,
|
|
361
|
+
# file-path-rich prompt agy's agentic Cascade can loop on its code_search/grep
|
|
362
|
+
# steps and never converge; `--print-timeout` is agy's native cap for print mode
|
|
363
|
+
# (defaults to 5m — see maintainer note above), so we pass it explicitly to let a
|
|
364
|
+
# stalled run self-terminate through the tool's own mechanism. A non-zero exit
|
|
365
|
+
# (timeout or crash) discards any partial output so the Step 2 transcript fallback
|
|
366
|
+
# / Step 3 stub take over.
|
|
367
|
+
agy --print-timeout 300s -p "$(cat /tmp/gsd-review-prompt-{phase}.md)" 2>/dev/null > /tmp/gsd-review-antigravity-{phase}.md
|
|
368
|
+
_AGY_RC=$?
|
|
369
|
+
if [ "$_AGY_RC" -ne 0 ]; then
|
|
370
|
+
: > /tmp/gsd-review-antigravity-{phase}.md
|
|
371
|
+
fi
|
|
355
372
|
|
|
356
373
|
# Step 2 — transcript fallback: catches Windows agy -p stdout bug (and any future stdout-silent edge cases).
|
|
357
374
|
# Reads only lines appended AFTER the pre-flight watermark. If agy failed before writing a new response,
|
|
@@ -41,15 +41,12 @@ Verify the work is ready to ship:
|
|
|
41
41
|
|
|
42
42
|
1. **Verification passed?**
|
|
43
43
|
```bash
|
|
44
|
-
|
|
45
|
-
STATUS=$(
|
|
44
|
+
VERIFICATION=$(gsd_run query verification.status "${PHASE_DIR}" 2>/dev/null)
|
|
45
|
+
STATUS=$(printf '%s' "$VERIFICATION" | jq -r '.status' 2>/dev/null || echo "")
|
|
46
|
+
NEXT_ACTION=$(printf '%s' "$VERIFICATION" | jq -r '.next_action' 2>/dev/null || echo "")
|
|
47
|
+
NEXT_COMMAND=$(printf '%s' "$VERIFICATION" | jq -r '.next_command' 2>/dev/null || echo "")
|
|
46
48
|
```
|
|
47
|
-
|
|
48
|
-
- `passed` → verification complete; continue to the next preflight check.
|
|
49
|
-
- `gaps_found` → run `/gsd:plan-phase ${PHASE_NUMBER} --gaps` to plan the fixes, then re-run `/gsd:execute-phase` before shipping.
|
|
50
|
-
- `human_needed` → complete the manual tests in `${PHASE_DIR}/*-UAT.md`, then re-run the verify step until status is `passed`.
|
|
51
|
-
- empty (no `*-VERIFICATION.md`) → the verify step never completed; re-run `/gsd:execute-phase`.
|
|
52
|
-
- any other value → unexpected status `${STATUS}`; re-run `/gsd:execute-phase` verification.
|
|
49
|
+
Only `passed` may ship. If `$STATUS` is `passed`, verification is complete — continue to the next preflight check. Any other value (including `gaps_found`, `human_needed`, `missing`, and `unknown`) blocks with `PHASE_VERIFICATION_INCOMPLETE`: present `$NEXT_ACTION` to the user and, when `$NEXT_COMMAND` is non-empty, show it as the command to run next. The query already handles missing files and unexpected values, so no per-status arm is needed.
|
|
53
50
|
|
|
54
51
|
2. **Clean working tree?**
|
|
55
52
|
```bash
|
|
@@ -56,7 +56,8 @@ Rotate through these perspectives — each naturally surfaces different blindspo
|
|
|
56
56
|
## Step 1: Initialize
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
|
|
59
|
+
_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 command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/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
|
|
60
|
+
INIT=$(gsd_run init phase-op "${PHASE}")
|
|
60
61
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
61
62
|
```
|
|
62
63
|
|
|
@@ -174,7 +174,6 @@ EXTRACT_JSON=$(node "$GSD_DIR/gsd-core/scripts/changeset/cli.cjs" extract \
|
|
|
174
174
|
--changelog "$CHANGELOG_TMP" \
|
|
175
175
|
--json 2>/dev/null)
|
|
176
176
|
EXTRACT_EXIT=$?
|
|
177
|
-
rm -f "$CHANGELOG_TMP"
|
|
178
177
|
|
|
179
178
|
if [ "$EXTRACT_EXIT" -eq 2 ]; then
|
|
180
179
|
# Exit 2 = no releases in range (e.g. versions are equal or changelog is sparse)
|
|
@@ -188,6 +187,8 @@ else
|
|
|
188
187
|
--to "$LATEST_VERSION" \
|
|
189
188
|
--changelog "$CHANGELOG_TMP" 2>/dev/null || echo "(changelog unavailable)")
|
|
190
189
|
fi
|
|
190
|
+
# Clean up temp changelog now that both extract runs are done
|
|
191
|
+
rm -f "$CHANGELOG_TMP"
|
|
191
192
|
```
|
|
192
193
|
|
|
193
194
|
3. Display preview and ask for confirmation, using `$CHANGELOG_PREVIEW` from the extract step above:
|
|
@@ -150,7 +150,7 @@ process.stdin.on('end', () => {
|
|
|
150
150
|
spawn(
|
|
151
151
|
process.execPath,
|
|
152
152
|
[gsdTools, 'state', 'record-session', '--stopped-at', stoppedAt],
|
|
153
|
-
{ cwd, detached: true, stdio: 'ignore' }
|
|
153
|
+
{ cwd, detached: true, stdio: 'ignore', windowsHide: true }
|
|
154
154
|
).unref();
|
|
155
155
|
warnData.criticalRecorded = true;
|
|
156
156
|
// Persist the sentinel so subsequent debounce cycles don't re-fire
|
|
@@ -18,7 +18,7 @@ const fs = require('fs');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const { spawnSync } = require('child_process');
|
|
20
20
|
|
|
21
|
-
const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000 };
|
|
21
|
+
const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000, windowsHide: true };
|
|
22
22
|
|
|
23
23
|
function git(args, cwd) {
|
|
24
24
|
return spawnSync('git', args, { ...SPAWNOPT, cwd });
|
|
@@ -150,7 +150,7 @@ process.stdin.on('end', () => {
|
|
|
150
150
|
spawn(
|
|
151
151
|
process.execPath,
|
|
152
152
|
[gsdTools, 'state', 'record-session', '--stopped-at', stoppedAt],
|
|
153
|
-
{ cwd, detached: true, stdio: 'ignore' }
|
|
153
|
+
{ cwd, detached: true, stdio: 'ignore', windowsHide: true }
|
|
154
154
|
).unref();
|
|
155
155
|
warnData.criticalRecorded = true;
|
|
156
156
|
// Persist the sentinel so subsequent debounce cycles don't re-fire
|
|
@@ -18,7 +18,7 @@ const fs = require('fs');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const { spawnSync } = require('child_process');
|
|
20
20
|
|
|
21
|
-
const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000 };
|
|
21
|
+
const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000, windowsHide: true };
|
|
22
22
|
|
|
23
23
|
function git(args, cwd) {
|
|
24
24
|
return spawnSync('git', args, { ...SPAWNOPT, cwd });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengsd/gsd-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-rc.1",
|
|
4
4
|
"description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"gsd-core": "bin/install.js",
|
|
@@ -62,6 +62,9 @@
|
|
|
62
62
|
"typescript": "^6.0.3",
|
|
63
63
|
"typescript-eslint": "^8.60.0"
|
|
64
64
|
},
|
|
65
|
+
"overrides": {
|
|
66
|
+
"qs": ">=6.15.2"
|
|
67
|
+
},
|
|
65
68
|
"optionalDependencies": {
|
|
66
69
|
"fallow": "^2.70.0"
|
|
67
70
|
},
|
|
@@ -4,6 +4,7 @@ const { execFileSync } = require('node:child_process');
|
|
|
4
4
|
const { readdirSync, readFileSync, existsSync } = require('node:fs');
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
|
|
7
|
+
const { ExitError } = require('./lib/cli-exit.cjs');
|
|
7
8
|
const { suiteOf } = require('./run-tests.cjs');
|
|
8
9
|
|
|
9
10
|
const CRITICAL_PATHS = [
|
|
@@ -409,7 +410,7 @@ function runNodeTestFiles(repoRoot, files) {
|
|
|
409
410
|
if (firstFailure === 0) firstFailure = code;
|
|
410
411
|
}
|
|
411
412
|
}
|
|
412
|
-
if (firstFailure !== 0)
|
|
413
|
+
if (firstFailure !== 0) throw new ExitError(firstFailure);
|
|
413
414
|
}
|
|
414
415
|
|
|
415
416
|
function runSuite(repoRoot, suite) {
|
|
@@ -442,7 +443,7 @@ function resolveBaseRef() {
|
|
|
442
443
|
* security), so every concrete match that pickAffectedTests put into `selected`
|
|
443
444
|
* belongs to one of those suites and will be exercised by running all three.
|
|
444
445
|
*/
|
|
445
|
-
function resolveRunPlan({ changedFiles, selected, widenRequired, criticalPath, noChanges }) {
|
|
446
|
+
function resolveRunPlan({ changedFiles: _changedFiles, selected, widenRequired, criticalPath, noChanges }) {
|
|
446
447
|
if (noChanges) {
|
|
447
448
|
return { mode: 'suite', suite: 'unit' };
|
|
448
449
|
}
|