@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
|
@@ -38,6 +38,7 @@ export * from "./db/queries.js";
|
|
|
38
38
|
export * from "./db/writers/cascades.js";
|
|
39
39
|
import { TERMINAL_STATUS_SQL } from "./db/sql-constants.js";
|
|
40
40
|
import { applyStatusTransition } from "./db/writers/status.js";
|
|
41
|
+
import { LAYOUT_SEGMENTS, derivePhaseSlug, milestoneIdToPhaseNum, milestoneIdUniqueSuffix, phaseDirName, } from "./layout-policy.js";
|
|
41
42
|
export function insertDecision(d) {
|
|
42
43
|
if (!getDbOrNull())
|
|
43
44
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
@@ -169,6 +170,44 @@ export function insertArtifact(a) {
|
|
|
169
170
|
":content_hash": contentHash,
|
|
170
171
|
});
|
|
171
172
|
}
|
|
173
|
+
function canonicalPhaseDirNameForDb(milestoneId, title) {
|
|
174
|
+
const phaseNum = milestoneIdToPhaseNum(milestoneId);
|
|
175
|
+
const slug = derivePhaseSlug(title || milestoneId);
|
|
176
|
+
const suffix = milestoneIdUniqueSuffix(milestoneId);
|
|
177
|
+
return phaseDirName(phaseNum, suffix ? `${suffix}-${slug}` : slug);
|
|
178
|
+
}
|
|
179
|
+
function reconcileMilestonePhaseArtifactPaths(milestoneId, title) {
|
|
180
|
+
const db = getDbOrNull();
|
|
181
|
+
const phaseNumPrefix = String(milestoneIdToPhaseNum(milestoneId)).padStart(2, "0");
|
|
182
|
+
const canonicalDir = canonicalPhaseDirNameForDb(milestoneId, title);
|
|
183
|
+
const staleRows = db.prepare(`SELECT path
|
|
184
|
+
FROM artifacts
|
|
185
|
+
WHERE milestone_id = :milestone_id
|
|
186
|
+
AND path LIKE :phase_prefix`).all({
|
|
187
|
+
":milestone_id": milestoneId,
|
|
188
|
+
":phase_prefix": `${LAYOUT_SEGMENTS.level1}/${phaseNumPrefix}-%/%`,
|
|
189
|
+
});
|
|
190
|
+
const updatePath = db.prepare("UPDATE artifacts SET path = :new_path WHERE path = :old_path");
|
|
191
|
+
const deletePath = db.prepare("DELETE FROM artifacts WHERE path = :path");
|
|
192
|
+
const existingPath = db.prepare("SELECT 1 AS present FROM artifacts WHERE path = :path");
|
|
193
|
+
for (const row of staleRows) {
|
|
194
|
+
const parts = row.path.split("/");
|
|
195
|
+
if (parts.length < 3)
|
|
196
|
+
continue;
|
|
197
|
+
if (parts[0] !== LAYOUT_SEGMENTS.level1)
|
|
198
|
+
continue;
|
|
199
|
+
if (parts[1] === canonicalDir)
|
|
200
|
+
continue;
|
|
201
|
+
if (!parts[1]?.startsWith(`${phaseNumPrefix}-`))
|
|
202
|
+
continue;
|
|
203
|
+
const newPath = [LAYOUT_SEGMENTS.level1, canonicalDir, ...parts.slice(2)].join("/");
|
|
204
|
+
if (existingPath.get({ ":path": newPath })) {
|
|
205
|
+
deletePath.run({ ":path": row.path });
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
updatePath.run({ ":new_path": newPath, ":old_path": row.path });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
172
211
|
export function insertMilestone(m) {
|
|
173
212
|
if (!getDbOrNull())
|
|
174
213
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
@@ -207,37 +246,42 @@ export function insertMilestone(m) {
|
|
|
207
246
|
export function upsertMilestonePlanning(milestoneId, planning) {
|
|
208
247
|
if (!getDbOrNull())
|
|
209
248
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
249
|
+
transaction(() => {
|
|
250
|
+
getDbOrNull().prepare(`UPDATE milestones SET
|
|
251
|
+
title = COALESCE(NULLIF(:title, ''), title),
|
|
252
|
+
status = COALESCE(NULLIF(:status, ''), status),
|
|
253
|
+
depends_on = COALESCE(:depends_on, depends_on),
|
|
254
|
+
vision = COALESCE(:vision, vision),
|
|
255
|
+
success_criteria = COALESCE(:success_criteria, success_criteria),
|
|
256
|
+
key_risks = COALESCE(:key_risks, key_risks),
|
|
257
|
+
proof_strategy = COALESCE(:proof_strategy, proof_strategy),
|
|
258
|
+
verification_contract = COALESCE(:verification_contract, verification_contract),
|
|
259
|
+
verification_integration = COALESCE(:verification_integration, verification_integration),
|
|
260
|
+
verification_operational = COALESCE(:verification_operational, verification_operational),
|
|
261
|
+
verification_uat = COALESCE(:verification_uat, verification_uat),
|
|
262
|
+
definition_of_done = COALESCE(:definition_of_done, definition_of_done),
|
|
263
|
+
requirement_coverage = COALESCE(:requirement_coverage, requirement_coverage),
|
|
264
|
+
boundary_map_markdown = COALESCE(:boundary_map_markdown, boundary_map_markdown)
|
|
265
|
+
WHERE id = :id`).run({
|
|
266
|
+
":id": milestoneId,
|
|
267
|
+
":title": planning.title ?? "",
|
|
268
|
+
":status": planning.status ?? "",
|
|
269
|
+
":depends_on": planning.depends_on ? JSON.stringify(planning.depends_on) : null,
|
|
270
|
+
":vision": planning.vision ?? null,
|
|
271
|
+
":success_criteria": planning.successCriteria ? JSON.stringify(planning.successCriteria) : null,
|
|
272
|
+
":key_risks": planning.keyRisks ? JSON.stringify(planning.keyRisks) : null,
|
|
273
|
+
":proof_strategy": planning.proofStrategy ? JSON.stringify(planning.proofStrategy) : null,
|
|
274
|
+
":verification_contract": planning.verificationContract ?? null,
|
|
275
|
+
":verification_integration": planning.verificationIntegration ?? null,
|
|
276
|
+
":verification_operational": planning.verificationOperational ?? null,
|
|
277
|
+
":verification_uat": planning.verificationUat ?? null,
|
|
278
|
+
":definition_of_done": planning.definitionOfDone ? JSON.stringify(planning.definitionOfDone) : null,
|
|
279
|
+
":requirement_coverage": planning.requirementCoverage ?? null,
|
|
280
|
+
":boundary_map_markdown": planning.boundaryMapMarkdown ?? null,
|
|
281
|
+
});
|
|
282
|
+
const finalTitle = planning.title?.trim();
|
|
283
|
+
if (finalTitle)
|
|
284
|
+
reconcileMilestonePhaseArtifactPaths(milestoneId, finalTitle);
|
|
241
285
|
});
|
|
242
286
|
}
|
|
243
287
|
export function insertSlice(s) {
|
|
@@ -11,7 +11,7 @@ import { loadFile, saveFile } from "./files.js";
|
|
|
11
11
|
import { isDbAvailable, getMilestone, getMilestoneSlices } from "./gsd-db.js";
|
|
12
12
|
import { parseRoadmapSlices } from "./roadmap-slices.js";
|
|
13
13
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
14
|
-
import { buildCompleteSlicePrompt, buildDiscussMilestonePrompt, buildExecuteTaskPrompt, buildPlanMilestonePrompt, buildPlanSlicePrompt, buildSkillActivationBlock, } from "./auto-prompts.js";
|
|
14
|
+
import { buildCompleteSlicePrompt, buildDiscussMilestonePrompt, buildExecuteTaskPrompt, buildPlanMilestonePrompt, buildPlanSlicePrompt, buildSkillActivationBlock, capPreamble, } from "./auto-prompts.js";
|
|
15
15
|
import { deriveState, isGhostMilestone } from "./state.js";
|
|
16
16
|
import { invalidateAllCaches } from "./cache.js";
|
|
17
17
|
import { startAutoDetached } from "./auto.js";
|
|
@@ -855,7 +855,9 @@ function resolveDiscussSliceBasePath(basePath, milestoneId) {
|
|
|
855
855
|
* slice summaries so the agent can ask grounded UX/behaviour questions
|
|
856
856
|
* without wasting a turn reading files.
|
|
857
857
|
*/
|
|
858
|
-
|
|
858
|
+
// Exported for tests (`prompt-budget-enforcement.test.ts`) — verifies the
|
|
859
|
+
// inlined-context cap. Not part of the public flow surface otherwise.
|
|
860
|
+
export async function buildDiscussSlicePrompt(mid, sid, sTitle, base, options) {
|
|
859
861
|
const inlined = [];
|
|
860
862
|
// Roadmap — always included so the agent sees surrounding slices
|
|
861
863
|
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
@@ -906,8 +908,12 @@ async function buildDiscussSlicePrompt(mid, sid, sTitle, base, options) {
|
|
|
906
908
|
}
|
|
907
909
|
}
|
|
908
910
|
}
|
|
911
|
+
// Cap the inlined block: it grows unbounded with each completed slice's full
|
|
912
|
+
// SUMMARY. `capPreamble` truncates at `### ` section boundaries — roadmap and
|
|
913
|
+
// milestone context come first (survive), completed-slice summaries come last
|
|
914
|
+
// (dropped first) when the executor's window can't hold everything.
|
|
909
915
|
const inlinedContext = inlined.length > 0
|
|
910
|
-
? `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`
|
|
916
|
+
? capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`)
|
|
911
917
|
: `## Inlined Context\n\n_(no context files found yet — go in blind and ask broad questions)_`;
|
|
912
918
|
const sliceDirPath = `.gsd/milestones/${mid}/slices/${sid}`;
|
|
913
919
|
const sliceContextPath = `${sliceDirPath}/${sid}-CONTEXT.md`;
|
|
@@ -916,7 +922,7 @@ async function buildDiscussSlicePrompt(mid, sid, sTitle, base, options) {
|
|
|
916
922
|
? `\n\n## Re-discuss Mode\n\nThis slice already has an existing context file (\`${sliceContextPath}\`) from a prior discussion. The user has chosen to re-discuss it. Read the existing context file, interview for any updates, changes, or new decisions, and rewrite the file with merged findings. Do NOT skip the interview — the user explicitly asked to revisit this slice.\n`
|
|
917
923
|
: "";
|
|
918
924
|
const inlinedTemplates = inlineTemplate("slice-context", "Slice Context");
|
|
919
|
-
return loadPrompt("guided-discuss-slice", {
|
|
925
|
+
return prependLanguageDirective(base, loadPrompt("guided-discuss-slice", {
|
|
920
926
|
milestoneId: mid,
|
|
921
927
|
sliceId: sid,
|
|
922
928
|
sliceTitle: sTitle,
|
|
@@ -927,7 +933,7 @@ async function buildDiscussSlicePrompt(mid, sid, sTitle, base, options) {
|
|
|
927
933
|
inlinedTemplates,
|
|
928
934
|
structuredQuestionsAvailable: options?.structuredQuestionsAvailable ?? "false",
|
|
929
935
|
commitInstruction: buildDocsCommitInstruction(`docs(${mid}/${sid}): slice context from discuss`),
|
|
930
|
-
});
|
|
936
|
+
}));
|
|
931
937
|
}
|
|
932
938
|
/**
|
|
933
939
|
* /gsd discuss — show a picker of non-done slices and run a slice interview.
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
import { readFileSync, existsSync, mkdirSync, statSync, unlinkSync } from "node:fs";
|
|
12
12
|
import { logWarning } from "./workflow-logger.js";
|
|
13
13
|
import { isClosedStatus } from "./status-guards.js";
|
|
14
|
-
import { dirname, join
|
|
14
|
+
import { dirname, join } from "node:path";
|
|
15
15
|
import { getAllMilestones, getMilestone, getMilestoneScopedArtifacts, getSliceScopedArtifacts, getMilestoneSlices, getSliceTasks, getTasksBySliceIds, getTask, getSlice, insertArtifact, deleteArtifactByPath, getGateResults, isDbAvailable, } from "./gsd-db.js";
|
|
16
|
-
import { resolveDir, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTasksDir, targetMilestoneFile, targetSliceFile, gsdProjectionRoot, gsdRoot, buildTaskFileName, } from "./paths.js";
|
|
16
|
+
import { resolveDir, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTasksDir, targetMilestoneFile, targetSliceFile, targetTaskFile, gsdProjectionRoot, gsdRoot, buildTaskFileName, } from "./paths.js";
|
|
17
17
|
import { saveFile, clearParseCache, registerCacheClearCallback } from "./files.js";
|
|
18
18
|
import { parseRoadmap, parsePlan } from "./parsers-legacy.js";
|
|
19
19
|
import { invalidateStateCache } from "./state.js";
|
|
20
20
|
import { clearPathCache, milestonesDir, legacyMilestonesDir, isLegacyMilestonesLayout, resolveMilestonePath, relSliceFile, canonicalPhaseDirName } from "./paths.js";
|
|
21
|
-
import { readCompatMarker, writeCompatMarker, computeProjectionSha } from "./compat/compat-marker.js";
|
|
21
|
+
import { readCompatMarker, writeCompatMarker, computeProjectionSha, deriveCompatProjectionKey } from "./compat/compat-marker.js";
|
|
22
22
|
// ─── Compat marker invalidation ───────────────────────────────────────────
|
|
23
23
|
// Every successful projection write pushes its (basePath, projectionPath,
|
|
24
24
|
// entities) here; invalidateCaches() drains it and refreshes .gsd/.compat.json
|
|
@@ -71,13 +71,7 @@ function flushProjectionWritesToMarker() {
|
|
|
71
71
|
*/
|
|
72
72
|
function toArtifactPath(absPath, basePath) {
|
|
73
73
|
const projectionRoot = gsdProjectionRoot(basePath);
|
|
74
|
-
|
|
75
|
-
const root = projectionRel && !projectionRel.startsWith("..") && !projectionRel.startsWith("/")
|
|
76
|
-
? projectionRoot
|
|
77
|
-
: gsdRoot(basePath);
|
|
78
|
-
const rel = relative(root, absPath);
|
|
79
|
-
// Normalize to forward slashes for consistent DB keys
|
|
80
|
-
return rel.replace(/\\/g, "/");
|
|
74
|
+
return deriveCompatProjectionKey(absPath, [projectionRoot, gsdRoot(basePath)]);
|
|
81
75
|
}
|
|
82
76
|
/**
|
|
83
77
|
* Invalidate all caches after a disk write.
|
|
@@ -612,17 +606,7 @@ export async function renderTaskSummary(basePath, milestoneId, sliceId, taskId)
|
|
|
612
606
|
if (!task || !task.full_summary_md) {
|
|
613
607
|
return false; // No summary to render — skip silently
|
|
614
608
|
}
|
|
615
|
-
|
|
616
|
-
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId);
|
|
617
|
-
if (!slicePath) {
|
|
618
|
-
process.stderr.write(`markdown-renderer: cannot resolve slice path for ${milestoneId}/${sliceId}\n`);
|
|
619
|
-
return false;
|
|
620
|
-
}
|
|
621
|
-
// Use the tasks/ subdir when it exists (legacy layout), otherwise use the
|
|
622
|
-
// slice path directly (flat-phase: task summaries live alongside plan files).
|
|
623
|
-
const tasksDir = resolveTasksDir(basePath, milestoneId, sliceId) ?? slicePath;
|
|
624
|
-
const fileName = buildTaskFileName(taskId, "SUMMARY");
|
|
625
|
-
const absPath = join(tasksDir, fileName);
|
|
609
|
+
const absPath = targetTaskFile(basePath, milestoneId, sliceId, taskId, "SUMMARY", getMilestone(milestoneId)?.title);
|
|
626
610
|
const artifactPath = toArtifactPath(absPath, basePath);
|
|
627
611
|
await writeAndStore(absPath, artifactPath, task.full_summary_md, {
|
|
628
612
|
artifact_type: "SUMMARY",
|
|
@@ -7,7 +7,7 @@ import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
|
|
|
7
7
|
import { join, basename, dirname } from 'node:path';
|
|
8
8
|
import { upsertDecision, upsertRequirement, insertArtifact, insertMilestone, insertSlice, insertTask, transaction, updateMilestoneStatus, updateSliceStatus, getMilestoneSlices, getSliceTasks, _getAdapter, } from './gsd-db.js';
|
|
9
9
|
import { openWorkflowDatabasePath } from './db-workspace.js';
|
|
10
|
-
import { resolveGsdRootFile, resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, legacyMilestonesDir, gsdRoot, resolveTaskFiles, resolveMilestonePath, } from './paths.js';
|
|
10
|
+
import { resolveGsdRootFile, resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, legacyMilestonesDir, gsdRoot, resolveTaskFiles, resolveTaskFile, resolveMilestonePath, } from './paths.js';
|
|
11
11
|
import { findMilestoneIds } from './guided-flow.js';
|
|
12
12
|
import { milestoneIdToPhaseNum } from './layout-policy.js';
|
|
13
13
|
import { parseRoadmap, parsePlan } from './parsers-legacy.js';
|
|
@@ -762,8 +762,7 @@ export function migrateHierarchyToDb(basePath, opts) {
|
|
|
762
762
|
legacyTasksDir = isLegacySlice
|
|
763
763
|
? resolveTasksDir(basePath, milestoneId, sliceEntry.id)
|
|
764
764
|
: null;
|
|
765
|
-
|
|
766
|
-
taskSummaryFile = join(summaryDir, `${taskEntry.id}-SUMMARY.md`);
|
|
765
|
+
taskSummaryFile = resolveTaskFile(basePath, milestoneId, sliceEntry.id, taskEntry.id, 'SUMMARY');
|
|
767
766
|
}
|
|
768
767
|
const hasTaskSummary = taskSummaryFile !== null && existsSync(taskSummaryFile);
|
|
769
768
|
// Pre-migration consistency (legacy tasks/ layout only): if a task is
|
|
@@ -783,9 +782,9 @@ export function migrateHierarchyToDb(basePath, opts) {
|
|
|
783
782
|
// first execute-task. The surviving SUMMARY wins over a stale checkbox.
|
|
784
783
|
// reopen-task removes the SUMMARY, so this never re-completes an
|
|
785
784
|
// intentionally reopened task.
|
|
786
|
-
// Flat-phase summaries are phase-scoped
|
|
787
|
-
//
|
|
788
|
-
//
|
|
785
|
+
// Flat-phase summaries are phase-scoped; when a milestone has multiple
|
|
786
|
+
// slices, require the summary parent frontmatter to match so one slice's
|
|
787
|
+
// completion does not attest a sibling's same-named task.
|
|
789
788
|
let summaryAttestsCompletion = hasTaskSummary;
|
|
790
789
|
if (summaryAttestsCompletion && !isLegacySlice && roadmap.slices.length > 1 && taskSummaryFile) {
|
|
791
790
|
try {
|
|
@@ -48,6 +48,8 @@ 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
|
+
// Mirrors gpt-5.5 list pricing until OpenAI publishes official gpt-5.6 pricing.
|
|
52
|
+
{ id: "gpt-5.6", inputPer1k: 0.005, outputPer1k: 0.03, updatedAt: "2026-07-08" },
|
|
51
53
|
// Google
|
|
52
54
|
{ id: "gemini-2.0-flash", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
|
|
53
55
|
{ id: "gemini-flash-2.0", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
|
|
@@ -46,10 +46,12 @@ 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
50
|
"o1": "heavy",
|
|
50
51
|
"o3": "heavy",
|
|
51
52
|
"o4-mini": "heavy",
|
|
52
53
|
"o4-mini-deep-research": "heavy",
|
|
54
|
+
"grok-4.5": "heavy",
|
|
53
55
|
};
|
|
54
56
|
// ─── Cost Table (per 1K input tokens, approximate USD) ───────────────────────
|
|
55
57
|
// Used for cross-provider cost comparison when multiple providers offer
|
|
@@ -82,11 +84,13 @@ const MODEL_COST_PER_1K_INPUT = {
|
|
|
82
84
|
"gpt-5.3-codex-spark": 0.0003,
|
|
83
85
|
"gpt-5.4": 0.005,
|
|
84
86
|
"gpt-5.5": 0.005,
|
|
87
|
+
"gpt-5.6": 0.005,
|
|
85
88
|
"o4-mini": 0.005,
|
|
86
89
|
"o4-mini-deep-research": 0.005,
|
|
87
90
|
"gemini-2.0-flash": 0.0001,
|
|
88
91
|
"gemini-2.5-pro": 0.00125,
|
|
89
92
|
"deepseek-chat": 0.00014,
|
|
93
|
+
"grok-4.5": 0.002,
|
|
90
94
|
};
|
|
91
95
|
// ─── Capability Profiles Data Table ──────────────────────────────────────────
|
|
92
96
|
// Per-model capability profiles (0–100 scale). Used for capability-aware
|
|
@@ -128,6 +132,9 @@ export const MODEL_CAPABILITY_PROFILES = {
|
|
|
128
132
|
// OpenAI's 2026-04-23 published eval deltas across coding, tool use, and long context.
|
|
129
133
|
// Source: https://openai.com/index/introducing-gpt-5-5/
|
|
130
134
|
"gpt-5.5": { coding: 96, debugging: 93, research: 89, reasoning: 95, speed: 42, longContext: 90, instruction: 93 },
|
|
135
|
+
// GPT-5.6 profile is provisional: a small uniform step over gpt-5.5, to be
|
|
136
|
+
// recalibrated once OpenAI publishes official eval results.
|
|
137
|
+
"gpt-5.6": { coding: 97, debugging: 94, research: 90, reasoning: 96, speed: 42, longContext: 91, instruction: 94 },
|
|
131
138
|
// ── OpenAI o-series (reasoning-first) ──────────────────────────────────────
|
|
132
139
|
"o1": { coding: 78, debugging: 82, research: 78, reasoning: 90, speed: 20, longContext: 65, instruction: 82 },
|
|
133
140
|
"o3": { coding: 80, debugging: 85, research: 80, reasoning: 92, speed: 25, longContext: 70, instruction: 85 },
|
|
@@ -139,6 +146,10 @@ export const MODEL_CAPABILITY_PROFILES = {
|
|
|
139
146
|
"gemini-flash-2.0": { coding: 50, debugging: 40, research: 50, reasoning: 40, speed: 95, longContext: 60, instruction: 65 },
|
|
140
147
|
// ── DeepSeek ───────────────────────────────────────────────────────────────
|
|
141
148
|
"deepseek-chat": { coding: 75, debugging: 65, research: 55, reasoning: 70, speed: 70, longContext: 55, instruction: 65 },
|
|
149
|
+
// ── xAI ────────────────────────────────────────────────────────────────────
|
|
150
|
+
// Grok 4.5 (2026-07): Opus-class frontier model tuned for coding and agentic
|
|
151
|
+
// work; notably faster and more token-efficient than peer heavy models.
|
|
152
|
+
"grok-4.5": { coding: 95, debugging: 90, research: 82, reasoning: 93, speed: 55, longContext: 80, instruction: 90 },
|
|
142
153
|
};
|
|
143
154
|
// ─── Base Task Requirements Data Table ───────────────────────────────────────
|
|
144
155
|
// Per-unit-type base requirement vectors. Weights indicate how important each
|
|
@@ -122,6 +122,14 @@ function cachedReaddir(dirPath) {
|
|
|
122
122
|
dirListCache.set(dirPath, entries);
|
|
123
123
|
return entries;
|
|
124
124
|
}
|
|
125
|
+
function isExistingFile(path) {
|
|
126
|
+
try {
|
|
127
|
+
return statSync(path).isFile();
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
125
133
|
/**
|
|
126
134
|
* Clear the volatile directory listing caches.
|
|
127
135
|
* Call after milestone transitions, file creation in planning directories,
|
|
@@ -198,6 +206,25 @@ export function buildTaskFileName(taskId, suffix) {
|
|
|
198
206
|
// This helper is deprecated but kept for backward-compat callers.
|
|
199
207
|
return `${taskId}-${suffix}.md`;
|
|
200
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Build a flat-phase task artifact file name.
|
|
211
|
+
* ("S06", "T03", "SUMMARY") → "S06-T03-SUMMARY.md"
|
|
212
|
+
*/
|
|
213
|
+
export function buildFlatTaskFileName(sliceId, taskId, suffix) {
|
|
214
|
+
return `${sliceId}-${taskId}-${suffix}.md`;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Extract the task ID from a task artifact filename.
|
|
218
|
+
* Supports flat-phase S##-T##-SUFFIX.md plus legacy T##-SUFFIX.md and
|
|
219
|
+
* T##-DESCRIPTOR-SUFFIX.md names.
|
|
220
|
+
*/
|
|
221
|
+
export function taskIdFromTaskFileName(fileName, suffix) {
|
|
222
|
+
const flat = new RegExp(`^S\\d+-(T\\d+)-${suffix}\\.md$`, "i").exec(fileName);
|
|
223
|
+
if (flat?.[1])
|
|
224
|
+
return flat[1].toUpperCase();
|
|
225
|
+
const legacy = new RegExp(`^(T\\d+)(?:-.*)?-${suffix}\\.md$`, "i").exec(fileName);
|
|
226
|
+
return legacy?.[1]?.toUpperCase() ?? null;
|
|
227
|
+
}
|
|
201
228
|
// ─── Resolvers ─────────────────────────────────────────────────────────────
|
|
202
229
|
/**
|
|
203
230
|
* Find a directory entry by ID prefix within a parent directory.
|
|
@@ -238,7 +265,7 @@ export function resolveFile(dir, idPrefix, suffix) {
|
|
|
238
265
|
return null;
|
|
239
266
|
const target = `${idPrefix}-${suffix}.md`.toUpperCase();
|
|
240
267
|
try {
|
|
241
|
-
const entries =
|
|
268
|
+
const entries = cachedReaddirWithTypes(dir).filter(e => e.isFile()).map(e => e.name);
|
|
242
269
|
// Direct match: ID-SUFFIX.md
|
|
243
270
|
const direct = entries.find(e => e.toUpperCase() === target);
|
|
244
271
|
if (direct)
|
|
@@ -259,19 +286,18 @@ export function resolveFile(dir, idPrefix, suffix) {
|
|
|
259
286
|
}
|
|
260
287
|
}
|
|
261
288
|
/**
|
|
262
|
-
* Find all task files matching a pattern in a tasks directory.
|
|
263
|
-
* Returns sorted file names matching T##-SUFFIX.md
|
|
289
|
+
* Find all task files matching a pattern in a tasks directory or flat phase dir.
|
|
290
|
+
* Returns sorted file names matching S##-T##-SUFFIX.md, T##-SUFFIX.md,
|
|
291
|
+
* or legacy T##-*-SUFFIX.md.
|
|
264
292
|
*/
|
|
265
293
|
export function resolveTaskFiles(tasksDir, suffix) {
|
|
266
294
|
if (!existsSync(tasksDir))
|
|
267
295
|
return [];
|
|
268
296
|
try {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
return cachedReaddir(tasksDir)
|
|
274
|
-
.filter(f => currentPattern.test(f) || legacyPattern.test(f))
|
|
297
|
+
return cachedReaddirWithTypes(tasksDir)
|
|
298
|
+
.filter(e => e.isFile())
|
|
299
|
+
.map(e => e.name)
|
|
300
|
+
.filter(f => taskIdFromTaskFileName(f, suffix) !== null)
|
|
275
301
|
.sort();
|
|
276
302
|
}
|
|
277
303
|
catch {
|
|
@@ -810,7 +836,7 @@ export function resolveMilestoneFile(basePath, milestoneId, suffix) {
|
|
|
810
836
|
const prefix = `${String(phaseNum).padStart(2, "0")}`;
|
|
811
837
|
const flatName = `${prefix}-${suffix}.md`;
|
|
812
838
|
const flatPath = join(mDir, flatName);
|
|
813
|
-
if (
|
|
839
|
+
if (isExistingFile(flatPath))
|
|
814
840
|
return flatPath;
|
|
815
841
|
// Legacy fallback: M001-SUFFIX.md
|
|
816
842
|
const file = resolveFile(mDir, milestoneId, suffix);
|
|
@@ -843,12 +869,12 @@ export function resolveSliceFile(basePath, milestoneId, sliceId, suffix) {
|
|
|
843
869
|
const planNum = sliceIdToPlanNum(sliceId);
|
|
844
870
|
const flatName = planFileName(phaseNum, planNum, suffix);
|
|
845
871
|
const flatPath = join(phaseDir, flatName);
|
|
846
|
-
if (
|
|
872
|
+
if (isExistingFile(flatPath))
|
|
847
873
|
return flatPath;
|
|
848
874
|
// Also check plan-number-only format MM-SUFFIX.md (written by buildSliceFileName)
|
|
849
875
|
const planOnlyName = `${String(planNum).padStart(2, "0")}-${suffix}.md`;
|
|
850
876
|
const planOnlyPath = join(phaseDir, planOnlyName);
|
|
851
|
-
if (
|
|
877
|
+
if (isExistingFile(planOnlyPath))
|
|
852
878
|
return planOnlyPath;
|
|
853
879
|
// Try prefix match for the phase+plan number (handles suffix variations)
|
|
854
880
|
const planPrefix = `${String(phaseNum).padStart(2, "0")}-${String(planNum).padStart(2, "0")}-`;
|
|
@@ -893,8 +919,11 @@ export function resolveTaskFile(basePath, milestoneId, sliceId, taskId, suffix)
|
|
|
893
919
|
const legacyBase = legacyMilestonesDir(basePath);
|
|
894
920
|
const isLegacy = phaseDir.startsWith(legacyBase + "/") || phaseDir.startsWith(legacyBase + "\\");
|
|
895
921
|
if (suffix !== "PLAN" && !isLegacy) {
|
|
896
|
-
const flatPath = join(phaseDir,
|
|
897
|
-
|
|
922
|
+
const flatPath = join(phaseDir, buildFlatTaskFileName(sliceId, taskId, suffix));
|
|
923
|
+
if (isExistingFile(flatPath))
|
|
924
|
+
return flatPath;
|
|
925
|
+
const legacyFlatPath = join(phaseDir, buildTaskFileName(taskId, suffix));
|
|
926
|
+
return isExistingFile(legacyFlatPath) ? legacyFlatPath : null;
|
|
898
927
|
}
|
|
899
928
|
const tDir = resolveTasksDir(basePath, milestoneId, sliceId);
|
|
900
929
|
if (tDir) {
|
|
@@ -1006,6 +1035,28 @@ export function targetSliceFile(basePath, milestoneId, sliceId, suffix, mileston
|
|
|
1006
1035
|
: planFileName(milestoneIdToPhaseNum(milestoneId), sliceIdToPlanNum(sliceId), suffix);
|
|
1007
1036
|
return join(dir, fileName);
|
|
1008
1037
|
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Build the canonical absolute write target for a task file.
|
|
1040
|
+
* Readers that need legacy flat-phase fallback should call resolveTaskFile.
|
|
1041
|
+
*/
|
|
1042
|
+
export function targetTaskFile(basePath, milestoneId, sliceId, taskId, suffix, milestoneTitle) {
|
|
1043
|
+
if (suffix === "PLAN") {
|
|
1044
|
+
return targetSliceFile(basePath, milestoneId, sliceId, "PLAN", milestoneTitle);
|
|
1045
|
+
}
|
|
1046
|
+
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
1047
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
1048
|
+
const isLegacy = mDir
|
|
1049
|
+
? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
|
|
1050
|
+
: isLegacyMilestonesLayout(basePath);
|
|
1051
|
+
const milestoneDir = mDir
|
|
1052
|
+
?? dirname(targetMilestoneFile(basePath, milestoneId, "ROADMAP", milestoneTitle));
|
|
1053
|
+
if (isLegacy) {
|
|
1054
|
+
const slicesDir = join(milestoneDir, "slices");
|
|
1055
|
+
const sliceDir = join(slicesDir, resolveDir(slicesDir, sliceId) ?? sliceId);
|
|
1056
|
+
return join(sliceDir, "tasks", buildTaskFileName(taskId, suffix));
|
|
1057
|
+
}
|
|
1058
|
+
return join(milestoneDir, buildFlatTaskFileName(sliceId, taskId, suffix));
|
|
1059
|
+
}
|
|
1009
1060
|
/**
|
|
1010
1061
|
* Build relative .gsd/ path to a slice file.
|
|
1011
1062
|
* Preserves an existing compatibility filename when present; otherwise falls
|
|
@@ -1036,5 +1087,5 @@ export function relTaskFile(basePath, milestoneId, sliceId, taskId, suffix, mile
|
|
|
1036
1087
|
return relSliceFile(basePath, milestoneId, sliceId, "PLAN");
|
|
1037
1088
|
}
|
|
1038
1089
|
const relS = relSlicePath(basePath, milestoneId, sliceId, milestoneTitle);
|
|
1039
|
-
return `${relS}/${
|
|
1090
|
+
return `${relS}/${buildFlatTaskFileName(sliceId, taskId, suffix)}`;
|
|
1040
1091
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CONFIGURABLE_PLANNING_SUBAGENT_UNITS } from "./preferences-types.js";
|
|
2
|
+
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
3
|
+
const CONFIGURABLE_UNITS = new Set(CONFIGURABLE_PLANNING_SUBAGENT_UNITS);
|
|
4
|
+
function configuredAllowedSubagents(unitType, preferences) {
|
|
5
|
+
if (!CONFIGURABLE_UNITS.has(unitType))
|
|
6
|
+
return [];
|
|
7
|
+
return preferences?.planning_subagents?.[unitType]?.allowed ?? [];
|
|
8
|
+
}
|
|
9
|
+
function mergeAllowedSubagents(current, configured) {
|
|
10
|
+
return Array.from(new Set([...current, ...configured]));
|
|
11
|
+
}
|
|
12
|
+
export function applyPlanningSubagentPreferences(unitType, policy, preferences) {
|
|
13
|
+
if (!policy)
|
|
14
|
+
return policy;
|
|
15
|
+
const configured = configuredAllowedSubagents(unitType, preferences);
|
|
16
|
+
if (configured.length === 0)
|
|
17
|
+
return policy;
|
|
18
|
+
if (policy.mode === "planning") {
|
|
19
|
+
return {
|
|
20
|
+
mode: "planning-dispatch",
|
|
21
|
+
allowedSubagents: mergeAllowedSubagents([], configured),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (policy.mode === "planning-dispatch") {
|
|
25
|
+
return {
|
|
26
|
+
...policy,
|
|
27
|
+
allowedSubagents: mergeAllowedSubagents(policy.allowedSubagents, configured),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return policy;
|
|
31
|
+
}
|
|
32
|
+
export function resolveEffectivePlanningToolsPolicy(unitType, policy, basePath) {
|
|
33
|
+
if (!basePath)
|
|
34
|
+
return policy;
|
|
35
|
+
const preferences = loadEffectiveGSDPreferences(basePath)?.preferences;
|
|
36
|
+
return applyPlanningSubagentPreferences(unitType, policy, preferences);
|
|
37
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
const PLANNING_DISPATCH_AGENT_REGISTRY = {
|
|
9
|
+
mnemo: { readOnlySpecialist: true },
|
|
10
|
+
scout: { readOnlySpecialist: true },
|
|
11
|
+
planner: { readOnlySpecialist: true },
|
|
12
|
+
reviewer: { readOnlySpecialist: true },
|
|
13
|
+
security: { readOnlySpecialist: true },
|
|
14
|
+
tester: { readOnlySpecialist: true },
|
|
15
|
+
};
|
|
16
|
+
export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set(Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
|
|
17
|
+
.filter(([, metadata]) => metadata.readOnlySpecialist)
|
|
18
|
+
.map(([agentId]) => agentId));
|
|
19
|
+
export function isReadOnlyPlanningDispatchAgent(agentId) {
|
|
20
|
+
const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId];
|
|
21
|
+
return metadata?.readOnlySpecialist === true;
|
|
22
|
+
}
|
|
23
|
+
export function allowedPlanningDispatchAgentsList() {
|
|
24
|
+
return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
|
|
25
|
+
}
|
|
@@ -61,6 +61,7 @@ export const KNOWN_PREFERENCE_KEYS = new Set([
|
|
|
61
61
|
"git",
|
|
62
62
|
"post_unit_hooks",
|
|
63
63
|
"pre_dispatch_hooks",
|
|
64
|
+
"planning_subagents",
|
|
64
65
|
"dynamic_routing",
|
|
65
66
|
"disabled_model_providers",
|
|
66
67
|
"uok",
|
|
@@ -134,6 +135,10 @@ export const KNOWN_UNIT_LABELS = [
|
|
|
134
135
|
"workflow-preferences", "discuss-project", "discuss-requirements",
|
|
135
136
|
"research-decision", "research-project",
|
|
136
137
|
];
|
|
138
|
+
export const CONFIGURABLE_PLANNING_SUBAGENT_UNITS = [
|
|
139
|
+
"plan-milestone",
|
|
140
|
+
"plan-slice",
|
|
141
|
+
];
|
|
137
142
|
export const SKILL_ACTIONS = new Set(["use", "prefer", "avoid"]);
|
|
138
143
|
/** The nine model-routing phase buckets. */
|
|
139
144
|
export const GSD_MODEL_PHASE_KEYS = [
|
|
@@ -9,7 +9,8 @@ import { isAbsolute } from "node:path";
|
|
|
9
9
|
import { VALID_BRANCH_NAME } from "./git-service.js";
|
|
10
10
|
import { normalizeStringArray } from "../shared/format-utils.js";
|
|
11
11
|
import { getGateIdsForTurn } from "./gate-registry.js";
|
|
12
|
-
import { KNOWN_PREFERENCE_KEYS, KNOWN_UNIT_LABELS, GSD_MODEL_PHASE_KEYS, SKILL_ACTIONS, } from "./preferences-types.js";
|
|
12
|
+
import { KNOWN_PREFERENCE_KEYS, KNOWN_UNIT_LABELS, CONFIGURABLE_PLANNING_SUBAGENT_UNITS, GSD_MODEL_PHASE_KEYS, SKILL_ACTIONS, } from "./preferences-types.js";
|
|
13
|
+
import { ALLOWED_PLANNING_DISPATCH_AGENTS, allowedPlanningDispatchAgentsList, } from "./planning-subagent-registry.js";
|
|
13
14
|
const VALID_TOKEN_PROFILES = new Set(["budget", "balanced", "quality", "burn-max"]);
|
|
14
15
|
const VALID_THINKING_LEVELS = new Set([
|
|
15
16
|
"off",
|
|
@@ -727,6 +728,52 @@ export function validatePreferences(preferences) {
|
|
|
727
728
|
validated.pre_dispatch_hooks = validPreHooks;
|
|
728
729
|
}
|
|
729
730
|
}
|
|
731
|
+
// ─── Planning Subagents ─────────────────────────────────────────────────
|
|
732
|
+
if (preferences.planning_subagents !== undefined) {
|
|
733
|
+
if (!preferences.planning_subagents ||
|
|
734
|
+
typeof preferences.planning_subagents !== "object" ||
|
|
735
|
+
Array.isArray(preferences.planning_subagents)) {
|
|
736
|
+
errors.push("planning_subagents must be an object keyed by planning unit type");
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
const validUnits = new Set(CONFIGURABLE_PLANNING_SUBAGENT_UNITS);
|
|
740
|
+
const validPlanningSubagents = {};
|
|
741
|
+
for (const [unitType, rawConfig] of Object.entries(preferences.planning_subagents)) {
|
|
742
|
+
if (!validUnits.has(unitType)) {
|
|
743
|
+
errors.push(`planning_subagents unknown or unsupported unit "${unitType}" — supported units: ` +
|
|
744
|
+
`${CONFIGURABLE_PLANNING_SUBAGENT_UNITS.join(", ")}`);
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
748
|
+
errors.push(`planning_subagents.${unitType} must be an object with an allowed array`);
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
const allowed = normalizeStringArray(rawConfig.allowed);
|
|
752
|
+
if (allowed.length === 0) {
|
|
753
|
+
errors.push(`planning_subagents.${unitType}.allowed must include at least one read-only planning specialist`);
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
const sanitizedAllowed = [];
|
|
757
|
+
for (const agentId of allowed) {
|
|
758
|
+
if (!ALLOWED_PLANNING_DISPATCH_AGENTS.has(agentId)) {
|
|
759
|
+
errors.push(`planning_subagents.${unitType}.allowed includes "${agentId}", which is not classified as a ` +
|
|
760
|
+
`read-only planning specialist. Allowed agents: ${allowedPlanningDispatchAgentsList()}`);
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
sanitizedAllowed.push(agentId);
|
|
764
|
+
}
|
|
765
|
+
const dedupedAllowed = Array.from(new Set(sanitizedAllowed));
|
|
766
|
+
if (dedupedAllowed.length > 0) {
|
|
767
|
+
validPlanningSubagents[unitType] = {
|
|
768
|
+
allowed: dedupedAllowed,
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
if (Object.keys(validPlanningSubagents).length > 0) {
|
|
773
|
+
validated.planning_subagents = validPlanningSubagents;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
730
777
|
// ─── Dynamic Routing ─────────────────────────────────────────────────
|
|
731
778
|
if (preferences.dynamic_routing !== undefined) {
|
|
732
779
|
if (typeof preferences.dynamic_routing === "object" && preferences.dynamic_routing !== null) {
|