@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
|
@@ -16,10 +16,11 @@ import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
|
16
16
|
import {
|
|
17
17
|
resolveMilestoneFile, resolveSliceFile, resolveSlicePath,
|
|
18
18
|
resolveTasksDir, resolveTaskFiles, resolveTaskFile,
|
|
19
|
+
taskIdFromTaskFileName,
|
|
19
20
|
relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath,
|
|
20
21
|
relTaskFile, resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile,
|
|
21
22
|
} from "./paths.js";
|
|
22
|
-
import { resolveInlineLevel, loadEffectiveGSDPreferences } from "./preferences.js";
|
|
23
|
+
import { resolveInlineLevel, loadEffectiveGSDPreferences, renderLanguageDirectiveForPrompt } from "./preferences.js";
|
|
23
24
|
import { createRepositoryRegistryFromPreferences } from "./repository-registry.js";
|
|
24
25
|
import { isContextModeEnabled } from "./preferences-types.js";
|
|
25
26
|
import { parseRoadmap } from "./parsers-legacy.js";
|
|
@@ -28,6 +29,7 @@ import type { GSDPreferences } from "./preferences.js";
|
|
|
28
29
|
import { join, basename, relative, sep } from "node:path";
|
|
29
30
|
import { existsSync } from "node:fs";
|
|
30
31
|
import { computeBudgets, resolveExecutorContextWindow, truncateAtSectionBoundary, type MinimalModelRegistry } from "./context-budget.js";
|
|
32
|
+
import type { TokenProvider } from "./token-counter.js";
|
|
31
33
|
import { getBlockingReworkFindingsForTask, getGateResults, getPendingGates, getPendingGatesForTurn } from "./gsd-db.js";
|
|
32
34
|
import {
|
|
33
35
|
GATE_REGISTRY,
|
|
@@ -76,6 +78,14 @@ export { buildSkillActivationBlock, buildSkillDiscoveryVars };
|
|
|
76
78
|
*/
|
|
77
79
|
const MAX_PREAMBLE_CHARS = 20_000;
|
|
78
80
|
|
|
81
|
+
function prependLanguageDirectiveForBase(base: string, prompt: string): string {
|
|
82
|
+
const directive = renderLanguageDirectiveForPrompt(
|
|
83
|
+
loadEffectiveGSDPreferences(base)?.preferences,
|
|
84
|
+
);
|
|
85
|
+
if (!directive || prompt.startsWith(directive)) return prompt;
|
|
86
|
+
return `${directive}\n\n${prompt}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
79
89
|
/**
|
|
80
90
|
* Resolve prompt budgets from the configured executor context window.
|
|
81
91
|
*
|
|
@@ -91,13 +101,29 @@ function resolvePromptBudgets(): ReturnType<typeof computeBudgets> {
|
|
|
91
101
|
const prefs = loadEffectiveGSDPreferences();
|
|
92
102
|
const sessionWindow = prefs?.preferences.context_window_override;
|
|
93
103
|
const windowTokens = resolveExecutorContextWindow(undefined, prefs?.preferences, sessionWindow);
|
|
94
|
-
return computeBudgets(windowTokens);
|
|
104
|
+
return computeBudgets(windowTokens, resolveExecutionProvider(prefs?.preferences));
|
|
95
105
|
} catch (e) {
|
|
96
106
|
logWarning("prompt", `resolvePromptBudgets failed: ${(e as Error).message}`);
|
|
97
107
|
return computeBudgets(200_000);
|
|
98
108
|
}
|
|
99
109
|
}
|
|
100
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Best-effort provider for the chars/token ratio: the executor's configured
|
|
113
|
+
* model profile is the only provider source reachable here (the runtime
|
|
114
|
+
* `sessionProvider` that reaches `formatExecutorConstraints` isn't threaded to
|
|
115
|
+
* `capPreamble`/summary callers). Undefined when no explicit provider is set —
|
|
116
|
+
* `computeBudgets` then uses the 4.0 default, i.e. today's behavior.
|
|
117
|
+
*/
|
|
118
|
+
function resolveExecutionProvider(prefs?: { models?: { execution?: unknown } }): TokenProvider | undefined {
|
|
119
|
+
const exec = prefs?.models?.execution;
|
|
120
|
+
if (exec && typeof exec === "object" && "provider" in exec) {
|
|
121
|
+
const provider = (exec as { provider?: unknown }).provider;
|
|
122
|
+
if (typeof provider === "string" && provider) return provider as TokenProvider;
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
101
127
|
/**
|
|
102
128
|
* Character budget for dependency/prior slice summaries injected into dispatch
|
|
103
129
|
* prompts. Scales with the executor's configured context window (issue #4435).
|
|
@@ -236,7 +262,7 @@ function formatCloseoutReviewInstructions(validationContent: string | null, vali
|
|
|
236
262
|
].join("\n");
|
|
237
263
|
}
|
|
238
264
|
|
|
239
|
-
function capPreamble(preamble: string): string {
|
|
265
|
+
export function capPreamble(preamble: string): string {
|
|
240
266
|
// Cap inlined context at min(static ceiling, scaled inline budget).
|
|
241
267
|
// The ceiling bounds repeated auto prompt payloads; the scaled
|
|
242
268
|
// budget tightens the cap for small-window users whose true safe limit is
|
|
@@ -246,6 +272,41 @@ function capPreamble(preamble: string): string {
|
|
|
246
272
|
return truncateAtSectionBoundary(preamble, budget).content;
|
|
247
273
|
}
|
|
248
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Cap the execute-task inline blocks against one shared budget in priority
|
|
277
|
+
* order. Unlike `capPreamble` (single concatenated preamble), execute-task
|
|
278
|
+
* feeds these blocks into separate, non-contiguous template placeholders, so
|
|
279
|
+
* they can't be joined and re-split — the budget is spent block-by-block.
|
|
280
|
+
*
|
|
281
|
+
* The task plan is the authoritative execution contract: it is never truncated
|
|
282
|
+
* here (it consumes budget first, whole). Remaining budget flows to the slice
|
|
283
|
+
* excerpt, then templates, each truncated at section boundaries so the lowest-
|
|
284
|
+
* priority context drops whole trailing sections first. When the task plan
|
|
285
|
+
* alone meets or exceeds the budget, the trailing blocks are dropped rather
|
|
286
|
+
* than the task plan being cut.
|
|
287
|
+
*/
|
|
288
|
+
function capExecuteTaskInlineBlocks(
|
|
289
|
+
taskPlan: string,
|
|
290
|
+
slicePlan: string,
|
|
291
|
+
templates: string,
|
|
292
|
+
budgetChars: number,
|
|
293
|
+
): { taskPlan: string; slicePlan: string; templates: string } {
|
|
294
|
+
let remaining = budgetChars - taskPlan.length;
|
|
295
|
+
if (remaining <= 0) {
|
|
296
|
+
return { taskPlan, slicePlan: "", templates: "" };
|
|
297
|
+
}
|
|
298
|
+
const cappedSlice = slicePlan.length <= remaining
|
|
299
|
+
? slicePlan
|
|
300
|
+
: truncateAtSectionBoundary(slicePlan, remaining).content;
|
|
301
|
+
remaining -= cappedSlice.length;
|
|
302
|
+
const cappedTemplates = remaining <= 0
|
|
303
|
+
? ""
|
|
304
|
+
: templates.length <= remaining
|
|
305
|
+
? templates
|
|
306
|
+
: truncateAtSectionBoundary(templates, remaining).content;
|
|
307
|
+
return { taskPlan, slicePlan: cappedSlice, templates: cappedTemplates };
|
|
308
|
+
}
|
|
309
|
+
|
|
249
310
|
type PromptContextMode = "inline" | "excerpt" | "on-demand" | "skipped";
|
|
250
311
|
|
|
251
312
|
interface PromptContextTelemetryEntry {
|
|
@@ -324,7 +385,7 @@ function prependContextModeToBlock(
|
|
|
324
385
|
block: string,
|
|
325
386
|
renderMode: ContextModeRenderMode = "standalone",
|
|
326
387
|
): string {
|
|
327
|
-
const toolSurface = composeToolSurfaceInstructions(unitType, { renderMode });
|
|
388
|
+
const toolSurface = composeToolSurfaceInstructions(unitType, { renderMode, basePath: base });
|
|
328
389
|
const contextMode = renderContextModeBlockForPrompt(unitType, base, renderMode);
|
|
329
390
|
const guidance = [toolSurface, contextMode].filter(Boolean).join("\n\n");
|
|
330
391
|
if (!guidance) return block;
|
|
@@ -405,7 +466,7 @@ function formatExecutorConstraints(
|
|
|
405
466
|
// so DEFAULT_CONTEXT_WINDOW stays the single source of truth.
|
|
406
467
|
windowTokens = resolveExecutorContextWindow(undefined, undefined, sessionContextWindow, sessionProvider);
|
|
407
468
|
}
|
|
408
|
-
const budgets = computeBudgets(windowTokens);
|
|
469
|
+
const budgets = computeBudgets(windowTokens, sessionProvider as TokenProvider | undefined);
|
|
409
470
|
const { min, max } = budgets.taskCountRange;
|
|
410
471
|
const execWindowK = Math.round(windowTokens / 1000);
|
|
411
472
|
const perTaskBudgetK = Math.round(budgets.inlineContextBudgetChars / 1000);
|
|
@@ -1431,6 +1492,18 @@ function resolveTaskSummariesLocation(
|
|
|
1431
1492
|
return { dir: slicePath, relPrefix: sRel };
|
|
1432
1493
|
}
|
|
1433
1494
|
|
|
1495
|
+
function summaryFileBelongsToSlice(
|
|
1496
|
+
fileName: string,
|
|
1497
|
+
base: string,
|
|
1498
|
+
mid: string,
|
|
1499
|
+
sid: string,
|
|
1500
|
+
): boolean {
|
|
1501
|
+
const tid = taskIdFromTaskFileName(fileName, "SUMMARY");
|
|
1502
|
+
if (!tid) return false;
|
|
1503
|
+
const resolved = resolveTaskFile(base, mid, sid, tid, "SUMMARY");
|
|
1504
|
+
return resolved !== null && basename(resolved) === fileName;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1434
1507
|
export async function getPriorTaskSummaryPaths(
|
|
1435
1508
|
mid: string, sid: string, currentTid: string, base: string,
|
|
1436
1509
|
): Promise<string[]> {
|
|
@@ -1442,7 +1515,10 @@ export async function getPriorTaskSummaryPaths(
|
|
|
1442
1515
|
|
|
1443
1516
|
return summaryFiles
|
|
1444
1517
|
.filter(f => {
|
|
1445
|
-
|
|
1518
|
+
if (!summaryFileBelongsToSlice(f, base, mid, sid)) return false;
|
|
1519
|
+
const tid = taskIdFromTaskFileName(f, "SUMMARY");
|
|
1520
|
+
if (!tid) return false;
|
|
1521
|
+
const num = parseInt(tid.replace(/^T/, ""), 10);
|
|
1446
1522
|
return num < currentNum;
|
|
1447
1523
|
})
|
|
1448
1524
|
.map(f => `${loc.relPrefix}/${f}`);
|
|
@@ -1475,8 +1551,9 @@ export async function getDependencyTaskSummaryPaths(
|
|
|
1475
1551
|
|
|
1476
1552
|
return summaryFiles
|
|
1477
1553
|
.filter((f) => {
|
|
1478
|
-
|
|
1479
|
-
const tid = f
|
|
1554
|
+
if (!summaryFileBelongsToSlice(f, base, mid, sid)) return false;
|
|
1555
|
+
const tid = taskIdFromTaskFileName(f, "SUMMARY");
|
|
1556
|
+
if (!tid) return false;
|
|
1480
1557
|
return depSet.has(tid);
|
|
1481
1558
|
})
|
|
1482
1559
|
.map((f) => `${loc.relPrefix}/${f}`);
|
|
@@ -1661,7 +1738,7 @@ export async function buildDiscussMilestonePrompt(
|
|
|
1661
1738
|
if (headless) {
|
|
1662
1739
|
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
1663
1740
|
const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
|
|
1664
|
-
|
|
1741
|
+
const prompt = loadPrompt("discuss-headless", {
|
|
1665
1742
|
seedContext: roadmapContent ?? "",
|
|
1666
1743
|
inlinedTemplates: contextTemplate,
|
|
1667
1744
|
workingDirectory: base,
|
|
@@ -1670,6 +1747,7 @@ export async function buildDiscussMilestonePrompt(
|
|
|
1670
1747
|
commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
|
|
1671
1748
|
multiMilestoneCommitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
|
|
1672
1749
|
});
|
|
1750
|
+
return prependLanguageDirectiveForBase(base, prompt);
|
|
1673
1751
|
}
|
|
1674
1752
|
|
|
1675
1753
|
const rawInlinedContext = await buildDiscussMilestoneInlinedContext(mid, base);
|
|
@@ -1700,10 +1778,11 @@ export async function buildDiscussMilestonePrompt(
|
|
|
1700
1778
|
const truncationNote = cappedDraftSeed !== draftSeed
|
|
1701
1779
|
? `\n\n_(Draft seed truncated; read the full draft at \`${draftRelPath}\` if needed.)_`
|
|
1702
1780
|
: "";
|
|
1703
|
-
|
|
1781
|
+
const promptWithDraftSeed = `${promptWithContextMode}\n\n## Prior Discussion (Draft Seed)\n\nThe following draft was captured from a prior multi-milestone discussion. Use it as seed material — the user has already provided this context. Start with a brief reflection on what the draft covers, then probe for any gaps or open questions before writing the full CONTEXT.md.\n\n${cappedDraftSeed}${truncationNote}`;
|
|
1782
|
+
return prependLanguageDirectiveForBase(base, promptWithDraftSeed);
|
|
1704
1783
|
}
|
|
1705
1784
|
|
|
1706
|
-
return promptWithContextMode;
|
|
1785
|
+
return prependLanguageDirectiveForBase(base, promptWithContextMode);
|
|
1707
1786
|
}
|
|
1708
1787
|
|
|
1709
1788
|
/**
|
|
@@ -2725,7 +2804,7 @@ export async function buildExecuteTaskPrompt(
|
|
|
2725
2804
|
// Compute verification budget for the executor's context window (issue #707)
|
|
2726
2805
|
const prefs = loadEffectiveGSDPreferences();
|
|
2727
2806
|
const contextWindow = resolveExecutorContextWindow(opts.modelRegistry, prefs?.preferences, opts.sessionContextWindow, opts.sessionProvider);
|
|
2728
|
-
const budgets = computeBudgets(contextWindow);
|
|
2807
|
+
const budgets = computeBudgets(contextWindow, opts.sessionProvider as TokenProvider | undefined);
|
|
2729
2808
|
const verificationBudget = `~${Math.round(budgets.verificationBudgetChars / 1000)}K chars`;
|
|
2730
2809
|
|
|
2731
2810
|
// Truncate carry-forward section when it exceeds 40% of inline context budget.
|
|
@@ -2842,10 +2921,26 @@ export async function buildExecuteTaskPrompt(
|
|
|
2842
2921
|
}
|
|
2843
2922
|
},
|
|
2844
2923
|
});
|
|
2845
|
-
const
|
|
2846
|
-
const
|
|
2924
|
+
const rawTaskPlanInline = requireComposedArtifactBlock(contractedContext.blocks, "execute-task", "task-plan");
|
|
2925
|
+
const rawSlicePlanExcerpt = requireComposedArtifactBlock(contractedContext.blocks, "execute-task", "slice-plan");
|
|
2847
2926
|
const contractedCarryForward = requireComposedArtifactBlock(contractedContext.blocks, "execute-task", "prior-task-summaries");
|
|
2848
|
-
const
|
|
2927
|
+
const rawContractedTemplates = requireComposedArtifactBlock(contractedContext.blocks, "execute-task", "templates");
|
|
2928
|
+
// Cap the static inline blocks against one shared budget so a small-window
|
|
2929
|
+
// executor can't overflow (the sibling builders cap via `capPreamble`;
|
|
2930
|
+
// execute-task's blocks feed separate template slots, so they share a budget
|
|
2931
|
+
// block-by-block). Carry-forward already has its own truncation above.
|
|
2932
|
+
const inlineBudget = Math.min(MAX_PREAMBLE_CHARS, budgets.inlineContextBudgetChars);
|
|
2933
|
+
const { taskPlan: taskPlanInline, slicePlan: slicePlanExcerpt, templates: contractedTemplates } =
|
|
2934
|
+
capExecuteTaskInlineBlocks(rawTaskPlanInline, rawSlicePlanExcerpt, rawContractedTemplates, inlineBudget);
|
|
2935
|
+
const inlineDropped = (rawTaskPlanInline.length + rawSlicePlanExcerpt.length + rawContractedTemplates.length)
|
|
2936
|
+
- (taskPlanInline.length + slicePlanExcerpt.length + contractedTemplates.length);
|
|
2937
|
+
trackPromptContext(
|
|
2938
|
+
contextTelemetry,
|
|
2939
|
+
"inline-cap",
|
|
2940
|
+
inlineDropped > 0 ? "excerpt" : "skipped",
|
|
2941
|
+
null,
|
|
2942
|
+
inlineDropped > 0 ? `dropped ${inlineDropped} chars (budget ${inlineBudget})` : "within budget",
|
|
2943
|
+
);
|
|
2849
2944
|
const onDemandResult = renderExecuteTaskOnDemandContext(base, mid, sid, contractedContext.onDemand);
|
|
2850
2945
|
const onDemandContext = onDemandResult.text;
|
|
2851
2946
|
trackPromptContext(
|
|
@@ -2941,12 +3036,14 @@ export async function buildCompleteSlicePrompt(
|
|
|
2941
3036
|
trackPromptContext(contextTelemetry, "prior-task-summaries", "skipped", null, "missing tasks dir");
|
|
2942
3037
|
return null;
|
|
2943
3038
|
}
|
|
2944
|
-
const summaryFiles = resolveTaskFiles(loc.dir, "SUMMARY")
|
|
3039
|
+
const summaryFiles = resolveTaskFiles(loc.dir, "SUMMARY")
|
|
3040
|
+
.filter((file) => summaryFileBelongsToSlice(file, base, mid, sid))
|
|
3041
|
+
.sort();
|
|
2945
3042
|
const blocks: string[] = [];
|
|
2946
3043
|
for (const file of summaryFiles) {
|
|
2947
3044
|
const absPath = join(loc.dir, file);
|
|
2948
3045
|
const relPath = `${loc.relPrefix}/${file}`;
|
|
2949
|
-
const taskId = file.replace(/-SUMMARY\.md$/i, "");
|
|
3046
|
+
const taskId = taskIdFromTaskFileName(file, "SUMMARY") ?? file.replace(/-SUMMARY\.md$/i, "");
|
|
2950
3047
|
blocks.push(await buildTaskSummaryExcerpt(absPath, relPath, taskId));
|
|
2951
3048
|
}
|
|
2952
3049
|
const body = blocks.length > 0 ? blocks.join("\n\n---\n\n") : null;
|
|
@@ -3559,7 +3656,9 @@ export async function buildReplanSlicePrompt(
|
|
|
3559
3656
|
let blockerTaskId = "";
|
|
3560
3657
|
const summaryLoc = resolveTaskSummariesLocation(base, mid, sid);
|
|
3561
3658
|
if (summaryLoc) {
|
|
3562
|
-
const summaryFiles = resolveTaskFiles(summaryLoc.dir, "SUMMARY")
|
|
3659
|
+
const summaryFiles = resolveTaskFiles(summaryLoc.dir, "SUMMARY")
|
|
3660
|
+
.filter((file) => summaryFileBelongsToSlice(file, base, mid, sid))
|
|
3661
|
+
.sort();
|
|
3563
3662
|
for (const file of summaryFiles) {
|
|
3564
3663
|
const absPath = join(summaryLoc.dir, file);
|
|
3565
3664
|
const content = await loadFile(absPath);
|
|
@@ -3567,7 +3666,7 @@ export async function buildReplanSlicePrompt(
|
|
|
3567
3666
|
const summary = parseSummary(content);
|
|
3568
3667
|
const relPath = `${summaryLoc.relPrefix}/${file}`;
|
|
3569
3668
|
if (summary.frontmatter.blocker_discovered) {
|
|
3570
|
-
blockerTaskId = summary.frontmatter.id || file.replace(/-SUMMARY\.md$/i, "");
|
|
3669
|
+
blockerTaskId = summary.frontmatter.id || taskIdFromTaskFileName(file, "SUMMARY") || file.replace(/-SUMMARY\.md$/i, "");
|
|
3571
3670
|
inlined.push(await buildTaskSummaryExcerpt(absPath, relPath, blockerTaskId, { blocker: true }));
|
|
3572
3671
|
}
|
|
3573
3672
|
}
|
|
@@ -39,8 +39,7 @@ import { isClosedStatus, isInactiveStatus } from "./status-guards.js";
|
|
|
39
39
|
import {
|
|
40
40
|
resolveSlicePath,
|
|
41
41
|
resolveSliceFile,
|
|
42
|
-
|
|
43
|
-
resolveTaskFiles,
|
|
42
|
+
resolveTaskFile,
|
|
44
43
|
relMilestoneFile,
|
|
45
44
|
relSliceFile,
|
|
46
45
|
buildSliceFileName,
|
|
@@ -324,13 +323,16 @@ export function writeReactiveExecuteBlocker(
|
|
|
324
323
|
const slicePath = resolveSlicePath(base, mid, sid);
|
|
325
324
|
if (!slicePath) return null;
|
|
326
325
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
)
|
|
326
|
+
// Resolve each batch task's SUMMARY with slice-qualified paths so flat-phase
|
|
327
|
+
// slices that reuse a task id (e.g. two T03s in one phase) don't collide: a
|
|
328
|
+
// sibling slice's summary must never make this slice's task look complete.
|
|
329
|
+
const hasSummary = (tid: string): boolean => {
|
|
330
|
+
const summaryPath = resolveTaskFile(base, mid, sid, tid, "SUMMARY");
|
|
331
|
+
return summaryPath !== null && existsSync(summaryPath);
|
|
332
|
+
};
|
|
331
333
|
|
|
332
|
-
const summaryPresent = batchIds.filter((tid) =>
|
|
333
|
-
const summaryMissing = batchIds.filter((tid) => !
|
|
334
|
+
const summaryPresent = batchIds.filter((tid) => hasSummary(tid));
|
|
335
|
+
const summaryMissing = batchIds.filter((tid) => !hasSummary(tid));
|
|
334
336
|
const completedTaskIds: string[] = [];
|
|
335
337
|
const skippedTaskIds: string[] = [];
|
|
336
338
|
const unchangedTaskIds: string[] = [];
|
|
@@ -3,11 +3,10 @@ import { AutoSession } from "./auto/session.js";
|
|
|
3
3
|
import type { CurrentUnit } from "./auto/session.js";
|
|
4
4
|
import type { SourceObservationStore } from "./source-observations.js";
|
|
5
5
|
import {
|
|
6
|
-
isDeterministicPolicyError,
|
|
7
|
-
isQueuedUserMessageSkip,
|
|
8
|
-
isToolInvocationError,
|
|
9
6
|
markToolEnd as markTrackedToolEnd,
|
|
10
7
|
markToolStart as markTrackedToolStart,
|
|
8
|
+
shouldClearToolInvocationErrorAfterSuccess,
|
|
9
|
+
updateToolInvocationError,
|
|
11
10
|
} from "./auto-tool-tracking.js";
|
|
12
11
|
// Re-exported as a pure pass-through. Must stay UNGATED (no autoSession.active
|
|
13
12
|
// argument, unlike markToolStart at the bottom of this file) so it is true in
|
|
@@ -99,13 +98,19 @@ export function markToolEnd(toolCallId: string): void {
|
|
|
99
98
|
|
|
100
99
|
export function recordToolInvocationError(toolName: string, errorMsg: string): void {
|
|
101
100
|
if (!autoSession.active) return;
|
|
102
|
-
|
|
103
|
-
autoSession.lastToolInvocationError
|
|
104
|
-
|
|
101
|
+
autoSession.lastToolInvocationError = updateToolInvocationError(
|
|
102
|
+
autoSession.lastToolInvocationError,
|
|
103
|
+
toolName,
|
|
104
|
+
errorMsg,
|
|
105
|
+
);
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
export function clearToolInvocationError(): void {
|
|
108
|
+
export function clearToolInvocationError(successfulToolName?: string): void {
|
|
108
109
|
if (!autoSession.active) return;
|
|
110
|
+
if (!shouldClearToolInvocationErrorAfterSuccess(
|
|
111
|
+
autoSession.lastToolInvocationError,
|
|
112
|
+
successfulToolName,
|
|
113
|
+
)) return;
|
|
109
114
|
autoSession.lastToolInvocationError = null;
|
|
110
115
|
}
|
|
111
116
|
|
|
@@ -88,6 +88,7 @@ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.
|
|
|
88
88
|
import { extractVerdict } from "./verdict-parser.js";
|
|
89
89
|
import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
|
|
90
90
|
import { parseProject } from "./schemas/parsers.js";
|
|
91
|
+
import { LAYOUT_SEGMENTS } from "./layout-policy.js";
|
|
91
92
|
|
|
92
93
|
import {
|
|
93
94
|
debugLog,
|
|
@@ -152,6 +153,33 @@ export function hasGitIndexLockForTest(basePath: string): boolean {
|
|
|
152
153
|
return existsSync(join(basePath, ".git", "index.lock"));
|
|
153
154
|
}
|
|
154
155
|
|
|
156
|
+
function isEmptyDirectory(dirPath: string): boolean {
|
|
157
|
+
try {
|
|
158
|
+
return existsSync(dirPath) && readdirSync(dirPath).length === 0;
|
|
159
|
+
} catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function reconcileFlatPhaseBootstrapLayout(basePath: string): boolean {
|
|
165
|
+
const gsdDir = join(basePath, ".gsd");
|
|
166
|
+
const phasesPath = join(gsdDir, LAYOUT_SEGMENTS.level1);
|
|
167
|
+
const milestonesPath = join(gsdDir, "milestones");
|
|
168
|
+
|
|
169
|
+
if (isEmptyDirectory(milestonesPath)) {
|
|
170
|
+
if (!existsSync(phasesPath)) mkdirSync(phasesPath, { recursive: true });
|
|
171
|
+
rmSync(milestonesPath, { recursive: true, force: true });
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!existsSync(phasesPath) && !existsSync(milestonesPath)) {
|
|
176
|
+
mkdirSync(phasesPath, { recursive: true });
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
155
183
|
export function _shouldAbortBootstrapForUnavailableDbForTest(
|
|
156
184
|
gsdDbPath: string,
|
|
157
185
|
dbAvailable: boolean,
|
|
@@ -1152,19 +1180,14 @@ export async function bootstrapAutoSession(
|
|
|
1152
1180
|
ensureGitignore(base, { manageGitignore });
|
|
1153
1181
|
if (manageGitignore !== false) untrackRuntimeFiles(base);
|
|
1154
1182
|
|
|
1155
|
-
// Bootstrap
|
|
1156
|
-
|
|
1157
|
-
// so checking .gsd/ existence would be dead code (#2942).
|
|
1158
|
-
const gsdDir = join(base, ".gsd");
|
|
1159
|
-
const milestonesPath = join(gsdDir, "milestones");
|
|
1160
|
-
if (!existsSync(milestonesPath)) {
|
|
1161
|
-
mkdirSync(milestonesPath, { recursive: true });
|
|
1183
|
+
// Bootstrap the flat-phase projection root and clean empty legacy scaffolds.
|
|
1184
|
+
if (reconcileFlatPhaseBootstrapLayout(base)) {
|
|
1162
1185
|
try {
|
|
1163
1186
|
nativeAddAll(base);
|
|
1164
1187
|
nativeCommit(base, "chore: init gsd");
|
|
1165
1188
|
} catch (err) {
|
|
1166
1189
|
/* nothing to commit */
|
|
1167
|
-
logWarning("engine", `
|
|
1190
|
+
logWarning("engine", `layout bootstrap commit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1168
1191
|
}
|
|
1169
1192
|
}
|
|
1170
1193
|
|
|
@@ -132,6 +132,8 @@ export function clearInFlightTools(): void {
|
|
|
132
132
|
*/
|
|
133
133
|
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Input validation error|Invalid arguments for tool|MCP error -32602|No such tool available|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON|does not provide an export named|Named export .* not found|Cannot find module|ERR_MODULE_NOT_FOUND|ERR_MODULE_NOT_EXPORTED|ERR_PACKAGE_PATH_NOT_EXPORTED/i;
|
|
134
134
|
const DETERMINISTIC_POLICY_ERROR_RE = /(?:^|\b)(?:HARD BLOCK:|Blocked: \/gsd queue is a planning tool|Direct writes to \.gsd\/STATE\.md and \.gsd\/gsd\.db are blocked|This is a mechanical gate)/i;
|
|
135
|
+
const SCHEDULE_WAKEUP_TOOL_NAME = "ScheduleWakeup";
|
|
136
|
+
const SCHEDULE_WAKEUP_CONTINUATION_ERROR = "`prompt` is required when `stop` is not true";
|
|
135
137
|
|
|
136
138
|
/**
|
|
137
139
|
* Matches the runtime's "tool not registered" error. Unlike the deterministic
|
|
@@ -151,6 +153,60 @@ export function isToolInvocationError(errorMsg: string): boolean {
|
|
|
151
153
|
return TOOL_INVOCATION_ERROR_RE.test(errorMsg) || isDeterministicPolicyError(errorMsg);
|
|
152
154
|
}
|
|
153
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Claude Code validates its native ScheduleWakeup tool outside GSD's schema.
|
|
158
|
+
* Keep this exact and tool-scoped so similarly worded business validation from
|
|
159
|
+
* unrelated tools does not pause auto-mode.
|
|
160
|
+
*/
|
|
161
|
+
export function isScheduleWakeupContinuationError(toolName: string, errorMsg: string): boolean {
|
|
162
|
+
return stripMcpToolPrefix(toolName) === SCHEDULE_WAKEUP_TOOL_NAME
|
|
163
|
+
&& errorMsg.trim() === SCHEDULE_WAKEUP_CONTINUATION_ERROR;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function shouldRecordToolInvocationError(toolName: string, errorMsg: string): boolean {
|
|
167
|
+
return isScheduleWakeupContinuationError(toolName, errorMsg)
|
|
168
|
+
|| isToolInvocationError(errorMsg)
|
|
169
|
+
|| isQueuedUserMessageSkip(errorMsg);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function isRecordedScheduleWakeupContinuationError(recordedError: string | null): boolean {
|
|
173
|
+
if (!recordedError) return false;
|
|
174
|
+
|
|
175
|
+
const separator = recordedError.indexOf(": ");
|
|
176
|
+
return separator >= 0 && isScheduleWakeupContinuationError(
|
|
177
|
+
recordedError.slice(0, separator),
|
|
178
|
+
recordedError.slice(separator + 2),
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function updateToolInvocationError(
|
|
183
|
+
recordedError: string | null,
|
|
184
|
+
toolName: string,
|
|
185
|
+
errorMsg: string,
|
|
186
|
+
): string | null {
|
|
187
|
+
if (!shouldRecordToolInvocationError(toolName, errorMsg)) return recordedError;
|
|
188
|
+
if (
|
|
189
|
+
isRecordedScheduleWakeupContinuationError(recordedError)
|
|
190
|
+
&& !isScheduleWakeupContinuationError(toolName, errorMsg)
|
|
191
|
+
) return recordedError;
|
|
192
|
+
|
|
193
|
+
return `${toolName}: ${errorMsg}`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* A failed continuation must survive successful diagnostic/read calls in the
|
|
198
|
+
* same turn. Only a later successful ScheduleWakeup proves the continuation
|
|
199
|
+
* was armed; all other invocation errors retain their existing clear-on-success
|
|
200
|
+
* behavior.
|
|
201
|
+
*/
|
|
202
|
+
export function shouldClearToolInvocationErrorAfterSuccess(
|
|
203
|
+
recordedError: string | null,
|
|
204
|
+
successfulToolName?: string,
|
|
205
|
+
): boolean {
|
|
206
|
+
return !isRecordedScheduleWakeupContinuationError(recordedError)
|
|
207
|
+
|| stripMcpToolPrefix(successfulToolName ?? "") === SCHEDULE_WAKEUP_TOOL_NAME;
|
|
208
|
+
}
|
|
209
|
+
|
|
154
210
|
/**
|
|
155
211
|
* Returns true if the error message indicates the called tool was not on the
|
|
156
212
|
* session's tool surface (MCP startup race — see TOOL_UNAVAILABLE_ERROR_RE).
|
|
@@ -10,6 +10,7 @@ import { existsSync, realpathSync, unlinkSync } from "node:fs";
|
|
|
10
10
|
import { isAbsolute, join, relative } from "node:path";
|
|
11
11
|
|
|
12
12
|
import { gsdRoot } from "./paths.js";
|
|
13
|
+
import { milestoneMetaPath } from "./git-service.js";
|
|
13
14
|
import { logWarning } from "./workflow-logger.js";
|
|
14
15
|
|
|
15
16
|
function isSamePath(a: string, b: string): boolean {
|
|
@@ -93,6 +94,9 @@ export function clearProjectRootStateFiles(
|
|
|
93
94
|
// worth removing on teardown.
|
|
94
95
|
const transientFiles = [
|
|
95
96
|
join(gsdDir, "STATE.md"),
|
|
97
|
+
// Integration-branch META now lives flat at .gsd/<MID>-META.json (ADR-045).
|
|
98
|
+
milestoneMetaPath(basePath, milestoneId),
|
|
99
|
+
// Legacy location — still cleaned for pre-migration trees.
|
|
96
100
|
join(gsdDir, "milestones", milestoneId, `${milestoneId}-META.json`),
|
|
97
101
|
];
|
|
98
102
|
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
_isSamePath as isSamePath,
|
|
17
17
|
_shouldReconcileWorktreeDb,
|
|
18
18
|
} from "./auto-worktree-cleanup.js";
|
|
19
|
-
import { resolveGsdPathContract } from "./paths.js";
|
|
19
|
+
import { dirIsContentBearingLegacyMilestone, resolveGsdPathContract } from "./paths.js";
|
|
20
20
|
import type { MilestoneScope } from "./workspace.js";
|
|
21
21
|
import { WorktreeStateProjection } from "./worktree-state-projection.js";
|
|
22
22
|
import { logWarning } from "./workflow-logger.js";
|
|
@@ -211,10 +211,17 @@ function syncMilestoneLayout(
|
|
|
211
211
|
if (!existsSync(mainMilestonesDir)) return;
|
|
212
212
|
|
|
213
213
|
try {
|
|
214
|
-
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
215
214
|
const mainMilestones = readdirSync(mainMilestonesDir, { withFileTypes: true })
|
|
216
215
|
.filter((entry) => entry.isDirectory())
|
|
217
|
-
.map((entry) => entry.name)
|
|
216
|
+
.map((entry) => entry.name)
|
|
217
|
+
.filter((name) =>
|
|
218
|
+
layoutSegment !== "milestones" ||
|
|
219
|
+
dirIsContentBearingLegacyMilestone(join(mainMilestonesDir, name)),
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
if (mainMilestones.length === 0) return;
|
|
223
|
+
|
|
224
|
+
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
218
225
|
|
|
219
226
|
for (const milestoneId of mainMilestones) {
|
|
220
227
|
syncMilestoneDirectory(
|
|
@@ -65,7 +65,7 @@ export function teardownAutoWorktree(
|
|
|
65
65
|
|
|
66
66
|
// Mirror cleanup steps from mergeMilestoneToMain abort path:
|
|
67
67
|
|
|
68
|
-
// 1. Remove transient state files (STATE.md, auto.lock, {MID}-META.json).
|
|
68
|
+
// 1. Remove transient state files (STATE.md, auto.lock, .gsd/{MID}-META.json).
|
|
69
69
|
// Non-fatal — must not block teardown.
|
|
70
70
|
try {
|
|
71
71
|
clearProjectRootStateFiles(originalBasePath, milestoneId);
|
|
@@ -110,9 +110,7 @@ import {
|
|
|
110
110
|
getOldestInFlightToolStart,
|
|
111
111
|
hasInteractiveToolInFlight,
|
|
112
112
|
clearInFlightTools,
|
|
113
|
-
|
|
114
|
-
isQueuedUserMessageSkip,
|
|
115
|
-
isDeterministicPolicyError,
|
|
113
|
+
updateToolInvocationError,
|
|
116
114
|
} from "./auto-tool-tracking.js";
|
|
117
115
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
118
116
|
import { recoverTimedOutUnit } from "./auto-timeout-recovery.js";
|
|
@@ -1001,14 +999,17 @@ export function markToolEnd(toolCallId: string): void {
|
|
|
1001
999
|
* Called from tool_execution_end when a GSD tool fails with isError.
|
|
1002
1000
|
* Stores the error if it matches:
|
|
1003
1001
|
* - tool-invocation-error pattern (malformed/truncated JSON)
|
|
1002
|
+
* - failed ScheduleWakeup continuation validation (#1379)
|
|
1004
1003
|
* - queued-user-message skip pattern
|
|
1005
1004
|
* - deterministic policy rejection (#4973, e.g. context_write_blocked)
|
|
1006
1005
|
*/
|
|
1007
1006
|
export function recordToolInvocationError(toolName: string, errorMsg: string): void {
|
|
1008
1007
|
if (!s.active) return;
|
|
1009
|
-
|
|
1010
|
-
s.lastToolInvocationError
|
|
1011
|
-
|
|
1008
|
+
s.lastToolInvocationError = updateToolInvocationError(
|
|
1009
|
+
s.lastToolInvocationError,
|
|
1010
|
+
toolName,
|
|
1011
|
+
errorMsg,
|
|
1012
|
+
);
|
|
1012
1013
|
}
|
|
1013
1014
|
|
|
1014
1015
|
export function getOldestInFlightToolAgeMs(): number {
|
|
@@ -3162,7 +3163,19 @@ export async function dispatchHookUnit(
|
|
|
3162
3163
|
workspaceRoot: s.basePath,
|
|
3163
3164
|
});
|
|
3164
3165
|
|
|
3165
|
-
const
|
|
3166
|
+
const cmdCtx = s.cmdCtx;
|
|
3167
|
+
if (typeof cmdCtx?.newSession !== "function") {
|
|
3168
|
+
const message = "Auto-mode has no command context for dispatch.";
|
|
3169
|
+
ctx.ui.notify(message, "error");
|
|
3170
|
+
const unitToCommit = previousCurrentUnit ?? s.currentUnit;
|
|
3171
|
+
if (unitToCommit) {
|
|
3172
|
+
await autoCommitUnit(s.basePath, unitToCommit.type, unitToCommit.id, ctx);
|
|
3173
|
+
}
|
|
3174
|
+
await stopAuto(ctx, pi, message, { preserveWorktree: true });
|
|
3175
|
+
return false;
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
const result = await cmdCtx.newSession({ workspaceRoot: s.basePath });
|
|
3166
3179
|
if (result.cancelled) {
|
|
3167
3180
|
await stopAuto(ctx, pi);
|
|
3168
3181
|
return false;
|
|
@@ -58,6 +58,7 @@ function registerAlias(pi: ExtensionAPI, toolDef: any, aliasName: string, canoni
|
|
|
58
58
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- toolDef shape matches ToolDefinition but varies by schema
|
|
59
59
|
function registerWorkflowTool(pi: ExtensionAPI, toolDef: any): void {
|
|
60
60
|
pi.registerTool(toolDef);
|
|
61
|
+
if (process.env.GSD_ADVERTISE_TOOL_ALIASES !== "1") return; // canonical-only model surface (see plan 035)
|
|
61
62
|
for (const alias of aliasesForWorkflowTool(toolDef.name)) {
|
|
62
63
|
registerAlias(pi, toolDef, alias, toolDef.name);
|
|
63
64
|
}
|