@opengsd/gsd-core 1.7.0-rc.5 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-executor.md +2 -1
- package/agents/gsd-security-auditor.md +13 -15
- package/agents/gsd-ui-checker.md +2 -0
- package/agents/gsd-ui-researcher.md +1 -0
- package/bin/install.js +975 -196
- package/commands/gsd/mempalace-capture.md +27 -1
- package/commands/gsd/surface.md +6 -6
- package/gsd-core/bin/gsd-tools.cjs +63 -2
- package/gsd-core/bin/lib/api-coverage.cjs +3 -4
- package/gsd-core/bin/lib/audit.cjs +7 -6
- package/gsd-core/bin/lib/capability-registry.cjs +503 -87
- package/gsd-core/bin/lib/capability-validator.cjs +56 -18
- package/gsd-core/bin/lib/check-command-router.cjs +1 -1
- package/gsd-core/bin/lib/clock.cjs +19 -0
- package/gsd-core/bin/lib/commands.cjs +48 -9
- package/gsd-core/bin/lib/config-loader.cjs +6 -2
- package/gsd-core/bin/lib/config.cjs +12 -0
- package/gsd-core/bin/lib/core-utils.cjs +8 -2
- package/gsd-core/bin/lib/drift.cjs +4 -4
- package/gsd-core/bin/lib/frontmatter.cjs +22 -0
- package/gsd-core/bin/lib/gsd2-import.cjs +2 -1
- package/gsd-core/bin/lib/host-integration.cjs +33 -8
- package/gsd-core/bin/lib/init.cjs +60 -53
- package/gsd-core/bin/lib/install-engine.cjs +93 -22
- package/gsd-core/bin/lib/installer-migration-authoring.cjs +2 -1
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +1 -1
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +342 -0
- package/gsd-core/bin/lib/markdown-table.cjs +698 -0
- package/gsd-core/bin/lib/mcp-server.cjs +18 -7
- package/gsd-core/bin/lib/milestone.cjs +217 -31
- package/gsd-core/bin/lib/phase-command-router.cjs +50 -2
- package/gsd-core/bin/lib/phase-lifecycle.cjs +62 -36
- package/gsd-core/bin/lib/phase-locator.cjs +23 -2
- package/gsd-core/bin/lib/phase.cjs +436 -61
- package/gsd-core/bin/lib/plan-scan.cjs +3 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +24 -7
- package/gsd-core/bin/lib/roadmap-parser.cjs +218 -13
- package/gsd-core/bin/lib/roadmap.cjs +100 -49
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +242 -44
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +3 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +24 -14
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +19 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +22 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +526 -29
- package/gsd-core/bin/lib/runtime-name-policy.cjs +63 -5
- package/gsd-core/bin/lib/schema-detect.cjs +2 -1
- package/gsd-core/bin/lib/security.cjs +7 -37
- package/gsd-core/bin/lib/shell-command-projection.cjs +176 -27
- package/gsd-core/bin/lib/smart-entry.cjs +4 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +30 -10
- package/gsd-core/bin/lib/state-transition.cjs +100 -45
- package/gsd-core/bin/lib/state.cjs +391 -126
- package/gsd-core/bin/lib/surface.cjs +12 -8
- package/gsd-core/bin/lib/template.cjs +2 -1
- package/gsd-core/bin/lib/uat.cjs +54 -8
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +249 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +23 -1
- package/gsd-core/bin/lib/verify.cjs +4 -3
- package/gsd-core/bin/lib/workstream.cjs +3 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +1 -1
- package/gsd-core/bin/lib/write-set.cjs +38 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -3
- package/gsd-core/references/checkpoints.md +12 -0
- package/gsd-core/references/ui-consideration-probe.md +73 -0
- package/gsd-core/templates/UI-SPEC.md +25 -0
- package/gsd-core/templates/VALIDATION.md +2 -0
- package/gsd-core/workflows/add-tests.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +7 -4
- package/gsd-core/workflows/debug.md +2 -0
- package/gsd-core/workflows/execute-phase.md +5 -3
- package/gsd-core/workflows/fast.md +8 -22
- package/gsd-core/workflows/plan-phase.md +6 -0
- package/gsd-core/workflows/progress.md +2 -2
- package/gsd-core/workflows/quick.md +2 -0
- package/gsd-core/workflows/review.md +42 -3
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/settings-advanced.md +7 -4
- package/gsd-core/workflows/ship.md +8 -2
- package/gsd-core/workflows/spec-phase.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +146 -1
- package/gsd-core/workflows/validate-phase.md +2 -2
- package/hooks/dist/gsd-statusline.js +164 -14
- package/hooks/dist/gsd-windsurf-pre-command.js +275 -0
- package/hooks/dist/gsd-windsurf-pre-write.js +132 -0
- package/hooks/dist/managed-hooks-registry.cjs +2 -0
- package/hooks/gsd-statusline.js +164 -14
- package/hooks/gsd-windsurf-pre-command.js +275 -0
- package/hooks/gsd-windsurf-pre-write.js +132 -0
- package/hooks/managed-hooks-registry.cjs +2 -0
- package/package.json +10 -4
- package/pi/gsd.cjs +354 -0
- package/scripts/build-hooks.js +3 -0
- package/scripts/ci-test-scope.cjs +39 -1
- package/scripts/gen-golden-install-parity-zcode.cjs +35 -35
- package/scripts/gen-install-tree-fixtures.cjs +75 -0
- package/scripts/gen-registry.cjs +128 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -1
- package/scripts/lint-table-schema-drift.cjs +157 -0
- package/scripts/lint-test-file-count.allowlist.json +2 -1
- package/scripts/registry-schema.cjs +565 -0
- package/scripts/validate-registry.cjs +117 -0
- package/skills/gsd-mempalace-capture/SKILL.md +27 -1
- package/skills/gsd-surface/SKILL.md +6 -6
- package/vscode/browser.js +197 -0
- package/vscode/extension.js +383 -0
- package/vscode/host-binding.js +113 -0
- package/vscode/package.json +96 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# UI-Consideration Probe — Spec-Completeness Reference
|
|
2
|
+
|
|
3
|
+
The **third** adapter of the shared `probe-core` resolution model (ADR-550 Decision 7), on
|
|
4
|
+
the **UI element/state axis**. It surfaces the shape-rooted UI *state* considerations a
|
|
5
|
+
UI-SPEC must resolve before a dimension may PASS — the visual analog of the requirement-side
|
|
6
|
+
[edge-probe](./edge-probe.md), reusing its exact lifecycle, validators, and plan-phase lift
|
|
7
|
+
(see edge-probe.md for the shared status×verification model — this doc does not re-argue it).
|
|
8
|
+
|
|
9
|
+
**Axis boundary (this is a MIXED axis).** This compiled taxonomy covers ONLY the finite,
|
|
10
|
+
project-independent shape-rooted content/robustness states. The **open**, domain/UX-dependent
|
|
11
|
+
considerations — real-time/offline/optimistic-UI, deep accessibility (WCAG breadth),
|
|
12
|
+
internationalization / RTL depth, and emerging interaction paradigms — are open-ended and are
|
|
13
|
+
prose-owned in the companion [domain-probes.md](./domain-probes.md) technology/UX bank, NOT
|
|
14
|
+
here. Forcing them into a closed compiled taxonomy is the wrong model.
|
|
15
|
+
|
|
16
|
+
## Inputs
|
|
17
|
+
|
|
18
|
+
A list of UI elements, each a `{ id, text, elements? }` record where `text` is the
|
|
19
|
+
researcher-authored description and `elements` is an optional author-supplied override of the
|
|
20
|
+
element classification. The six element kinds are: `form`, `list-collection`, `nav`, `media`,
|
|
21
|
+
`interactive-control`, `static-content`. When `elements` is absent, a heuristic classifier
|
|
22
|
+
proposes kinds from the prose (propose-then-confirm) — the author may correct the kind.
|
|
23
|
+
|
|
24
|
+
## Taxonomy (8 categories)
|
|
25
|
+
|
|
26
|
+
Closed and small by design: the finite, project-independent content/robustness states every
|
|
27
|
+
UI surface must account for. Growth toward open UX topics happens in `domain-probes.md`, not by
|
|
28
|
+
bloating this closed core.
|
|
29
|
+
|
|
30
|
+
| id | name | applies to element kinds | consideration question |
|
|
31
|
+
|----|------|--------------------------|------------------------|
|
|
32
|
+
| empty | Empty / no data | form, list-collection, media | What is shown when there is no data — zero items, an unfilled form, or absent media? |
|
|
33
|
+
| loading | Loading / in-flight | form, list-collection, media, nav | What is shown while data or content is still loading (skeleton, spinner, progressive reveal)? |
|
|
34
|
+
| error | Error / failure | form, list-collection, media, nav | What is shown when the load or submit fails (message, retry affordance, partial fallback)? |
|
|
35
|
+
| populated | Populated / happy path | list-collection, media | What does the normal populated (happy-path) state look like at a typical volume of content? |
|
|
36
|
+
| partial | Partial / incomplete | form, list-collection | What is shown for partial or incomplete data — some fields or rows present, others missing? |
|
|
37
|
+
| overflow | Overflow / truncation | list-collection, nav, static-content | What happens when content exceeds its container — scroll, clip, wrap, or truncate? |
|
|
38
|
+
| zero-one-many | Zero / one / many | list-collection | How does the layout read at zero, one, and many items (singular vs plural copy, spacing)? |
|
|
39
|
+
| long-text | Long text | form, static-content, interactive-control, nav | What happens with unusually long text — truncation, wrapping, ellipsis, or reflow? |
|
|
40
|
+
|
|
41
|
+
## Relevance filter + resolution states
|
|
42
|
+
|
|
43
|
+
The probe reuses the edge-probe rails verbatim (ADR-550 Decision 7 — see
|
|
44
|
+
[edge-probe.md](./edge-probe.md#relevance-filter--resolution-states) for the full model):
|
|
45
|
+
|
|
46
|
+
1. **Relevance filter first.** Classify each element's kind(s), then raise only the categories
|
|
47
|
+
whose `applies to element kinds` intersect. A static label is never asked about loading or
|
|
48
|
+
empty state — that is what makes an unresolved consideration meaningful.
|
|
49
|
+
2. **Dismissal requires a reason string.** Silence is not a resolution; the reason is the audit
|
|
50
|
+
trail.
|
|
51
|
+
3. **Zero-classification surfaces one `unclassified` candidate (#1110).** An element whose prose
|
|
52
|
+
matched no kind cue yields exactly one soft `unclassified — review manually` item
|
|
53
|
+
(`category: "unclassified"`, `status: "unresolved"`) — never a silent drop, never a guessed
|
|
54
|
+
kind. `unclassified` is a review signal, **not** a ninth taxonomy category; an explicit
|
|
55
|
+
`elements: []` opt-out stays silent.
|
|
56
|
+
|
|
57
|
+
Each raised consideration carries the shared two orthogonal axes — `status`
|
|
58
|
+
(`resolved | dismissed | unresolved`) and, when resolved, a `verification` tier
|
|
59
|
+
(`explicit | backstop`). A `backstop` consideration lifts into `must_haves.truths` and, at
|
|
60
|
+
verify time, is confirmed only by explicit evidence (a wired held-out/property test) or routes
|
|
61
|
+
to `insufficient_spec → human_needed` — never a silent pass (the honest-verifier disposition,
|
|
62
|
+
#1154). See [honest-verifier.md](./honest-verifier.md).
|
|
63
|
+
|
|
64
|
+
## Closed / open boundary
|
|
65
|
+
|
|
66
|
+
The **8 ids above are the closed, compiled subset** — finite and project-independent, so a
|
|
67
|
+
compiled taxonomy is legitimate (the same property that makes edge-probe's data-shape taxonomy
|
|
68
|
+
closed). The **open subset is prose-owned in [domain-probes.md](./domain-probes.md)**:
|
|
69
|
+
real-time/offline/optimistic-UI, deep accessibility (WCAG breadth), i18n / RTL depth, and
|
|
70
|
+
emerging interaction paradigms (gesture/voice/reduced-motion/print) are open-ended and
|
|
71
|
+
cue-triggered — they do not belong in this closed taxonomy. This probe **complements** the
|
|
72
|
+
`gsd-ui-checker` six quality dimensions (it adds a state-coverage axis); it does not change the
|
|
73
|
+
BLOCK/FLAG/PASS enum or the dimensions themselves.
|
|
@@ -79,6 +79,31 @@ Accent reserved for: {explicit list — never "all interactive elements"}
|
|
|
79
79
|
|
|
80
80
|
---
|
|
81
81
|
|
|
82
|
+
## UI Considerations
|
|
83
|
+
|
|
84
|
+
> Populated by the ui-phase UI-consideration probe (Step 9.5) and lifted by plan-phase's
|
|
85
|
+
> `## UI Considerations` lift rule via the identical rule as SPEC `## Edge Coverage`. Shape-rooted UI *state*
|
|
86
|
+
> coverage (empty / loading / error / populated / partial / overflow / zero-one-many / long-text).
|
|
87
|
+
> Empty-state and error-state COPY live in `## Copywriting Contract` above — this section covers
|
|
88
|
+
> state coverage and REFERENCES those rows rather than restating the copy (de-dup).
|
|
89
|
+
|
|
90
|
+
Applicable state considerations resolved: {N covered, M backstop, K unresolved — or "none applicable"}
|
|
91
|
+
|
|
92
|
+
| Category | Element(s) | Status | Resolution / Reason |
|
|
93
|
+
|----------|------------|--------|---------------------|
|
|
94
|
+
| {empty} | {list-collection} | ✅ covered | {concrete truth string — e.g. "Empty results render the documented 'No results' copy"} |
|
|
95
|
+
| {long-text} | {static-content} | 🧪 backstop | {held-out/visual UI-state test — lifts as `{ statement, verification: backstop }`} |
|
|
96
|
+
| {overflow} | {list-collection} | ⚠ unresolved | {planner treats as assumption} |
|
|
97
|
+
|
|
98
|
+
<!-- Status vocabulary (locked by probe-core projectTruths):
|
|
99
|
+
✅ covered → a plain truth string lifted into must_haves.truths
|
|
100
|
+
🧪 backstop → a flat scalar { statement, verification: backstop }; at verify time, no explicit
|
|
101
|
+
evidence → insufficient_spec → human_needed (never a silent pass, #1154)
|
|
102
|
+
⚠ unresolved → an explicit planner assumption (surfaced, never silently dropped)
|
|
103
|
+
Rows are REPLACED (not appended) on a probe re-run — idempotent. -->
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
82
107
|
## Registry Safety
|
|
83
108
|
|
|
84
109
|
| Registry | Blocks Used | Safety Gate |
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
phase: {N}
|
|
3
3
|
slug: {phase-slug}
|
|
4
|
+
# status lifecycle: draft (seeded by plan-phase) → validated (set by validate-phase §6)
|
|
5
|
+
# audit-milestone §5.5 distinguishes NOT-VALIDATED (draft) from PARTIAL (validated + nyquist_compliant: false) (#2117)
|
|
4
6
|
status: draft
|
|
5
7
|
nyquist_compliant: false
|
|
6
8
|
wave_0_complete: false
|
|
@@ -308,7 +308,7 @@ If there are passing tests to commit:
|
|
|
308
308
|
|
|
309
309
|
```bash
|
|
310
310
|
git add {test files}
|
|
311
|
-
git commit -m "test(phase-${phase_number}): add unit and E2E tests from add-tests command"
|
|
311
|
+
git commit -m "test(phase-${phase_number}): add unit and E2E tests from add-tests command" -- {test files}
|
|
312
312
|
```
|
|
313
313
|
|
|
314
314
|
Present next steps:
|
|
@@ -153,17 +153,20 @@ Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` a
|
|
|
153
153
|
|
|
154
154
|
If no active validate-phase step hook exists: skip entirely.
|
|
155
155
|
|
|
156
|
-
For each phase directory, check `*-VALIDATION.md`. If exists, parse frontmatter (`nyquist_compliant`, `wave_0_complete`).
|
|
156
|
+
For each phase directory, check `*-VALIDATION.md`. If exists, parse frontmatter (`status`, `nyquist_compliant`, `wave_0_complete`).
|
|
157
157
|
|
|
158
158
|
Classify per phase:
|
|
159
159
|
|
|
160
160
|
| Status | Condition |
|
|
161
161
|
|--------|-----------|
|
|
162
|
-
| COMPLIANT | `nyquist_compliant: true` and all tasks green |
|
|
163
|
-
| PARTIAL |
|
|
162
|
+
| COMPLIANT | `status: validated` and `nyquist_compliant: true` and all tasks green |
|
|
163
|
+
| PARTIAL | `status: validated` and (`nyquist_compliant: false` or red/pending) |
|
|
164
|
+
| NOT-VALIDATED | `status: draft` (or absent) — validate-phase has not yet reconciled this file (#2117) |
|
|
164
165
|
| MISSING | No VALIDATION.md |
|
|
165
166
|
|
|
166
|
-
|
|
167
|
+
> **NOT-VALIDATED vs PARTIAL (#2117):** A phase reads `status: draft` when it was seeded by plan-phase but never reconciled by validate-phase, OR when its `VALIDATION.md` predates the `status` field (files written before #2117 stay `draft` whether or not validation ran). In both cases `nyquist_compliant` is not authoritative, so this is a coverage TODO ("run validate-phase") — not a compliance failure. Re-running validate-phase promotes the file to `status: validated` and yields the real COMPLIANT/PARTIAL verdict. Only `status: validated` + `nyquist_compliant: false` is a genuine PARTIAL.
|
|
168
|
+
|
|
169
|
+
Add to audit YAML: `nyquist: { compliant_phases, partial_phases, not_validated_phases, missing_phases, overall }`
|
|
167
170
|
|
|
168
171
|
Discovery only — never auto-calls `/gsd:validate-phase`.
|
|
169
172
|
|
|
@@ -190,6 +190,8 @@ Create `.planning/debug/{slug}.md` with initial state using the Write tool (neve
|
|
|
190
190
|
|
|
191
191
|
After initial context setup, spawn the session manager to handle the full checkpoint/continuation loop. The session manager handles specialist_hint dispatch internally: when gsd-debugger returns ROOT CAUSE FOUND it extracts the specialist_hint field and invokes the matching skill (e.g. typescript-expert, swift-concurrency) before offering fix options.
|
|
192
192
|
|
|
193
|
+
> **Foreground, blocking spawn — #2196.** The `Agent(subagent_type="gsd-debug-session-manager", …)` call below is FOREGROUND and BLOCKING — it returns the compact session summary directly. Wait for it; do not background it, and do not poll for it. Never pass an agent or session identifier to `TaskOutput` — an agent ID is NOT a task ID, so `TaskOutput <agent-id>` always returns `No task found with ID`. If the spawn returns no usable result (the handoff is lost), do NOT claim the session is still running: preserve the checkpoint at `.planning/debug/{slug}.md`, report the failed handoff plainly, and resume by re-spawning the session manager or via `/gsd:debug continue {slug}`.
|
|
194
|
+
|
|
193
195
|
Print before spawning (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
|
|
194
196
|
```
|
|
195
197
|
[debug] Delegating loop to session manager...
|
|
@@ -1056,11 +1056,13 @@ AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null || echo "fal
|
|
|
1056
1056
|
```
|
|
1057
1057
|
|
|
1058
1058
|
When executor returns a checkpoint AND `AUTO_MODE` is `true`:
|
|
1059
|
-
- **human-verify** → Auto-spawn continuation agent with `{user_response}` = `"approved"`. Log `⚡ Auto-approved checkpoint`.
|
|
1060
|
-
- **decision** → Auto-spawn continuation agent with `{user_response}` = first option from checkpoint details. Log `⚡ Auto-selected: [option]`.
|
|
1059
|
+
- **human-verify** → Auto-spawn continuation agent with `{user_response}` = `"approved"`. Log `⚡ Auto-approved checkpoint`. **Except `blocking-human`.**
|
|
1060
|
+
- **decision** → Auto-spawn continuation agent with `{user_response}` = first option from checkpoint details. Log `⚡ Auto-selected: [option]`. **Except `blocking-human`.**
|
|
1061
1061
|
- **human-action** → Present to user (existing behavior below). Auth gates cannot be automated.
|
|
1062
1062
|
|
|
1063
|
-
**
|
|
1063
|
+
**Carve-out — overrides all branches above.** If the returned `Gate:` is `blocking-human`, or its `<what-built>` mentions `Package verification required before install` or `Package install failed — human verification required`, never auto-approve or auto-select, regardless of type. Present to user (standard flow below). Log `⛔ blocking-human gate — auto-mode suspended`.
|
|
1064
|
+
|
|
1065
|
+
**Standard flow (not auto-mode, human-action, or blocking-human):**
|
|
1064
1066
|
|
|
1065
1067
|
1. Spawn agent for checkpoint plan
|
|
1066
1068
|
2. Agent runs until checkpoint task or auth gate → returns structured state
|
|
@@ -64,32 +64,18 @@ Use conventional commit format: `fix:`, `feat:`, `docs:`, `chore:`, `refactor:`
|
|
|
64
64
|
|
|
65
65
|
<step name="log_to_state">
|
|
66
66
|
If `.planning/STATE.md` exists and has a "Quick Tasks Completed" table, append a row
|
|
67
|
-
that matches the existing table's schema
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
that matches the existing table's schema via the schema-backed `gsd-tools
|
|
68
|
+
quick-tasks-append` helper (`markdown-table.cjs`'s `appendQuickTaskRow`; #2133,
|
|
69
|
+
ADR-2143 §3/§7). If no table exists, skip silently. If the table's schema is
|
|
70
|
+
unrecognized, the helper fails loud (non-zero exit) instead of silently guessing
|
|
71
|
+
a column count — this replaces the prior inline `awk NF-2` arithmetic that was
|
|
72
|
+
the root cause of #2133.
|
|
70
73
|
|
|
71
74
|
```bash
|
|
75
|
+
_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
|
|
72
76
|
# Detect whether STATE.md has a Quick Tasks Completed table
|
|
73
77
|
if grep -q "Quick Tasks Completed" .planning/STATE.md 2>/dev/null; then
|
|
74
|
-
|
|
75
|
-
# quick.md Step 7 creates a 5-column table:
|
|
76
|
-
# | # | Description | Date | Commit | Directory |
|
|
77
|
-
# Count pipe characters in the header to determine column count.
|
|
78
|
-
HEADER_LINE=$(grep -A2 "Quick Tasks Completed" .planning/STATE.md 2>/dev/null | grep "^|" | head -1)
|
|
79
|
-
# Count columns: number of | separators minus 1 gives column count
|
|
80
|
-
COL_COUNT=$(echo "$HEADER_LINE" | awk -F'|' '{print NF-1}')
|
|
81
|
-
|
|
82
|
-
if [ "$COL_COUNT" -eq 5 ] && echo "$HEADER_LINE" | grep -qi "Description" && echo "$HEADER_LINE" | grep -qi "Commit" && echo "$HEADER_LINE" | grep -qi "Directory"; then
|
|
83
|
-
# 5-column schema from quick.md Step 7: | # | Description | Date | Commit | Directory |
|
|
84
|
-
# Determine the next row number by counting existing data rows (non-separator, non-header).
|
|
85
|
-
NEXT_NUM=$(awk '/Quick Tasks Completed/{found=1} found && /^\|/ && !/^[|][-: |]*[|]$/ && !/Description/{count++} END{print count+1}' .planning/STATE.md 2>/dev/null || echo "1")
|
|
86
|
-
# Get the latest commit hash (short)
|
|
87
|
-
COMMIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "—")
|
|
88
|
-
echo "| $NEXT_NUM | $TASK | $(date +%Y-%m-%d) | $COMMIT_HASH | — |" >> .planning/STATE.md
|
|
89
|
-
else
|
|
90
|
-
# Unrecognized table schema — skip to avoid appending a malformed row.
|
|
91
|
-
echo "⚠ fast.md log_to_state: Quick Tasks Completed table has unrecognized schema (${COL_COUNT} columns); skipping STATE.md update."
|
|
92
|
-
fi
|
|
78
|
+
gsd_run quick-tasks-append --task "$TASK" || echo "⚠ fast.md log_to_state: could not append Quick Tasks row (see message above); continuing."
|
|
93
79
|
fi
|
|
94
80
|
```
|
|
95
81
|
</step>
|
|
@@ -610,6 +610,10 @@ SKETCH_FINDINGS_PATH=$(ls ./.claude/skills/sketch-findings-*/SKILL.md 2>/dev/nul
|
|
|
610
610
|
PHASE_DIR_FOR_SPEC=$(_gsd_field "$INIT" phase_dir)
|
|
611
611
|
SPEC_FILE=$(ls "${PHASE_DIR_FOR_SPEC}"/*-SPEC.md 2>/dev/null | grep -Ev -- '-(AI|UI)-SPEC\.md$' | head -1)
|
|
612
612
|
SPEC_PATH="${SPEC_FILE}"
|
|
613
|
+
# Resolve the phase UI-SPEC separately (the glob above excludes -UI-SPEC.md); it carries the
|
|
614
|
+
# ## UI Considerations section the planner lifts by the same rule as ## Edge Coverage (#1867).
|
|
615
|
+
UI_SPEC_FILE=$(ls "${PHASE_DIR_FOR_SPEC}"/*-UI-SPEC.md 2>/dev/null | head -1)
|
|
616
|
+
UI_SPEC_PATH="${UI_SPEC_FILE}"
|
|
613
617
|
```
|
|
614
618
|
|
|
615
619
|
## 7.5. Verify Nyquist Artifacts
|
|
@@ -808,6 +812,7 @@ Output consumed by /gsd:execute-phase. Plans need:
|
|
|
808
812
|
- must_haves for goal-backward verification
|
|
809
813
|
- If the SPEC has an `## Edge Coverage` section, lift every `covered` edge's acceptance criterion into `must_haves.truths` as a plain string, and every `backstop` edge **as a structured flat-scalar marker** — an object item `{ statement: <the check>, verification: backstop }`, NOT a prose note (the verifier branches deterministically on the `verification: backstop` field; a parenthetical is unparseable — the #1110 fragility). Use a flat scalar `verification:` continuation key, never a nested object (ADR-550 #1278). At verify time a `backstop` truth the verifier cannot confirm with explicit evidence abstains → `human_needed` (reason `insufficient_spec`), never a silent pass (#1154; see `references/honest-verifier.md`). `unresolved` edges are explicit assumptions — surface them in the plan, do not silently drop them. **Otherwise** (`EDGE_ABSENT`): apply the SAME lift to the fallback report `{COVERAGE}` (per §C of `references/specless-probe-fallback.md`); a SPEC-supplied section is never re-run.
|
|
810
814
|
- If the SPEC has a `## Prohibitions` section, lift every resolved prohibition into the `must_haves.prohibitions:` sibling block (NOT `truths` — ADR-550 D3) with `statement`+`status`+`verification`, via the single `projectProhibitions` serializer (Hyrum — no second serializer); unresolved -> flagged assumptions, don't drop; never put a must-NOT under `truths`. **Otherwise** (`PROHIB_ABSENT`), author the recalled prohibitions into the SAME block via the SAME `projectProhibitions` contract but **descriptor-less** (no `check_*`) so each disposes flagged-unverified; never auto-dismiss. Section-level precedence + no-silent-drop equality apply (§C).
|
|
815
|
+
- If a `-UI-SPEC.md` exists (resolved above as `UI_SPEC_PATH`) with a `## UI Considerations` section, lift it by the **identical rule** as `## Edge Coverage` above — `covered` → `must_haves.truths` string, `backstop` → flat scalar `{ statement, verification: backstop }`, `unresolved` → explicit planner assumption (no new verb — ADR-550 #1278/#1154; #1867). Read it from `UI_SPEC_PATH` (the SPEC glob excludes `-UI-SPEC.md`).
|
|
811
816
|
- **"Artifacts this phase produces" section (MANDATORY)** — list every symbol this phase creates: decorators, classes, functions, CLI flags, struct/dataclass fields, new file paths. The plan-review-convergence source-grounding pass reads this section to exclude newly-created symbols from drift verification; omitting it causes new symbols to be flagged for acknowledgement.
|
|
812
817
|
</downstream_consumer>
|
|
813
818
|
|
|
@@ -854,6 +859,7 @@ Every task MUST include these fields — they are NOT optional:
|
|
|
854
859
|
- [ ] must_haves derived from phase goal
|
|
855
860
|
- [ ] Every PLAN.md includes an "Artifacts this phase produces" section listing symbols created by this phase (decorators, classes, functions, CLI flags, struct/dataclass fields, new file paths)
|
|
856
861
|
- [ ] Every SPEC ## Edge Coverage covered/backstop edge is represented in a plan's must_haves (no silent drops)
|
|
862
|
+
- [ ] Every UI-SPEC ## UI Considerations covered/backstop consideration is represented in a plan's must_haves (no silent drops)
|
|
857
863
|
- [ ] Every SPEC ## Prohibitions resolved item is represented in a plan's must_haves.prohibitions (no silent drops)
|
|
858
864
|
</quality_gate>
|
|
859
865
|
```
|
|
@@ -536,7 +536,7 @@ State: "Current phase is {X}. Milestone has {N} phases (highest: {Y})."
|
|
|
536
536
|
| Condition | Meaning | Action |
|
|
537
537
|
|-----------|---------|--------|
|
|
538
538
|
| current phase < highest phase | More phases remain | Go to **Route C** |
|
|
539
|
-
| current phase = highest phase |
|
|
539
|
+
| current phase = highest phase | All phases complete | Go to **Route D** |
|
|
540
540
|
|
|
541
541
|
---
|
|
542
542
|
|
|
@@ -602,7 +602,7 @@ NEXT_HAS_UI=$(echo "$NEXT_PHASE_SECTION" | grep -qi "UI hint.*yes" && echo "true
|
|
|
602
602
|
|
|
603
603
|
---
|
|
604
604
|
|
|
605
|
-
**Route D:
|
|
605
|
+
**Route D: All phases complete (milestone ready to close)**
|
|
606
606
|
|
|
607
607
|
```
|
|
608
608
|
---
|
|
@@ -971,6 +971,8 @@ Use `date` from init:
|
|
|
971
971
|
| ${quick_id} | ${DESCRIPTION} | ${date} | ${commit_hash} | [${quick_id}-${slug}](./quick/${quick_id}-${slug}/) |
|
|
972
972
|
```
|
|
973
973
|
|
|
974
|
+
For a schema-safe append outside this workflow (e.g. from fast.md), `gsd-tools quick-tasks-append --task <text>` performs the equivalent write via the shared, schema-backed `appendQuickTaskRow` helper (#2133, ADR-2143 §3/§7).
|
|
975
|
+
|
|
974
976
|
**7d. Update "Last activity" line:**
|
|
975
977
|
|
|
976
978
|
Use `date` from init:
|
|
@@ -255,6 +255,8 @@ shell-interpolated). Exact invocation in `gsd-core/references/reviewer-instances
|
|
|
255
255
|
|
|
256
256
|
For each selected CLI, invoke in sequence (not parallel — avoid rate limits):
|
|
257
257
|
|
|
258
|
+
**Timeout guidance (#2194):** prompt-fed source-grounded reviews are slow — measured ~570s for Codex at `xhigh` effort and ~525s for headless Claude on a large plan set. Each of the Gemini / Claude / Codex blocks below MUST be invoked with a high Bash `timeout:` — at least `900000` (15 min), and `1200000` (20 min) for Codex `xhigh` or headless Claude — so a lane is not killed mid-review. On Claude Code, raise the host cap via `BASH_MAX_TIMEOUT_MS` if a review can exceed it. A silent empty output after a long run is a **timeout kill, not a crash** — the Codex `0xc0000142` misdiagnosis persisted because the empty-output branches below cannot distinguish the two; treat an empty result on a slow lane as a dropped lane and re-run with more time rather than diagnosing a CLI/sandbox failure. A cross-AI review that silently drops a lane is blind in one eye.
|
|
259
|
+
|
|
258
260
|
**Gemini:**
|
|
259
261
|
```bash
|
|
260
262
|
if [ -n "$GEMINI_MODEL" ] && [ "$GEMINI_MODEL" != "null" ]; then
|
|
@@ -364,7 +366,12 @@ fi
|
|
|
364
366
|
# prompt as an ARGUMENT, not stdin. A full review prompt can exceed the OS argument limit, so
|
|
365
367
|
# reference the prompt file by path rather than inlining it. Capture stderr so a failure is
|
|
366
368
|
# diagnosable instead of a silent empty result.
|
|
367
|
-
|
|
369
|
+
# #2176: same absolute-root anchor as the Antigravity block — cursor-agent runs
|
|
370
|
+
# in the repo cwd, but repo-relative references in the assembled prompt still
|
|
371
|
+
# need an explicit root to resolve against. rev-parse (not bare pwd) so the
|
|
372
|
+
# anchor is correct even when /gsd:review is invoked from a repo subdirectory.
|
|
373
|
+
_CURSOR_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
374
|
+
CURSOR_PROMPT_ARG="Read the file at /tmp/gsd-review-prompt-{phase}.md in full and carry out the review request it contains. The repository under review is at $_CURSOR_ROOT — resolve every relative file path in the review request against that absolute root. Output only the resulting markdown review. Do not edit any files."
|
|
368
375
|
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
|
|
369
376
|
if [ ! -s /tmp/gsd-review-cursor-{phase}.md ]; then
|
|
370
377
|
echo "Cursor review failed or returned empty output. stderr:" > /tmp/gsd-review-cursor-{phase}.md
|
|
@@ -456,7 +463,19 @@ if [ -n "$AGY_MODEL" ] && [ "$AGY_MODEL" != "null" ]; then
|
|
|
456
463
|
else
|
|
457
464
|
set --
|
|
458
465
|
fi
|
|
459
|
-
|
|
466
|
+
# #2176: grant the reviewer the repo under review. Without --add-dir, agy's
|
|
467
|
+
# permission context never receives the cwd repo — the agent anchors on its own
|
|
468
|
+
# ~/.gemini/antigravity-cli/scratch dir and reviews the plan text in isolation
|
|
469
|
+
# (the exact failure the Review Instructions forbid). Capability-probed like the
|
|
470
|
+
# Codex bypass flag so an older agy without --add-dir still runs; the prompt
|
|
471
|
+
# anchor below keeps absolute-path reads possible on that fallback.
|
|
472
|
+
if agy --help 2>/dev/null | grep -q -- '--add-dir'; then
|
|
473
|
+
set -- "$@" --add-dir "$_AGY_WS"
|
|
474
|
+
fi
|
|
475
|
+
# #2176: anchor the prompt to the absolute repo root so repo-relative references
|
|
476
|
+
# in the assembled review prompt resolve even on the no---add-dir fallback, and
|
|
477
|
+
# require an explicit self-report if the reviewer still cannot read the repo.
|
|
478
|
+
_AGY_PROMPT="Read the file at /tmp/gsd-review-prompt-{phase}.md in full and carry out the review request it contains. The repository under review is at $_AGY_WS — resolve every relative file path in the review request against that absolute root and verify claims against those files. If you cannot read files under $_AGY_WS, begin your output with the exact line REVIEWED-WITHOUT-REPO-ACCESS before the review. Output only the resulting markdown review. Do not edit any files."
|
|
460
479
|
# Capability-probe an external wall-clock killer (GNU coreutils `timeout` or the
|
|
461
480
|
# macOS Homebrew `gtimeout`). Stock macOS ships NEITHER — a bare `timeout …` would
|
|
462
481
|
# fail with rc 127 ("command not found") and silently lose the reviewer, so fall
|
|
@@ -523,6 +542,26 @@ if [ ! -s /tmp/gsd-review-antigravity-{phase}.md ]; then
|
|
|
523
542
|
echo "If no agy run started, that is the pre-session-stall case: check whether a new ~/.gemini/antigravity-cli/brain/<conv-id>/ dir appeared within ~30s of launch."
|
|
524
543
|
} > /tmp/gsd-review-antigravity-{phase}.md
|
|
525
544
|
fi
|
|
545
|
+
|
|
546
|
+
# #2176: blind-review marker. Two tells that the reviewer ran without repo
|
|
547
|
+
# access: the prompt's mandated REVIEWED-WITHOUT-REPO-ACCESS self-report in the
|
|
548
|
+
# first lines of output, or the agent DECLARING the scratch dir as its
|
|
549
|
+
# workspace. Both patterns are anchored — the self-report to the head of the
|
|
550
|
+
# file, the scratch tell to a workspace-declaration phrasing — so a grounded
|
|
551
|
+
# review that merely QUOTES these strings (e.g. reviewing this very file) is
|
|
552
|
+
# never mis-stamped. Stamp a machine-readable marker so the Consensus Summary
|
|
553
|
+
# down-weights the review instead of counting an ungrounded verdict at full
|
|
554
|
+
# weight. (Temp file + mv, no in-place sed — BSD/GNU safe.)
|
|
555
|
+
if [ -s /tmp/gsd-review-antigravity-{phase}.md ] && \
|
|
556
|
+
{ head -5 /tmp/gsd-review-antigravity-{phase}.md | grep -q 'REVIEWED-WITHOUT-REPO-ACCESS' || \
|
|
557
|
+
grep -qiE '(workspace|working) (directory|dir).{0,40}antigravity-cli/scratch' /tmp/gsd-review-antigravity-{phase}.md; }; then
|
|
558
|
+
{
|
|
559
|
+
echo "> [reviewed-without-repo-access] This reviewer ran without visibility into the repo under review — down-weight its verdict in the Consensus Summary."
|
|
560
|
+
echo ""
|
|
561
|
+
cat /tmp/gsd-review-antigravity-{phase}.md
|
|
562
|
+
} > /tmp/gsd-review-antigravity-{phase}.md.tmp && \
|
|
563
|
+
mv /tmp/gsd-review-antigravity-{phase}.md.tmp /tmp/gsd-review-antigravity-{phase}.md
|
|
564
|
+
fi
|
|
526
565
|
```
|
|
527
566
|
|
|
528
567
|
**Ollama (local, OpenAI-compatible):**
|
|
@@ -835,7 +874,7 @@ trimmed_reviewers: # only present if at least one reviewer was trimmed
|
|
|
835
874
|
|
|
836
875
|
## Consensus Summary
|
|
837
876
|
|
|
838
|
-
{synthesize common concerns across all reviewers. CodeRabbit is a diff-only reviewer (it never received the source-grounding prompt), so do not weight its verdict as a grounded plan review — fold in its diff findings, but base plan-level consensus on the prompt-fed reviewers.}
|
|
877
|
+
{synthesize common concerns across all reviewers. CodeRabbit is a diff-only reviewer (it never received the source-grounding prompt), so do not weight its verdict as a grounded plan review — fold in its diff findings, but base plan-level consensus on the prompt-fed reviewers. A reviewer output carrying the `[reviewed-without-repo-access]` marker (or beginning with `REVIEWED-WITHOUT-REPO-ACCESS`) ran without repo access (#2176) — treat it the same way: note its concerns, but do not count its verdict at full consensus weight.}
|
|
839
878
|
|
|
840
879
|
### Agreed Strengths
|
|
841
880
|
{strengths mentioned by 2+ reviewers}
|
|
@@ -108,7 +108,7 @@ Agent(
|
|
|
108
108
|
"<files_to_read>{PLAN, SUMMARY, impl files, SECURITY.md}</files_to_read>" +
|
|
109
109
|
"<threat_register>{threat register}</threat_register>" +
|
|
110
110
|
"<config>asvs_level: {SECURITY_ASVS}, block_on: {SECURITY_BLOCK_ON}</config>" +
|
|
111
|
-
"<constraints>Never modify implementation files. Verify mitigations exist — do not scan for new threats. Escalate implementation gaps.</constraints>" +
|
|
111
|
+
"<constraints>Never modify implementation files. Verify mitigations exist — do not scan for new threats. Escalate implementation gaps. Return a structured verdict only — do NOT write SECURITY.md (the orchestrator owns the file write).</constraints>" +
|
|
112
112
|
"${AGENT_SKILLS_AUDITOR}",
|
|
113
113
|
subagent_type="gsd-security-auditor",
|
|
114
114
|
model="{AUDITOR_MODEL}",
|
|
@@ -360,7 +360,9 @@ Built-in tier defaults by runtime:
|
|
|
360
360
|
| `opencode` | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-5` | `anthropic/claude-haiku-4-5` |
|
|
361
361
|
| `copilot` | `claude-opus-4-8` | `claude-sonnet-5` | `claude-haiku-4-5` |
|
|
362
362
|
| `hermes` | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-5` | `anthropic/claude-haiku-4-5` |
|
|
363
|
-
|
|
|
363
|
+
| `kilo` | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-5` | `anthropic/claude-haiku-4-5` |
|
|
364
|
+
| `pi` | `claude-opus-4-8` | `claude-sonnet-5` | `claude-haiku-4-5` |
|
|
365
|
+
| Group B (`cline`, `cursor`, `windsurf`, `augment`, `trae`, `codebuddy`, `antigravity`) | (no built-in default — your runtime handles model selection) | | |
|
|
364
366
|
|
|
365
367
|
Display a table to the user showing the effective configuration:
|
|
366
368
|
|
|
@@ -387,8 +389,8 @@ AskUserQuestion([
|
|
|
387
389
|
options: [
|
|
388
390
|
{ label: "Keep current (<runtime>)", description: "Configure overrides for the current runtime." },
|
|
389
391
|
{ label: "Common runtimes", description: "claude, codex, gemini, qwen" },
|
|
390
|
-
{ label: "Additional runtimes", description: "opencode, copilot, hermes" },
|
|
391
|
-
{ label: "Other (Group B or custom)", description: "
|
|
392
|
+
{ label: "Additional runtimes", description: "opencode, copilot, hermes, kilo" },
|
|
393
|
+
{ label: "Other (Group B or custom)", description: "cline, cursor, windsurf, augment, trae, codebuddy, antigravity, or a custom runtime string." }
|
|
392
394
|
]
|
|
393
395
|
}
|
|
394
396
|
])
|
|
@@ -423,7 +425,8 @@ AskUserQuestion([
|
|
|
423
425
|
options: [
|
|
424
426
|
{ label: "opencode", description: "OpenCode (uses anthropic/ prefix)." },
|
|
425
427
|
{ label: "copilot", description: "GitHub Copilot." },
|
|
426
|
-
{ label: "hermes", description: "Hermes (uses anthropic/ prefix)." }
|
|
428
|
+
{ label: "hermes", description: "Hermes (uses anthropic/ prefix)." },
|
|
429
|
+
{ label: "kilo", description: "Kilo Code (uses anthropic/ prefix)." }
|
|
427
430
|
]
|
|
428
431
|
}
|
|
429
432
|
])
|
|
@@ -394,9 +394,15 @@ gsd_run query state.update "Last Activity" "$(date +%Y-%m-%d)"
|
|
|
394
394
|
gsd_run query state.update "Status" "Phase ${PHASE_NUMBER} shipped — PR #${PR_NUMBER}"
|
|
395
395
|
```
|
|
396
396
|
|
|
397
|
-
If `commit_docs` is true
|
|
397
|
+
If `commit_docs` is true, commit the ship-note AND push it onto the PR branch so
|
|
398
|
+
it reaches the default branch when the PR merges. Without this push the ship-note
|
|
399
|
+
commit stays local-only and is silently discarded when the branch is deleted on
|
|
400
|
+
merge (#2138). The `[ci skip]` trailer suppresses the redundant pipeline the push
|
|
401
|
+
would otherwise trigger (GitHub honors `[ci skip]` / `[skip ci]`):
|
|
402
|
+
|
|
398
403
|
```bash
|
|
399
|
-
gsd_run query commit "docs(${padded_phase}): ship phase ${PHASE_NUMBER} — PR #${PR_NUMBER}" --files .planning/STATE.md
|
|
404
|
+
gsd_run query commit "docs(${padded_phase}): ship phase ${PHASE_NUMBER} — PR #${PR_NUMBER} [ci skip]" --files .planning/STATE.md
|
|
405
|
+
git push origin ${CURRENT_BRANCH} 2>&1 || echo "⚠ track_shipping: ship-note push failed — it is local-only; rerun: git push origin ${CURRENT_BRANCH}"
|
|
400
406
|
```
|
|
401
407
|
</step>
|
|
402
408
|
|
|
@@ -456,7 +456,7 @@ Write to: `{phase_dir}/{padded_phase}-SPEC.md`
|
|
|
456
456
|
|
|
457
457
|
```bash
|
|
458
458
|
git add "${phase_dir}/${padded_phase}-SPEC.md"
|
|
459
|
-
git commit -m "spec(phase-${phase_number}): add SPEC.md for ${phase_name} — ${requirement_count} requirements (#2213)"
|
|
459
|
+
git commit -m "spec(phase-${phase_number}): add SPEC.md for ${phase_name} — ${requirement_count} requirements (#2213)" -- "${phase_dir}/${padded_phase}-SPEC.md"
|
|
460
460
|
```
|
|
461
461
|
|
|
462
462
|
If `commit_docs` is false: Skip commit. Note that SPEC.md was written but not committed.
|
|
@@ -597,7 +597,7 @@ Do NOT auto-invoke any further slash commands.
|
|
|
597
597
|
|
|
598
598
|
---
|
|
599
599
|
|
|
600
|
-
**Route B:
|
|
600
|
+
**Route B: All phases complete (milestone ready to close)**
|
|
601
601
|
|
|
602
602
|
**This route is only reached when:**
|
|
603
603
|
- `is_last_phase: true` AND no other active workstreams exist (or flat mode)
|