@opengsd/gsd-pi 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -9
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-verification.js +25 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -3
- package/dist/resources/extensions/gsd/db/engine.js +8 -2
- package/dist/resources/extensions/gsd/db-canonical-foundation-schema.js +120 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +4 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +16 -4
- 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/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 +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- 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 +7 -7
- 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/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 +12 -2
- package/packages/gsd-cloud/dist/background-cli.test.js +157 -80
- package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -1
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +36 -12
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +6 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +106 -24
- 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 +5 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.js +429 -61
- package/packages/gsd-cloud/dist/runtime-process.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.test.js +493 -47
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -1
- 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/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 +113 -2
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +84 -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/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-model-selection.ts +1 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-verification.ts +46 -12
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +4 -3
- package/src/resources/extensions/gsd/db/engine.ts +9 -1
- package/src/resources/extensions/gsd/db-canonical-foundation-schema.ts +129 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +5 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +15 -4
- 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/db-canonical-foundation.test.ts +459 -0
- package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +64 -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/single-writer-invariant.test.ts +1 -0
- 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/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/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/{EAhnhYMt5UVOiG9-iPDjc → 8ub6oiEp2YnlOHQU20LJr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{EAhnhYMt5UVOiG9-iPDjc → 8ub6oiEp2YnlOHQU20LJr}/_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.11.0**
|
|
32
32
|
|
|
33
|
-
- **
|
|
34
|
-
- **gsd:**
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
- **
|
|
39
|
-
- **
|
|
40
|
-
- **
|
|
33
|
+
- **gsd:** Add canonical database foundation (#1426).
|
|
34
|
+
- **gsd-cloud:** Add macOS cloud monitor app and runtime telemetry (#1399).
|
|
35
|
+
- **Added:** Add workflow authority baseline gate (#1422).
|
|
36
|
+
- **issue:** [Feature]: Support using pi-llama-cpp for local models (#1425).
|
|
37
|
+
- **issue:** [Bug]: GPT-5.6 ships as the nonexistent bare `gpt-5.6` slug — the real routable models are gpt-5.6-sol/terra/luna (#1424).
|
|
38
|
+
- **issue:** Fix(doctor): artifact_file_missing false positive for active-worktree artifacts; checkbox_db_status_divergence regression on plan-slice re-dispatch (#1420).
|
|
39
|
+
- **issue:** Planning_subagents should support user-defined planning agents.
|
|
40
|
+
- **issue:** Auto-verification.js writes VERIFY.json to legacy tasks/ subdir in flat-phase projects.
|
|
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
|
+
2b84d39575210a02
|
|
@@ -821,7 +821,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
821
821
|
// provider the user is not logged into and surface as "Not logged in · Please
|
|
822
822
|
// run /login" before pausing and resetting to claude-code/claude-sonnet-4-6.
|
|
823
823
|
const manualSessionOverride = getSessionModelOverride(ctx.sessionManager.getSessionId());
|
|
824
|
-
const sessionProviderIsCustom = isCustomProvider(ctx.model?.provider);
|
|
824
|
+
const sessionProviderIsCustom = isCustomProvider(ctx.model?.provider, ctx.modelRegistry);
|
|
825
825
|
const profileModelIds = modelIdsForProfileResolution(ctx.modelRegistry, resolveProfileAnchorProvider(ctx.model?.provider), resolveDisabledModelProvidersFromPreferences());
|
|
826
826
|
const preferredModel = sessionProviderIsCustom
|
|
827
827
|
? null
|
|
@@ -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 @@ 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) {
|
|
@@ -18,7 +18,8 @@ import { createBaseSchemaObjects } from "../db-base-schema.js";
|
|
|
18
18
|
import { createCoordinationTablesV24 } from "../db-coordination-schema.js";
|
|
19
19
|
import { createDbConnectionCache } from "../db-connection-cache.js";
|
|
20
20
|
import { backupDatabaseBeforeMigration, isMigrationBackupError } from "../db-migration-backup.js";
|
|
21
|
-
import { applyMigrationV2Artifacts, applyMigrationV3Memories, applyMigrationV4DecisionMadeBy, applyMigrationV5HierarchyTables, applyMigrationV6SliceSummaries, applyMigrationV7Dependencies, applyMigrationV8PlanningFields, applyMigrationV9Ordering, applyMigrationV10ReplanTrigger, applyMigrationV11TaskPlanning, applyMigrationV12QualityGates, applyMigrationV13HotPathIndexes, applyMigrationV14SliceDependencies, applyMigrationV15AuditTables, applyMigrationV16EscalationSource, applyMigrationV17TaskEscalation, applyMigrationV18MemorySources, applyMigrationV19MemoryFts, applyMigrationV20MemoryRelations, applyMigrationV21StructuredMemories, applyMigrationV22QualityGateRepair, applyMigrationV23MilestoneQueue, applyMigrationV26MilestoneCommitAttributions, applyMigrationV27ArtifactHash, applyMigrationV28MemoryLastHitAt, applyMigrationV29RepositoryTargets, applyMigrationV30ReworkBriefs, } from "../db-migration-steps.js";
|
|
21
|
+
import { applyMigrationV2Artifacts, applyMigrationV3Memories, applyMigrationV4DecisionMadeBy, applyMigrationV5HierarchyTables, applyMigrationV6SliceSummaries, applyMigrationV7Dependencies, applyMigrationV8PlanningFields, applyMigrationV9Ordering, applyMigrationV10ReplanTrigger, applyMigrationV11TaskPlanning, applyMigrationV12QualityGates, applyMigrationV13HotPathIndexes, applyMigrationV14SliceDependencies, applyMigrationV15AuditTables, applyMigrationV16EscalationSource, applyMigrationV17TaskEscalation, applyMigrationV18MemorySources, applyMigrationV19MemoryFts, applyMigrationV20MemoryRelations, applyMigrationV21StructuredMemories, applyMigrationV22QualityGateRepair, applyMigrationV23MilestoneQueue, applyMigrationV26MilestoneCommitAttributions, applyMigrationV27ArtifactHash, applyMigrationV28MemoryLastHitAt, applyMigrationV29RepositoryTargets, applyMigrationV30ReworkBriefs, applyMigrationV31CanonicalFoundation, } from "../db-migration-steps.js";
|
|
22
|
+
import { createCanonicalFoundationSchemaV31 } from "../db-canonical-foundation-schema.js";
|
|
22
23
|
import { isMemoriesFtsAvailableSchema, rebuildMemoriesFtsSchemaOnce, tryCreateMemoriesFtsSchema, } from "../db-memory-fts-schema.js";
|
|
23
24
|
import { createDbOpenState } from "../db-open-state.js";
|
|
24
25
|
import { createRuntimeKvTableV25 } from "../db-runtime-kv-schema.js";
|
|
@@ -58,7 +59,7 @@ const providerLoader = createSqliteProviderLoader({
|
|
|
58
59
|
nodeVersion: process.versions.node,
|
|
59
60
|
writeStderr: (message) => process.stderr.write(message),
|
|
60
61
|
});
|
|
61
|
-
export const SCHEMA_VERSION =
|
|
62
|
+
export const SCHEMA_VERSION = 31;
|
|
62
63
|
function initSchema(db, fileBacked, dbPath) {
|
|
63
64
|
const conservativeFilePragmas = fileBacked && _isLikelyWslDrvFsPathForTest(dbPath);
|
|
64
65
|
if (fileBacked)
|
|
@@ -104,6 +105,7 @@ function initSchema(db, fileBacked, dbPath) {
|
|
|
104
105
|
else {
|
|
105
106
|
createCoordinationTablesV24(db);
|
|
106
107
|
createRuntimeKvTableV25(db);
|
|
108
|
+
createCanonicalFoundationSchemaV31(db);
|
|
107
109
|
// Fresh install — all tables are created above with the full current schema,
|
|
108
110
|
// so it is safe to create all migration-specific indexes here. For existing
|
|
109
111
|
// databases these indexes are created inside the individual migration guards
|
|
@@ -318,6 +320,10 @@ function migrateSchema(db, dbPath) {
|
|
|
318
320
|
applyMigrationV30ReworkBriefs(db);
|
|
319
321
|
recordSchemaVersion(db, 30);
|
|
320
322
|
}
|
|
323
|
+
if (currentVersion < 31) {
|
|
324
|
+
applyMigrationV31CanonicalFoundation(db);
|
|
325
|
+
recordSchemaVersion(db, 31);
|
|
326
|
+
}
|
|
321
327
|
if (_migrationFaultForTest)
|
|
322
328
|
throw new Error("migration fault injected for test");
|
|
323
329
|
db.exec("COMMIT");
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Additive v31 authority, operation provenance, domain event, and outbox schema.
|
|
3
|
+
/**
|
|
4
|
+
* v31 mapping:
|
|
5
|
+
* - schema_version remains DDL compatibility, not the domain revision.
|
|
6
|
+
* - audit_events remains optional operational telemetry, not domain history.
|
|
7
|
+
* - milestone_commit_attributions remains Git-specific, not operation provenance.
|
|
8
|
+
* - command_queue and runtime_kv remain coordination/cache surfaces, not an outbox.
|
|
9
|
+
*/
|
|
10
|
+
export function createCanonicalFoundationSchemaV31(db) {
|
|
11
|
+
db.exec(`
|
|
12
|
+
CREATE TABLE IF NOT EXISTS project_authority (
|
|
13
|
+
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
|
|
14
|
+
project_id TEXT NOT NULL UNIQUE,
|
|
15
|
+
project_root_realpath TEXT NOT NULL DEFAULT '',
|
|
16
|
+
revision INTEGER NOT NULL DEFAULT 0 CHECK (revision >= 0),
|
|
17
|
+
authority_epoch INTEGER NOT NULL DEFAULT 0 CHECK (authority_epoch >= 0),
|
|
18
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
19
|
+
updated_at TEXT NOT NULL DEFAULT ''
|
|
20
|
+
)
|
|
21
|
+
`);
|
|
22
|
+
db.exec(`
|
|
23
|
+
CREATE TABLE IF NOT EXISTS workflow_operations (
|
|
24
|
+
operation_id TEXT PRIMARY KEY,
|
|
25
|
+
project_id TEXT NOT NULL,
|
|
26
|
+
operation_type TEXT NOT NULL,
|
|
27
|
+
idempotency_key TEXT NOT NULL,
|
|
28
|
+
expected_revision INTEGER NOT NULL CHECK (expected_revision >= 0),
|
|
29
|
+
resulting_revision INTEGER NOT NULL CHECK (resulting_revision = expected_revision + 1),
|
|
30
|
+
expected_authority_epoch INTEGER NOT NULL CHECK (expected_authority_epoch >= 0),
|
|
31
|
+
resulting_authority_epoch INTEGER NOT NULL CHECK (
|
|
32
|
+
resulting_authority_epoch = expected_authority_epoch OR
|
|
33
|
+
resulting_authority_epoch = expected_authority_epoch + 1
|
|
34
|
+
),
|
|
35
|
+
actor_type TEXT NOT NULL,
|
|
36
|
+
actor_id TEXT DEFAULT NULL,
|
|
37
|
+
source_transport TEXT NOT NULL,
|
|
38
|
+
trace_id TEXT DEFAULT NULL,
|
|
39
|
+
turn_id TEXT DEFAULT NULL,
|
|
40
|
+
request_hash TEXT NOT NULL,
|
|
41
|
+
created_at TEXT NOT NULL,
|
|
42
|
+
UNIQUE (project_id, idempotency_key),
|
|
43
|
+
UNIQUE (project_id, resulting_revision),
|
|
44
|
+
UNIQUE (operation_id, project_id, resulting_revision, resulting_authority_epoch),
|
|
45
|
+
FOREIGN KEY (project_id) REFERENCES project_authority(project_id)
|
|
46
|
+
)
|
|
47
|
+
`);
|
|
48
|
+
db.exec(`
|
|
49
|
+
CREATE TABLE IF NOT EXISTS workflow_domain_events (
|
|
50
|
+
event_id TEXT PRIMARY KEY,
|
|
51
|
+
operation_id TEXT NOT NULL,
|
|
52
|
+
event_index INTEGER NOT NULL DEFAULT 0 CHECK (event_index >= 0),
|
|
53
|
+
project_id TEXT NOT NULL,
|
|
54
|
+
project_revision INTEGER NOT NULL CHECK (project_revision > 0),
|
|
55
|
+
authority_epoch INTEGER NOT NULL CHECK (authority_epoch >= 0),
|
|
56
|
+
event_type TEXT NOT NULL,
|
|
57
|
+
entity_type TEXT NOT NULL,
|
|
58
|
+
entity_id TEXT NOT NULL,
|
|
59
|
+
caused_by_event_id TEXT DEFAULT NULL,
|
|
60
|
+
payload_json TEXT NOT NULL DEFAULT '{}',
|
|
61
|
+
created_at TEXT NOT NULL,
|
|
62
|
+
UNIQUE (operation_id, event_index),
|
|
63
|
+
FOREIGN KEY (operation_id, project_id, project_revision, authority_epoch)
|
|
64
|
+
REFERENCES workflow_operations(
|
|
65
|
+
operation_id, project_id, resulting_revision, resulting_authority_epoch
|
|
66
|
+
),
|
|
67
|
+
FOREIGN KEY (caused_by_event_id) REFERENCES workflow_domain_events(event_id)
|
|
68
|
+
)
|
|
69
|
+
`);
|
|
70
|
+
db.exec(`
|
|
71
|
+
CREATE TRIGGER IF NOT EXISTS trg_workflow_domain_events_immutable_update
|
|
72
|
+
BEFORE UPDATE ON workflow_domain_events
|
|
73
|
+
BEGIN
|
|
74
|
+
SELECT RAISE(ABORT, 'workflow domain events are immutable');
|
|
75
|
+
END
|
|
76
|
+
`);
|
|
77
|
+
db.exec(`
|
|
78
|
+
CREATE TRIGGER IF NOT EXISTS trg_workflow_domain_events_immutable_delete
|
|
79
|
+
BEFORE DELETE ON workflow_domain_events
|
|
80
|
+
BEGIN
|
|
81
|
+
SELECT RAISE(ABORT, 'workflow domain events are immutable');
|
|
82
|
+
END
|
|
83
|
+
`);
|
|
84
|
+
db.exec(`
|
|
85
|
+
CREATE TABLE IF NOT EXISTS workflow_outbox (
|
|
86
|
+
outbox_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
87
|
+
event_id TEXT NOT NULL,
|
|
88
|
+
destination TEXT NOT NULL,
|
|
89
|
+
available_at TEXT NOT NULL DEFAULT '',
|
|
90
|
+
attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
|
|
91
|
+
claimed_by TEXT DEFAULT NULL,
|
|
92
|
+
claim_expires_at TEXT DEFAULT NULL,
|
|
93
|
+
delivered_at TEXT DEFAULT NULL,
|
|
94
|
+
last_error TEXT DEFAULT NULL,
|
|
95
|
+
UNIQUE (event_id, destination),
|
|
96
|
+
FOREIGN KEY (event_id) REFERENCES workflow_domain_events(event_id)
|
|
97
|
+
)
|
|
98
|
+
`);
|
|
99
|
+
db.exec(`
|
|
100
|
+
CREATE INDEX IF NOT EXISTS idx_workflow_operations_created
|
|
101
|
+
ON workflow_operations(project_id, created_at, operation_id)
|
|
102
|
+
`);
|
|
103
|
+
db.exec(`
|
|
104
|
+
CREATE INDEX IF NOT EXISTS idx_workflow_domain_events_entity
|
|
105
|
+
ON workflow_domain_events(project_id, entity_type, entity_id, project_revision, event_index)
|
|
106
|
+
`);
|
|
107
|
+
db.exec(`
|
|
108
|
+
CREATE INDEX IF NOT EXISTS idx_workflow_outbox_pending
|
|
109
|
+
ON workflow_outbox(delivered_at, available_at, outbox_id)
|
|
110
|
+
`);
|
|
111
|
+
db.exec(`
|
|
112
|
+
INSERT OR IGNORE INTO project_authority (
|
|
113
|
+
singleton, project_id, project_root_realpath,
|
|
114
|
+
revision, authority_epoch, created_at, updated_at
|
|
115
|
+
) VALUES (
|
|
116
|
+
1, lower(hex(randomblob(16))), '',
|
|
117
|
+
0, 0, '', ''
|
|
118
|
+
)
|
|
119
|
+
`);
|
|
120
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Schema migration DDL steps for the GSD database facade.
|
|
3
|
+
import { createCanonicalFoundationSchemaV31 } from "./db-canonical-foundation-schema.js";
|
|
3
4
|
import { ensureColumn } from "./db-schema-metadata.js";
|
|
4
5
|
export function applyMigrationV2Artifacts(db) {
|
|
5
6
|
db.exec(`
|
|
@@ -448,3 +449,6 @@ export function applyMigrationV30ReworkBriefs(db) {
|
|
|
448
449
|
db.exec("CREATE INDEX IF NOT EXISTS idx_rework_briefs_task ON rework_briefs(milestone_id, slice_id, task_id)");
|
|
449
450
|
db.exec("CREATE INDEX IF NOT EXISTS idx_rework_findings_status ON rework_brief_findings(brief_id, severity, status)");
|
|
450
451
|
}
|
|
452
|
+
export function applyMigrationV31CanonicalFoundation(db) {
|
|
453
|
+
createCanonicalFoundationSchemaV31(db);
|
|
454
|
+
}
|
|
@@ -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, "\\$&");
|
|
@@ -77,7 +78,8 @@ function checkboxDbStatusMilestoneIds(basePath, milestoneIds) {
|
|
|
77
78
|
}
|
|
78
79
|
function checkProjectionCheckboxDbStatus(basePath, milestoneIds, issues) {
|
|
79
80
|
for (const milestoneId of milestoneIds) {
|
|
80
|
-
const
|
|
81
|
+
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, milestoneId);
|
|
82
|
+
const roadmapPath = resolveMilestoneFile(artifactBasePath, milestoneId, "ROADMAP");
|
|
81
83
|
const slices = getMilestoneSlices(milestoneId);
|
|
82
84
|
if (roadmapPath && existsSync(roadmapPath)) {
|
|
83
85
|
try {
|
|
@@ -95,7 +97,7 @@ function checkProjectionCheckboxDbStatus(basePath, milestoneIds, issues) {
|
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
for (const slice of slices) {
|
|
98
|
-
const planPath = resolveSliceFile(
|
|
100
|
+
const planPath = resolveSliceFile(artifactBasePath, milestoneId, slice.id, "PLAN");
|
|
99
101
|
if (!planPath || !existsSync(planPath))
|
|
100
102
|
continue;
|
|
101
103
|
try {
|
|
@@ -134,7 +136,7 @@ function isClearedByMilestoneShellProjectionFlush(basePath, issue, reRenderedMil
|
|
|
134
136
|
function artifactExistsOnDisk(basePath, artifactPath, row) {
|
|
135
137
|
return resolveArtifactDiskPath(basePath, artifactPath, row) !== null;
|
|
136
138
|
}
|
|
137
|
-
function resolveLiteralArtifactDiskPath(basePath, artifactPath) {
|
|
139
|
+
function resolveLiteralArtifactDiskPath(basePath, artifactPath, row) {
|
|
138
140
|
const relativeArtifactPath = artifactPathRelativeToGsd(artifactPath);
|
|
139
141
|
if (isAbsolute(relativeArtifactPath)) {
|
|
140
142
|
return existsSync(relativeArtifactPath) ? relativeArtifactPath : null;
|
|
@@ -144,6 +146,16 @@ function resolveLiteralArtifactDiskPath(basePath, artifactPath) {
|
|
|
144
146
|
if (isPathInside(root, candidate) && existsSync(candidate))
|
|
145
147
|
return candidate;
|
|
146
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
|
+
}
|
|
147
159
|
return null;
|
|
148
160
|
}
|
|
149
161
|
function relativeToGsdRoot(basePath, diskPath) {
|
|
@@ -183,7 +195,7 @@ function resolveArtifactDiskPath(basePath, artifactPath, row) {
|
|
|
183
195
|
if (flatPath)
|
|
184
196
|
return flatPath;
|
|
185
197
|
}
|
|
186
|
-
return resolveLiteralArtifactDiskPath(basePath, artifactPath);
|
|
198
|
+
return resolveLiteralArtifactDiskPath(basePath, artifactPath, row);
|
|
187
199
|
}
|
|
188
200
|
function taskExistsInPlan(basePath, milestoneId, sliceId, taskId) {
|
|
189
201
|
const planPath = resolveSliceFile(basePath, milestoneId, sliceId, "PLAN");
|
|
@@ -48,8 +48,9 @@ export const BUNDLED_COST_TABLE = [
|
|
|
48
48
|
// GPT-5.5 API list price, also used for live Codex OAuth routing.
|
|
49
49
|
// Source: https://openai.com/api/pricing/
|
|
50
50
|
{ id: "gpt-5.5", inputPer1k: 0.005, outputPer1k: 0.03, updatedAt: "2026-04-23" },
|
|
51
|
-
|
|
52
|
-
{ id: "gpt-5.6", inputPer1k: 0.005, outputPer1k: 0.
|
|
51
|
+
{ id: "gpt-5.6-sol", inputPer1k: 0.005, outputPer1k: 0.03, tiers: [{ inputTokensAbove: 272000, inputPer1k: 0.01, outputPer1k: 0.045 }], updatedAt: "2026-07-11" },
|
|
52
|
+
{ id: "gpt-5.6-terra", inputPer1k: 0.0025, outputPer1k: 0.015, tiers: [{ inputTokensAbove: 272000, inputPer1k: 0.005, outputPer1k: 0.0225 }], updatedAt: "2026-07-11" },
|
|
53
|
+
{ id: "gpt-5.6-luna", inputPer1k: 0.001, outputPer1k: 0.006, tiers: [{ inputTokensAbove: 272000, inputPer1k: 0.002, outputPer1k: 0.009 }], updatedAt: "2026-07-11" },
|
|
53
54
|
// Google
|
|
54
55
|
{ id: "gemini-2.0-flash", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
|
|
55
56
|
{ id: "gemini-flash-2.0", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
|
|
@@ -63,7 +64,9 @@ export const BUNDLED_COST_TABLE = [
|
|
|
63
64
|
export function lookupModelCost(modelId) {
|
|
64
65
|
const bareId = modelId.includes("/") ? modelId.split("/").pop() : modelId;
|
|
65
66
|
return BUNDLED_COST_TABLE.find(e => e.id === bareId)
|
|
66
|
-
?? BUNDLED_COST_TABLE.find(e => bareId.
|
|
67
|
+
?? BUNDLED_COST_TABLE.find(e => bareId.startsWith(`${e.id}-`) ||
|
|
68
|
+
bareId.startsWith(`${e.id}:`) ||
|
|
69
|
+
bareId.startsWith(`${e.id}@`));
|
|
67
70
|
}
|
|
68
71
|
/**
|
|
69
72
|
* Compare two models by input cost. Returns negative if a is cheaper.
|
|
@@ -46,7 +46,9 @@ export const MODEL_CAPABILITY_TIER = {
|
|
|
46
46
|
"gpt-5.3-codex": "heavy",
|
|
47
47
|
"gpt-5.4": "heavy",
|
|
48
48
|
"gpt-5.5": "heavy",
|
|
49
|
-
"gpt-5.6": "heavy",
|
|
49
|
+
"gpt-5.6-sol": "heavy",
|
|
50
|
+
"gpt-5.6-terra": "heavy",
|
|
51
|
+
"gpt-5.6-luna": "heavy",
|
|
50
52
|
"o1": "heavy",
|
|
51
53
|
"o3": "heavy",
|
|
52
54
|
"o4-mini": "heavy",
|
|
@@ -84,7 +86,9 @@ const MODEL_COST_PER_1K_INPUT = {
|
|
|
84
86
|
"gpt-5.3-codex-spark": 0.0003,
|
|
85
87
|
"gpt-5.4": 0.005,
|
|
86
88
|
"gpt-5.5": 0.005,
|
|
87
|
-
"gpt-5.6": 0.005,
|
|
89
|
+
"gpt-5.6-sol": 0.005,
|
|
90
|
+
"gpt-5.6-terra": 0.0025,
|
|
91
|
+
"gpt-5.6-luna": 0.001,
|
|
88
92
|
"o4-mini": 0.005,
|
|
89
93
|
"o4-mini-deep-research": 0.005,
|
|
90
94
|
"gemini-2.0-flash": 0.0001,
|
|
@@ -132,9 +136,10 @@ export const MODEL_CAPABILITY_PROFILES = {
|
|
|
132
136
|
// OpenAI's 2026-04-23 published eval deltas across coding, tool use, and long context.
|
|
133
137
|
// Source: https://openai.com/index/introducing-gpt-5-5/
|
|
134
138
|
"gpt-5.5": { coding: 96, debugging: 93, research: 89, reasoning: 95, speed: 42, longContext: 90, instruction: 93 },
|
|
135
|
-
// GPT-5.6
|
|
136
|
-
|
|
137
|
-
"gpt-5.6": { coding:
|
|
139
|
+
// GPT-5.6 profiles are provisional until official eval results are available.
|
|
140
|
+
"gpt-5.6-sol": { coding: 97, debugging: 94, research: 90, reasoning: 96, speed: 42, longContext: 91, instruction: 94 },
|
|
141
|
+
"gpt-5.6-terra": { coding: 96, debugging: 93, research: 89, reasoning: 95, speed: 48, longContext: 91, instruction: 93 },
|
|
142
|
+
"gpt-5.6-luna": { coding: 92, debugging: 88, research: 84, reasoning: 91, speed: 72, longContext: 91, instruction: 90 },
|
|
138
143
|
// ── OpenAI o-series (reasoning-first) ──────────────────────────────────────
|
|
139
144
|
"o1": { coding: 78, debugging: 82, research: 78, reasoning: 90, speed: 20, longContext: 65, instruction: 82 },
|
|
140
145
|
"o3": { coding: 80, debugging: 85, research: 80, reasoning: 92, speed: 25, longContext: 70, instruction: 85 },
|
|
@@ -16,10 +16,18 @@ const PLANNING_DISPATCH_AGENT_REGISTRY = {
|
|
|
16
16
|
export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set(Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
|
|
17
17
|
.filter(([, metadata]) => metadata.readOnlySpecialist)
|
|
18
18
|
.map(([agentId]) => agentId));
|
|
19
|
-
|
|
19
|
+
function configuredPlanningDispatchAgents(registry) {
|
|
20
|
+
return Object.entries(registry ?? {})
|
|
21
|
+
.filter(([, metadata]) => metadata.read_only_specialist === true)
|
|
22
|
+
.map(([agentId]) => agentId);
|
|
23
|
+
}
|
|
24
|
+
export function isReadOnlyPlanningDispatchAgent(agentId, registry) {
|
|
20
25
|
const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId];
|
|
21
|
-
return metadata?.readOnlySpecialist === true;
|
|
26
|
+
return metadata?.readOnlySpecialist === true || registry?.[agentId]?.read_only_specialist === true;
|
|
22
27
|
}
|
|
23
|
-
export function allowedPlanningDispatchAgentsList() {
|
|
24
|
-
return
|
|
28
|
+
export function allowedPlanningDispatchAgentsList(registry) {
|
|
29
|
+
return Array.from(new Set([
|
|
30
|
+
...ALLOWED_PLANNING_DISPATCH_AGENTS,
|
|
31
|
+
...configuredPlanningDispatchAgents(registry),
|
|
32
|
+
])).join(", ");
|
|
25
33
|
}
|