@opengsd/gsd-pi 1.1.1-dev.9f86580 → 1.1.1-dev.b2556262
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/dist/headless-recover.js +56 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/index.js +39 -22
- package/dist/resources/extensions/browser-tools/state.js +12 -0
- package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
- package/dist/resources/extensions/browser-tools/utils.js +3 -3
- package/dist/resources/extensions/gsd/auto/loop.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +43 -10
- package/dist/resources/extensions/gsd/auto/session.js +20 -1
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +72 -12
- package/dist/resources/extensions/gsd/auto-model-selection.js +128 -9
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -19
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +14 -11
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -65
- package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
- package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
- package/dist/resources/extensions/gsd/db-writer.js +35 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/dist/resources/extensions/gsd/gsd-db.js +480 -172
- package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
- package/dist/resources/extensions/gsd/md-importer.js +38 -3
- package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
- package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
- package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
- package/dist/resources/extensions/gsd/preferences-models.js +110 -43
- package/dist/resources/extensions/gsd/preferences-types.js +13 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
- package/dist/resources/extensions/gsd/preferences.js +4 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
- package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
- package/dist/resources/extensions/gsd/source-observations.js +306 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
- package/dist/resources/extensions/gsd/state.js +7 -3
- package/dist/resources/extensions/gsd/tool-contract.js +14 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +1 -9
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -6
- package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
- package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +57 -429
- package/dist/resources/extensions/gsd/uat-policy.js +130 -0
- package/dist/resources/extensions/gsd/uat-run.js +414 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
- package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
- package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
- package/dist/resources/extensions/subagent/agents.js +1 -0
- package/dist/resources/extensions/subagent/index.js +27 -12
- package/dist/resources/extensions/subagent/launch.js +7 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +4 -4
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/dist/native.js +22 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +30 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +23 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +25 -24
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/utils.d.ts +11 -0
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +119 -6
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/themes.js +1 -1
- package/pkg/dist/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/index.ts +39 -22
- package/src/resources/extensions/browser-tools/state.ts +13 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
- package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
- package/src/resources/extensions/browser-tools/utils.ts +3 -3
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +42 -10
- package/src/resources/extensions/gsd/auto/session.ts +22 -1
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +85 -12
- package/src/resources/extensions/gsd/auto-model-selection.ts +164 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +23 -20
- package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +13 -10
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +225 -72
- package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
- package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
- package/src/resources/extensions/gsd/db-writer.ts +38 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/src/resources/extensions/gsd/gsd-db.ts +564 -186
- package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
- package/src/resources/extensions/gsd/md-importer.ts +49 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
- package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
- package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
- package/src/resources/extensions/gsd/preferences-models.ts +112 -43
- package/src/resources/extensions/gsd/preferences-types.ts +39 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
- package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
- package/src/resources/extensions/gsd/source-observations.ts +402 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
- package/src/resources/extensions/gsd/state.ts +7 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +16 -2
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +73 -6
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
- package/src/resources/extensions/gsd/tool-contract.ts +28 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +1 -11
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -6
- package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
- package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +66 -526
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/uat-policy.ts +191 -0
- package/src/resources/extensions/gsd/uat-run.ts +550 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
- package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
- package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
- package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
- package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
- package/src/resources/extensions/subagent/agents.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +28 -3
- package/src/resources/extensions/subagent/launch.ts +8 -0
- package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
- /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
|
@@ -20,82 +20,103 @@ export function resolveModelForUnit(unitType) {
|
|
|
20
20
|
return resolved?.primary;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* Ordered phase-bucket chain a unit type resolves against, most-specific
|
|
24
|
+
* first. The first chain entry with a configured value wins; later entries
|
|
25
|
+
* are siblings the unit falls back to (e.g. `discuss → planning`).
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* Single source of truth for the unit-type → phase mapping, shared by model
|
|
28
|
+
* resolution (`resolveModelWithFallbacksForUnit`) and thinking resolution
|
|
29
|
+
* (`resolveThinkingLevelForUnit`) so the two never drift (ADR-026).
|
|
29
30
|
*/
|
|
30
|
-
export function
|
|
31
|
-
const prefs = loadEffectiveGSDPreferences(undefined, { availableModelIds: [] });
|
|
32
|
-
const models = prefs?.preferences?.models;
|
|
33
|
-
if (!models)
|
|
34
|
-
return undefined;
|
|
35
|
-
const m = models;
|
|
36
|
-
let phaseConfig;
|
|
31
|
+
export function phaseChainForUnit(unitType) {
|
|
37
32
|
switch (unitType) {
|
|
38
33
|
case "research-milestone":
|
|
39
34
|
case "research-slice":
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
// Deep-mode project research orchestrator. Reads PROJECT.md / REQUIREMENTS.md
|
|
36
|
+
// and fans out research subagents. Routes to the research bucket.
|
|
37
|
+
case "research-project":
|
|
38
|
+
return ["research"];
|
|
42
39
|
case "plan-milestone":
|
|
43
40
|
case "plan-slice":
|
|
44
41
|
case "refine-slice":
|
|
45
42
|
case "replan-slice":
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
return ["planning"];
|
|
44
|
+
// Deep-mode project-level discussion units route to the same model bucket
|
|
45
|
+
// as milestone-level discussion (interactive interview style). Workflow
|
|
46
|
+
// preferences and research-decision are tiny ask_user_questions style units
|
|
47
|
+
// that share the discuss bucket because they are conversational. All fall
|
|
48
|
+
// back to planning when no `discuss` bucket is set.
|
|
48
49
|
case "discuss-milestone":
|
|
49
50
|
case "discuss-slice":
|
|
50
|
-
// Deep-mode project-level discussion units route to the same model
|
|
51
|
-
// bucket as milestone-level discussion (interactive interview style).
|
|
52
51
|
case "discuss-project":
|
|
53
52
|
case "discuss-requirements":
|
|
54
|
-
// Workflow preferences and research-decision are tiny ask_user_questions
|
|
55
|
-
// style units; they share the discuss bucket because they are
|
|
56
|
-
// conversational rather than research/execution. Falling back to planning
|
|
57
|
-
// when no `discuss` bucket is set keeps parity with the milestone units.
|
|
58
53
|
case "workflow-preferences":
|
|
59
54
|
case "research-decision":
|
|
60
|
-
|
|
61
|
-
break;
|
|
62
|
-
// Deep-mode project research orchestrator. Reads PROJECT.md / REQUIREMENTS.md
|
|
63
|
-
// and fans out research subagents. Routes to the research bucket so it
|
|
64
|
-
// gets the research-tier model when one is configured.
|
|
65
|
-
case "research-project":
|
|
66
|
-
phaseConfig = m.research;
|
|
67
|
-
break;
|
|
55
|
+
return ["discuss", "planning"];
|
|
68
56
|
case "execute-task":
|
|
69
57
|
case "reactive-execute":
|
|
70
|
-
|
|
71
|
-
break;
|
|
58
|
+
return ["execution"];
|
|
72
59
|
case "execute-task-simple":
|
|
73
|
-
|
|
74
|
-
break;
|
|
60
|
+
return ["execution_simple", "execution"];
|
|
75
61
|
case "complete-slice":
|
|
76
62
|
case "complete-milestone":
|
|
77
63
|
case "worktree-merge":
|
|
78
|
-
|
|
79
|
-
break;
|
|
64
|
+
return ["completion"];
|
|
80
65
|
case "run-uat":
|
|
81
|
-
|
|
82
|
-
break;
|
|
66
|
+
return ["uat", "completion"];
|
|
83
67
|
case "reassess-roadmap":
|
|
84
68
|
case "rewrite-docs":
|
|
85
69
|
case "gate-evaluate":
|
|
86
70
|
case "validate-milestone":
|
|
87
|
-
|
|
88
|
-
break;
|
|
71
|
+
return ["validation", "planning"];
|
|
89
72
|
default:
|
|
90
73
|
// Subagent unit types (e.g., "subagent", "subagent/scout")
|
|
91
74
|
if (unitType === "subagent" || unitType.startsWith("subagent/")) {
|
|
92
|
-
|
|
93
|
-
break;
|
|
75
|
+
return ["subagent"];
|
|
94
76
|
}
|
|
95
77
|
return undefined;
|
|
96
78
|
}
|
|
97
|
-
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Find the phase bucket whose `models` entry wins the chain for a unit, plus
|
|
82
|
+
* that entry. Returns undefined when no phase in the chain is configured.
|
|
83
|
+
*/
|
|
84
|
+
function resolveWinningPhase(models, chain) {
|
|
85
|
+
if (!models)
|
|
98
86
|
return undefined;
|
|
87
|
+
for (const key of chain) {
|
|
88
|
+
const config = models[key];
|
|
89
|
+
// Falsy check (not `!= null`) so an empty-string model is treated as
|
|
90
|
+
// unconfigured and the chain falls through — matches the pre-refactor
|
|
91
|
+
// switch, which bailed via `if (!phaseConfig)`.
|
|
92
|
+
if (!config)
|
|
93
|
+
continue;
|
|
94
|
+
// An object entry only "wins" if it provides a usable model. A model-less
|
|
95
|
+
// object (e.g. `{ provider: x }`, or `{}` left after stripping an invalid
|
|
96
|
+
// `thinking`) must not shadow sibling fallback or yield `{ primary: undefined }`.
|
|
97
|
+
if (typeof config === "object" && !config.model)
|
|
98
|
+
continue;
|
|
99
|
+
return { phase: key, config };
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolve model and fallbacks for a given auto-mode unit type.
|
|
105
|
+
* Returns the primary model and ordered fallbacks, or undefined if not configured.
|
|
106
|
+
*
|
|
107
|
+
* Supports both legacy string format and extended object format:
|
|
108
|
+
* - Legacy: `planning: claude-opus-4-6`
|
|
109
|
+
* - Extended: `planning: { model: claude-opus-4-6, fallbacks: [glm-5, minimax-m2.5] }`
|
|
110
|
+
*/
|
|
111
|
+
export function resolveModelWithFallbacksForUnit(unitType) {
|
|
112
|
+
const prefs = loadEffectiveGSDPreferences(undefined, { availableModelIds: [] });
|
|
113
|
+
const chain = phaseChainForUnit(unitType);
|
|
114
|
+
if (!chain)
|
|
115
|
+
return undefined;
|
|
116
|
+
const winner = resolveWinningPhase(prefs?.preferences?.models, chain);
|
|
117
|
+
if (!winner)
|
|
118
|
+
return undefined;
|
|
119
|
+
const phaseConfig = winner.config;
|
|
99
120
|
// Normalize: string -> { model, fallbacks: [] }
|
|
100
121
|
if (typeof phaseConfig === "string") {
|
|
101
122
|
return { primary: phaseConfig, fallbacks: [] };
|
|
@@ -110,6 +131,52 @@ export function resolveModelWithFallbacksForUnit(unitType) {
|
|
|
110
131
|
fallbacks: phaseConfig.fallbacks ?? [],
|
|
111
132
|
};
|
|
112
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Resolve the explicitly configured reasoning effort for a unit type (ADR-026).
|
|
136
|
+
*
|
|
137
|
+
* Thinking travels with the model. The chain is walked most-specific-first up to
|
|
138
|
+
* and including the phase whose model won; at each level inline
|
|
139
|
+
* `models.<phase>.thinking` is preferred, then the same phase's `thinking` block
|
|
140
|
+
* entry. This means:
|
|
141
|
+
* - a more-specific block key (`thinking.execution_simple`) surfaces even when
|
|
142
|
+
* the model only resolves on a less-specific sibling (`models.execution`);
|
|
143
|
+
* - inline thinking is honored even on a model-less `models.<phase>` entry
|
|
144
|
+
* (e.g. `{ thinking: "high" }` with no `model`);
|
|
145
|
+
* - a unit that claimed its own model bucket never borrows a *less*-specific
|
|
146
|
+
* sibling's thinking (the walk stops at the winning phase).
|
|
147
|
+
* When no model is configured anywhere in the chain, the walk spans the full
|
|
148
|
+
* chain so inline thinking and the `thinking` block both resolve on their own
|
|
149
|
+
* sibling chain.
|
|
150
|
+
*
|
|
151
|
+
* Returns undefined when nothing explicit is configured — the dispatch path
|
|
152
|
+
* then falls back to the session/default level and applies the code-writing
|
|
153
|
+
* floor. Session level, defaults, the floor, and capability clamping are NOT
|
|
154
|
+
* applied here.
|
|
155
|
+
*/
|
|
156
|
+
export function resolveThinkingLevelForUnit(unitType) {
|
|
157
|
+
const prefs = loadEffectiveGSDPreferences(undefined, { availableModelIds: [] })?.preferences;
|
|
158
|
+
if (!prefs)
|
|
159
|
+
return undefined;
|
|
160
|
+
const chain = phaseChainForUnit(unitType);
|
|
161
|
+
if (!chain)
|
|
162
|
+
return undefined;
|
|
163
|
+
const models = prefs.models;
|
|
164
|
+
const block = prefs.thinking;
|
|
165
|
+
// Walk most-specific-first, up to and including the winning model phase (or
|
|
166
|
+
// the full chain when no model is configured), checking inline then block.
|
|
167
|
+
const winner = resolveWinningPhase(models, chain);
|
|
168
|
+
const limit = winner ? chain.indexOf(winner.phase) + 1 : chain.length;
|
|
169
|
+
for (let i = 0; i < limit; i++) {
|
|
170
|
+
const key = chain[i];
|
|
171
|
+
const entry = models?.[key];
|
|
172
|
+
if (typeof entry === "object" && entry?.thinking)
|
|
173
|
+
return entry.thinking; // inline (incl. model-less)
|
|
174
|
+
const blockLevel = block?.[key];
|
|
175
|
+
if (blockLevel)
|
|
176
|
+
return blockLevel; // block
|
|
177
|
+
}
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
113
180
|
/**
|
|
114
181
|
* Resolve the default session model from GSD preferences.
|
|
115
182
|
*
|
|
@@ -46,6 +46,7 @@ export const KNOWN_PREFERENCE_KEYS = new Set([
|
|
|
46
46
|
"skill_rules",
|
|
47
47
|
"custom_instructions",
|
|
48
48
|
"models",
|
|
49
|
+
"thinking",
|
|
49
50
|
"skill_discovery",
|
|
50
51
|
"skill_staleness_days",
|
|
51
52
|
"auto_supervisor",
|
|
@@ -133,6 +134,18 @@ export const KNOWN_UNIT_LABELS = [
|
|
|
133
134
|
"research-decision", "research-project",
|
|
134
135
|
];
|
|
135
136
|
export const SKILL_ACTIONS = new Set(["use", "prefer", "avoid"]);
|
|
137
|
+
/** The nine model-routing phase buckets. */
|
|
138
|
+
export const GSD_MODEL_PHASE_KEYS = [
|
|
139
|
+
"research",
|
|
140
|
+
"planning",
|
|
141
|
+
"discuss",
|
|
142
|
+
"execution",
|
|
143
|
+
"execution_simple",
|
|
144
|
+
"completion",
|
|
145
|
+
"validation",
|
|
146
|
+
"subagent",
|
|
147
|
+
"uat",
|
|
148
|
+
];
|
|
136
149
|
/**
|
|
137
150
|
* Format a skill reference for the system prompt.
|
|
138
151
|
* If resolved, shows the path so the agent knows exactly where to read.
|
|
@@ -8,8 +8,18 @@
|
|
|
8
8
|
import { isAbsolute } from "node:path";
|
|
9
9
|
import { VALID_BRANCH_NAME } from "./git-service.js";
|
|
10
10
|
import { normalizeStringArray } from "../shared/format-utils.js";
|
|
11
|
-
import {
|
|
11
|
+
import { getGateIdsForTurn } from "./gate-registry.js";
|
|
12
|
+
import { KNOWN_PREFERENCE_KEYS, KNOWN_UNIT_LABELS, GSD_MODEL_PHASE_KEYS, SKILL_ACTIONS, } from "./preferences-types.js";
|
|
12
13
|
const VALID_TOKEN_PROFILES = new Set(["budget", "balanced", "quality", "burn-max"]);
|
|
14
|
+
const VALID_THINKING_LEVELS = new Set([
|
|
15
|
+
"off",
|
|
16
|
+
"minimal",
|
|
17
|
+
"low",
|
|
18
|
+
"medium",
|
|
19
|
+
"high",
|
|
20
|
+
"xhigh",
|
|
21
|
+
]);
|
|
22
|
+
const KNOWN_MODEL_PHASE_KEYS = new Set(GSD_MODEL_PHASE_KEYS);
|
|
13
23
|
const VALID_UOK_TURN_ACTIONS = new Set([
|
|
14
24
|
"commit",
|
|
15
25
|
"snapshot",
|
|
@@ -23,6 +33,7 @@ const VALID_POST_UNIT_HOOK_ON_BLOCK_ACTIONS = new Set([
|
|
|
23
33
|
"queue-slice",
|
|
24
34
|
"pause",
|
|
25
35
|
]);
|
|
36
|
+
const VALID_GATE_EVALUATE_SLICE_GATES = new Set(getGateIdsForTurn("gate-evaluate"));
|
|
26
37
|
export function validatePreferences(preferences) {
|
|
27
38
|
const errors = [];
|
|
28
39
|
const warnings = [];
|
|
@@ -375,12 +386,60 @@ export function validatePreferences(preferences) {
|
|
|
375
386
|
// ─── Models ─────────────────────────────────────────────────────────
|
|
376
387
|
if (preferences.models !== undefined) {
|
|
377
388
|
if (preferences.models && typeof preferences.models === "object") {
|
|
378
|
-
|
|
389
|
+
// Static check for inline per-phase thinking (ADR-026). The resolved
|
|
390
|
+
// model isn't known until dispatch, so capability is clamped there; here
|
|
391
|
+
// we warn on illegal level strings AND strip them, so a typo can't reach
|
|
392
|
+
// resolveThinkingLevelForUnit and be treated as explicit configuration.
|
|
393
|
+
const sanitizedModels = {};
|
|
394
|
+
for (const [phase, entry] of Object.entries(preferences.models)) {
|
|
395
|
+
if (entry && typeof entry === "object" && "thinking" in entry) {
|
|
396
|
+
const level = entry.thinking;
|
|
397
|
+
if (level !== undefined && !VALID_THINKING_LEVELS.has(level)) {
|
|
398
|
+
warnings.push(`models.${phase}.thinking "${String(level)}" is not a valid thinking level ` +
|
|
399
|
+
`(off, minimal, low, medium, high, xhigh) — ignored`);
|
|
400
|
+
const { thinking: _ignored, ...rest } = entry;
|
|
401
|
+
// If stripping the bad thinking leaves no usable model, drop the
|
|
402
|
+
// phase entirely rather than storing a hollow `{}` / `{ provider }`
|
|
403
|
+
// entry that resolveWinningPhase would otherwise treat as configured.
|
|
404
|
+
if (rest.model) {
|
|
405
|
+
sanitizedModels[phase] = rest;
|
|
406
|
+
}
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
sanitizedModels[phase] = entry;
|
|
411
|
+
}
|
|
412
|
+
validated.models = sanitizedModels;
|
|
379
413
|
}
|
|
380
414
|
else {
|
|
381
415
|
errors.push("models must be an object");
|
|
382
416
|
}
|
|
383
417
|
}
|
|
418
|
+
// ─── Thinking (separate per-phase block, ADR-026) ───────────────────
|
|
419
|
+
if (preferences.thinking !== undefined) {
|
|
420
|
+
if (preferences.thinking && typeof preferences.thinking === "object" && !Array.isArray(preferences.thinking)) {
|
|
421
|
+
const validatedThinking = {};
|
|
422
|
+
for (const [phase, level] of Object.entries(preferences.thinking)) {
|
|
423
|
+
if (!KNOWN_MODEL_PHASE_KEYS.has(phase)) {
|
|
424
|
+
warnings.push(`unknown thinking phase "${phase}" — must be one of: ` +
|
|
425
|
+
`${[...KNOWN_MODEL_PHASE_KEYS].join(", ")} — ignored`);
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (!VALID_THINKING_LEVELS.has(level)) {
|
|
429
|
+
warnings.push(`thinking.${phase} "${String(level)}" is not a valid thinking level ` +
|
|
430
|
+
`(off, minimal, low, medium, high, xhigh) — ignored`);
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
validatedThinking[phase] = level;
|
|
434
|
+
}
|
|
435
|
+
if (Object.keys(validatedThinking).length > 0) {
|
|
436
|
+
validated.thinking = validatedThinking;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
errors.push("thinking must be an object");
|
|
441
|
+
}
|
|
442
|
+
}
|
|
384
443
|
// ─── Auto Supervisor ────────────────────────────────────────────────
|
|
385
444
|
if (preferences.auto_supervisor !== undefined) {
|
|
386
445
|
if (preferences.auto_supervisor && typeof preferences.auto_supervisor === "object") {
|
|
@@ -931,7 +990,13 @@ export function validatePreferences(preferences) {
|
|
|
931
990
|
}
|
|
932
991
|
if (ge.slice_gates !== undefined) {
|
|
933
992
|
if (Array.isArray(ge.slice_gates) && ge.slice_gates.every((g) => typeof g === "string")) {
|
|
934
|
-
|
|
993
|
+
const invalid = ge.slice_gates.filter((g) => !VALID_GATE_EVALUATE_SLICE_GATES.has(g));
|
|
994
|
+
if (invalid.length === 0) {
|
|
995
|
+
validGe.slice_gates = ge.slice_gates;
|
|
996
|
+
}
|
|
997
|
+
else {
|
|
998
|
+
errors.push(`gate_evaluation.slice_gates must contain only gate-evaluate slice gates: ${[...VALID_GATE_EVALUATE_SLICE_GATES].join(", ")}`);
|
|
999
|
+
}
|
|
935
1000
|
}
|
|
936
1001
|
else {
|
|
937
1002
|
errors.push("gate_evaluation.slice_gates must be an array of strings");
|
|
@@ -37,7 +37,7 @@ export function resolveSkillStalenessDays(basePath) {
|
|
|
37
37
|
return prefs?.preferences.skill_staleness_days ?? 60;
|
|
38
38
|
}
|
|
39
39
|
// ─── Re-exports: models ─────────────────────────────────────────────────────
|
|
40
|
-
export { resolveModelForUnit, resolveModelWithFallbacksForUnit, getNextFallbackModel, isTransientNetworkError, validateModelId, updatePreferencesModels, resolveDynamicRoutingConfig, resolveAutoSupervisorConfig, resolveProfileDefaults, getProfileTierMap, resolveEffectiveProfile, resolveInlineLevel, resolveContextSelection, resolveSearchProviderFromPreferences, resolveDisabledModelProvidersFromPreferences, } from "./preferences-models.js";
|
|
40
|
+
export { resolveModelForUnit, resolveModelWithFallbacksForUnit, resolveThinkingLevelForUnit, phaseChainForUnit, getNextFallbackModel, isTransientNetworkError, validateModelId, updatePreferencesModels, resolveDynamicRoutingConfig, resolveAutoSupervisorConfig, resolveProfileDefaults, getProfileTierMap, resolveEffectiveProfile, resolveInlineLevel, resolveContextSelection, resolveSearchProviderFromPreferences, resolveDisabledModelProvidersFromPreferences, } from "./preferences-models.js";
|
|
41
41
|
// ─── Re-exports: MCP ────────────────────────────────────────────────────────
|
|
42
42
|
export { resolveModelMcpConfig } from "./preferences-mcp.js";
|
|
43
43
|
// ─── Path Constants & Getters ───────────────────────────────────────────────
|
|
@@ -330,6 +330,9 @@ function mergePreferences(base, override) {
|
|
|
330
330
|
skill_rules: [...(base.skill_rules ?? []), ...(override.skill_rules ?? [])],
|
|
331
331
|
custom_instructions: mergeStringLists(base.custom_instructions, override.custom_instructions),
|
|
332
332
|
models: { ...(base.models ?? {}), ...(override.models ?? {}) },
|
|
333
|
+
thinking: (base.thinking || override.thinking)
|
|
334
|
+
? { ...(base.thinking ?? {}), ...(override.thinking ?? {}) }
|
|
335
|
+
: undefined,
|
|
333
336
|
skill_discovery: override.skill_discovery ?? base.skill_discovery,
|
|
334
337
|
skill_staleness_days: override.skill_staleness_days ?? base.skill_staleness_days,
|
|
335
338
|
auto_supervisor: { ...(base.auto_supervisor ?? {}), ...(override.auto_supervisor ?? {}) },
|
|
@@ -38,7 +38,7 @@ You are evaluating **quality gates in parallel** for this slice. Each gate is an
|
|
|
38
38
|
3. **Verify each gate wrote its result** by checking that `gsd_save_gate_result` was called for each gate ID.
|
|
39
39
|
- Call it **directly** — do **not** use `ToolSearch` (it is not available in GSD).
|
|
40
40
|
- Inside Claude Code use the active MCP-scoped workflow name for `gsd_save_gate_result`; otherwise use `gsd_save_gate_result`.
|
|
41
|
-
- Always pass all required fields (camelCase): `milestoneId`, `sliceId`, `gateId`, `verdict`, `rationale
|
|
41
|
+
- Always pass all required fields (camelCase): `milestoneId`, `sliceId`, `gateId`, `verdict`, `rationale`, and `findings` (empty string if none). Never call with an empty `{}` object.
|
|
42
42
|
4. **Report the batch outcome** — which gates passed, which flagged concerns, and which were omitted as not applicable.
|
|
43
43
|
|
|
44
44
|
Gate agents may return `verdict: "omitted"` if the gate question is not applicable to this slice (e.g., no auth surface for Q3, no existing requirements touched for Q4). This is expected for simple slices.
|
|
@@ -44,7 +44,7 @@ If slice research is inlined, trust its architectural findings, but verify every
|
|
|
44
44
|
6. Include Threat Surface (Q3), Requirement Impact (Q4), proof level, observability, integration closure, Failure Modes (Q5), Load Profile (Q6), and Negative Tests (Q7) only where applicable.
|
|
45
45
|
7. Right-size tasks. Simple slices can be one task; split only when context, ownership, or verification boundaries justify it.
|
|
46
46
|
8. Task `verify` commands must be safe, simple commands. Do not use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`. If multiple checks are needed, create a small test file and run it with `node --test` or a package test script, or use separate simple commands joined only with `&&`. For absence checks, verify a pattern does not exist with `! grep -q 'pattern' file` or `! rg -q 'pattern' file`; do not use `grep -c` or `rg -c` to assert zero matches because count commands exit 1 when they find zero matches, and the verification gate treats that as failure.
|
|
47
|
-
9. Each task needs the exact `gsd_plan_slice.tasks[]` shape: `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. `description` should contain the Why / Do / Done-when narrative. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even when there is only one path (for example, `"inputs": ["src/index.ts"]`, never `"inputs": "src/index.ts"`). Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands. **`expectedOutput` must only list files the task actually creates or overwrites on disk.** Do NOT include files the task merely reads, verifies, or
|
|
47
|
+
9. Each task needs the exact `gsd_plan_slice.tasks[]` shape: `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. `description` should contain the Why / Do / Done-when narrative. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even when there is only one path (for example, `"inputs": ["src/index.ts"]`, never `"inputs": "src/index.ts"`). Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands. **`expectedOutput` must only list files the task actually creates or overwrites on disk.** Do NOT include files the task merely reads, verifies, tests, or describes — those belong in `inputs`, `verify`, `description`, or slice success criteria. If a task is a pure verification or test task that produces no new files, `expectedOutput` must be `[]`; if it writes a test-result log or assertion output file, list only that concrete file path. A file that does not yet exist on disk and is needed as an `input` must be produced by an earlier task's `expectedOutput` — if no prior task creates it, add a task before this one that does.
|
|
48
48
|
10. Persist with `gsd_plan_slice` using `milestoneId`, `sliceId`, `goal`, optional `successCriteria`/`proofLevel`/`integrationClosure`/`observabilityImpact`, and `tasks`. `gsd_plan_slice` handles task persistence transactionally and renders `{{outputPath}}` plus task plans; do not call `gsd_plan_task`. The DB-backed tool is the canonical write path. Do **not** rely on direct `PLAN.md` writes as the source of truth.
|
|
49
49
|
11. Self-audit before finishing: goal/demo closure, requirement coverage, deliverable coverage audit (cross-check every file listed in CONTEXT.md `## Scope` / `### In Scope` against task `files` or `expectedOutput`), locked decisions, concrete paths, dependency order, wiring, scope size, proof truthfulness, feature completeness, and quality gates. Quality gates: non-trivial slices/tasks include specific Q3-Q7 coverage where applicable.
|
|
50
50
|
12. If planning creates structural decisions, call `gsd_decision_save` for each; the tool persists the decision and regenerates `.gsd/DECISIONS.md`.
|
|
@@ -64,7 +64,7 @@ Then:
|
|
|
64
64
|
2. {{skillActivation}} Record the installed skills you expect executors to use in each task plan's `skills_used` frontmatter.
|
|
65
65
|
3. Define slice-level verification: the objective stopping condition. Plan real test files with real assertions; for simple slices, executable commands are fine.
|
|
66
66
|
4. For non-trivial slices, plan observability / proof level / integration closure, threat surface, and requirement impact. Omit entirely for simple slices.
|
|
67
|
-
5. Decompose the slice into tasks that fit one context window each. Every task passed to `gsd_plan_slice` must use the exact keys `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. Put Why / Do / Done-when detail in `description`. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even for one path (for example, `"expectedOutput": ["src/index.ts"]`, never `"expectedOutput": "src/index.ts"`).
|
|
67
|
+
5. Decompose the slice into tasks that fit one context window each. Every task passed to `gsd_plan_slice` must use the exact keys `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. Put Why / Do / Done-when detail in `description`. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even for one path (for example, `"expectedOutput": ["src/index.ts"]`, never `"expectedOutput": "src/index.ts"`). `expectedOutput` is path-only: list only files the task creates or overwrites, and use `[]` for pure verification tasks.
|
|
68
68
|
6. **Persist planning state through `gsd_plan_slice`.** Call it with the full payload. The tool writes to the DB and renders `{{outputPath}}` and `{{slicePath}}/tasks/T##-PLAN.md` automatically. Do NOT rely on direct `PLAN.md` writes.
|
|
69
69
|
7. **Self-audit the plan.** If every task were completed exactly as written, the slice goal/demo should be true. Every must-have maps to a task. Inputs and Expected Output are backtick-wrapped file paths.
|
|
70
70
|
8. If refinement produced structural decisions that diverge from the sketch, call `gsd_decision_save` for each; the tool persists the decision and regenerates `.gsd/DECISIONS.md`.
|
|
@@ -194,7 +194,11 @@ export function parseRoadmapSlices(content) {
|
|
|
194
194
|
const depends = depsMatch && depsMatch[1].trim()
|
|
195
195
|
? expandDependencies(depsMatch[1].split(",").map(s => s.trim()))
|
|
196
196
|
: [];
|
|
197
|
-
|
|
197
|
+
// ADR-011: the renderer writes a `[sketch]` badge for sketch slices.
|
|
198
|
+
// Parse it back so the is_sketch flag survives a markdown → DB re-import
|
|
199
|
+
// (e.g. /gsd recover); otherwise the flag was silently lost.
|
|
200
|
+
const isSketch = /\[sketch\]/i.test(rest);
|
|
201
|
+
currentSlice = { id, title, risk, depends, done, demo: "", isSketch };
|
|
198
202
|
continue;
|
|
199
203
|
}
|
|
200
204
|
if (currentSlice && line.trim().startsWith(">")) {
|
|
@@ -29,6 +29,8 @@ export function validateContent(unitType, artifactPath) {
|
|
|
29
29
|
return [];
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
+
const TASK_MARKER_RE = /^\s*(?:-\s+\[[ xX]\]\s+\*\*T\d+:|#{2,4}\s+T\d+\b)/gm;
|
|
33
|
+
const SLICE_MARKER_RE = /^\s*(?:-\s+\[[ xX]\]\s+\*\*S\d+:|#{2,4}\s+S\d+\b)/gm;
|
|
32
34
|
const VALIDATORS = {
|
|
33
35
|
"plan-slice": validatePlanSlice,
|
|
34
36
|
"plan-milestone": validatePlanMilestone,
|
|
@@ -36,10 +38,10 @@ const VALIDATORS = {
|
|
|
36
38
|
function validatePlanSlice(content) {
|
|
37
39
|
const violations = [];
|
|
38
40
|
// Must have at least 1 task entry — single-task slices are valid (#3649)
|
|
39
|
-
const taskCount = (content.match(
|
|
41
|
+
const taskCount = (content.match(TASK_MARKER_RE) || []).length;
|
|
40
42
|
if (taskCount < 1) {
|
|
41
43
|
violations.push({
|
|
42
|
-
severity: "
|
|
44
|
+
severity: "error",
|
|
43
45
|
reason: `Slice plan has ${taskCount} task(s) — expected at least 1`,
|
|
44
46
|
});
|
|
45
47
|
}
|
|
@@ -62,10 +64,10 @@ function validatePlanSlice(content) {
|
|
|
62
64
|
function validatePlanMilestone(content) {
|
|
63
65
|
const violations = [];
|
|
64
66
|
// Must have at least 1 slice entry
|
|
65
|
-
const sliceCount = (content.match(
|
|
67
|
+
const sliceCount = (content.match(SLICE_MARKER_RE) || []).length;
|
|
66
68
|
if (sliceCount < 1) {
|
|
67
69
|
violations.push({
|
|
68
|
-
severity: "
|
|
70
|
+
severity: "error",
|
|
69
71
|
reason: `Milestone roadmap has ${sliceCount} slice(s) — expected at least 1`,
|
|
70
72
|
});
|
|
71
73
|
}
|