@opengsd/gsd-pi 1.9.0 → 1.10.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 -10
- package/dist/headless.js +2 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
- 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/unit-phase.js +37 -5
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +2 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -5
- package/dist/resources/extensions/gsd/auto-start.js +29 -9
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +40 -0
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +15 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -24
- package/dist/resources/extensions/gsd/commands-verdict.js +10 -9
- package/dist/resources/extensions/gsd/compat/compat-marker.js +80 -5
- package/dist/resources/extensions/gsd/constants.js +12 -13
- package/dist/resources/extensions/gsd/context-masker.js +97 -21
- package/dist/resources/extensions/gsd/db/engine.js +5 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +22 -0
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +24 -8
- package/dist/resources/extensions/gsd/error-classifier.js +12 -2
- package/dist/resources/extensions/gsd/exec-sandbox.js +1 -0
- package/dist/resources/extensions/gsd/flat-phase-migration.js +12 -0
- package/dist/resources/extensions/gsd/git-service.js +19 -7
- package/dist/resources/extensions/gsd/gsd-db.js +75 -31
- package/dist/resources/extensions/gsd/guided-flow.js +11 -5
- package/dist/resources/extensions/gsd/markdown-renderer.js +5 -21
- package/dist/resources/extensions/gsd/md-importer.js +5 -6
- package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
- package/dist/resources/extensions/gsd/model-router.js +11 -0
- package/dist/resources/extensions/gsd/paths.js +66 -15
- package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
- package/dist/resources/extensions/gsd/preferences-types.js +5 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
- package/dist/resources/extensions/gsd/preferences.js +17 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
- package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
- package/dist/resources/extensions/gsd/skill-activation.js +17 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +98 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +4 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +5 -2
- package/dist/resources/extensions/gsd/stop-notice.js +9 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +12 -5
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
- package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
- package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
- package/dist/resources/extensions/gsd/workspace.js +2 -1
- package/dist/resources/extensions/gsd/worktree-state-projection.js +20 -18
- package/dist/resources/extensions/shared/interview-ui.js +43 -6
- 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 +8 -8
- 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 +8 -8
- 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 +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/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/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.js +1 -0
- package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +9 -3
- 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 +248 -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 +121 -15
- 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 +1 -3
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +9 -7
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.d.ts +27 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.js +272 -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 +97 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
- package/packages/gsd-cloud/package.json +2 -2
- package/packages/mcp-server/README.md +7 -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/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +5 -5
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.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/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +76 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +70 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +6 -1
- package/packages/pi-ai/dist/providers/anthropic.js.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.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +103 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.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/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.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 +11 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- 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/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
- 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/unit-phase.ts +41 -5
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +118 -19
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
- package/src/resources/extensions/gsd/auto-runtime-state.ts +12 -7
- package/src/resources/extensions/gsd/auto-start.ts +31 -8
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +56 -0
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +20 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -12
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -29
- package/src/resources/extensions/gsd/commands-verdict.ts +16 -9
- package/src/resources/extensions/gsd/compat/compat-marker.ts +99 -5
- package/src/resources/extensions/gsd/constants.ts +14 -13
- package/src/resources/extensions/gsd/context-masker.ts +98 -2
- package/src/resources/extensions/gsd/db/engine.ts +5 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +22 -0
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +30 -7
- package/src/resources/extensions/gsd/error-classifier.ts +13 -2
- package/src/resources/extensions/gsd/exec-sandbox.ts +1 -0
- package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -0
- package/src/resources/extensions/gsd/git-service.ts +19 -6
- package/src/resources/extensions/gsd/gsd-db.ts +85 -33
- package/src/resources/extensions/gsd/guided-flow.ts +11 -4
- package/src/resources/extensions/gsd/markdown-renderer.ts +5 -23
- package/src/resources/extensions/gsd/md-importer.ts +5 -5
- package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
- package/src/resources/extensions/gsd/model-router.ts +12 -0
- package/src/resources/extensions/gsd/paths.ts +73 -15
- package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
- package/src/resources/extensions/gsd/preferences.ts +25 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
- package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
- package/src/resources/extensions/gsd/skill-activation.ts +17 -3
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +132 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +4 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +4 -2
- package/src/resources/extensions/gsd/stop-notice.ts +11 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -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/before-provider-context-management.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +76 -1
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
- package/src/resources/extensions/gsd/tests/db-engine-cjs-compat.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/external-markdown-edit.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +8 -9
- package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
- package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
- 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 +34 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -5
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
- package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
- package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
- package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
- package/src/resources/extensions/gsd/workspace.ts +2 -1
- package/src/resources/extensions/gsd/worktree-state-projection.ts +21 -24
- package/src/resources/extensions/shared/interview-ui.ts +47 -8
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +29 -0
- /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → EAhnhYMt5UVOiG9-iPDjc}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → EAhnhYMt5UVOiG9-iPDjc}/_ssgManifest.js +0 -0
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
legacyMilestonesDir,
|
|
32
32
|
gsdRoot,
|
|
33
33
|
resolveTaskFiles,
|
|
34
|
+
resolveTaskFile,
|
|
34
35
|
resolveMilestonePath,
|
|
35
36
|
} from './paths.js';
|
|
36
37
|
import { findMilestoneIds } from './guided-flow.js';
|
|
@@ -925,8 +926,7 @@ export function migrateHierarchyToDb(
|
|
|
925
926
|
legacyTasksDir = isLegacySlice
|
|
926
927
|
? resolveTasksDir(basePath, milestoneId, sliceEntry.id)
|
|
927
928
|
: null;
|
|
928
|
-
|
|
929
|
-
taskSummaryFile = join(summaryDir, `${taskEntry.id}-SUMMARY.md`);
|
|
929
|
+
taskSummaryFile = resolveTaskFile(basePath, milestoneId, sliceEntry.id, taskEntry.id, 'SUMMARY');
|
|
930
930
|
}
|
|
931
931
|
const hasTaskSummary = taskSummaryFile !== null && existsSync(taskSummaryFile);
|
|
932
932
|
|
|
@@ -950,9 +950,9 @@ export function migrateHierarchyToDb(
|
|
|
950
950
|
// first execute-task. The surviving SUMMARY wins over a stale checkbox.
|
|
951
951
|
// reopen-task removes the SUMMARY, so this never re-completes an
|
|
952
952
|
// intentionally reopened task.
|
|
953
|
-
// Flat-phase summaries are phase-scoped
|
|
954
|
-
//
|
|
955
|
-
//
|
|
953
|
+
// Flat-phase summaries are phase-scoped; when a milestone has multiple
|
|
954
|
+
// slices, require the summary parent frontmatter to match so one slice's
|
|
955
|
+
// completion does not attest a sibling's same-named task.
|
|
956
956
|
let summaryAttestsCompletion = hasTaskSummary;
|
|
957
957
|
if (summaryAttestsCompletion && !isLegacySlice && roadmap.slices.length > 1 && taskSummaryFile) {
|
|
958
958
|
try {
|
|
@@ -62,6 +62,8 @@ export const BUNDLED_COST_TABLE: ModelCostEntry[] = [
|
|
|
62
62
|
// GPT-5.5 API list price, also used for live Codex OAuth routing.
|
|
63
63
|
// Source: https://openai.com/api/pricing/
|
|
64
64
|
{ id: "gpt-5.5", inputPer1k: 0.005, outputPer1k: 0.03, updatedAt: "2026-04-23" },
|
|
65
|
+
// Mirrors gpt-5.5 list pricing until OpenAI publishes official gpt-5.6 pricing.
|
|
66
|
+
{ id: "gpt-5.6", inputPer1k: 0.005, outputPer1k: 0.03, updatedAt: "2026-07-08" },
|
|
65
67
|
|
|
66
68
|
// Google
|
|
67
69
|
{ id: "gemini-2.0-flash", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
|
|
@@ -111,10 +111,12 @@ export const MODEL_CAPABILITY_TIER: Record<string, ComplexityTier> = {
|
|
|
111
111
|
"gpt-5.3-codex": "heavy",
|
|
112
112
|
"gpt-5.4": "heavy",
|
|
113
113
|
"gpt-5.5": "heavy",
|
|
114
|
+
"gpt-5.6": "heavy",
|
|
114
115
|
"o1": "heavy",
|
|
115
116
|
"o3": "heavy",
|
|
116
117
|
"o4-mini": "heavy",
|
|
117
118
|
"o4-mini-deep-research": "heavy",
|
|
119
|
+
"grok-4.5": "heavy",
|
|
118
120
|
};
|
|
119
121
|
|
|
120
122
|
// ─── Cost Table (per 1K input tokens, approximate USD) ───────────────────────
|
|
@@ -149,11 +151,13 @@ const MODEL_COST_PER_1K_INPUT: Record<string, number> = {
|
|
|
149
151
|
"gpt-5.3-codex-spark": 0.0003,
|
|
150
152
|
"gpt-5.4": 0.005,
|
|
151
153
|
"gpt-5.5": 0.005,
|
|
154
|
+
"gpt-5.6": 0.005,
|
|
152
155
|
"o4-mini": 0.005,
|
|
153
156
|
"o4-mini-deep-research": 0.005,
|
|
154
157
|
"gemini-2.0-flash": 0.0001,
|
|
155
158
|
"gemini-2.5-pro": 0.00125,
|
|
156
159
|
"deepseek-chat": 0.00014,
|
|
160
|
+
"grok-4.5": 0.002,
|
|
157
161
|
};
|
|
158
162
|
|
|
159
163
|
// ─── Capability Profiles Data Table ──────────────────────────────────────────
|
|
@@ -198,6 +202,9 @@ export const MODEL_CAPABILITY_PROFILES: Record<string, ModelCapabilities> = {
|
|
|
198
202
|
// OpenAI's 2026-04-23 published eval deltas across coding, tool use, and long context.
|
|
199
203
|
// Source: https://openai.com/index/introducing-gpt-5-5/
|
|
200
204
|
"gpt-5.5": { coding: 96, debugging: 93, research: 89, reasoning: 95, speed: 42, longContext: 90, instruction: 93 },
|
|
205
|
+
// GPT-5.6 profile is provisional: a small uniform step over gpt-5.5, to be
|
|
206
|
+
// recalibrated once OpenAI publishes official eval results.
|
|
207
|
+
"gpt-5.6": { coding: 97, debugging: 94, research: 90, reasoning: 96, speed: 42, longContext: 91, instruction: 94 },
|
|
201
208
|
|
|
202
209
|
// ── OpenAI o-series (reasoning-first) ──────────────────────────────────────
|
|
203
210
|
"o1": { coding: 78, debugging: 82, research: 78, reasoning: 90, speed: 20, longContext: 65, instruction: 82 },
|
|
@@ -212,6 +219,11 @@ export const MODEL_CAPABILITY_PROFILES: Record<string, ModelCapabilities> = {
|
|
|
212
219
|
|
|
213
220
|
// ── DeepSeek ───────────────────────────────────────────────────────────────
|
|
214
221
|
"deepseek-chat": { coding: 75, debugging: 65, research: 55, reasoning: 70, speed: 70, longContext: 55, instruction: 65 },
|
|
222
|
+
|
|
223
|
+
// ── xAI ────────────────────────────────────────────────────────────────────
|
|
224
|
+
// Grok 4.5 (2026-07): Opus-class frontier model tuned for coding and agentic
|
|
225
|
+
// work; notably faster and more token-efficient than peer heavy models.
|
|
226
|
+
"grok-4.5": { coding: 95, debugging: 90, research: 82, reasoning: 93, speed: 55, longContext: 80, instruction: 90 },
|
|
215
227
|
};
|
|
216
228
|
|
|
217
229
|
// ─── Base Task Requirements Data Table ───────────────────────────────────────
|
|
@@ -136,6 +136,14 @@ function cachedReaddir(dirPath: string): string[] {
|
|
|
136
136
|
return entries;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
function isExistingFile(path: string): boolean {
|
|
140
|
+
try {
|
|
141
|
+
return statSync(path).isFile();
|
|
142
|
+
} catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
139
147
|
/**
|
|
140
148
|
* Clear the volatile directory listing caches.
|
|
141
149
|
* Call after milestone transitions, file creation in planning directories,
|
|
@@ -223,6 +231,26 @@ export function buildTaskFileName(taskId: string, suffix: string): string {
|
|
|
223
231
|
return `${taskId}-${suffix}.md`;
|
|
224
232
|
}
|
|
225
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Build a flat-phase task artifact file name.
|
|
236
|
+
* ("S06", "T03", "SUMMARY") → "S06-T03-SUMMARY.md"
|
|
237
|
+
*/
|
|
238
|
+
export function buildFlatTaskFileName(sliceId: string, taskId: string, suffix: string): string {
|
|
239
|
+
return `${sliceId}-${taskId}-${suffix}.md`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Extract the task ID from a task artifact filename.
|
|
244
|
+
* Supports flat-phase S##-T##-SUFFIX.md plus legacy T##-SUFFIX.md and
|
|
245
|
+
* T##-DESCRIPTOR-SUFFIX.md names.
|
|
246
|
+
*/
|
|
247
|
+
export function taskIdFromTaskFileName(fileName: string, suffix: string): string | null {
|
|
248
|
+
const flat = new RegExp(`^S\\d+-(T\\d+)-${suffix}\\.md$`, "i").exec(fileName);
|
|
249
|
+
if (flat?.[1]) return flat[1].toUpperCase();
|
|
250
|
+
const legacy = new RegExp(`^(T\\d+)(?:-.*)?-${suffix}\\.md$`, "i").exec(fileName);
|
|
251
|
+
return legacy?.[1]?.toUpperCase() ?? null;
|
|
252
|
+
}
|
|
253
|
+
|
|
226
254
|
// ─── Resolvers ─────────────────────────────────────────────────────────────
|
|
227
255
|
|
|
228
256
|
/**
|
|
@@ -264,7 +292,7 @@ export function resolveFile(dir: string, idPrefix: string, suffix: string): stri
|
|
|
264
292
|
if (!existsSync(dir)) return null;
|
|
265
293
|
const target = `${idPrefix}-${suffix}.md`.toUpperCase();
|
|
266
294
|
try {
|
|
267
|
-
const entries =
|
|
295
|
+
const entries = cachedReaddirWithTypes(dir).filter(e => e.isFile()).map(e => e.name);
|
|
268
296
|
// Direct match: ID-SUFFIX.md
|
|
269
297
|
const direct = entries.find(e => e.toUpperCase() === target);
|
|
270
298
|
if (direct) return direct;
|
|
@@ -284,18 +312,17 @@ export function resolveFile(dir: string, idPrefix: string, suffix: string): stri
|
|
|
284
312
|
}
|
|
285
313
|
|
|
286
314
|
/**
|
|
287
|
-
* Find all task files matching a pattern in a tasks directory.
|
|
288
|
-
* Returns sorted file names matching T##-SUFFIX.md
|
|
315
|
+
* Find all task files matching a pattern in a tasks directory or flat phase dir.
|
|
316
|
+
* Returns sorted file names matching S##-T##-SUFFIX.md, T##-SUFFIX.md,
|
|
317
|
+
* or legacy T##-*-SUFFIX.md.
|
|
289
318
|
*/
|
|
290
319
|
export function resolveTaskFiles(tasksDir: string, suffix: string): string[] {
|
|
291
320
|
if (!existsSync(tasksDir)) return [];
|
|
292
321
|
try {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
return cachedReaddir(tasksDir)
|
|
298
|
-
.filter(f => currentPattern.test(f) || legacyPattern.test(f))
|
|
322
|
+
return cachedReaddirWithTypes(tasksDir)
|
|
323
|
+
.filter(e => e.isFile())
|
|
324
|
+
.map(e => e.name)
|
|
325
|
+
.filter(f => taskIdFromTaskFileName(f, suffix) !== null)
|
|
299
326
|
.sort();
|
|
300
327
|
} catch {
|
|
301
328
|
return [];
|
|
@@ -843,7 +870,7 @@ export function resolveMilestoneFile(
|
|
|
843
870
|
const prefix = `${String(phaseNum).padStart(2, "0")}`;
|
|
844
871
|
const flatName = `${prefix}-${suffix}.md`;
|
|
845
872
|
const flatPath = join(mDir, flatName);
|
|
846
|
-
if (
|
|
873
|
+
if (isExistingFile(flatPath)) return flatPath;
|
|
847
874
|
// Legacy fallback: M001-SUFFIX.md
|
|
848
875
|
const file = resolveFile(mDir, milestoneId, suffix);
|
|
849
876
|
return file ? join(mDir, file) : null;
|
|
@@ -878,11 +905,11 @@ export function resolveSliceFile(
|
|
|
878
905
|
const planNum = sliceIdToPlanNum(sliceId);
|
|
879
906
|
const flatName = planFileName(phaseNum, planNum, suffix);
|
|
880
907
|
const flatPath = join(phaseDir, flatName);
|
|
881
|
-
if (
|
|
908
|
+
if (isExistingFile(flatPath)) return flatPath;
|
|
882
909
|
// Also check plan-number-only format MM-SUFFIX.md (written by buildSliceFileName)
|
|
883
910
|
const planOnlyName = `${String(planNum).padStart(2, "0")}-${suffix}.md`;
|
|
884
911
|
const planOnlyPath = join(phaseDir, planOnlyName);
|
|
885
|
-
if (
|
|
912
|
+
if (isExistingFile(planOnlyPath)) return planOnlyPath;
|
|
886
913
|
// Try prefix match for the phase+plan number (handles suffix variations)
|
|
887
914
|
const planPrefix = `${String(phaseNum).padStart(2, "0")}-${String(planNum).padStart(2, "0")}-`;
|
|
888
915
|
try {
|
|
@@ -931,8 +958,10 @@ export function resolveTaskFile(
|
|
|
931
958
|
const isLegacy = phaseDir.startsWith(legacyBase + "/") || phaseDir.startsWith(legacyBase + "\\");
|
|
932
959
|
|
|
933
960
|
if (suffix !== "PLAN" && !isLegacy) {
|
|
934
|
-
const flatPath = join(phaseDir,
|
|
935
|
-
|
|
961
|
+
const flatPath = join(phaseDir, buildFlatTaskFileName(sliceId, taskId, suffix));
|
|
962
|
+
if (isExistingFile(flatPath)) return flatPath;
|
|
963
|
+
const legacyFlatPath = join(phaseDir, buildTaskFileName(taskId, suffix));
|
|
964
|
+
return isExistingFile(legacyFlatPath) ? legacyFlatPath : null;
|
|
936
965
|
}
|
|
937
966
|
|
|
938
967
|
const tDir = resolveTasksDir(basePath, milestoneId, sliceId);
|
|
@@ -1066,6 +1095,35 @@ export function targetSliceFile(
|
|
|
1066
1095
|
return join(dir, fileName);
|
|
1067
1096
|
}
|
|
1068
1097
|
|
|
1098
|
+
/**
|
|
1099
|
+
* Build the canonical absolute write target for a task file.
|
|
1100
|
+
* Readers that need legacy flat-phase fallback should call resolveTaskFile.
|
|
1101
|
+
*/
|
|
1102
|
+
export function targetTaskFile(
|
|
1103
|
+
basePath: string, milestoneId: string, sliceId: string,
|
|
1104
|
+
taskId: string, suffix: string, milestoneTitle?: string
|
|
1105
|
+
): string {
|
|
1106
|
+
if (suffix === "PLAN") {
|
|
1107
|
+
return targetSliceFile(basePath, milestoneId, sliceId, "PLAN", milestoneTitle);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
1111
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
1112
|
+
const isLegacy = mDir
|
|
1113
|
+
? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
|
|
1114
|
+
: isLegacyMilestonesLayout(basePath);
|
|
1115
|
+
const milestoneDir = mDir
|
|
1116
|
+
?? dirname(targetMilestoneFile(basePath, milestoneId, "ROADMAP", milestoneTitle));
|
|
1117
|
+
|
|
1118
|
+
if (isLegacy) {
|
|
1119
|
+
const slicesDir = join(milestoneDir, "slices");
|
|
1120
|
+
const sliceDir = join(slicesDir, resolveDir(slicesDir, sliceId) ?? sliceId);
|
|
1121
|
+
return join(sliceDir, "tasks", buildTaskFileName(taskId, suffix));
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
return join(milestoneDir, buildFlatTaskFileName(sliceId, taskId, suffix));
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1069
1127
|
/**
|
|
1070
1128
|
* Build relative .gsd/ path to a slice file.
|
|
1071
1129
|
* Preserves an existing compatibility filename when present; otherwise falls
|
|
@@ -1105,5 +1163,5 @@ export function relTaskFile(
|
|
|
1105
1163
|
return relSliceFile(basePath, milestoneId, sliceId, "PLAN");
|
|
1106
1164
|
}
|
|
1107
1165
|
const relS = relSlicePath(basePath, milestoneId, sliceId, milestoneTitle);
|
|
1108
|
-
return `${relS}/${
|
|
1166
|
+
return `${relS}/${buildFlatTaskFileName(sliceId, taskId, suffix)}`;
|
|
1109
1167
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { CONFIGURABLE_PLANNING_SUBAGENT_UNITS, type GSDPreferences } from "./preferences-types.js";
|
|
2
|
+
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
3
|
+
import type { ToolsPolicy } from "./unit-context-manifest.js";
|
|
4
|
+
|
|
5
|
+
const CONFIGURABLE_UNITS = new Set<string>(CONFIGURABLE_PLANNING_SUBAGENT_UNITS);
|
|
6
|
+
|
|
7
|
+
function configuredAllowedSubagents(
|
|
8
|
+
unitType: string,
|
|
9
|
+
preferences: GSDPreferences | null | undefined,
|
|
10
|
+
): readonly string[] {
|
|
11
|
+
if (!CONFIGURABLE_UNITS.has(unitType)) return [];
|
|
12
|
+
return preferences?.planning_subagents?.[
|
|
13
|
+
unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>
|
|
14
|
+
]?.allowed ?? [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function mergeAllowedSubagents(
|
|
18
|
+
current: readonly string[],
|
|
19
|
+
configured: readonly string[],
|
|
20
|
+
): readonly string[] {
|
|
21
|
+
return Array.from(new Set([...current, ...configured]));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function applyPlanningSubagentPreferences(
|
|
25
|
+
unitType: string,
|
|
26
|
+
policy: ToolsPolicy | null | undefined,
|
|
27
|
+
preferences: GSDPreferences | null | undefined,
|
|
28
|
+
): ToolsPolicy | null | undefined {
|
|
29
|
+
if (!policy) return policy;
|
|
30
|
+
const configured = configuredAllowedSubagents(unitType, preferences);
|
|
31
|
+
if (configured.length === 0) return policy;
|
|
32
|
+
|
|
33
|
+
if (policy.mode === "planning") {
|
|
34
|
+
return {
|
|
35
|
+
mode: "planning-dispatch",
|
|
36
|
+
allowedSubagents: mergeAllowedSubagents([], configured),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (policy.mode === "planning-dispatch") {
|
|
41
|
+
return {
|
|
42
|
+
...policy,
|
|
43
|
+
allowedSubagents: mergeAllowedSubagents(policy.allowedSubagents, configured),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return policy;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function resolveEffectivePlanningToolsPolicy(
|
|
51
|
+
unitType: string,
|
|
52
|
+
policy: ToolsPolicy | null | undefined,
|
|
53
|
+
basePath?: string,
|
|
54
|
+
): ToolsPolicy | null | undefined {
|
|
55
|
+
if (!basePath) return policy;
|
|
56
|
+
const preferences = loadEffectiveGSDPreferences(basePath)?.preferences;
|
|
57
|
+
return applyPlanningSubagentPreferences(unitType, policy, preferences);
|
|
58
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only planning specialists that controlled planning dispatch may use.
|
|
3
|
+
*
|
|
4
|
+
* Unit manifests and project preferences still declare per-unit subsets. This
|
|
5
|
+
* registry is the global safety classification checked by the write gate and
|
|
6
|
+
* preference validation before any configured planning allowlist takes effect.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const PLANNING_DISPATCH_AGENT_REGISTRY = {
|
|
10
|
+
mnemo: { readOnlySpecialist: true },
|
|
11
|
+
scout: { readOnlySpecialist: true },
|
|
12
|
+
planner: { readOnlySpecialist: true },
|
|
13
|
+
reviewer: { readOnlySpecialist: true },
|
|
14
|
+
security: { readOnlySpecialist: true },
|
|
15
|
+
tester: { readOnlySpecialist: true },
|
|
16
|
+
} as const satisfies Record<string, { readonly readOnlySpecialist: boolean }>;
|
|
17
|
+
|
|
18
|
+
export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set<string>(
|
|
19
|
+
Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
|
|
20
|
+
.filter(([, metadata]) => metadata.readOnlySpecialist)
|
|
21
|
+
.map(([agentId]) => agentId),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export function isReadOnlyPlanningDispatchAgent(agentId: string): boolean {
|
|
25
|
+
const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId as keyof typeof PLANNING_DISPATCH_AGENT_REGISTRY];
|
|
26
|
+
return metadata?.readOnlySpecialist === true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function allowedPlanningDispatchAgentsList(): string {
|
|
30
|
+
return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
|
|
31
|
+
}
|
|
@@ -141,6 +141,7 @@ export const KNOWN_PREFERENCE_KEYS = new Set<string>([
|
|
|
141
141
|
"git",
|
|
142
142
|
"post_unit_hooks",
|
|
143
143
|
"pre_dispatch_hooks",
|
|
144
|
+
"planning_subagents",
|
|
144
145
|
"dynamic_routing",
|
|
145
146
|
"disabled_model_providers",
|
|
146
147
|
"uok",
|
|
@@ -217,6 +218,20 @@ export const KNOWN_UNIT_LABELS = [
|
|
|
217
218
|
] as const;
|
|
218
219
|
export type UnitLabel = (typeof KNOWN_UNIT_LABELS)[number];
|
|
219
220
|
|
|
221
|
+
export const CONFIGURABLE_PLANNING_SUBAGENT_UNITS = [
|
|
222
|
+
"plan-milestone",
|
|
223
|
+
"plan-slice",
|
|
224
|
+
] as const;
|
|
225
|
+
export type ConfigurablePlanningSubagentUnit = (typeof CONFIGURABLE_PLANNING_SUBAGENT_UNITS)[number];
|
|
226
|
+
|
|
227
|
+
export interface PlanningSubagentUnitConfig {
|
|
228
|
+
allowed?: string[];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export type PlanningSubagentsConfig = Partial<
|
|
232
|
+
Record<ConfigurablePlanningSubagentUnit, PlanningSubagentUnitConfig>
|
|
233
|
+
>;
|
|
234
|
+
|
|
220
235
|
|
|
221
236
|
export const SKILL_ACTIONS = new Set(["use", "prefer", "avoid"]);
|
|
222
237
|
|
|
@@ -476,6 +491,7 @@ export interface GSDPreferences {
|
|
|
476
491
|
git?: GitPreferences;
|
|
477
492
|
post_unit_hooks?: PostUnitHookConfig[];
|
|
478
493
|
pre_dispatch_hooks?: PreDispatchHookConfig[];
|
|
494
|
+
planning_subagents?: PlanningSubagentsConfig;
|
|
479
495
|
dynamic_routing?: DynamicRoutingConfig;
|
|
480
496
|
/** Provider IDs to exclude from /model and automatic model routing while leaving tool auth intact. */
|
|
481
497
|
disabled_model_providers?: string[];
|
|
@@ -17,6 +17,7 @@ import { getGateIdsForTurn } from "./gate-registry.js";
|
|
|
17
17
|
import {
|
|
18
18
|
KNOWN_PREFERENCE_KEYS,
|
|
19
19
|
KNOWN_UNIT_LABELS,
|
|
20
|
+
CONFIGURABLE_PLANNING_SUBAGENT_UNITS,
|
|
20
21
|
GSD_MODEL_PHASE_KEYS,
|
|
21
22
|
|
|
22
23
|
SKILL_ACTIONS,
|
|
@@ -26,6 +27,10 @@ import {
|
|
|
26
27
|
type GSDSkillRule,
|
|
27
28
|
type GSDThinkingLevel,
|
|
28
29
|
} from "./preferences-types.js";
|
|
30
|
+
import {
|
|
31
|
+
ALLOWED_PLANNING_DISPATCH_AGENTS,
|
|
32
|
+
allowedPlanningDispatchAgentsList,
|
|
33
|
+
} from "./planning-subagent-registry.js";
|
|
29
34
|
|
|
30
35
|
const VALID_TOKEN_PROFILES = new Set<TokenProfile>(["budget", "balanced", "quality", "burn-max"]);
|
|
31
36
|
const VALID_THINKING_LEVELS = new Set<GSDThinkingLevel>([
|
|
@@ -747,6 +752,63 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
747
752
|
}
|
|
748
753
|
}
|
|
749
754
|
|
|
755
|
+
// ─── Planning Subagents ─────────────────────────────────────────────────
|
|
756
|
+
if (preferences.planning_subagents !== undefined) {
|
|
757
|
+
if (
|
|
758
|
+
!preferences.planning_subagents ||
|
|
759
|
+
typeof preferences.planning_subagents !== "object" ||
|
|
760
|
+
Array.isArray(preferences.planning_subagents)
|
|
761
|
+
) {
|
|
762
|
+
errors.push("planning_subagents must be an object keyed by planning unit type");
|
|
763
|
+
} else {
|
|
764
|
+
const validUnits = new Set<string>(CONFIGURABLE_PLANNING_SUBAGENT_UNITS);
|
|
765
|
+
const validPlanningSubagents: NonNullable<GSDPreferences["planning_subagents"]> = {};
|
|
766
|
+
|
|
767
|
+
for (const [unitType, rawConfig] of Object.entries(preferences.planning_subagents as Record<string, unknown>)) {
|
|
768
|
+
if (!validUnits.has(unitType)) {
|
|
769
|
+
errors.push(
|
|
770
|
+
`planning_subagents unknown or unsupported unit "${unitType}" — supported units: ` +
|
|
771
|
+
`${CONFIGURABLE_PLANNING_SUBAGENT_UNITS.join(", ")}`,
|
|
772
|
+
);
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
776
|
+
errors.push(`planning_subagents.${unitType} must be an object with an allowed array`);
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
const allowed = normalizeStringArray((rawConfig as Record<string, unknown>).allowed);
|
|
781
|
+
if (allowed.length === 0) {
|
|
782
|
+
errors.push(`planning_subagents.${unitType}.allowed must include at least one read-only planning specialist`);
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const sanitizedAllowed: string[] = [];
|
|
787
|
+
for (const agentId of allowed) {
|
|
788
|
+
if (!ALLOWED_PLANNING_DISPATCH_AGENTS.has(agentId)) {
|
|
789
|
+
errors.push(
|
|
790
|
+
`planning_subagents.${unitType}.allowed includes "${agentId}", which is not classified as a ` +
|
|
791
|
+
`read-only planning specialist. Allowed agents: ${allowedPlanningDispatchAgentsList()}`,
|
|
792
|
+
);
|
|
793
|
+
continue;
|
|
794
|
+
}
|
|
795
|
+
sanitizedAllowed.push(agentId);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const dedupedAllowed = Array.from(new Set(sanitizedAllowed));
|
|
799
|
+
if (dedupedAllowed.length > 0) {
|
|
800
|
+
validPlanningSubagents[unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>] = {
|
|
801
|
+
allowed: dedupedAllowed,
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (Object.keys(validPlanningSubagents).length > 0) {
|
|
807
|
+
validated.planning_subagents = validPlanningSubagents;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
750
812
|
// ─── Dynamic Routing ─────────────────────────────────────────────────
|
|
751
813
|
if (preferences.dynamic_routing !== undefined) {
|
|
752
814
|
if (typeof preferences.dynamic_routing === "object" && preferences.dynamic_routing !== null) {
|
|
@@ -817,6 +817,7 @@ function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPr
|
|
|
817
817
|
: undefined,
|
|
818
818
|
post_unit_hooks: mergePostUnitHooks(base.post_unit_hooks, override.post_unit_hooks),
|
|
819
819
|
pre_dispatch_hooks: mergePreDispatchHooks(base.pre_dispatch_hooks, override.pre_dispatch_hooks),
|
|
820
|
+
planning_subagents: mergePlanningSubagents(base.planning_subagents, override.planning_subagents),
|
|
820
821
|
dynamic_routing: (base.dynamic_routing || override.dynamic_routing)
|
|
821
822
|
? { ...(base.dynamic_routing ?? {}), ...(override.dynamic_routing ?? {}) } as DynamicRoutingConfig
|
|
822
823
|
: undefined,
|
|
@@ -943,6 +944,30 @@ function mergePreDispatchHooks(
|
|
|
943
944
|
return merged.length > 0 ? merged : undefined;
|
|
944
945
|
}
|
|
945
946
|
|
|
947
|
+
function mergePlanningSubagents(
|
|
948
|
+
base?: GSDPreferences["planning_subagents"],
|
|
949
|
+
override?: GSDPreferences["planning_subagents"],
|
|
950
|
+
): GSDPreferences["planning_subagents"] | undefined {
|
|
951
|
+
if (!base && !override) return undefined;
|
|
952
|
+
const merged: NonNullable<GSDPreferences["planning_subagents"]> = {};
|
|
953
|
+
const unitTypes = new Set([
|
|
954
|
+
...Object.keys(base ?? {}),
|
|
955
|
+
...Object.keys(override ?? {}),
|
|
956
|
+
]);
|
|
957
|
+
|
|
958
|
+
for (const unitType of unitTypes) {
|
|
959
|
+
const allowed = mergeStringLists(
|
|
960
|
+
base?.[unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>]?.allowed,
|
|
961
|
+
override?.[unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>]?.allowed,
|
|
962
|
+
);
|
|
963
|
+
if (allowed?.length) {
|
|
964
|
+
merged[unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>] = { allowed };
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
969
|
+
}
|
|
970
|
+
|
|
946
971
|
// ─── System Prompt Rendering ──────────────────────────────────────────────────
|
|
947
972
|
|
|
948
973
|
export function renderPreferencesForSystemPrompt(
|
|
@@ -24,18 +24,18 @@ Roadmap, slice summaries, assessments, requirements, decisions, and project cont
|
|
|
24
24
|
|
|
25
25
|
### Step 1 - Dispatch Parallel Reviewers
|
|
26
26
|
|
|
27
|
-
The Inlined Context above already preloads the evidence reviewers need — the roadmap, per-slice SUMMARY/ASSESSMENT excerpts, requirements, and verification classes. **Embed the relevant preloaded evidence directly into each reviewer's task prompt** so reviewers work from it instead of re-reading the same artifacts from disk. Each reviewer should read a full file only when its excerpt is missing, truncated, or internally inconsistent — never as a routine first step. This avoids three reviewers independently re-surveying artifacts the orchestrator already holds.
|
|
27
|
+
The Inlined Context above already preloads the evidence reviewers need — the roadmap, per-slice SUMMARY/ASSESSMENT excerpts, requirements, and verification classes. **Embed the relevant preloaded evidence directly into each reviewer's task prompt** so reviewers work from it instead of re-reading the same artifacts from disk. Each reviewer should read a full file only when its excerpt is missing, truncated, or internally inconsistent — never as a routine first step. When a reviewer needs a full artifact, use only explicit file paths from the On-demand Validation Artifacts / On-demand Milestone Context blocks or discover files with `find .gsd -type f`; never pass a phase, slice, `tasks/`, or `slices/` directory to `read` or `readFileSync`. This avoids three reviewers independently re-surveying artifacts the orchestrator already holds.
|
|
28
28
|
|
|
29
29
|
Call `subagent` with `tasks: [...]` containing ALL THREE reviewers simultaneously:
|
|
30
30
|
|
|
31
31
|
**Reviewer A - Requirements Coverage**
|
|
32
|
-
Prompt: "Review milestone {{milestoneId}} requirements coverage. Working directory: {{workingDirectory}}. Use the preloaded requirements and slice SUMMARY evidence embedded in this task — do not re-read them from disk. For each requirement, mark COVERED, PARTIAL, or MISSING against that evidence. Read a full SUMMARY
|
|
32
|
+
Prompt: "Review milestone {{milestoneId}} requirements coverage. Working directory: {{workingDirectory}}. Use the preloaded requirements and slice SUMMARY evidence embedded in this task — do not re-read them from disk. For each requirement, mark COVERED, PARTIAL, or MISSING against that evidence. Read a full SUMMARY only from an explicit file path in the On-demand Validation Artifacts list, or discover candidates with `find .gsd -type f -name '*-SUMMARY.md'`; never read a directory path. Output table: Requirement | Status | Evidence. End with one-line verdict: PASS if all covered, NEEDS-ATTENTION if partials exist, FAIL if any missing."
|
|
33
33
|
|
|
34
34
|
**Reviewer B - Cross-Slice Integration**
|
|
35
|
-
Prompt: "Review milestone {{milestoneId}} cross-slice integration. Working directory: {{workingDirectory}}. Use the preloaded roadmap and slice SUMMARY evidence embedded in this task — do not re-read them from disk. Find the boundary map (produces/consumes contracts) in the roadmap. For each boundary, confirm producer SUMMARY produced the artifact and consumer SUMMARY consumed it. Read `{{roadmapPath}}` or a full SUMMARY only if the preloaded evidence is missing, truncated, or inconsistent. Output table: Boundary | Producer Summary | Consumer Summary | Status. End with one-line verdict: PASS if all boundaries honored, NEEDS-ATTENTION if any gaps."
|
|
35
|
+
Prompt: "Review milestone {{milestoneId}} cross-slice integration. Working directory: {{workingDirectory}}. Use the preloaded roadmap and slice SUMMARY evidence embedded in this task — do not re-read them from disk. Find the boundary map (produces/consumes contracts) in the roadmap. For each boundary, confirm producer SUMMARY produced the artifact and consumer SUMMARY consumed it. Read `{{roadmapPath}}` or a full SUMMARY from the On-demand Validation Artifacts list only if the preloaded evidence is missing, truncated, or inconsistent; never read a directory path. Output table: Boundary | Producer Summary | Consumer Summary | Status. End with one-line verdict: PASS if all boundaries honored, NEEDS-ATTENTION if any gaps."
|
|
36
36
|
|
|
37
37
|
**Reviewer C - Assessment & Acceptance Criteria**
|
|
38
|
-
Prompt: "Review milestone {{milestoneId}} assessment evidence and acceptance criteria. Working directory: {{workingDirectory}}. Use the preloaded milestone context, slice SUMMARY, and ASSESSMENT evidence embedded in this task — do not re-read them from disk. Read
|
|
38
|
+
Prompt: "Review milestone {{milestoneId}} assessment evidence and acceptance criteria. Working directory: {{workingDirectory}}. Use the preloaded milestone context, slice SUMMARY, and ASSESSMENT evidence embedded in this task — do not re-read them from disk. Read the milestone context from the On-demand Milestone Context file path, and read full SUMMARY or ASSESSMENT files only from explicit paths in the On-demand Validation Artifacts list, if the preloaded excerpt is missing, truncated, or inconsistent. UAT files are specs, not evidence. Verify each criterion maps to passing evidence. Then review the inlined `Verification Classes (from planning)` table. For every planned row in that table, output a `Verification Classes` table with columns `Class | Planned Check | Evidence | Verdict`. Preserve every planned non-empty class row; do not summarize, rename, combine, or omit planned classes. The first cell of each row must be exactly `Contract`, `Integration`, `Operational`, or `UAT` when that class is present in planning. If a planned class lacks evidence, still include its canonical row and mark the verdict NEEDS-ATTENTION or FAIL. If a planned browser/UAT class has no ASSESSMENT with browser/runtime actions and assertions, return NEEDS-ATTENTION. If no verification classes were planned, say that explicitly. Output sections `Acceptance Criteria` with checklist `[ ] Criterion | Evidence`, and `Verification Classes` with the table. End with one-line verdict: PASS if all criteria and classes are covered by evidence, NEEDS-ATTENTION if gaps exist."
|
|
39
39
|
|
|
40
40
|
### Step 2 - Synthesize Findings
|
|
41
41
|
|
|
@@ -85,6 +85,6 @@ If verdict is `needs-remediation`:
|
|
|
85
85
|
|
|
86
86
|
**You MUST call `gsd_validate_milestone` before finishing. Do not manually write `{{validationPath}}`.**
|
|
87
87
|
|
|
88
|
-
**File system safety:** When scanning milestone directories, use `
|
|
88
|
+
**File system safety:** When scanning milestone directories, use `find .gsd -type f` first and read only files. In flat-phase projects, `.gsd/phases/<NN>-<slug>/` is a directory, not an artifact. Never pass a directory path such as a phase directory, `tasks/`, or `slices/` directly to `read`, `readFile`, or `readFileSync`.
|
|
89
89
|
|
|
90
90
|
When done, say: "Milestone {{milestoneId}} validation complete — verdict: <verdict>." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
* Provider Payload Policy - ordered shaping of provider request payloads.
|
|
3
3
|
*
|
|
4
4
|
* The order is intentional:
|
|
5
|
-
* 1.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* 1. superseded GSD context injections (memory/guided/forensics) are removed,
|
|
6
|
+
* keeping only the latest, for every mode,
|
|
7
|
+
* 2. observation budgeting masks old tool results in auto-mode,
|
|
8
|
+
* 3. display truncation caps tool-result text for every mode,
|
|
9
|
+
* 4. the protected Source Context Block is appended after truncation,
|
|
10
|
+
* 5. supported models receive the configured service tier.
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import type { ContextManagementConfig } from "./preferences-types.js";
|
|
@@ -14,6 +16,8 @@ import type { ServiceTierSetting } from "./service-tier.js";
|
|
|
14
16
|
import {
|
|
15
17
|
createObservationMask,
|
|
16
18
|
createResponsesInputObservationMask,
|
|
19
|
+
filterSupersededContextInjections,
|
|
20
|
+
filterSupersededResponsesContextInjections,
|
|
17
21
|
truncateContextResultMessages,
|
|
18
22
|
truncateResponsesInputResultItems,
|
|
19
23
|
} from "./context-masker.js";
|
|
@@ -80,10 +84,20 @@ function applyContextManagement(
|
|
|
80
84
|
deps: ProviderPayloadPolicyDeps,
|
|
81
85
|
): void {
|
|
82
86
|
const config = deps.loadContextManagementConfig();
|
|
87
|
+
applyContextInjectionFilter(payload);
|
|
83
88
|
applyObservationBudget(payload, config, deps.isAutoActive());
|
|
84
89
|
applyDisplayTruncation(payload, config);
|
|
85
90
|
}
|
|
86
91
|
|
|
92
|
+
function applyContextInjectionFilter(payload: Record<string, unknown>): void {
|
|
93
|
+
if (Array.isArray(payload.messages)) {
|
|
94
|
+
payload.messages = filterSupersededContextInjections(payload.messages as MessagePayload);
|
|
95
|
+
}
|
|
96
|
+
if (Array.isArray(payload.input)) {
|
|
97
|
+
payload.input = filterSupersededResponsesContextInjections(payload.input as ResponsesInputPayload);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
87
101
|
function applyObservationBudget(
|
|
88
102
|
payload: Record<string, unknown>,
|
|
89
103
|
config: ContextManagementConfig | undefined,
|
|
@@ -14,7 +14,7 @@ interface DestructivePattern {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const DESTRUCTIVE_PATTERNS: readonly DestructivePattern[] = [
|
|
17
|
-
{ pattern: /\brm\s+(
|
|
17
|
+
{ pattern: /\brm\s+((?:-(?!-)[^\s]*[rR][^\s]*|--recursive)\s+|.*\s+(?:-(?!-)[^\s]*[rR][^\s]*|--recursive)(?:\s|$))/, label: "recursive delete" },
|
|
18
18
|
{ pattern: /\bgit\s+push\s+.*--force/, label: "force push" },
|
|
19
19
|
{ pattern: /\bgit\s+push\s+-f\b/, label: "force push" },
|
|
20
20
|
{ pattern: /\bgit\s+reset\s+--hard/, label: "hard reset" },
|
|
@@ -131,10 +131,23 @@ function resolvePreferredSkillNames(
|
|
|
131
131
|
* to prevent prompt injection via crafted directory names. */
|
|
132
132
|
const SAFE_SKILL_NAME = /^[a-z0-9][a-z0-9-]*$/;
|
|
133
133
|
|
|
134
|
-
function
|
|
134
|
+
function escapeXml(str: string): string {
|
|
135
|
+
return str
|
|
136
|
+
.replace(/&/g, "&")
|
|
137
|
+
.replace(/</g, "<")
|
|
138
|
+
.replace(/>/g, ">")
|
|
139
|
+
.replace(/"/g, """)
|
|
140
|
+
.replace(/'/g, "'");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function formatSkillActivationBlock(skillNames: string[], skillPaths: Map<string, string>): string {
|
|
135
144
|
const safe = skillNames.filter(name => SAFE_SKILL_NAME.test(name));
|
|
136
145
|
if (safe.length === 0) return "";
|
|
137
|
-
const reads = safe.map(name =>
|
|
146
|
+
const reads = safe.map(name => {
|
|
147
|
+
const path = skillPaths.get(name);
|
|
148
|
+
if (path) return `Read the skill file at \`${escapeXml(path)}\``;
|
|
149
|
+
return `Find '${name}' in <available_skills>, copy its <location> value, and pass that exact path to read`;
|
|
150
|
+
}).join(". ");
|
|
138
151
|
return `<skill_activation>${reads}.</skill_activation>`;
|
|
139
152
|
}
|
|
140
153
|
|
|
@@ -203,6 +216,7 @@ export function buildSkillActivationBlock(params: {
|
|
|
203
216
|
const visibleSkills = loaded;
|
|
204
217
|
const manifestScopedSkills = filterSkillsByManifest(visibleSkills, params.unitType);
|
|
205
218
|
const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
|
|
219
|
+
const installedSkillPaths = new Map(visibleSkills.map(skill => [normalizeSkillReference(skill.name), skill.filePath]));
|
|
206
220
|
warnIfManifestHasMissingSkills(params.unitType, installedNames);
|
|
207
221
|
const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
|
|
208
222
|
const matched = new Set<string>();
|
|
@@ -252,7 +266,7 @@ export function buildSkillActivationBlock(params: {
|
|
|
252
266
|
const ordered = [...matched]
|
|
253
267
|
.filter(name => installedNames.has(name) && !avoided.has(name))
|
|
254
268
|
.sort();
|
|
255
|
-
const activationBlock = formatSkillActivationBlock(ordered);
|
|
269
|
+
const activationBlock = formatSkillActivationBlock(ordered, installedSkillPaths);
|
|
256
270
|
|
|
257
271
|
// Omit recommendations when the system catalog is manifest-scoped for this
|
|
258
272
|
// unit — skill names are already listed in <available_skills>.
|