@opengsd/gsd-core 1.8.0 → 1.9.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +31 -1
- package/agents/gsd-code-fixer.md +107 -34
- package/agents/gsd-codebase-mapper.md +1 -1
- package/agents/gsd-debug-session-manager.md +36 -0
- package/agents/gsd-executor.md +20 -7
- package/agents/gsd-intel-updater.md +3 -3
- package/agents/gsd-phase-researcher.md +4 -2
- package/agents/gsd-plan-checker.md +20 -0
- package/agents/gsd-planner.md +15 -23
- package/agents/gsd-project-researcher.md +2 -2
- package/agents/gsd-ui-auditor.md +0 -40
- package/bin/install.js +236 -107
- package/commands/gsd/plan-review-convergence.md +5 -1
- package/gsd-core/bin/gsd-tools.cjs +882 -4
- package/gsd-core/bin/lib/api-coverage.cjs +22 -8
- package/gsd-core/bin/lib/audit.cjs +8 -8
- package/gsd-core/bin/lib/capability-consent.cjs +40 -1
- package/gsd-core/bin/lib/capability-lifecycle.cjs +58 -0
- package/gsd-core/bin/lib/capability-loader.cjs +23 -1
- package/gsd-core/bin/lib/capability-registry.cjs +1353 -132
- package/gsd-core/bin/lib/capability-trust.cjs +468 -33
- package/gsd-core/bin/lib/capability-validator.cjs +882 -6
- package/gsd-core/bin/lib/check-command-router.cjs +12 -2
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +15 -0
- package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +102 -12
- package/gsd-core/bin/lib/claude-orchestration.cjs +125 -22
- package/gsd-core/bin/lib/commands.cjs +246 -18
- package/gsd-core/bin/lib/config-loader.cjs +200 -28
- package/gsd-core/bin/lib/config.cjs +90 -5
- package/gsd-core/bin/lib/estimate-cli.cjs +336 -0
- package/gsd-core/bin/lib/frontmatter.cjs +125 -15
- package/gsd-core/bin/lib/host-integration.cjs +215 -8
- package/gsd-core/bin/lib/init.cjs +44 -19
- package/gsd-core/bin/lib/install-engine.cjs +1 -0
- package/gsd-core/bin/lib/milestone.cjs +36 -9
- package/gsd-core/bin/lib/model-catalog.cjs +51 -1
- package/gsd-core/bin/lib/observability/logger.cjs +7 -2
- package/gsd-core/bin/lib/phase-command-router.cjs +10 -1
- package/gsd-core/bin/lib/phase-estimation.cjs +398 -0
- package/gsd-core/bin/lib/phase-id.cjs +278 -5
- package/gsd-core/bin/lib/phase.cjs +61 -6
- package/gsd-core/bin/lib/plan-drift-guard.cjs +1 -1
- package/gsd-core/bin/lib/plan-scan.cjs +1 -1
- package/gsd-core/bin/lib/planning-workspace.cjs +9 -2
- package/gsd-core/bin/lib/profile-output.cjs +34 -8
- package/gsd-core/bin/lib/project-root.cjs +48 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +927 -0
- package/gsd-core/bin/lib/review-lane-invocation.cjs +348 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +594 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +114 -32
- package/gsd-core/bin/lib/roadmap-parser.cjs +54 -6
- package/gsd-core/bin/lib/roadmap.cjs +10 -4
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +31 -4
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +1 -1
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +140 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +15 -2
- package/gsd-core/bin/lib/smart-entry.cjs +1 -1
- package/gsd-core/bin/lib/state-document.cjs +164 -20
- package/gsd-core/bin/lib/state-transition.cjs +28 -10
- package/gsd-core/bin/lib/state.cjs +141 -21
- package/gsd-core/bin/lib/uat-predicate.cjs +6 -4
- package/gsd-core/bin/lib/uat.cjs +9 -7
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +2 -2
- package/gsd-core/bin/lib/unusable-input.cjs +216 -0
- package/gsd-core/bin/lib/validate.cjs +32 -0
- package/gsd-core/bin/lib/verification.cjs +51 -14
- package/gsd-core/bin/lib/verify.cjs +146 -22
- package/gsd-core/bin/lib/worktree-safety.cjs +360 -15
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -13
- package/gsd-core/bin/shared/model-catalog.json +5 -0
- package/gsd-core/bin/shared/runtime-aliases.manifest.json +5 -0
- package/gsd-core/references/context-budget.md +40 -0
- package/gsd-core/references/gate-prompts.md +6 -3
- package/gsd-core/references/model-profile-resolution.md +64 -13
- package/gsd-core/references/offer-next.md +88 -0
- package/gsd-core/references/planning-config.md +2 -1
- package/gsd-core/references/reviewer-instances.md +28 -21
- package/gsd-core/references/runtime-aware-dispatch.md +42 -0
- package/gsd-core/references/ui-consideration-probe.md +2 -2
- package/gsd-core/references/worktree-branch-check.md +4 -4
- package/gsd-core/templates/summary-minimal.md +4 -0
- package/gsd-core/templates/summary-standard.md +4 -0
- package/gsd-core/templates/summary.md +7 -0
- package/gsd-core/workflows/ai-integration-phase.md +4 -4
- package/gsd-core/workflows/audit-fix.md +4 -0
- package/gsd-core/workflows/audit-milestone.md +8 -0
- package/gsd-core/workflows/autonomous.md +19 -15
- package/gsd-core/workflows/check-todos.md +2 -2
- package/gsd-core/workflows/code-review-fix.md +14 -6
- package/gsd-core/workflows/code-review.md +93 -21
- package/gsd-core/workflows/debug.md +10 -2
- package/gsd-core/workflows/diagnose-issues.md +4 -0
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -4
- package/gsd-core/workflows/discuss-phase/modes/auto.md +0 -6
- package/gsd-core/workflows/discuss-phase-assumptions.md +15 -9
- package/gsd-core/workflows/discuss-phase.md +2 -2
- package/gsd-core/workflows/docs-update.md +8 -0
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +4 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +160 -0
- package/gsd-core/workflows/execute-phase.md +85 -115
- package/gsd-core/workflows/execute-plan.md +5 -4
- package/gsd-core/workflows/explore.md +4 -0
- package/gsd-core/workflows/extract-learnings.md +21 -0
- package/gsd-core/workflows/help/modes/full.md +3 -3
- package/gsd-core/workflows/import.md +4 -1
- package/gsd-core/workflows/ingest-docs.md +4 -0
- package/gsd-core/workflows/map-codebase.md +13 -6
- package/gsd-core/workflows/new-milestone.md +10 -2
- package/gsd-core/workflows/new-project.md +11 -4
- package/gsd-core/workflows/next.md +5 -2
- package/gsd-core/workflows/plan-phase.md +42 -46
- package/gsd-core/workflows/plan-review-convergence.md +18 -14
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick.md +14 -3
- package/gsd-core/workflows/review.md +146 -575
- package/gsd-core/workflows/scan.md +9 -1
- package/gsd-core/workflows/secure-phase.md +10 -2
- package/gsd-core/workflows/ship.md +41 -11
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/ui-phase.md +8 -1
- package/gsd-core/workflows/ui-review.md +8 -1
- package/gsd-core/workflows/update.md +104 -5
- package/gsd-core/workflows/validate-phase.md +10 -2
- package/gsd-core/workflows/verify-work.md +8 -1
- package/hooks/dist/gsd-cursor-session-start.js +6 -2
- package/hooks/dist/gsd-cursor-stop.js +6 -2
- package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
- package/hooks/dist/gsd-graphify-update.sh +9 -0
- package/hooks/dist/gsd-phase-boundary.sh +14 -2
- package/hooks/dist/gsd-prompt-guard.js +101 -2
- package/hooks/dist/gsd-read-guard.js +100 -2
- package/hooks/dist/gsd-read-injection-scanner.js +109 -2
- package/hooks/dist/gsd-statusline.js +9 -6
- package/hooks/dist/gsd-workflow-guard.js +110 -6
- package/hooks/dist/gsd-worktree-path-guard.js +132 -8
- package/hooks/dist/lib/cursor-workspace.js +74 -0
- package/hooks/gsd-cursor-session-start.js +6 -2
- package/hooks/gsd-cursor-stop.js +6 -2
- package/hooks/gsd-cursor-subagent-start.js +6 -2
- package/hooks/gsd-graphify-update.sh +9 -0
- package/hooks/gsd-phase-boundary.sh +14 -2
- package/hooks/gsd-prompt-guard.js +101 -2
- package/hooks/gsd-read-guard.js +100 -2
- package/hooks/gsd-read-injection-scanner.js +109 -2
- package/hooks/gsd-statusline.js +9 -6
- package/hooks/gsd-workflow-guard.js +110 -6
- package/hooks/gsd-worktree-path-guard.js +132 -8
- package/hooks/lib/cursor-workspace.js +74 -0
- package/package.json +7 -7
- package/pi/gsd.cjs +26 -1
- package/scripts/check-coverage-gate.cjs +51 -0
- package/scripts/check-glossary-refs.cjs +24 -0
- package/scripts/ci-test-scope.cjs +67 -17
- package/scripts/gen-adr-index.cjs +6 -4
- package/scripts/gen-capability-matrix.cjs +26 -2
- package/scripts/gen-capability-registry.cjs +132 -34
- package/scripts/gen-emitted-baseline.cjs +145 -0
- package/scripts/gen-registry.cjs +39 -15
- package/scripts/lint-compiled-artifact-sync.cjs +146 -0
- package/scripts/lint-emitted-drift-ack.cjs +149 -0
- package/scripts/lint-fix-has-regression-test.cjs +131 -0
- package/scripts/lint-resolution-provenance.cjs +9 -0
- package/scripts/mutation-matrix.cjs +4 -0
- package/scripts/prompt-injection-scan.sh +6 -0
- package/scripts/registry-schema.cjs +372 -94
- package/scripts/release-notes/conventional-title.cjs +19 -1
- package/scripts/release-notes/format-github-release-notes.cjs +7 -3
- package/scripts/validate-registry.cjs +10 -6
- package/scripts/workflow-size.cjs +16 -8
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
- package/vscode/package.json +1 -1
- package/scripts/gen-golden-install-parity-zcode.cjs +0 -77
- package/scripts/update-size-baseline.cjs +0 -68
|
@@ -1,38 +1,89 @@
|
|
|
1
1
|
# Model Profile Resolution
|
|
2
2
|
|
|
3
|
-
Resolve
|
|
3
|
+
Resolve each agent's model through `gsd-tools`, then pass it to the `Agent()` spawn — or
|
|
4
|
+
omit the parameter entirely when nothing resolved.
|
|
4
5
|
|
|
5
6
|
## Resolution Pattern
|
|
6
7
|
|
|
8
|
+
Prefer the field your workflow's own `init.*` payload already emits (every orchestrator
|
|
9
|
+
init that spawns subagents carries one — `mapper_model`, `planner_model`,
|
|
10
|
+
`executor_model`, `doc_writer_model`, …). Declare it in the workflow's parse line so the
|
|
11
|
+
binding is stated, not implied:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Parse JSON for: `mapper_model`, …
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
When the agent type is only known at runtime — a capability hook naming its own agent, for
|
|
18
|
+
example — resolve it directly instead:
|
|
19
|
+
|
|
7
20
|
```bash
|
|
8
|
-
|
|
21
|
+
AGENT_MODEL=$(gsd_run query resolve-model "<agent-type>" --raw)
|
|
9
22
|
```
|
|
10
23
|
|
|
11
|
-
|
|
24
|
+
Both surfaces return the same thing: a model string for the active runtime, or the **empty
|
|
25
|
+
string** when nothing resolved.
|
|
12
26
|
|
|
13
27
|
## Lookup Table
|
|
14
28
|
|
|
15
29
|
@~/.claude/gsd-core/references/model-profiles.md
|
|
16
30
|
|
|
17
|
-
|
|
31
|
+
## Passing the model to a spawn
|
|
18
32
|
|
|
19
33
|
```
|
|
20
|
-
|
|
34
|
+
Agent(
|
|
21
35
|
prompt="...",
|
|
22
36
|
subagent_type="gsd-planner",
|
|
23
|
-
model="{
|
|
37
|
+
model="{planner_model}"
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Substitute the field **this workflow bound** — never a generic placeholder name.
|
|
42
|
+
|
|
43
|
+
**#2517 — omit, do not emit an empty model.** When the resolved value is `"inherit"` or
|
|
44
|
+
empty, **omit the `model=` parameter entirely**:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
Agent(
|
|
48
|
+
prompt="...",
|
|
49
|
+
subagent_type="gsd-planner"
|
|
24
50
|
)
|
|
25
51
|
```
|
|
26
52
|
|
|
27
|
-
|
|
53
|
+
No model parameter is passed at all — `planner_model` resolved to `"inherit"` or empty, and
|
|
54
|
+
omitting it inherits the orchestrator's model. Passing either value through as an argument
|
|
55
|
+
instead 404s on non-Claude runtimes.
|
|
56
|
+
|
|
57
|
+
This is not cosmetic, and both values really occur. `model_profile: "inherit"` — and any
|
|
58
|
+
opus-tier agent — resolves to the literal string `"inherit"`. `resolve_model_ids: "omit"`
|
|
59
|
+
resolves to the **empty string** whenever the project sets it explicitly or the active
|
|
60
|
+
runtime has no native tier aliases; an agent type absent from the profile table takes that
|
|
61
|
+
same empty-string path, because it has no tier for the earlier steps to resolve. Emitting
|
|
62
|
+
either value verbatim fails the spawn on every runtime without native tier aliases.
|
|
63
|
+
|
|
64
|
+
**#2684 — substitute a field your workflow actually bound.** `model="{…}"` must name a key
|
|
65
|
+
your own `init.*` payload emits, a shell variable you assigned, or a field on your declared
|
|
66
|
+
parse line. A placeholder that resolves to nothing does not fail loudly — the orchestrator
|
|
67
|
+
silently invents a value, which is the invisible partial application ADR-1411 prohibits.
|
|
68
|
+
`tests/model-omit-when-inherit-guard.test.cjs` enforces both rules.
|
|
69
|
+
|
|
70
|
+
## Profile semantics
|
|
71
|
+
|
|
72
|
+
**Note:** Opus-tier agents resolve to `"inherit"` (not `"opus"`). This causes the agent to
|
|
73
|
+
use the parent session's model, avoiding conflicts with organization policies that may
|
|
74
|
+
block specific opus versions — and, per the rule above, means the `model=` parameter is
|
|
75
|
+
omitted rather than set.
|
|
28
76
|
|
|
29
|
-
If `model_profile` is `"adaptive"`, agents resolve to role-based assignments (opus/sonnet/
|
|
77
|
+
If `model_profile` is `"adaptive"`, agents resolve to role-based assignments (opus/sonnet/
|
|
78
|
+
haiku based on agent type).
|
|
30
79
|
|
|
31
|
-
If `model_profile` is `"inherit"`, all agents resolve to `"inherit"` (useful for OpenCode
|
|
80
|
+
If `model_profile` is `"inherit"`, all agents resolve to `"inherit"` (useful for OpenCode
|
|
81
|
+
`/model`).
|
|
32
82
|
|
|
33
83
|
## Usage
|
|
34
84
|
|
|
35
|
-
1.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
85
|
+
1. Bind the model once — from the `init.*` payload field, or `query resolve-model` when the
|
|
86
|
+
agent type is runtime-determined
|
|
87
|
+
2. Declare the bound field on the workflow's parse line
|
|
88
|
+
3. Pass `model="{bound_field}"` on each `Agent()` spawn
|
|
89
|
+
4. Omit `model=` entirely whenever the bound value is `"inherit"` or empty
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
offer-next.md — extracted from execute-phase.md step "offer_next" (#2537).
|
|
3
|
+
Eagerly @-referenced from execute-phase.md so runtime behavior is unchanged; the
|
|
4
|
+
extraction restores byte-budget headroom the frozen ceiling exists to provide.
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
**Exception:** If `gaps_found`, the `verify_phase_goal` step already presents the gap-closure path (`/gsd:plan-phase {X} --gaps`). No additional routing needed — skip auto-advance.
|
|
9
|
+
|
|
10
|
+
**No-transition check (spawned by auto-advance chain):**
|
|
11
|
+
|
|
12
|
+
Parse `--no-transition` flag from $ARGUMENTS.
|
|
13
|
+
|
|
14
|
+
**If `--no-transition` flag present:**
|
|
15
|
+
|
|
16
|
+
Execute-phase was spawned by plan-phase's auto-advance. Do NOT run transition.md.
|
|
17
|
+
After verification passes and roadmap is updated, return completion status to parent:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
## PHASE COMPLETE
|
|
21
|
+
|
|
22
|
+
Phase: ${PHASE_NUMBER} - ${PHASE_NAME}
|
|
23
|
+
Plans: ${completed_count}/${total_count}
|
|
24
|
+
Verification: {Passed | Gaps Found}
|
|
25
|
+
|
|
26
|
+
[Include aggregate_results output]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
STOP. Do not proceed to auto-advance or transition.
|
|
30
|
+
|
|
31
|
+
**If `--no-transition` flag is NOT present:**
|
|
32
|
+
|
|
33
|
+
**Auto-advance detection:**
|
|
34
|
+
|
|
35
|
+
1. Parse `--auto` flag from $ARGUMENTS
|
|
36
|
+
2. Read consolidated auto-mode (`active` = chain flag OR user preference; chain flag already synced in init step):
|
|
37
|
+
```bash
|
|
38
|
+
AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null || echo "false")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**If `--auto` flag present OR `AUTO_MODE` is true (AND verification passed with no gaps):**
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
╔══════════════════════════════════════════╗
|
|
45
|
+
║ AUTO-ADVANCING → TRANSITION ║
|
|
46
|
+
║ Phase {X} verified, continuing chain ║
|
|
47
|
+
╚══════════════════════════════════════════╝
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Execute the transition workflow inline (do NOT use Agent — orchestrator context is ~10-15%, transition needs phase completion data already in context):
|
|
51
|
+
|
|
52
|
+
Read and follow `~/.claude/gsd-core/workflows/transition.md`, passing through the `--auto` flag so it propagates to the next phase invocation.
|
|
53
|
+
|
|
54
|
+
**If neither `--auto` nor `AUTO_MODE` is true:**
|
|
55
|
+
|
|
56
|
+
**STOP. Do not auto-advance. Do not execute transition. Do not plan next phase. Present options to the user and wait.**
|
|
57
|
+
|
|
58
|
+
**IMPORTANT: There is NO `/gsd-transition` command. Never suggest it. The transition workflow is internal only.**
|
|
59
|
+
|
|
60
|
+
Check whether CONTEXT.md already exists for the next phase:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
ls .planning/phases/*{next}*/{next}-CONTEXT.md 2>/dev/null || echo "no-context"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
If CONTEXT.md does **not** exist for the next phase, present:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
## ✓ Phase {X}: {Name} Complete
|
|
70
|
+
|
|
71
|
+
/gsd:progress ${GSD_WS} — see updated roadmap
|
|
72
|
+
/gsd:discuss-phase {next} ${GSD_WS} — start here: discuss next phase before planning ← recommended
|
|
73
|
+
/gsd:plan-phase {next} ${GSD_WS} — plan next phase (skip discuss)
|
|
74
|
+
/gsd:execute-phase {next} ${GSD_WS} — execute next phase (skip discuss and plan)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If CONTEXT.md **exists** for the next phase, present:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
## ✓ Phase {X}: {Name} Complete
|
|
81
|
+
|
|
82
|
+
/gsd:progress ${GSD_WS} — see updated roadmap
|
|
83
|
+
/gsd:plan-phase {next} ${GSD_WS} — start here: plan next phase (CONTEXT.md already present) ← recommended
|
|
84
|
+
/gsd:discuss-phase {next} ${GSD_WS} — re-discuss next phase
|
|
85
|
+
/gsd:execute-phase {next} ${GSD_WS} — execute next phase (skip planning)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Only suggest the commands listed above. Do not invent or hallucinate command names.
|
|
@@ -255,6 +255,7 @@ Set via `workflow.*` namespace in config.json (e.g., `"workflow": { "research":
|
|
|
255
255
|
| `workflow.auto_advance` | boolean | `false` | `true`, `false` | Auto-advance to next phase after completion |
|
|
256
256
|
| `workflow.node_repair` | boolean | `true` | `true`, `false` | Attempt automatic repair of failed plan nodes |
|
|
257
257
|
| `workflow.node_repair_budget` | number | `2` | Any positive integer | Max repair retries per failed node |
|
|
258
|
+
| `workflow.smart_zone_tokens` | number | `100000` | Any positive integer | Smart-zone token budget for phase-effort estimation (#2630, ADR-2629). A phase whose estimate exceeds this is flagged with a split recommendation — advisory only, never a block. A *policy default*, not a benchmark constant: degradation begins before the advertised context window is full, but the effective ceiling is model- and task-dependent, so the calibration loop corrects it per project. _Alias:_ `smart_zone_tokens` is the flat-key form used in `CONFIG_DEFAULTS`; `workflow.smart_zone_tokens` is the canonical namespaced form. |
|
|
258
259
|
| `workflow.ai_integration_phase` | boolean | `true` | `true`, `false` | Run /gsd:ai-integration-phase before planning AI system phases |
|
|
259
260
|
| `workflow.api_coverage_gate` | boolean | `true` | `true`, `false` | Require an explicit API-coverage decision (full-by-default, opt-out-not-opt-in) before a phase that integrates an external API/SDK/service can seal. At plan:pre prompts a COVERAGE.md matrix; at verify:pre a blocking gate fails the seal unless the matrix exists with every non-integrated capability an explicit, reasoned opt-out (#1562) |
|
|
260
261
|
| `workflow.ui_phase` | boolean | `true` | `true`, `false` | Generate UI-SPEC.md for frontend phases |
|
|
@@ -395,7 +396,7 @@ Several config fields affect each other or trigger special behavior:
|
|
|
395
396
|
|
|
396
397
|
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.
|
|
397
398
|
|
|
398
|
-
9. **`workflow.use_worktrees` and branch divergence** -- When `use_worktrees` is `true` (default), executor worktrees are forked from `origin/HEAD` by the Claude Code
|
|
399
|
+
9. **`workflow.use_worktrees` and branch divergence** -- When `use_worktrees` is `true` (default), executor worktrees are forked from `origin/HEAD` -- by the host's own harness on `dispatch.isolation: harness-worktree` runtimes (Claude Code, Cursor), or by GSD itself on `orchestrator-worktree` runtimes (Codex, OpenCode, Kimi, Kimi Code). The divergence behavior below is identical either way, because the fork base is a property of the repository rather than of whoever creates the worktree. 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.
|
|
399
400
|
|
|
400
401
|
---
|
|
401
402
|
|
|
@@ -58,32 +58,39 @@ cannot diverge (`DEFECT.GENERATIVE-FIX`; parity-locked in
|
|
|
58
58
|
|
|
59
59
|
## Invocation
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
`{phase}`-keyed `/tmp` path) and runs as a distinct reviewer identity.
|
|
61
|
+
An instance resolves **through** a lane; it is not a lane itself (ADR-2782 D8). It takes no part in
|
|
62
|
+
the roster, the flag set, or lane uniqueness — which is why an instance heading
|
|
63
|
+
(`## OpenCode Review (opencode-deepseek)`) must never be read as a lane section.
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
Since Phase 5b (#2799) `invoke_reviewers` iterates declared lanes rather than hand-authored per-CLI
|
|
66
|
+
blocks, so an instance is invoked through the same single seam as its base lane, with two
|
|
67
|
+
substitutions:
|
|
67
68
|
|
|
68
69
|
```bash
|
|
69
|
-
# $
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
fi
|
|
70
|
+
# $INSTANCE_NAME is the reviewer identity (e.g. opencode-deepseek); $INSTANCE_MODEL / $INSTANCE_AGENT
|
|
71
|
+
# come from the instance spec. --run-dir is the run-scoped mktemp directory created once in
|
|
72
|
+
# gather_context (#2358) — the same directory every lane uses.
|
|
73
|
+
#
|
|
74
|
+
# The instance's OWN model replaces the lane's configured model, and the output lands under the
|
|
75
|
+
# INSTANCE name so two instances of one adapter never overwrite each other.
|
|
76
|
+
gsd_run query review-lane invoke \
|
|
77
|
+
--slug "$INSTANCE_CLI" \
|
|
78
|
+
--run-dir "$RUN_DIR" --repo-root "$REPO_ROOT" \
|
|
79
|
+
--model "$INSTANCE_MODEL" ${INSTANCE_AGENT:+--agent "$INSTANCE_AGENT"} \
|
|
80
|
+
--as "$INSTANCE_NAME"
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
`--as` is what makes the run write `{run_dir}/gsd-review-${INSTANCE_NAME}.md` instead of the lane's
|
|
84
|
+
own `{run_dir}/gsd-review-<slug>.md`.
|
|
85
|
+
|
|
86
|
+
Everything the lane declares — probe, prompt channel, output channel, timeout floor, empty-output
|
|
87
|
+
policy, handler — applies unchanged to an instance. That is the point of routing instances through
|
|
88
|
+
the lane rather than duplicating its invocation: a cross-cutting fix reaches instances for free,
|
|
89
|
+
where the previous per-adapter block had to be copied and kept in sync by hand.
|
|
90
|
+
|
|
91
|
+
Only `opencode` honours an `agent` field in v1; it is ignored by other adapters. `model` and `agent`
|
|
92
|
+
are opaque pass-through strings and are NEVER interpolated into a shell string — the runner spawns
|
|
93
|
+
with an argv array and `shell: false`.
|
|
87
94
|
|
|
88
95
|
---
|
|
89
96
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Runtime-Aware Subagent Dispatch (epic #2505 Phase 4 / #2508)
|
|
2
|
+
|
|
3
|
+
GSD workflows dispatch specialized subagents by role (planner, executor,
|
|
4
|
+
verifier, …). On **named-dispatch runtimes** (Claude Code, OpenCode, Cursor,
|
|
5
|
+
Cline, … — every runtime whose descriptor declares `hostIntegration.dispatch.namedDispatch: true`), the role name dispatches the named subagent directly.
|
|
6
|
+
|
|
7
|
+
On **built-in-only runtimes** (kimi-code — three built-in subagents only:
|
|
8
|
+
`coder`, `explore`, `plan`; no custom registration per
|
|
9
|
+
`moonshotai.github.io/kimi-code/en/customization/agents`), a GSD role name is
|
|
10
|
+
unknown and the dispatch must use the closest built-in.
|
|
11
|
+
|
|
12
|
+
## Resolution
|
|
13
|
+
|
|
14
|
+
Before dispatching a subagent by role, resolve the type for the current runtime
|
|
15
|
+
via the `resolve-dispatch-type` query. Pass the requested role name; the query
|
|
16
|
+
returns the name unchanged on named-dispatch runtimes and maps to the closest
|
|
17
|
+
built-in (`coder`/`explore`/`plan`) on kimi-code. The `|| echo` fallback
|
|
18
|
+
preserves named-dispatch behavior on older GSD installs that lack the query.
|
|
19
|
+
|
|
20
|
+
The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3 / #2510) regardless of the
|
|
21
|
+
resolved type — on non-Claude runtimes with no `agent_skills` config,
|
|
22
|
+
`gsd-tools query agent-skills <role>` returns the installed agent prompt as
|
|
23
|
+
the block. So a coder dispatch with the planner persona injected gives kimi-code
|
|
24
|
+
the planner's behavior in the coder built-in's process.
|
|
25
|
+
|
|
26
|
+
## Suffix → built-in map
|
|
27
|
+
|
|
28
|
+
| Agent role suffix | Built-in | Rationale |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `-planner`, `-roadmapper`, `-selector`, `-spec` | `plan` | Plans/designs; no file writes |
|
|
31
|
+
| `-researcher`, `-mapper`, `-checker`, `-verifier`, `-auditor`, `-analyzer`, `-synthesizer`, `-profiler`, `-curator`, `-classifier`, `-reviewer` | `explore` | Read-only investigation |
|
|
32
|
+
| everything else (`-executor`, `-fixer`, `-writer`, `-debugger`, …) | `coder` | General-purpose with full tool set |
|
|
33
|
+
| `general-purpose`, `general`, `default`, `sonnet`, `opus`, `haiku` | `coder` | Already-generic names |
|
|
34
|
+
|
|
35
|
+
## Why not a hook?
|
|
36
|
+
|
|
37
|
+
Kimi Code's documented PreToolUse hook API
|
|
38
|
+
(`moonshotai.github.io/kimi-code/en/customization/hooks`) supports only
|
|
39
|
+
`permissionDecision: allow|deny` on blockable events — it cannot rewrite the
|
|
40
|
+
dispatch payload's role field in flight. A PreToolUse-remap hook (the epic's
|
|
41
|
+
original "Option B") is therefore infeasible; this per-dispatch resolution
|
|
42
|
+
(Option A) is the documented-API-correct path.
|
|
@@ -30,8 +30,8 @@ bloating this closed core.
|
|
|
30
30
|
| id | name | applies to element kinds | consideration question |
|
|
31
31
|
|----|------|--------------------------|------------------------|
|
|
32
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)? |
|
|
33
|
+
| loading | Loading / in-flight | form, list-collection, media, nav, interactive-control | What is shown while data or content is still loading (skeleton, spinner, progressive reveal)? |
|
|
34
|
+
| error | Error / failure | form, list-collection, media, nav, interactive-control | What is shown when the load or submit fails (message, retry affordance, partial fallback)? |
|
|
35
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
36
|
| partial | Partial / incomplete | form, list-collection | What is shown for partial or incomplete data — some fields or rows present, others missing? |
|
|
37
37
|
| overflow | Overflow / truncation | list-collection, nav, static-content | What happens when content exceeds its container — scroll, clip, wrap, or truncate? |
|
|
@@ -17,7 +17,7 @@ did not create (#48).
|
|
|
17
17
|
<worktree_branch_check>
|
|
18
18
|
FIRST ACTION: HEAD assertion MUST run before anything else, and this block is
|
|
19
19
|
VERIFY-ONLY. Worktrees spawned by Claude Code's `isolation="worktree"` use the
|
|
20
|
-
`worktree-agent-<id
|
|
20
|
+
`agent-<id>` namespace (previously `worktree-agent-<id>`; both are accepted). The orchestrator owns this worktree's lifecycle;
|
|
21
21
|
a sub-agent MUST NOT hold state-correction primitives (hard-reset, update-ref,
|
|
22
22
|
force-move, index-discard) on a worktree it did not create (#48, #2924). If ANY
|
|
23
23
|
assertion below fails, HALT immediately — print the FATAL line, `exit 42`, and let
|
|
@@ -27,11 +27,11 @@ commit.
|
|
|
27
27
|
HEAD_REF=$(git symbolic-ref --quiet HEAD || echo "DETACHED")
|
|
28
28
|
ACTUAL_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
29
29
|
if [ "$HEAD_REF" = "DETACHED" ] || echo "$ACTUAL_BRANCH" | grep -Eq '^(main|master|develop|trunk|release/.*)$'; then
|
|
30
|
-
echo "FATAL: worktree HEAD on '$ACTUAL_BRANCH' (expected worktree-agent-*); refusing to commit or self-recover via 'git update-ref' (#2924)." >&2
|
|
30
|
+
echo "FATAL: worktree HEAD on '$ACTUAL_BRANCH' (expected agent-* or worktree-agent-*); refusing to commit or self-recover via 'git update-ref' (#2924)." >&2
|
|
31
31
|
exit 42
|
|
32
32
|
fi
|
|
33
|
-
if ! echo "$ACTUAL_BRANCH" | grep -Eq '^worktree-agent-[A-Za-z0-9._/-]+$'; then
|
|
34
|
-
echo "FATAL: worktree HEAD '$ACTUAL_BRANCH' is not in the worktree-agent-* namespace; refusing to commit (#2924)." >&2
|
|
33
|
+
if ! echo "$ACTUAL_BRANCH" | grep -Eq '^(worktree-)?agent-[A-Za-z0-9._/-]+$'; then
|
|
34
|
+
echo "FATAL: worktree HEAD '$ACTUAL_BRANCH' is not in the agent-* / worktree-agent-* namespace; refusing to commit (#2924)." >&2
|
|
35
35
|
exit 42
|
|
36
36
|
fi
|
|
37
37
|
ACTUAL_BASE=$(git rev-parse HEAD)
|
|
@@ -6,6 +6,10 @@ tags: [searchable tech]
|
|
|
6
6
|
provides:
|
|
7
7
|
- [bullet list of what was built/delivered]
|
|
8
8
|
affects: [list of phase names or keywords]
|
|
9
|
+
actuals:
|
|
10
|
+
tokens: [chars/4 over files actually changed]
|
|
11
|
+
tasks: [tasks completed]
|
|
12
|
+
commits: [commits made]
|
|
9
13
|
tech-stack:
|
|
10
14
|
added: [libraries/tools]
|
|
11
15
|
patterns: [architectural/code patterns]
|
|
@@ -6,6 +6,10 @@ tags: [searchable tech]
|
|
|
6
6
|
provides:
|
|
7
7
|
- [bullet list of what was built/delivered]
|
|
8
8
|
affects: [list of phase names or keywords]
|
|
9
|
+
actuals:
|
|
10
|
+
tokens: [chars/4 over files actually changed]
|
|
11
|
+
tasks: [tasks completed]
|
|
12
|
+
commits: [commits made]
|
|
9
13
|
tech-stack:
|
|
10
14
|
added: [libraries/tools]
|
|
11
15
|
patterns: [architectural/code patterns]
|
|
@@ -21,6 +21,13 @@ provides:
|
|
|
21
21
|
- [bullet list of what this phase built/delivered]
|
|
22
22
|
affects: [list of phase names or keywords that will need this context]
|
|
23
23
|
|
|
24
|
+
# Actuals (#2632) — pairs with the plan's `estimate` to calibrate future estimates.
|
|
25
|
+
# Same estimateTokens scale (chars/4 over the realized diff), never a harness token count.
|
|
26
|
+
actuals:
|
|
27
|
+
tokens: [chars/4 over files actually changed]
|
|
28
|
+
tasks: [tasks completed]
|
|
29
|
+
commits: [commits made]
|
|
30
|
+
|
|
24
31
|
# Tech tracking
|
|
25
32
|
tech-stack:
|
|
26
33
|
added: [libraries/tools added in this phase]
|
|
@@ -33,10 +33,10 @@ Parse JSON for: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded
|
|
|
33
33
|
|
|
34
34
|
Resolve agent models:
|
|
35
35
|
```bash
|
|
36
|
-
SELECTOR_MODEL=$(gsd_run query resolve-model gsd-framework-selector
|
|
37
|
-
RESEARCHER_MODEL=$(gsd_run query resolve-model gsd-ai-researcher
|
|
38
|
-
DOMAIN_MODEL=$(gsd_run query resolve-model gsd-domain-researcher
|
|
39
|
-
PLANNER_MODEL=$(gsd_run query resolve-model gsd-eval-planner
|
|
36
|
+
SELECTOR_MODEL=$(gsd_run query resolve-model gsd-framework-selector --pick model 2>/dev/null || true)
|
|
37
|
+
RESEARCHER_MODEL=$(gsd_run query resolve-model gsd-ai-researcher --pick model 2>/dev/null || true)
|
|
38
|
+
DOMAIN_MODEL=$(gsd_run query resolve-model gsd-domain-researcher --pick model 2>/dev/null || true)
|
|
39
|
+
PLANNER_MODEL=$(gsd_run query resolve-model gsd-eval-planner --pick model 2>/dev/null || true)
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Check config:
|
|
@@ -94,6 +94,10 @@ final output — do not proceed to fixing.
|
|
|
94
94
|
<step name="fix-loop">
|
|
95
95
|
For each **auto-fixable** finding (up to `--max`, ordered by severity desc):
|
|
96
96
|
|
|
97
|
+
<!-- #2508 runtime-aware-dispatch -->
|
|
98
|
+
|
|
99
|
+
> **Runtime-aware dispatch (#2508 Phase 4).** GSD workflows dispatch specialized subagents by role. Before dispatching on a built-in-only runtime (kimi-code — three built-ins only), resolve the role to a built-in via `gsd_run query resolve-dispatch-type --requested <role> --raw`. On named-dispatch runtimes (Claude/OpenCode/…) the role is returned unchanged; on kimi-code it maps to `coder`/`explore`/`plan` by role-suffix. The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3) regardless. See @gsd-core/references/runtime-aware-dispatch.md.
|
|
100
|
+
|
|
97
101
|
**a. Spawn executor agent** (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)**:**
|
|
98
102
|
```
|
|
99
103
|
Agent(
|
|
@@ -69,6 +69,10 @@ Extract `MILESTONE_REQ_IDS` from REQUIREMENTS.md traceability table — all REQ-
|
|
|
69
69
|
|
|
70
70
|
Print: "Spawning integration checker (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)"
|
|
71
71
|
|
|
72
|
+
<!-- #2517 model-omit-on-inherit -->
|
|
73
|
+
|
|
74
|
+
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`integration_checker_model`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
|
75
|
+
|
|
72
76
|
```
|
|
73
77
|
Agent(
|
|
74
78
|
prompt="Check cross-phase integration and E2E flows.
|
|
@@ -82,6 +86,10 @@ Milestone Requirements:
|
|
|
82
86
|
|
|
83
87
|
MUST map each integration finding to affected requirement IDs where applicable.
|
|
84
88
|
|
|
89
|
+
<!-- #2508 runtime-aware-dispatch -->
|
|
90
|
+
|
|
91
|
+
> **Runtime-aware dispatch (#2508 Phase 4).** GSD workflows dispatch specialized subagents by role. Before dispatching on a built-in-only runtime (kimi-code — three built-ins only), resolve the role to a built-in via `gsd_run query resolve-dispatch-type --requested <role> --raw`. On named-dispatch runtimes (Claude/OpenCode/…) the role is returned unchanged; on kimi-code it maps to `coder`/`explore`/`plan` by role-suffix. The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3) regardless. See @gsd-core/references/runtime-aware-dispatch.md.
|
|
92
|
+
|
|
85
93
|
Verify cross-phase wiring and E2E user flows.
|
|
86
94
|
${AGENT_SKILLS_CHECKER}",
|
|
87
95
|
subagent_type="gsd-integration-checker",
|
|
@@ -44,19 +44,6 @@ PLAN_STRATEGY="local"
|
|
|
44
44
|
if echo "$ARGUMENTS" | grep -qE '(^|[[:space:]])\-\-(converge|cross-ai)([[:space:]]|$)'; then
|
|
45
45
|
PLAN_STRATEGY="converge"
|
|
46
46
|
fi
|
|
47
|
-
|
|
48
|
-
CONVERGENCE_ARGS=""
|
|
49
|
-
for REVIEW_FLAG in --codex --gemini --claude --opencode --ollama --lm-studio --llama-cpp --all --text; do
|
|
50
|
-
if echo "$ARGUMENTS" | grep -qE "(^|[[:space:]])${REVIEW_FLAG}([[:space:]]|$)"; then
|
|
51
|
-
CONVERGENCE_ARGS="${CONVERGENCE_ARGS} ${REVIEW_FLAG}"
|
|
52
|
-
fi
|
|
53
|
-
done
|
|
54
|
-
|
|
55
|
-
MAX_CYCLES_ARG=""
|
|
56
|
-
if echo "$ARGUMENTS" | grep -qE '\-\-max-cycles\s+[0-9]+'; then
|
|
57
|
-
MAX_CYCLES_ARG=$(echo "$ARGUMENTS" | grep -oE '\-\-max-cycles\s+[0-9]+' | awk '{print $2}')
|
|
58
|
-
CONVERGENCE_ARGS="${CONVERGENCE_ARGS} --max-cycles ${MAX_CYCLES_ARG}"
|
|
59
|
-
fi
|
|
60
47
|
```
|
|
61
48
|
|
|
62
49
|
When `--only` is set, also set `FROM_PHASE` to the same value so existing filter logic applies.
|
|
@@ -76,6 +63,23 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
|
76
63
|
If `PLAN_STRATEGY` is `converge`, fail fast unless the existing convergence feature gate is enabled:
|
|
77
64
|
|
|
78
65
|
```bash
|
|
66
|
+
# Lane flags derived from the declared roster (#2800/#2272); --all and --text are convergence
|
|
67
|
+
# controls, not reviewer lanes, so they stay literal.
|
|
68
|
+
# This block must stay AFTER the launcher preamble (above) because it calls `gsd_run` —
|
|
69
|
+
# do not move it back above the preamble in a future edit.
|
|
70
|
+
CONVERGENCE_ARGS=""
|
|
71
|
+
for REVIEW_FLAG in $(gsd_run review-lane flags) --all --text; do
|
|
72
|
+
if echo "$ARGUMENTS" | grep -qE "(^|[[:space:]])${REVIEW_FLAG}([[:space:]]|$)"; then
|
|
73
|
+
CONVERGENCE_ARGS="${CONVERGENCE_ARGS} ${REVIEW_FLAG}"
|
|
74
|
+
fi
|
|
75
|
+
done
|
|
76
|
+
|
|
77
|
+
MAX_CYCLES_ARG=""
|
|
78
|
+
if echo "$ARGUMENTS" | grep -qE '\-\-max-cycles\s+[0-9]+'; then
|
|
79
|
+
MAX_CYCLES_ARG=$(echo "$ARGUMENTS" | grep -oE '\-\-max-cycles\s+[0-9]+' | awk '{print $2}')
|
|
80
|
+
CONVERGENCE_ARGS="${CONVERGENCE_ARGS} --max-cycles ${MAX_CYCLES_ARG}"
|
|
81
|
+
fi
|
|
82
|
+
|
|
79
83
|
if [ "$PLAN_STRATEGY" = "converge" ]; then
|
|
80
84
|
CONVERGENCE_ENABLED=$(gsd_run query config-get workflow.plan_review_convergence 2>/dev/null || echo "false")
|
|
81
85
|
if [ "$CONVERGENCE_ENABLED" != "true" ]; then
|
|
@@ -490,7 +494,7 @@ Skill(skill="gsd-code-review", args="${PHASE_NUM} --fix --auto")
|
|
|
490
494
|
After execute, read canonical verification:
|
|
491
495
|
|
|
492
496
|
```bash
|
|
493
|
-
VERIFY_STATUS=$(gsd_run query verification.status "${PHASE_DIR}" 2>/dev/null
|
|
497
|
+
VERIFY_STATUS=$(gsd_run query verification.status "${PHASE_DIR}" --pick status 2>/dev/null || true)
|
|
494
498
|
```
|
|
495
499
|
|
|
496
500
|
If `PHASE_DIR` is absent, re-fetch `init.phase-op ${PHASE_NUM}` and parse `phase_dir`.
|
|
@@ -548,7 +552,7 @@ Skill(skill="gsd-execute-phase", args="${PHASE_NUM} --no-transition")
|
|
|
548
552
|
|
|
549
553
|
Re-read verification status:
|
|
550
554
|
```bash
|
|
551
|
-
VERIFY_STATUS=$(gsd_run query verification.status "${PHASE_DIR}" 2>/dev/null
|
|
555
|
+
VERIFY_STATUS=$(gsd_run query verification.status "${PHASE_DIR}" --pick status 2>/dev/null || true)
|
|
552
556
|
```
|
|
553
557
|
|
|
554
558
|
If `passed` or `human_needed`: route normally.
|
|
@@ -156,7 +156,7 @@ Re-run `init todos` to get updated count, then update STATE.md "### Pending Todo
|
|
|
156
156
|
</step>
|
|
157
157
|
|
|
158
158
|
<step name="git_commit">
|
|
159
|
-
If todo was moved to
|
|
159
|
+
If todo was moved to completed/, commit the change:
|
|
160
160
|
|
|
161
161
|
```bash
|
|
162
162
|
git rm --cached .planning/todos/pending/[filename] 2>/dev/null || true
|
|
@@ -178,5 +178,5 @@ Confirm: "Committed: docs: start work on todo - [title]"
|
|
|
178
178
|
- [ ] Appropriate actions offered
|
|
179
179
|
- [ ] Selected action executed
|
|
180
180
|
- [ ] STATE.md updated if todo count changed
|
|
181
|
-
- [ ] Changes committed to git (if todo moved to
|
|
181
|
+
- [ ] Changes committed to git (if todo moved to completed/)
|
|
182
182
|
</success_criteria>
|
|
@@ -118,7 +118,7 @@ Parse REVIEW.md frontmatter to check status and extract context for --auto loop:
|
|
|
118
118
|
REVIEW_STATUS=$(REVIEW_PATH="${REVIEW_PATH}" node -e "
|
|
119
119
|
const fs = require('fs');
|
|
120
120
|
const content = fs.readFileSync(process.env.REVIEW_PATH, 'utf-8');
|
|
121
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
121
|
+
const match = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
122
122
|
if (match && /status:\s*(\S+)/.test(match[1])) {
|
|
123
123
|
console.log(match[1].match(/status:\s*(\S+)/)[1]);
|
|
124
124
|
} else {
|
|
@@ -144,7 +144,7 @@ Extract review depth for --auto re-review:
|
|
|
144
144
|
REVIEW_DEPTH=$(REVIEW_PATH="${REVIEW_PATH}" node -e "
|
|
145
145
|
const fs = require('fs');
|
|
146
146
|
const content = fs.readFileSync(process.env.REVIEW_PATH, 'utf-8');
|
|
147
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
147
|
+
const match = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
148
148
|
if (match && /depth:\s*(\S+)/.test(match[1])) {
|
|
149
149
|
console.log(match[1].match(/depth:\s*(\S+)/)[1]);
|
|
150
150
|
} else {
|
|
@@ -163,7 +163,7 @@ while IFS= read -r line; do
|
|
|
163
163
|
done < <(REVIEW_PATH="${REVIEW_PATH}" node -e "
|
|
164
164
|
const fs = require('fs');
|
|
165
165
|
const content = fs.readFileSync(process.env.REVIEW_PATH, 'utf-8');
|
|
166
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
166
|
+
const match = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
167
167
|
if (match) {
|
|
168
168
|
const fm = match[1];
|
|
169
169
|
// Try YAML array format: files_reviewed_list: [file1, file2]
|
|
@@ -197,6 +197,14 @@ echo "Fix scope: ${FIX_SCOPE}"
|
|
|
197
197
|
|
|
198
198
|
Use Agent() to spawn agent:
|
|
199
199
|
|
|
200
|
+
<!-- #2508 runtime-aware-dispatch -->
|
|
201
|
+
|
|
202
|
+
> **Runtime-aware dispatch (#2508 Phase 4).** GSD workflows dispatch specialized subagents by role. Before dispatching on a built-in-only runtime (kimi-code — three built-ins only), resolve the role to a built-in via `gsd_run query resolve-dispatch-type --requested <role> --raw`. On named-dispatch runtimes (Claude/OpenCode/…) the role is returned unchanged; on kimi-code it maps to `coder`/`explore`/`plan` by role-suffix. The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3) regardless. See @gsd-core/references/runtime-aware-dispatch.md.
|
|
203
|
+
|
|
204
|
+
<!-- #2517 model-omit-on-inherit -->
|
|
205
|
+
|
|
206
|
+
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`FIXER_MODEL`, `REVIEWER_MODEL`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
|
207
|
+
|
|
200
208
|
```text
|
|
201
209
|
Agent(subagent_type="gsd-code-fixer", model="{FIXER_MODEL}", prompt="
|
|
202
210
|
<files_to_read>
|
|
@@ -298,7 +306,7 @@ ${AGENT_SKILLS_REVIEWER}")
|
|
|
298
306
|
NEW_STATUS=$(REVIEW_PATH="${REVIEW_PATH}" node -e "
|
|
299
307
|
const fs = require('fs');
|
|
300
308
|
const content = fs.readFileSync(process.env.REVIEW_PATH, 'utf-8');
|
|
301
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
309
|
+
const match = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
302
310
|
if (match && /status:\s*(\S+)/.test(match[1])) {
|
|
303
311
|
console.log(match[1].match(/status:\s*(\S+)/)[1]);
|
|
304
312
|
} else {
|
|
@@ -364,7 +372,7 @@ if [ -f "${FIX_REPORT_PATH}" ]; then
|
|
|
364
372
|
HAS_STATUS=$(REVIEW_PATH="${REVIEW_PATH}" node -e "
|
|
365
373
|
const fs = require('fs');
|
|
366
374
|
const content = fs.readFileSync(process.env.FIX_REPORT_PATH, 'utf-8');
|
|
367
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
375
|
+
const match = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
368
376
|
if (match && /status:/.test(match[1])) { console.log('valid'); } else { console.log('invalid'); }
|
|
369
377
|
" 2>/dev/null)
|
|
370
378
|
|
|
@@ -421,7 +429,7 @@ Extract frontmatter fields:
|
|
|
421
429
|
FIX_FRONTMATTER=$(REVIEW_PATH="${REVIEW_PATH}" node -e "
|
|
422
430
|
const fs = require('fs');
|
|
423
431
|
const content = fs.readFileSync(process.env.FIX_REPORT_PATH, 'utf-8');
|
|
424
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
432
|
+
const match = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
425
433
|
if (match) process.stdout.write(match[1]);
|
|
426
434
|
" 2>/dev/null)
|
|
427
435
|
|