@opengsd/gsd-pi 1.9.0-dev.e10b60d4 → 1.10.0-dev.a5e42e99
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/README.md +10 -9
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/loop.js +24 -4
- package/dist/resources/extensions/gsd/auto/run-unit.js +19 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
- package/dist/resources/extensions/gsd/auto-start.js +30 -10
- package/dist/resources/extensions/gsd/auto-verification.js +25 -12
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
- package/dist/resources/extensions/gsd/auto.js +12 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +37 -6
- package/dist/resources/extensions/gsd/flat-phase-migration.js +12 -0
- package/dist/resources/extensions/gsd/gsd-db.js +75 -31
- package/dist/resources/extensions/gsd/model-cost-table.js +6 -3
- package/dist/resources/extensions/gsd/model-router.js +10 -5
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +12 -4
- package/dist/resources/extensions/gsd/preferences-models.js +50 -10
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +41 -6
- package/dist/resources/extensions/gsd/preferences.js +7 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +3 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -1
- package/dist/resources/extensions/gsd/verification-evidence.js +5 -3
- package/dist/resources/extensions/gsd/worktree-state-projection.js +20 -18
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +2 -2
- package/dist/resources/extensions/subagent/index.js +1 -1
- package/dist/startup-model-validation.d.ts +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- 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 +6 -6
- package/dist/web/standalone/.next/server/chunks/1991.js +2 -2
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- 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/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +7 -6
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.d.ts +1 -1
- package/packages/contracts/dist/rpc.d.ts.map +1 -1
- package/packages/contracts/dist/rpc.js +1 -1
- package/packages/contracts/dist/rpc.js.map +1 -1
- package/packages/contracts/dist/rpc.test.js +1 -1
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- 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/cli/args.js +2 -2
- package/packages/gsd-agent-modes/dist/cli/args.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +21 -5
- package/packages/gsd-cloud/dist/background-cli.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/background-cli.test.js +325 -0
- package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +146 -16
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.js +7 -1
- package/packages/gsd-cloud/dist/cloud-config.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +7 -4
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +115 -31
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.test.js +224 -59
- package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts +3 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js +36 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts +32 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.js +640 -0
- package/packages/gsd-cloud/dist/runtime-process.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js +543 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts +117 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js +291 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js +434 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js.map +1 -0
- package/packages/gsd-cloud/package.json +2 -2
- package/packages/mcp-server/dist/cli-runner.d.ts +3 -0
- package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
- package/packages/mcp-server/dist/cli-runner.js +119 -33
- package/packages/mcp-server/dist/cli-runner.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +2 -2
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +130 -2
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +101 -9
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.js +18 -6
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +3 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/google.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +9 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +54 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +1 -0
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme.d.ts +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +1 -0
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/loop.ts +48 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +20 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -0
- package/src/resources/extensions/gsd/auto-start.ts +32 -9
- package/src/resources/extensions/gsd/auto-verification.ts +46 -12
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
- package/src/resources/extensions/gsd/auto.ts +13 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +4 -3
- package/src/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +42 -6
- package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -0
- package/src/resources/extensions/gsd/gsd-db.ts +85 -33
- package/src/resources/extensions/gsd/model-cost-table.ts +14 -3
- package/src/resources/extensions/gsd/model-router.ts +10 -5
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +18 -4
- package/src/resources/extensions/gsd/preferences-models.ts +54 -10
- package/src/resources/extensions/gsd/preferences-types.ts +10 -2
- package/src/resources/extensions/gsd/preferences-validation.ts +49 -6
- package/src/resources/extensions/gsd/preferences.ts +13 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +3 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +74 -1
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +8 -9
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +22 -7
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +71 -4
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-faults.test.ts +238 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.ts +141 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-projection-conflict.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.ts +72 -0
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +40 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +5 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +5 -2
- package/src/resources/extensions/gsd/worktree-state-projection.ts +21 -24
- package/src/resources/extensions/ollama/ollama-chat-provider.ts +2 -2
- package/src/resources/extensions/ollama/tests/ollama-chat-provider-think.test.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +1 -1
- /package/dist/web/standalone/.next/static/{V9MAVyYVPboQUB9KTTAMi → xwUaOqui04jIIFVsIBLiL}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{V9MAVyYVPboQUB9KTTAMi → xwUaOqui04jIIFVsIBLiL}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -28,16 +28,16 @@ See [CHANGELOG.md](./CHANGELOG.md) for release-by-release fixes and [Legacy Rele
|
|
|
28
28
|
## Latest Release Highlights
|
|
29
29
|
|
|
30
30
|
<!-- release-highlights:start -->
|
|
31
|
-
Latest release: **v1.
|
|
31
|
+
Latest release: **v1.10.0**
|
|
32
32
|
|
|
33
|
-
- **
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
- **gsd:**
|
|
39
|
-
- **gsd:**
|
|
40
|
-
- **gsd:**
|
|
33
|
+
- **pi-ai:** Add Meta Muse Spark 1.1 to the model catalog.
|
|
34
|
+
- **gsd:** Surface cacheRetention as a settable prompt-cache TTL preference.
|
|
35
|
+
- **models:** Add `gpt-5.6-sol`, `gpt-5.6-terra`, and `gpt-5.6-luna` as first-class models.
|
|
36
|
+
- **models:** Add Grok 4.5 as a first-class xAI model.
|
|
37
|
+
- **agent-core:** Pin compaction summarization reasoning to low, bound degenerate-chunk retry.
|
|
38
|
+
- **gsd:** Filter superseded context injections from provider payload.
|
|
39
|
+
- **gsd:** Stop advertising alias tool schemas on model-facing surfaces.
|
|
40
|
+
- **gsd:** Cap execute-task and discuss-slice inlined context; provider-aware budgets.
|
|
41
41
|
|
|
42
42
|
<!-- release-highlights:end -->
|
|
43
43
|
|
|
@@ -194,6 +194,7 @@ Then use slash commands inside the GSD session:
|
|
|
194
194
|
| --- | --- |
|
|
195
195
|
| `src/` | Core runtime resources and bundled extensions |
|
|
196
196
|
| `packages/` | Workspace packages used by the CLI, agent, TUI, RPC, and native bridge |
|
|
197
|
+
| `apps/` | Standalone native apps, such as the GSD Cloud Monitor menu bar app |
|
|
197
198
|
| `native/` | Native engine packaging and platform binaries |
|
|
198
199
|
| `studio/` | Desktop studio app |
|
|
199
200
|
| `web/` | Web UI and API surface |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
d05c1e678c1d85d7
|
|
@@ -261,7 +261,22 @@ async function enforceMinRequestInterval(s, prefs) {
|
|
|
261
261
|
await new Promise(r => setTimeout(r, decision.waitMs));
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
-
function
|
|
264
|
+
async function snapshotCrashedUnitWork(ctx, s, deps, iterData) {
|
|
265
|
+
try {
|
|
266
|
+
const commitMsg = await deps.autoCommitUnit?.(s.basePath, iterData.unitType, iterData.unitId, ctx);
|
|
267
|
+
if (commitMsg) {
|
|
268
|
+
debugLog("autoLoop", {
|
|
269
|
+
phase: "crash-snapshot-commit",
|
|
270
|
+
unitType: iterData.unitType,
|
|
271
|
+
unitId: iterData.unitId,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch (snapshotErr) {
|
|
276
|
+
logWarning("dispatch", `unit crash snapshot failed: ${snapshotErr instanceof Error ? snapshotErr.message : String(snapshotErr)}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async function closeOutCrashedUnit(ctx, s, deps, iterData, err) {
|
|
265
280
|
const summary = formatDispatchExceptionSummary({ error: err });
|
|
266
281
|
try {
|
|
267
282
|
emitOpenUnitEndForUnit(s.basePath, iterData.unitType, iterData.unitId, "cancelled", {
|
|
@@ -278,6 +293,7 @@ function closeOutCrashedUnit(s, iterData, err) {
|
|
|
278
293
|
catch (closeoutErr) {
|
|
279
294
|
logWarning("dispatch", `unit crash closeout failed: ${closeoutErr instanceof Error ? closeoutErr.message : String(closeoutErr)}`);
|
|
280
295
|
}
|
|
296
|
+
await snapshotCrashedUnitWork(ctx, s, deps, iterData);
|
|
281
297
|
}
|
|
282
298
|
/**
|
|
283
299
|
* Main auto-mode execution loop. Iterates: orchestration.advance → guards →
|
|
@@ -400,11 +416,15 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
400
416
|
active: s.active,
|
|
401
417
|
iteration,
|
|
402
418
|
maxIterations: MAX_LOOP_ITERATIONS,
|
|
403
|
-
hasCommandContext:
|
|
419
|
+
hasCommandContext: typeof s.cmdCtx?.newSession === "function",
|
|
404
420
|
sessionLockValid: true,
|
|
405
421
|
});
|
|
406
422
|
if (commandContextDecision.action === "stop" && commandContextDecision.reason === "missing-command-context") {
|
|
407
423
|
debugLog("autoLoop", { phase: "exit", reason: "no-cmdCtx" });
|
|
424
|
+
if (s.currentUnit) {
|
|
425
|
+
await deps.autoCommitUnit?.(s.basePath, s.currentUnit.type, s.currentUnit.id, ctx);
|
|
426
|
+
}
|
|
427
|
+
await deps.stopAuto(ctx, pi, commandContextDecision.message, { preserveWorktree: true });
|
|
408
428
|
finishTurn("stopped", "manual-attention", commandContextDecision.reason);
|
|
409
429
|
break;
|
|
410
430
|
}
|
|
@@ -586,7 +606,7 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
586
606
|
if (err instanceof ModelPolicyDispatchBlockedError) {
|
|
587
607
|
throw err;
|
|
588
608
|
}
|
|
589
|
-
closeOutCrashedUnit(s, iterData, err);
|
|
609
|
+
await closeOutCrashedUnit(ctx, s, deps, iterData, err);
|
|
590
610
|
throw err;
|
|
591
611
|
}
|
|
592
612
|
if (unitPhaseResult.action === "next") {
|
|
@@ -1109,7 +1129,7 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
1109
1129
|
if (err instanceof ModelPolicyDispatchBlockedError) {
|
|
1110
1130
|
throw err;
|
|
1111
1131
|
}
|
|
1112
|
-
closeOutCrashedUnit(s, iterData, err);
|
|
1132
|
+
await closeOutCrashedUnit(ctx, s, deps, iterData, err);
|
|
1113
1133
|
dispatchSettled = settleDispatchFailed(dispatchId, formatDispatchExceptionSummary({ error: err }), {
|
|
1114
1134
|
markFailed: markDispatchFailed,
|
|
1115
1135
|
logWriteFailure: logDispatchLedgerWriteFailure,
|
|
@@ -58,6 +58,24 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
58
58
|
debugLog("runUnit", { phase: "start", unitType, unitId });
|
|
59
59
|
// ── Session creation with timeout ──
|
|
60
60
|
debugLog("runUnit", { phase: "session-create", unitType, unitId });
|
|
61
|
+
const cmdCtx = s.cmdCtx;
|
|
62
|
+
if (typeof cmdCtx?.newSession !== "function") {
|
|
63
|
+
const msg = "command context is missing newSession";
|
|
64
|
+
debugLog("runUnit", {
|
|
65
|
+
phase: "session-error",
|
|
66
|
+
unitType,
|
|
67
|
+
unitId,
|
|
68
|
+
error: msg,
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
status: "cancelled",
|
|
72
|
+
errorContext: {
|
|
73
|
+
message: `Session creation failed: ${msg}`,
|
|
74
|
+
category: "session-failed",
|
|
75
|
+
isTransient: false,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
61
79
|
let sessionResult;
|
|
62
80
|
let sessionTimeoutHandle;
|
|
63
81
|
const mySessionSwitchGeneration = ++sessionSwitchGeneration;
|
|
@@ -67,7 +85,7 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
67
85
|
const sessionAbortController = new AbortController();
|
|
68
86
|
_setSessionSwitchInFlight(true);
|
|
69
87
|
try {
|
|
70
|
-
const sessionPromise =
|
|
88
|
+
const sessionPromise = cmdCtx.newSession({
|
|
71
89
|
abortSignal: sessionAbortController.signal,
|
|
72
90
|
workspaceRoot: s.basePath,
|
|
73
91
|
}).finally(() => {
|
|
@@ -46,9 +46,10 @@ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.
|
|
|
46
46
|
import { extractVerdict } from "./verdict-parser.js";
|
|
47
47
|
import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
|
|
48
48
|
import { parseProject } from "./schemas/parsers.js";
|
|
49
|
+
import { LAYOUT_SEGMENTS } from "./layout-policy.js";
|
|
49
50
|
import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
|
|
50
51
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
51
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, } from "node:fs";
|
|
52
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, } from "node:fs";
|
|
52
53
|
import { join } from "node:path";
|
|
53
54
|
import { validateDirectory } from "./validate-directory.js";
|
|
54
55
|
import { isCustomProvider, resolveDefaultSessionModel, resolveDynamicRoutingConfig, } from "./preferences-models.js";
|
|
@@ -73,6 +74,30 @@ const MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS = 2;
|
|
|
73
74
|
export function hasGitIndexLockForTest(basePath) {
|
|
74
75
|
return existsSync(join(basePath, ".git", "index.lock"));
|
|
75
76
|
}
|
|
77
|
+
function isEmptyDirectory(dirPath) {
|
|
78
|
+
try {
|
|
79
|
+
return existsSync(dirPath) && readdirSync(dirPath).length === 0;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function reconcileFlatPhaseBootstrapLayout(basePath) {
|
|
86
|
+
const gsdDir = join(basePath, ".gsd");
|
|
87
|
+
const phasesPath = join(gsdDir, LAYOUT_SEGMENTS.level1);
|
|
88
|
+
const milestonesPath = join(gsdDir, "milestones");
|
|
89
|
+
if (isEmptyDirectory(milestonesPath)) {
|
|
90
|
+
if (!existsSync(phasesPath))
|
|
91
|
+
mkdirSync(phasesPath, { recursive: true });
|
|
92
|
+
rmSync(milestonesPath, { recursive: true, force: true });
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
if (!existsSync(phasesPath) && !existsSync(milestonesPath)) {
|
|
96
|
+
mkdirSync(phasesPath, { recursive: true });
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
76
101
|
export function _shouldAbortBootstrapForUnavailableDbForTest(gsdDbPath, dbAvailable, pathExists = existsSync) {
|
|
77
102
|
return pathExists(gsdDbPath) && !dbAvailable;
|
|
78
103
|
}
|
|
@@ -796,7 +821,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
796
821
|
// provider the user is not logged into and surface as "Not logged in · Please
|
|
797
822
|
// run /login" before pausing and resetting to claude-code/claude-sonnet-4-6.
|
|
798
823
|
const manualSessionOverride = getSessionModelOverride(ctx.sessionManager.getSessionId());
|
|
799
|
-
const sessionProviderIsCustom = isCustomProvider(ctx.model?.provider);
|
|
824
|
+
const sessionProviderIsCustom = isCustomProvider(ctx.model?.provider, ctx.modelRegistry);
|
|
800
825
|
const profileModelIds = modelIdsForProfileResolution(ctx.modelRegistry, resolveProfileAnchorProvider(ctx.model?.provider), resolveDisabledModelProvidersFromPreferences());
|
|
801
826
|
const preferredModel = sessionProviderIsCustom
|
|
802
827
|
? null
|
|
@@ -868,20 +893,15 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
868
893
|
ensureGitignore(base, { manageGitignore });
|
|
869
894
|
if (manageGitignore !== false)
|
|
870
895
|
untrackRuntimeFiles(base);
|
|
871
|
-
// Bootstrap
|
|
872
|
-
|
|
873
|
-
// so checking .gsd/ existence would be dead code (#2942).
|
|
874
|
-
const gsdDir = join(base, ".gsd");
|
|
875
|
-
const milestonesPath = join(gsdDir, "milestones");
|
|
876
|
-
if (!existsSync(milestonesPath)) {
|
|
877
|
-
mkdirSync(milestonesPath, { recursive: true });
|
|
896
|
+
// Bootstrap the flat-phase projection root and clean empty legacy scaffolds.
|
|
897
|
+
if (reconcileFlatPhaseBootstrapLayout(base)) {
|
|
878
898
|
try {
|
|
879
899
|
nativeAddAll(base);
|
|
880
900
|
nativeCommit(base, "chore: init gsd");
|
|
881
901
|
}
|
|
882
902
|
catch (err) {
|
|
883
903
|
/* nothing to commit */
|
|
884
|
-
logWarning("engine", `
|
|
904
|
+
logWarning("engine", `layout bootstrap commit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
885
905
|
}
|
|
886
906
|
}
|
|
887
907
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Post-unit verification gate for GSD auto-mode units.
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { relMilestoneFile, resolveSlicePath } from "./paths.js";
|
|
4
|
+
import { legacyMilestonesDir, relMilestoneFile, resolveMilestonePath, resolveSlicePath } from "./paths.js";
|
|
5
5
|
import { resolveMilestoneValidationVerdict } from "./milestone-validation-verdict.js";
|
|
6
6
|
import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
|
|
7
7
|
import { parseUnitId } from "./unit-id.js";
|
|
@@ -24,6 +24,20 @@ import { getLedger } from "./metrics.js";
|
|
|
24
24
|
import { getUnitCostSpikeAction, resolveUnitCostSpikeMultiplier } from "./auto-budget.js";
|
|
25
25
|
import { formatPostUnitStatusCard } from "./auto-status-message.js";
|
|
26
26
|
import { detectWebApp } from "./web-app-uat.js";
|
|
27
|
+
function resolveVerificationEvidenceLocation(basePath, milestoneId, sliceId) {
|
|
28
|
+
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
29
|
+
if (!mDir)
|
|
30
|
+
return null;
|
|
31
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
32
|
+
const isLegacy = mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\");
|
|
33
|
+
if (!isLegacy) {
|
|
34
|
+
return { dir: mDir, fileSliceId: sliceId };
|
|
35
|
+
}
|
|
36
|
+
const sDir = resolveSlicePath(basePath, milestoneId, sliceId);
|
|
37
|
+
if (!sDir)
|
|
38
|
+
return null;
|
|
39
|
+
return { dir: join(sDir, "tasks") };
|
|
40
|
+
}
|
|
27
41
|
function getCurrentUnitCostStats(unitId) {
|
|
28
42
|
const ledger = getLedger();
|
|
29
43
|
if (!ledger || !Array.isArray(ledger.units) || ledger.units.length === 0) {
|
|
@@ -431,11 +445,10 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|
|
431
445
|
const taskAlreadyComplete = taskRow?.status === "complete" || taskRow?.status === "done";
|
|
432
446
|
if (mid && sid && tid) {
|
|
433
447
|
try {
|
|
434
|
-
const
|
|
435
|
-
if (
|
|
436
|
-
const tasksDir = join(sDir, "tasks");
|
|
448
|
+
const evidenceLocation = resolveVerificationEvidenceLocation(s.basePath, mid, sid);
|
|
449
|
+
if (evidenceLocation) {
|
|
437
450
|
if (result.passed) {
|
|
438
|
-
writeVerificationJSON(result,
|
|
451
|
+
writeVerificationJSON(result, evidenceLocation.dir, tid, s.currentUnit.id, undefined, undefined, evidenceLocation.fileSliceId);
|
|
439
452
|
}
|
|
440
453
|
else {
|
|
441
454
|
const nextAttempt = attempt + 1;
|
|
@@ -444,7 +457,7 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|
|
444
457
|
verdict.retryable &&
|
|
445
458
|
autoFixEnabled &&
|
|
446
459
|
nextAttempt <= maxRetries;
|
|
447
|
-
writeVerificationJSON(result,
|
|
460
|
+
writeVerificationJSON(result, evidenceLocation.dir, tid, s.currentUnit.id, includeRetryMetadata ? nextAttempt : undefined, includeRetryMetadata ? maxRetries : undefined, evidenceLocation.fileSliceId);
|
|
448
461
|
}
|
|
449
462
|
}
|
|
450
463
|
}
|
|
@@ -560,9 +573,8 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|
|
560
573
|
// Re-write verification evidence JSON with post-execution checks
|
|
561
574
|
if (postExecChecks && postExecChecks.length > 0 && mid && sid && tid) {
|
|
562
575
|
try {
|
|
563
|
-
const
|
|
564
|
-
if (
|
|
565
|
-
const tasksDir = join(sDir, "tasks");
|
|
576
|
+
const evidenceLocation = resolveVerificationEvidenceLocation(s.basePath, mid, sid);
|
|
577
|
+
if (evidenceLocation) {
|
|
566
578
|
// Add postExecutionChecks to the result for the JSON write
|
|
567
579
|
const resultWithPostExec = {
|
|
568
580
|
...result,
|
|
@@ -570,7 +582,7 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|
|
570
582
|
passed: result.passed && !postExecBlockingFailure,
|
|
571
583
|
};
|
|
572
584
|
// Manually write with postExecutionChecks field
|
|
573
|
-
writeVerificationJSONWithPostExec(resultWithPostExec,
|
|
585
|
+
writeVerificationJSONWithPostExec(resultWithPostExec, evidenceLocation.dir, tid, s.currentUnit.id, postExecChecks, postExecBlockingFailure ? attempt + 1 : undefined, postExecBlockingFailure ? maxRetries : undefined, evidenceLocation.fileSliceId);
|
|
574
586
|
}
|
|
575
587
|
}
|
|
576
588
|
catch (evidenceErr) {
|
|
@@ -738,7 +750,7 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|
|
738
750
|
* Write verification evidence JSON with post-execution checks included.
|
|
739
751
|
* This is a variant of writeVerificationJSON that adds the postExecutionChecks field.
|
|
740
752
|
*/
|
|
741
|
-
function writeVerificationJSONWithPostExec(result, tasksDir, taskId, unitId, postExecutionChecks, retryAttempt, maxRetries) {
|
|
753
|
+
function writeVerificationJSONWithPostExec(result, tasksDir, taskId, unitId, postExecutionChecks, retryAttempt, maxRetries, sliceId) {
|
|
742
754
|
mkdirSync(tasksDir, { recursive: true });
|
|
743
755
|
const evidence = {
|
|
744
756
|
schemaVersion: 1,
|
|
@@ -774,6 +786,7 @@ function writeVerificationJSONWithPostExec(result, tasksDir, taskId, unitId, pos
|
|
|
774
786
|
fixAvailable: w.fixAvailable,
|
|
775
787
|
}));
|
|
776
788
|
}
|
|
777
|
-
const
|
|
789
|
+
const fileName = sliceId ? `${sliceId}-${taskId}-VERIFY.json` : `${taskId}-VERIFY.json`;
|
|
790
|
+
const filePath = join(tasksDir, fileName);
|
|
778
791
|
writeFileSync(filePath, JSON.stringify(evidence, null, 2) + "\n", "utf-8");
|
|
779
792
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { cpSync, existsSync, lstatSync as lstatSyncFn, mkdirSync, readdirSync, } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { _isSamePath as isSamePath, } from "./auto-worktree-cleanup.js";
|
|
8
|
-
import { resolveGsdPathContract } from "./paths.js";
|
|
8
|
+
import { dirIsContentBearingLegacyMilestone, resolveGsdPathContract } from "./paths.js";
|
|
9
9
|
import { WorktreeStateProjection } from "./worktree-state-projection.js";
|
|
10
10
|
import { logWarning } from "./workflow-logger.js";
|
|
11
11
|
const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
|
|
@@ -143,10 +143,14 @@ function syncMilestoneLayout(mainGsd, wtGsd, layoutSegment, synced) {
|
|
|
143
143
|
if (!existsSync(mainMilestonesDir))
|
|
144
144
|
return;
|
|
145
145
|
try {
|
|
146
|
-
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
147
146
|
const mainMilestones = readdirSync(mainMilestonesDir, { withFileTypes: true })
|
|
148
147
|
.filter((entry) => entry.isDirectory())
|
|
149
|
-
.map((entry) => entry.name)
|
|
148
|
+
.map((entry) => entry.name)
|
|
149
|
+
.filter((name) => layoutSegment !== "milestones" ||
|
|
150
|
+
dirIsContentBearingLegacyMilestone(join(mainMilestonesDir, name)));
|
|
151
|
+
if (mainMilestones.length === 0)
|
|
152
|
+
return;
|
|
153
|
+
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
150
154
|
for (const milestoneId of mainMilestones) {
|
|
151
155
|
syncMilestoneDirectory(mainMilestonesDir, wtMilestonesDir, milestoneId, synced);
|
|
152
156
|
}
|
|
@@ -2440,7 +2440,18 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
|
|
|
2440
2440
|
startedAt: hookStartedAt,
|
|
2441
2441
|
workspaceRoot: s.basePath,
|
|
2442
2442
|
});
|
|
2443
|
-
const
|
|
2443
|
+
const cmdCtx = s.cmdCtx;
|
|
2444
|
+
if (typeof cmdCtx?.newSession !== "function") {
|
|
2445
|
+
const message = "Auto-mode has no command context for dispatch.";
|
|
2446
|
+
ctx.ui.notify(message, "error");
|
|
2447
|
+
const unitToCommit = previousCurrentUnit ?? s.currentUnit;
|
|
2448
|
+
if (unitToCommit) {
|
|
2449
|
+
await autoCommitUnit(s.basePath, unitToCommit.type, unitToCommit.id, ctx);
|
|
2450
|
+
}
|
|
2451
|
+
await stopAuto(ctx, pi, message, { preserveWorktree: true });
|
|
2452
|
+
return false;
|
|
2453
|
+
}
|
|
2454
|
+
const result = await cmdCtx.newSession({ workspaceRoot: s.basePath });
|
|
2444
2455
|
if (result.cancelled) {
|
|
2445
2456
|
await stopAuto(ctx, pi);
|
|
2446
2457
|
return false;
|
|
@@ -5,7 +5,7 @@ import { minimatch } from "minimatch";
|
|
|
5
5
|
import { GSD_PHASE_SCOPE_DISPLAY_REASON, shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
6
6
|
import { canonicalToolName } from "../engine-hook-contract.js";
|
|
7
7
|
import { loadJsonFileOrNull } from "../json-persistence.js";
|
|
8
|
-
import { getIsolationMode } from "../preferences.js";
|
|
8
|
+
import { getIsolationMode, loadEffectiveGSDPreferences } from "../preferences.js";
|
|
9
9
|
import { compileSubagentPermissionContract } from "../unit-context-manifest.js";
|
|
10
10
|
import { allowedPlanningDispatchAgentsList, isReadOnlyPlanningDispatchAgent, } from "../planning-subagent-registry.js";
|
|
11
11
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -1118,6 +1118,7 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
1118
1118
|
const dispatchContract = compileSubagentPermissionContract(policy);
|
|
1119
1119
|
const allowedSubagents = dispatchContract.allowedSubagents;
|
|
1120
1120
|
const allowed = new Set(allowedSubagents);
|
|
1121
|
+
const planningSubagentRegistry = loadEffectiveGSDPreferences(basePath)?.preferences.planning_subagent_registry;
|
|
1121
1122
|
// When agentClasses is undefined, the caller has not been updated to extract
|
|
1122
1123
|
// agent identities yet. Block and warn so stale callers surface in telemetry
|
|
1123
1124
|
// instead of silently bypassing the gate.
|
|
@@ -1131,9 +1132,9 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
1131
1132
|
if (requested.length === 0) {
|
|
1132
1133
|
return { block: false };
|
|
1133
1134
|
}
|
|
1134
|
-
const globallyDisallowed = requested.find(a => !isReadOnlyPlanningDispatchAgent(a));
|
|
1135
|
+
const globallyDisallowed = requested.find(a => !isReadOnlyPlanningDispatchAgent(a, planningSubagentRegistry));
|
|
1135
1136
|
if (globallyDisallowed) {
|
|
1136
|
-
return planningBlock(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`);
|
|
1137
|
+
return planningBlock(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList(planningSubagentRegistry)}) may be dispatched from ${policy.mode} units`);
|
|
1137
1138
|
}
|
|
1138
1139
|
const disallowedByPolicy = requested.find(a => !allowed.has(a));
|
|
1139
1140
|
if (disallowedByPolicy) {
|
|
@@ -124,11 +124,11 @@ Diagnostics record the file path, scope (global/project), severity (error/warnin
|
|
|
124
124
|
- `validation` — used for gate evaluation, roadmap reassessment, milestone validation, and doc rewrites. Falls back to `planning` if unset.
|
|
125
125
|
- `uat` — used for UAT runs. Falls back to `completion` if unset.
|
|
126
126
|
|
|
127
|
-
- `thinking`: per-phase reasoning effort (ADR-026), separate from `models`. Same phase keys as `models`. Values: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`. Thinking travels with the model — model choice and reasoning effort are independent controls, so you can run one model across phases at different reasoning levels.
|
|
127
|
+
- `thinking`: per-phase reasoning effort (ADR-026), separate from `models`. Same phase keys as `models`. Values: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Thinking travels with the model — model choice and reasoning effort are independent controls, so you can run one model across phases at different reasoning levels.
|
|
128
128
|
- Two equivalent ways to set it: inline as `models.<phase>.thinking`, or as a separate `thinking:` block keyed by phase. For the same phase, the inline value wins over the block; project preferences win over global; a phase that's unset inherits via the same sibling chain as `models` (e.g. `discuss → planning`).
|
|
129
129
|
- If no thinking is configured for a phase, the session level (set via `/model`) is used, exactly as before — this is fully backward-compatible.
|
|
130
130
|
- `execute-task` (code-writing) has a measured reasoning floor of `medium`: at lower levels models stop planning edits and thrash on file re-reads. The floor applies to the session/default path. An **explicit** `execution` thinking level bypasses the floor and is honored verbatim (with a one-time advisory) — set `execution: low` deliberately if you want it.
|
|
131
|
-
- Levels a model can't support are clamped to the nearest supported level at dispatch and never sent to the provider, so a model/level mismatch never fails a unit mid-run. `xhigh` support
|
|
131
|
+
- Levels a model can't support are clamped to the nearest supported level at dispatch and never sent to the provider, so a model/level mismatch never fails a unit mid-run. `xhigh` and `max` support are model-dependent; current examples include `gpt-5.6-sol`, `gpt-5.6-terra`, and `gpt-5.6-luna`, which advertise both.
|
|
132
132
|
|
|
133
133
|
- `skill_staleness_days`: number — skills unused for this many days get deprioritized during discovery. Set to `0` to disable staleness tracking. Default: `60`.
|
|
134
134
|
|
|
@@ -357,24 +357,33 @@ In `"parent"` mode, slice/task `targetRepositories` default to the declared chil
|
|
|
357
357
|
- `"replace"` requires `prompt`.
|
|
358
358
|
- `"skip"` is valid with no additional fields.
|
|
359
359
|
|
|
360
|
+
- `planning_subagent_registry`: object — optional classification for custom planning agents. Each key is an agent id and must set:
|
|
361
|
+
- `read_only_specialist`: boolean — set to `true` to classify the custom agent as safe for planning dispatch.
|
|
362
|
+
|
|
360
363
|
- `planning_subagents`: object — project-local widening for read-only planning subagent dispatch. Supported unit keys are `plan-milestone` and `plan-slice`; each has:
|
|
361
364
|
- `allowed`: string[] — additional planning-safe agents for that unit.
|
|
362
365
|
|
|
363
|
-
Agents must
|
|
366
|
+
Agents must be built-in read-only planning specialists (`mnemo`, `scout`, `planner`, `reviewer`, `security`, or `tester`) or registered in `planning_subagent_registry` with `read_only_specialist: true`. The write gate still blocks source writes outside `.gsd/**`, unrestricted bash, stale subagent calls without agent identities, agents outside the read-only registry, and agents not listed for the active unit.
|
|
364
367
|
|
|
365
368
|
Example:
|
|
366
369
|
|
|
367
370
|
```yaml
|
|
371
|
+
planning_subagent_registry:
|
|
372
|
+
my-custom-planner:
|
|
373
|
+
read_only_specialist: true
|
|
374
|
+
|
|
368
375
|
planning_subagents:
|
|
369
376
|
plan-milestone:
|
|
370
377
|
allowed:
|
|
371
378
|
- scout
|
|
372
379
|
- planner
|
|
380
|
+
- my-custom-planner
|
|
373
381
|
- security
|
|
374
382
|
plan-slice:
|
|
375
383
|
allowed:
|
|
376
384
|
- scout
|
|
377
385
|
- planner
|
|
386
|
+
- my-custom-planner
|
|
378
387
|
- reviewer
|
|
379
388
|
- security
|
|
380
389
|
```
|
|
@@ -13,6 +13,7 @@ import { parseRoadmapSlices } from "./roadmap-slices.js";
|
|
|
13
13
|
import { parsePlan } from "./parsers-legacy.js";
|
|
14
14
|
import { parseSummary } from "./files.js";
|
|
15
15
|
import { LAYOUT_SEGMENTS } from "./layout-policy.js";
|
|
16
|
+
import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
|
|
16
17
|
const USER_AUTHORED_ARTIFACT_TYPES = new Set(["CONTEXT", "RESEARCH"]);
|
|
17
18
|
function escapeRegExp(value) {
|
|
18
19
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -58,9 +59,27 @@ function reportCheckboxDbStatusDivergence(issues, basePath, filePath, scope, uni
|
|
|
58
59
|
fixable: false,
|
|
59
60
|
});
|
|
60
61
|
}
|
|
62
|
+
function bareDuplicateMilestoneId(milestoneId) {
|
|
63
|
+
const match = milestoneId.match(/^(M\d{3})-[a-z0-9]{6}$/i);
|
|
64
|
+
return match?.[1]?.toUpperCase() ?? null;
|
|
65
|
+
}
|
|
66
|
+
function checkboxDbStatusMilestoneIds(basePath, milestoneIds) {
|
|
67
|
+
if (!hasFlatPhaseLayout(basePath))
|
|
68
|
+
return milestoneIds;
|
|
69
|
+
// Flat-phase directories are keyed by phase number. A restored
|
|
70
|
+
// M003-xxxxxx row alongside M003 is a stale duplicate for the same
|
|
71
|
+
// phases/03-* projection, so checking both can compare DB status against two
|
|
72
|
+
// competing PLAN files and report a persistent false divergence.
|
|
73
|
+
const allIds = new Set(milestoneIds.map((id) => id.toUpperCase()));
|
|
74
|
+
return milestoneIds.filter((milestoneId) => {
|
|
75
|
+
const bareId = bareDuplicateMilestoneId(milestoneId);
|
|
76
|
+
return !bareId || !allIds.has(bareId);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
61
79
|
function checkProjectionCheckboxDbStatus(basePath, milestoneIds, issues) {
|
|
62
80
|
for (const milestoneId of milestoneIds) {
|
|
63
|
-
const
|
|
81
|
+
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, milestoneId);
|
|
82
|
+
const roadmapPath = resolveMilestoneFile(artifactBasePath, milestoneId, "ROADMAP");
|
|
64
83
|
const slices = getMilestoneSlices(milestoneId);
|
|
65
84
|
if (roadmapPath && existsSync(roadmapPath)) {
|
|
66
85
|
try {
|
|
@@ -78,7 +97,7 @@ function checkProjectionCheckboxDbStatus(basePath, milestoneIds, issues) {
|
|
|
78
97
|
}
|
|
79
98
|
}
|
|
80
99
|
for (const slice of slices) {
|
|
81
|
-
const planPath = resolveSliceFile(
|
|
100
|
+
const planPath = resolveSliceFile(artifactBasePath, milestoneId, slice.id, "PLAN");
|
|
82
101
|
if (!planPath || !existsSync(planPath))
|
|
83
102
|
continue;
|
|
84
103
|
try {
|
|
@@ -117,7 +136,7 @@ function isClearedByMilestoneShellProjectionFlush(basePath, issue, reRenderedMil
|
|
|
117
136
|
function artifactExistsOnDisk(basePath, artifactPath, row) {
|
|
118
137
|
return resolveArtifactDiskPath(basePath, artifactPath, row) !== null;
|
|
119
138
|
}
|
|
120
|
-
function resolveLiteralArtifactDiskPath(basePath, artifactPath) {
|
|
139
|
+
function resolveLiteralArtifactDiskPath(basePath, artifactPath, row) {
|
|
121
140
|
const relativeArtifactPath = artifactPathRelativeToGsd(artifactPath);
|
|
122
141
|
if (isAbsolute(relativeArtifactPath)) {
|
|
123
142
|
return existsSync(relativeArtifactPath) ? relativeArtifactPath : null;
|
|
@@ -127,6 +146,16 @@ function resolveLiteralArtifactDiskPath(basePath, artifactPath) {
|
|
|
127
146
|
if (isPathInside(root, candidate) && existsSync(candidate))
|
|
128
147
|
return candidate;
|
|
129
148
|
}
|
|
149
|
+
if (row?.milestone_id) {
|
|
150
|
+
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, row.milestone_id);
|
|
151
|
+
if (artifactBasePath !== basePath) {
|
|
152
|
+
for (const root of [gsdProjectionRoot(artifactBasePath), gsdRoot(artifactBasePath)]) {
|
|
153
|
+
const candidate = join(root, relativeArtifactPath);
|
|
154
|
+
if (isPathInside(root, candidate) && existsSync(candidate))
|
|
155
|
+
return candidate;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
130
159
|
return null;
|
|
131
160
|
}
|
|
132
161
|
function relativeToGsdRoot(basePath, diskPath) {
|
|
@@ -166,7 +195,7 @@ function resolveArtifactDiskPath(basePath, artifactPath, row) {
|
|
|
166
195
|
if (flatPath)
|
|
167
196
|
return flatPath;
|
|
168
197
|
}
|
|
169
|
-
return resolveLiteralArtifactDiskPath(basePath, artifactPath);
|
|
198
|
+
return resolveLiteralArtifactDiskPath(basePath, artifactPath, row);
|
|
170
199
|
}
|
|
171
200
|
function taskExistsInPlan(basePath, milestoneId, sliceId, taskId) {
|
|
172
201
|
const planPath = resolveSliceFile(basePath, milestoneId, sliceId, "PLAN");
|
|
@@ -322,7 +351,9 @@ function staleMilestonesArtifactRowFixable(basePath, row, artifactRows) {
|
|
|
322
351
|
}
|
|
323
352
|
function stalePhasesArtifactRowFixable(basePath, row, artifactRows) {
|
|
324
353
|
const issuePath = artifactPathRelativeToGsd(row.path);
|
|
325
|
-
return issuePath.startsWith(`${LAYOUT_SEGMENTS.level1}/`) &&
|
|
354
|
+
return issuePath.startsWith(`${LAYOUT_SEGMENTS.level1}/`) &&
|
|
355
|
+
(hasPresentFlatPhaseReplacement(basePath, row, artifactRows) ||
|
|
356
|
+
hasPresentMilestonesReplacement(basePath, row, artifactRows));
|
|
326
357
|
}
|
|
327
358
|
function staleArtifactRowFixable(basePath, row, artifactRows) {
|
|
328
359
|
return staleMilestonesArtifactRowFixable(basePath, row, artifactRows) ||
|
|
@@ -658,7 +689,7 @@ export async function checkEngineHealth(basePath, issues, fixesApplied, options)
|
|
|
658
689
|
// block doctor.
|
|
659
690
|
try {
|
|
660
691
|
if (isDbAvailable()) {
|
|
661
|
-
checkProjectionCheckboxDbStatus(basePath, getAllMilestones().map((milestone) => milestone.id), issues);
|
|
692
|
+
checkProjectionCheckboxDbStatus(basePath, checkboxDbStatusMilestoneIds(basePath, getAllMilestones().map((milestone) => milestone.id)), issues);
|
|
662
693
|
}
|
|
663
694
|
}
|
|
664
695
|
catch {
|
|
@@ -130,6 +130,17 @@ function isInsideFlatProjectionBackup(backupDir, src) {
|
|
|
130
130
|
const phaseBackupDir = join(backupDir, "__phases");
|
|
131
131
|
return src === phaseBackupDir || src.startsWith(`${phaseBackupDir}/`) || src.startsWith(`${phaseBackupDir}\\`);
|
|
132
132
|
}
|
|
133
|
+
function removeFlatProjectionBackup(backupDir) {
|
|
134
|
+
const phaseBackupDir = join(backupDir, "__phases");
|
|
135
|
+
if (!existsSync(phaseBackupDir))
|
|
136
|
+
return;
|
|
137
|
+
try {
|
|
138
|
+
removePathWithRetries(phaseBackupDir);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
logWarning("migration", `flat-phase migration succeeded but could not remove temporary ${LAYOUT_SEGMENTS.level1}/ backup: ${err.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
133
144
|
function restoreFlatProjectionFromBackup(basePath, backupDir) {
|
|
134
145
|
const phaseBackupDir = join(backupDir, "__phases");
|
|
135
146
|
if (!existsSync(phaseBackupDir))
|
|
@@ -433,4 +444,5 @@ export async function migrateToFlatPhase(basePath) {
|
|
|
433
444
|
catch (err) {
|
|
434
445
|
logWarning("migration", `flat-phase migration succeeded but could not remove ${LEGACY_MIGRATING_SEGMENT}: ${err.message}`);
|
|
435
446
|
}
|
|
447
|
+
removeFlatProjectionBackup(backupDir);
|
|
436
448
|
}
|