gsd-pi 2.80.0-dev.c5c38454b → 2.80.0-dev.cf9433f56
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 +4 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +66 -45
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +124 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
- package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
- package/dist/resources/extensions/gsd/auto.js +77 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +21 -2
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
- package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
- package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
- package/dist/resources/extensions/gsd/context-budget.js +37 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
- package/dist/resources/extensions/gsd/detection.js +106 -0
- package/dist/resources/extensions/gsd/git-service.js +36 -4
- package/dist/resources/extensions/gsd/gsd-db.js +46 -13
- package/dist/resources/extensions/gsd/guided-flow.js +80 -14
- package/dist/resources/extensions/gsd/memory-store.js +69 -12
- package/dist/resources/extensions/gsd/migrate/command.js +40 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +7 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
- package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
- package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
- package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
- package/dist/resources/extensions/gsd/worktree-resolver.js +33 -17
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +3 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -17
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
- package/packages/mcp-server/src/workflow-tools.ts +30 -16
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +15 -5
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +8 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +38 -0
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
- package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +3 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +24 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +18 -8
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +20 -8
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +50 -8
- package/src/resources/extensions/gsd/auto/phases.ts +77 -48
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +18 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
- package/src/resources/extensions/gsd/auto-prompts.ts +133 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
- package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
- package/src/resources/extensions/gsd/auto.ts +92 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
- package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
- package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
- package/src/resources/extensions/gsd/context-budget.ts +44 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
- package/src/resources/extensions/gsd/detection.ts +128 -0
- package/src/resources/extensions/gsd/git-service.ts +46 -8
- package/src/resources/extensions/gsd/gsd-db.ts +50 -13
- package/src/resources/extensions/gsd/guided-flow.ts +96 -14
- package/src/resources/extensions/gsd/memory-store.ts +77 -12
- package/src/resources/extensions/gsd/migrate/command.ts +47 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +7 -0
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +72 -1
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
- package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +63 -1
- package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
- package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
- package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
- package/src/resources/extensions/gsd/worktree-resolver.ts +36 -15
- /package/dist/web/standalone/.next/static/{TCSim36ZpcPu2WgeoC45g → -5nHJWzSdG-WkPMul_khA}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{TCSim36ZpcPu2WgeoC45g → -5nHJWzSdG-WkPMul_khA}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -259,6 +259,7 @@ Full documentation is in the [`docs/`](./docs/) directory:
|
|
|
259
259
|
|
|
260
260
|
- **[Architecture](./docs/dev/architecture.md)** — system design and dispatch pipeline
|
|
261
261
|
- **[CI/CD Pipeline](./docs/dev/ci-cd-pipeline.md)** — three-stage promotion pipeline (Dev → Test → Prod)
|
|
262
|
+
- **[E2E Testing](./tests/e2e/README.md)** — real-process CLI/runtime coverage and CI runner expectations
|
|
262
263
|
- **[Pipeline Simplification (ADR-003)](./docs/dev/ADR-003-pipeline-simplification.md)** — merged research into planning, mechanical completion
|
|
263
264
|
- **[VS Code Extension](./vscode-extension/README.md)** — chat participant, sidebar dashboard, RPC integration
|
|
264
265
|
|
|
@@ -361,7 +362,7 @@ The database is authoritative for milestones, slices, tasks, requirements, decis
|
|
|
361
362
|
|
|
362
363
|
2. **Context pre-loading** — The dispatch prompt includes inlined task plans, slice plans, prior task summaries, dependency summaries, roadmap excerpts, and decisions register. The LLM starts with everything it needs instead of spending tool calls reading files.
|
|
363
364
|
|
|
364
|
-
3. **Context Mode** — Context Mode is enabled by default and gives
|
|
365
|
+
3. **Context Mode** — Context Mode is enabled by default and gives eligible auto-mode units guidance for preserving context. Agents are steered toward `gsd_exec` for noisy scans, builds, tests, and diagnostics; capped stdout/stderr and metadata are saved under `.gsd/exec/` while only a short digest enters the conversation. `gsd_exec_search` lets agents reuse prior runs instead of repeating expensive checks, and `gsd_resume` reads a prior compaction snapshot from `.gsd/last-snapshot.md` when one exists. Opt out with `context_mode.enabled: false` to disable Context Mode guidance, snapshot injection, `gsd_exec`, `gsd_exec_search`, and `gsd_resume`; tune sandbox timeout/output caps and environment forwarding with `context_mode.exec_timeout_ms`, `context_mode.exec_stdout_cap_bytes`, `context_mode.exec_digest_chars`, and `context_mode.exec_env_allowlist`.
|
|
365
366
|
|
|
366
367
|
4. **Git isolation** — When `git.isolation` is set to `worktree` or `branch`, each milestone runs on its own `milestone/<MID>` branch (in a worktree or in-place). All slice work commits sequentially — no branch switching, no merge conflicts. When the milestone completes, it's squash-merged to main as one clean commit. The default is `none` (work on the current branch), configurable via preferences. If `worktree` is configured in a repo with no committed `HEAD`, GSD temporarily behaves as `none` until the first commit exists because git worktrees need a committed start point.
|
|
367
368
|
|
|
@@ -659,10 +660,11 @@ auto_report: true
|
|
|
659
660
|
| `unique_milestone_ids` | Uses unique milestone names to avoid clashes when working in teams of people |
|
|
660
661
|
| `git.isolation` | `none` (default), `worktree`, or `branch` — enable worktree or branch isolation for milestone work. `worktree` requires a committed `HEAD`; zero-commit repos temporarily run as `none` |
|
|
661
662
|
| `git.manage_gitignore` | Set `false` to prevent GSD from modifying `.gitignore` |
|
|
662
|
-
| `context_mode.enabled` | Context Mode is default-on; set `false` to disable `gsd_exec`,
|
|
663
|
+
| `context_mode.enabled` | Context Mode is default-on; set `false` to disable prompt guidance, snapshot injection, `gsd_exec`, `gsd_exec_search`, and `gsd_resume` |
|
|
663
664
|
| `context_mode.exec_timeout_ms` | Timeout for sandboxed `gsd_exec` runs (default: 30000) |
|
|
664
665
|
| `context_mode.exec_stdout_cap_bytes` | Persisted stdout cap for `gsd_exec` output (default: 1048576) |
|
|
665
666
|
| `context_mode.exec_digest_chars` | Trailing stdout characters returned to the agent context (default: 300) |
|
|
667
|
+
| `context_mode.exec_env_allowlist` | Environment variables forwarded to sandboxed `gsd_exec` runs in addition to `PATH` and `HOME` |
|
|
666
668
|
| `verification_commands` | Array of shell commands to run after task execution (e.g., `["npm run lint", "npm run test"]`) |
|
|
667
669
|
| `verification_auto_fix` | Auto-retry on verification failures (default: true) |
|
|
668
670
|
| `verification_max_retries` | Max retries for verification failures (default: 2) |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
9ae4402464ddbafa
|
|
@@ -28,7 +28,7 @@ Then do the thing `STATE.md` says to do next.
|
|
|
28
28
|
## The Hierarchy
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
Milestone → a shippable version (
|
|
31
|
+
Milestone → a shippable version (1-10 slices, sized to the work)
|
|
32
32
|
Slice → one demoable vertical capability (1-7 tasks)
|
|
33
33
|
Task → one context-window-sized unit of work (fits in one session)
|
|
34
34
|
```
|
|
@@ -331,7 +331,7 @@ The **Don't Hand-Roll** and **Common Pitfalls** sections prevent the most expens
|
|
|
331
331
|
|
|
332
332
|
**For a milestone (roadmap):**
|
|
333
333
|
1. Read `M###-CONTEXT.md`, `M###-RESEARCH.md`, and `.gsd/DECISIONS.md` if they exist.
|
|
334
|
-
2. Decompose the vision into
|
|
334
|
+
2. Decompose the vision into 1-10 demoable vertical slices. Prefer one slice for tiny, single-file, or static work unless the request clearly spans independent capabilities.
|
|
335
335
|
3. Order by risk (high-risk first to validate feasibility early).
|
|
336
336
|
4. Write `M###-ROADMAP.md` with checkboxes, risk levels, dependencies, demo sentences.
|
|
337
337
|
5. **Write the boundary map** — for each slice, specify what it produces (functions, types, interfaces, endpoints) and what it consumes from upstream slices. This forces interface thinking before implementation and enables deterministic verification that slices actually connect.
|
|
@@ -25,6 +25,8 @@ import { normalizeRealPath } from "../paths.js";
|
|
|
25
25
|
import { decideCooldownRecovery, decideDispatchClaim, decideEngineDispatch, decideFinalizeResult, decideInfrastructureError, decideIterationErrorRecovery, decideMemoryPressure, decideModelPolicyBlocked, decideMinRequestInterval, decideWorkflowLoop, formatDispatchExceptionSummary, formatUnhandledDispatchErrorSummary, resolveUnitRequestTimestamp, shouldUseCustomEnginePath, } from "./workflow-kernel.js";
|
|
26
26
|
import { hydrateCustomVerifyRetryCounts, saveCustomVerifyRetryCounts, } from "./custom-verify-retry-store.js";
|
|
27
27
|
import { settleDispatchCompleted, settleDispatchFailed, } from "./workflow-dispatch-ledger.js";
|
|
28
|
+
import { emitOpenUnitEndForUnit } from "../crash-recovery.js";
|
|
29
|
+
import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
28
30
|
import { openDispatchClaim } from "./workflow-dispatch-claim.js";
|
|
29
31
|
import { completeWorkflowIteration } from "./workflow-iteration-completion.js";
|
|
30
32
|
import { createWorkflowJournalReporter } from "./workflow-journal-reporter.js";
|
|
@@ -133,6 +135,24 @@ async function enforceMinRequestInterval(s, prefs) {
|
|
|
133
135
|
await new Promise(r => setTimeout(r, decision.waitMs));
|
|
134
136
|
}
|
|
135
137
|
}
|
|
138
|
+
function closeOutCrashedUnit(s, iterData, err) {
|
|
139
|
+
const summary = formatDispatchExceptionSummary({ error: err });
|
|
140
|
+
try {
|
|
141
|
+
emitOpenUnitEndForUnit(s.basePath, iterData.unitType, iterData.unitId, "cancelled", {
|
|
142
|
+
message: summary,
|
|
143
|
+
category: "unit-exception",
|
|
144
|
+
isTransient: false,
|
|
145
|
+
});
|
|
146
|
+
writeUnitRuntimeRecord(s.basePath, iterData.unitType, iterData.unitId, s.currentUnit?.startedAt ?? Date.now(), {
|
|
147
|
+
phase: "crashed",
|
|
148
|
+
lastProgressAt: Date.now(),
|
|
149
|
+
lastProgressKind: "unit-exception",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch (closeoutErr) {
|
|
153
|
+
logWarning("dispatch", `unit crash closeout failed: ${closeoutErr instanceof Error ? closeoutErr.message : String(closeoutErr)}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
136
156
|
/**
|
|
137
157
|
* Main auto-mode execution loop. Iterates: derive → dispatch → guards →
|
|
138
158
|
* runUnit → finalize → repeat. Exits when s.active becomes false or a
|
|
@@ -392,7 +412,17 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
392
412
|
}
|
|
393
413
|
// ── Unit execution (shared with dev path) ──
|
|
394
414
|
await enforceMinRequestInterval(s, prefs);
|
|
395
|
-
|
|
415
|
+
let unitPhaseResult;
|
|
416
|
+
try {
|
|
417
|
+
unitPhaseResult = await runUnitPhaseViaContract(dispatchContract, ic, iterData, loopState, undefined, unitDispatchDeps);
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
if (err instanceof ModelPolicyDispatchBlockedError) {
|
|
421
|
+
throw err;
|
|
422
|
+
}
|
|
423
|
+
closeOutCrashedUnit(s, iterData, err);
|
|
424
|
+
throw err;
|
|
425
|
+
}
|
|
396
426
|
if (unitPhaseResult.action === "next") {
|
|
397
427
|
const requestTimestamp = resolveUnitRequestTimestamp(unitPhaseResult.data);
|
|
398
428
|
if (requestTimestamp !== undefined)
|
|
@@ -580,6 +610,7 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
580
610
|
if (err instanceof ModelPolicyDispatchBlockedError) {
|
|
581
611
|
throw err;
|
|
582
612
|
}
|
|
613
|
+
closeOutCrashedUnit(s, iterData, err);
|
|
583
614
|
dispatchSettled = settleDispatchFailed(dispatchId, formatDispatchExceptionSummary({ error: err }), {
|
|
584
615
|
markFailed: markDispatchFailed,
|
|
585
616
|
logWriteFailure: logDispatchLedgerWriteFailure,
|
|
@@ -13,22 +13,22 @@ import { detectStuck } from "./detect-stuck.js";
|
|
|
13
13
|
import { runUnit } from "./run-unit.js";
|
|
14
14
|
import { debugLog } from "../debug-logger.js";
|
|
15
15
|
import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare } from "../worktree-root.js";
|
|
16
|
-
import {
|
|
16
|
+
import { classifyProject } from "../detection.js";
|
|
17
17
|
import { MergeConflictError } from "../git-service.js";
|
|
18
18
|
import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
|
|
19
19
|
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
20
20
|
import { resumeAutoAfterProviderDelay } from "../bootstrap/provider-error-resume.js";
|
|
21
21
|
import { join, basename } from "node:path";
|
|
22
|
-
import { existsSync, cpSync
|
|
22
|
+
import { existsSync, cpSync } from "node:fs";
|
|
23
23
|
import { logWarning, logError, _resetLogs, drainLogs, drainAndSummarize, formatForNotification, hasAnyIssues, } from "../workflow-logger.js";
|
|
24
24
|
import { gsdRoot } from "../paths.js";
|
|
25
25
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
26
|
-
import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps } from "../auto-recovery.js";
|
|
26
|
+
import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps, refreshRecoveryDbForArtifact } from "../auto-recovery.js";
|
|
27
27
|
import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
28
28
|
import { withTimeout, FINALIZE_PRE_TIMEOUT_MS, FINALIZE_POST_TIMEOUT_MS } from "./finalize-timeout.js";
|
|
29
29
|
import { getEligibleSlices } from "../slice-parallel-eligibility.js";
|
|
30
30
|
import { startSliceParallel } from "../slice-parallel-orchestrator.js";
|
|
31
|
-
import { isDbAvailable, getMilestoneSlices
|
|
31
|
+
import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
|
|
32
32
|
import { ensurePlanV2Graph, isEmptyPlanV2GraphResult, isMissingFinalizedContextResult } from "../uok/plan-v2.js";
|
|
33
33
|
import { resolveUokFlags } from "../uok/flags.js";
|
|
34
34
|
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
@@ -42,13 +42,6 @@ import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit,
|
|
|
42
42
|
function isSamePathLocal(a, b) {
|
|
43
43
|
return normalizeWorktreePathForCompare(a) === normalizeWorktreePathForCompare(b);
|
|
44
44
|
}
|
|
45
|
-
function refreshPlanSliceRecoveryDbIfNeeded(unitType) {
|
|
46
|
-
if (unitType !== "plan-slice")
|
|
47
|
-
return true;
|
|
48
|
-
if (!isDbAvailable())
|
|
49
|
-
return true;
|
|
50
|
-
return refreshOpenDatabaseFromDisk();
|
|
51
|
-
}
|
|
52
45
|
// ─── Session timeout auto-resume state ────────────────────────────────────────
|
|
53
46
|
let consecutiveSessionTimeouts = 0;
|
|
54
47
|
const MAX_SESSION_TIMEOUT_AUTO_RESUMES = 3;
|
|
@@ -498,7 +491,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
498
491
|
}
|
|
499
492
|
// #2909: postflight — restore stashed changes after successful merge
|
|
500
493
|
if (preflightTransition.stashPushed) {
|
|
501
|
-
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
494
|
+
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, preflightTransition.stashMarker, ctx.ui.notify.bind(ctx.ui));
|
|
502
495
|
}
|
|
503
496
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
504
497
|
deps.invalidateAllCaches();
|
|
@@ -574,7 +567,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
574
567
|
}
|
|
575
568
|
// #2909: postflight — restore stashed changes after successful merge
|
|
576
569
|
if (preflightAllComplete.stashPushed) {
|
|
577
|
-
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
570
|
+
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, preflightAllComplete.stashMarker, ctx.ui.notify.bind(ctx.ui));
|
|
578
571
|
}
|
|
579
572
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
580
573
|
}
|
|
@@ -660,7 +653,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
660
653
|
}
|
|
661
654
|
// #2909: postflight — restore stashed changes after successful merge
|
|
662
655
|
if (preflightComplete.stashPushed) {
|
|
663
|
-
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, ctx.ui.notify.bind(ctx.ui));
|
|
656
|
+
deps.postflightPopStash(s.originalBasePath || s.basePath, s.currentMilestoneId, preflightComplete.stashMarker, ctx.ui.notify.bind(ctx.ui));
|
|
664
657
|
}
|
|
665
658
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
666
659
|
}
|
|
@@ -795,11 +788,18 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
795
788
|
level: 1,
|
|
796
789
|
action: "artifact-found",
|
|
797
790
|
});
|
|
798
|
-
|
|
799
|
-
if (!
|
|
800
|
-
ctx.ui.notify(
|
|
791
|
+
const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
|
|
792
|
+
if (!recoveryDb.ok) {
|
|
793
|
+
ctx.ui.notify(recoveryDb.fatal
|
|
794
|
+
? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
|
|
795
|
+
: `${recoveryDb.message} Keeping stuck state for retry.`, "warning");
|
|
796
|
+
if (recoveryDb.fatal) {
|
|
797
|
+
await deps.pauseAuto(ctx, pi);
|
|
798
|
+
return { action: "break", reason: recoveryDb.reason };
|
|
799
|
+
}
|
|
801
800
|
return { action: "continue" };
|
|
802
801
|
}
|
|
802
|
+
ctx.ui.notify(`Stuck recovery: artifact for ${unitType} ${unitId} found on disk. Invalidating caches.`, "info");
|
|
803
803
|
deps.invalidateAllCaches();
|
|
804
804
|
loopState.recentUnits.length = 0;
|
|
805
805
|
loopState.stuckRecoveryAttempts = 0;
|
|
@@ -818,13 +818,20 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
818
818
|
level: 2,
|
|
819
819
|
action: "artifact-found",
|
|
820
820
|
});
|
|
821
|
-
|
|
822
|
-
if (
|
|
821
|
+
const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
|
|
822
|
+
if (recoveryDb.ok) {
|
|
823
|
+
ctx.ui.notify(`Stuck recovery: artifact for ${unitType} ${unitId} found on disk after cache invalidation. Continuing.`, "info");
|
|
823
824
|
loopState.recentUnits.length = 0;
|
|
824
825
|
loopState.stuckRecoveryAttempts = 0;
|
|
825
826
|
return { action: "continue" };
|
|
826
827
|
}
|
|
827
|
-
ctx.ui.notify(
|
|
828
|
+
ctx.ui.notify(recoveryDb.fatal
|
|
829
|
+
? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
|
|
830
|
+
: `${recoveryDb.message} Stopping for manual recovery.`, "warning");
|
|
831
|
+
if (recoveryDb.fatal) {
|
|
832
|
+
await deps.pauseAuto(ctx, pi);
|
|
833
|
+
return { action: "break", reason: recoveryDb.reason };
|
|
834
|
+
}
|
|
828
835
|
}
|
|
829
836
|
debugLog("autoLoop", {
|
|
830
837
|
phase: "stuck-detected",
|
|
@@ -1084,8 +1091,9 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1084
1091
|
// Verify the working directory is a valid git checkout with project
|
|
1085
1092
|
// files before dispatching work. A broken worktree causes agents to
|
|
1086
1093
|
// hallucinate summaries since they cannot read or write any files.
|
|
1087
|
-
// Uses
|
|
1088
|
-
//
|
|
1094
|
+
// Uses project classification so project presence is not conflated with
|
|
1095
|
+
// ecosystem marker detection. Static/minimal repos become untyped-existing.
|
|
1096
|
+
let projectClassification = null;
|
|
1089
1097
|
if (s.basePath && unitType === "execute-task") {
|
|
1090
1098
|
const gitMarker = join(s.basePath, ".git");
|
|
1091
1099
|
const hasGit = deps.existsSync(gitMarker);
|
|
@@ -1096,30 +1104,26 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1096
1104
|
await deps.stopAuto(ctx, pi, msg);
|
|
1097
1105
|
return { action: "break", reason: "worktree-invalid" };
|
|
1098
1106
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
+
projectClassification = classifyProject(s.basePath);
|
|
1108
|
+
if (projectClassification.kind === "invalid-repo") {
|
|
1109
|
+
const msg = `Worktree health check failed: ${s.basePath} classified as invalid-repo (${projectClassification.reason}) — refusing to dispatch ${unitType} ${unitId}`;
|
|
1110
|
+
debugLog("runUnitPhase", { phase: "worktree-health-invalid-repo", basePath: s.basePath, classification: projectClassification });
|
|
1111
|
+
if (projectClassification.reason === "missing .git" && hasGit) {
|
|
1112
|
+
ctx.ui.notify(`Warning: ${s.basePath} project classification could not confirm .git; assuming it has no project content yet — proceeding as greenfield project because worktree health reported .git present`, "warning");
|
|
1113
|
+
}
|
|
1114
|
+
else {
|
|
1115
|
+
ctx.ui.notify(msg, "error");
|
|
1116
|
+
await deps.stopAuto(ctx, pi, msg);
|
|
1117
|
+
return { action: "break", reason: "worktree-invalid" };
|
|
1118
|
+
}
|
|
1107
1119
|
}
|
|
1108
|
-
|
|
1109
|
-
debugLog("runUnitPhase", { phase: "
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
? hasProjectFileInAncestor(s.basePath, deps.existsSync)
|
|
1116
|
-
: false;
|
|
1117
|
-
if (!hasProjectFile && !hasSrcDir && !hasXcodeBundle && !hasProjectFileInParent) {
|
|
1118
|
-
// Greenfield projects won't have project files yet — the first task creates them.
|
|
1119
|
-
// Log a warning but allow execution to proceed. The .git check above is sufficient
|
|
1120
|
-
// to ensure we're in a valid working directory.
|
|
1121
|
-
debugLog("runUnitPhase", { phase: "worktree-health-warn-greenfield", basePath: s.basePath, hasProjectFile, hasSrcDir, hasXcodeBundle });
|
|
1122
|
-
ctx.ui.notify(`Warning: ${s.basePath} has no recognized project files — proceeding as greenfield project`, "warning");
|
|
1120
|
+
else if (projectClassification.kind === "greenfield") {
|
|
1121
|
+
debugLog("runUnitPhase", { phase: "worktree-health-greenfield", basePath: s.basePath, classification: projectClassification });
|
|
1122
|
+
ctx.ui.notify(`Warning: ${s.basePath} has no project content yet — proceeding as greenfield project`, "warning");
|
|
1123
|
+
}
|
|
1124
|
+
else if (projectClassification.kind === "untyped-existing") {
|
|
1125
|
+
debugLog("runUnitPhase", { phase: "worktree-health-untyped-existing", basePath: s.basePath, classification: projectClassification });
|
|
1126
|
+
ctx.ui.notify(`Notice: ${s.basePath} has existing project content but no recognized tooling markers — using generic file-level workflow guidance`, "info");
|
|
1123
1127
|
}
|
|
1124
1128
|
}
|
|
1125
1129
|
// Detect retry and capture previous tier for escalation
|
|
@@ -1182,6 +1186,16 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1182
1186
|
}
|
|
1183
1187
|
// Prompt injection
|
|
1184
1188
|
let finalPrompt = prompt;
|
|
1189
|
+
if (unitType === "execute-task") {
|
|
1190
|
+
projectClassification ??= classifyProject(s.basePath);
|
|
1191
|
+
if (projectClassification.kind === "untyped-existing") {
|
|
1192
|
+
const samples = projectClassification.contentFiles.slice(0, 8).join(", ") || "project files";
|
|
1193
|
+
finalPrompt +=
|
|
1194
|
+
"\n\n**Project classification:** Existing untyped project. No recognized build/tooling markers were detected, " +
|
|
1195
|
+
"so use generic file-level workflow guidance. Task plans and completion summaries must list every concrete " +
|
|
1196
|
+
`project file changed in \`files\` or \`expected_output\`. Detected content sample: ${samples}.`;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1185
1199
|
if (s.pendingVerificationRetry) {
|
|
1186
1200
|
const retryCtx = s.pendingVerificationRetry;
|
|
1187
1201
|
s.pendingVerificationRetry = null;
|
|
@@ -1665,6 +1679,13 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
1665
1679
|
}
|
|
1666
1680
|
// Both pre and post verification completed without timeout — reset counter
|
|
1667
1681
|
loopState.consecutiveFinalizeTimeouts = 0;
|
|
1682
|
+
if (preUnitSnapshot) {
|
|
1683
|
+
writeUnitRuntimeRecord(s.basePath, preUnitSnapshot.type, preUnitSnapshot.id, preUnitSnapshot.startedAt, {
|
|
1684
|
+
phase: "finalized",
|
|
1685
|
+
lastProgressAt: Date.now(),
|
|
1686
|
+
lastProgressKind: "finalize-success",
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1668
1689
|
s.currentUnit = null;
|
|
1669
1690
|
clearCurrentPhase();
|
|
1670
1691
|
// Surface accumulated workflow-logger issues for this unit to the user.
|
|
@@ -17,6 +17,7 @@ import { bumpTurnGeneration } from "./turn-epoch.js";
|
|
|
17
17
|
// scoped pendingResolve + pendingAgentEndQueue pattern.
|
|
18
18
|
let _currentResolve = null;
|
|
19
19
|
let _sessionSwitchInFlight = false;
|
|
20
|
+
let _pendingSwitchCancellation = null;
|
|
20
21
|
// ─── Setters (needed for cross-module mutation) ─────────────────────────────
|
|
21
22
|
export function _setCurrentResolve(fn) {
|
|
22
23
|
_currentResolve = fn;
|
|
@@ -27,6 +28,11 @@ export function _setSessionSwitchInFlight(v) {
|
|
|
27
28
|
export function _clearCurrentResolve() {
|
|
28
29
|
_currentResolve = null;
|
|
29
30
|
}
|
|
31
|
+
export function _consumePendingSwitchCancellation() {
|
|
32
|
+
const pending = _pendingSwitchCancellation;
|
|
33
|
+
_pendingSwitchCancellation = null;
|
|
34
|
+
return pending;
|
|
35
|
+
}
|
|
30
36
|
// ─── resolveAgentEnd ─────────────────────────────────────────────────────────
|
|
31
37
|
/**
|
|
32
38
|
* Called from the agent_end event handler in index.ts to resolve the
|
|
@@ -90,8 +96,18 @@ export function resolveAgentEndCancelled(errorContext) {
|
|
|
90
96
|
debugLog("resolveAgentEndCancelled", { status: "resolving-cancelled" });
|
|
91
97
|
const r = _currentResolve;
|
|
92
98
|
_currentResolve = null;
|
|
99
|
+
_pendingSwitchCancellation = null;
|
|
93
100
|
r({ status: "cancelled", ...(errorContext ? { errorContext } : {}) });
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
if (_sessionSwitchInFlight) {
|
|
104
|
+
bumpTurnGeneration(`cancelled-during-switch:${errorContext?.category ?? "unknown"}`);
|
|
105
|
+
_pendingSwitchCancellation = errorContext ? { errorContext } : {};
|
|
106
|
+
debugLog("resolveAgentEndCancelled", { status: "queued-during-switch" });
|
|
107
|
+
return false;
|
|
94
108
|
}
|
|
109
|
+
debugLog("resolveAgentEndCancelled", { status: "no-pending-resolve" });
|
|
110
|
+
return false;
|
|
95
111
|
}
|
|
96
112
|
// ─── resetPendingResolve (test helper) ───────────────────────────────────────
|
|
97
113
|
/**
|
|
@@ -101,6 +117,7 @@ export function resolveAgentEndCancelled(errorContext) {
|
|
|
101
117
|
export function _resetPendingResolve() {
|
|
102
118
|
_currentResolve = null;
|
|
103
119
|
_sessionSwitchInFlight = false;
|
|
120
|
+
_pendingSwitchCancellation = null;
|
|
104
121
|
}
|
|
105
122
|
export function _hasPendingResolveForTest() {
|
|
106
123
|
return _currentResolve !== null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// GSD-2 + src/resources/extensions/gsd/auto/run-unit.ts - Runs one GSD auto-mode unit from session creation through agent completion.
|
|
2
2
|
import { NEW_SESSION_TIMEOUT_MS } from "./session.js";
|
|
3
|
-
import { _clearCurrentResolve, _setCurrentResolve, _setSessionSwitchInFlight } from "./resolve.js";
|
|
3
|
+
import { _clearCurrentResolve, _consumePendingSwitchCancellation, _setCurrentResolve, _setSessionSwitchInFlight, } from "./resolve.js";
|
|
4
4
|
import { getCurrentTurnGeneration, runWithTurnGeneration, } from "./turn-epoch.js";
|
|
5
5
|
import { debugLog } from "../debug-logger.js";
|
|
6
6
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -71,6 +71,7 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
71
71
|
catch (sessionErr) {
|
|
72
72
|
if (sessionTimeoutHandle)
|
|
73
73
|
clearTimeout(sessionTimeoutHandle);
|
|
74
|
+
_consumePendingSwitchCancellation();
|
|
74
75
|
const msg = sessionErr instanceof Error ? sessionErr.message : String(sessionErr);
|
|
75
76
|
debugLog("runUnit", {
|
|
76
77
|
phase: "session-error",
|
|
@@ -83,15 +84,18 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
83
84
|
if (sessionTimeoutHandle)
|
|
84
85
|
clearTimeout(sessionTimeoutHandle);
|
|
85
86
|
if (sessionResult.cancelled) {
|
|
87
|
+
_consumePendingSwitchCancellation();
|
|
86
88
|
debugLog("runUnit-session-timeout", { unitType, unitId });
|
|
87
89
|
return { status: "cancelled", errorContext: { message: "Session creation timed out", category: "timeout", isTransient: true } };
|
|
88
90
|
}
|
|
89
91
|
if (!s.active) {
|
|
92
|
+
_consumePendingSwitchCancellation();
|
|
90
93
|
return { status: "cancelled" };
|
|
91
94
|
}
|
|
92
95
|
if (s.currentUnitModel && typeof pi.setModel === "function") {
|
|
93
96
|
const restored = await pi.setModel(s.currentUnitModel, { persist: false });
|
|
94
97
|
if (!restored) {
|
|
98
|
+
_consumePendingSwitchCancellation();
|
|
95
99
|
const message = `Failed to restore configured model ${s.currentUnitModel.provider}/${s.currentUnitModel.id} after session creation`;
|
|
96
100
|
ctx.ui.notify(`${message}. Cancelling unit before dispatch.`, "warning");
|
|
97
101
|
return {
|
|
@@ -111,6 +115,14 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
111
115
|
const unitPromise = new Promise((resolve) => {
|
|
112
116
|
_setCurrentResolve(resolve);
|
|
113
117
|
});
|
|
118
|
+
const pendingSwitchCancellation = _consumePendingSwitchCancellation();
|
|
119
|
+
if (pendingSwitchCancellation) {
|
|
120
|
+
_clearCurrentResolve();
|
|
121
|
+
return {
|
|
122
|
+
status: "cancelled",
|
|
123
|
+
...(pendingSwitchCancellation.errorContext ? { errorContext: pendingSwitchCancellation.errorContext } : {}),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
114
126
|
// ── Provider request-readiness pre-check (#4555) ──
|
|
115
127
|
// Verify the provider can accept requests before dispatching. If the token
|
|
116
128
|
// has expired since bootstrap, return cancelled immediately so the unit is
|
|
@@ -25,7 +25,7 @@ import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceh
|
|
|
25
25
|
import { regenerateIfMissing } from "./workflow-projections.js";
|
|
26
26
|
import { syncStateToProjectRoot } from "./auto-worktree.js";
|
|
27
27
|
import { normalizeWorktreePathForCompare } from "./worktree-root.js";
|
|
28
|
-
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
|
|
28
|
+
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter, getVerificationEvidence } from "./gsd-db.js";
|
|
29
29
|
import { renderPlanCheckboxes } from "./markdown-renderer.js";
|
|
30
30
|
import { consumeSignal } from "./session-status-io.js";
|
|
31
31
|
import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookState, resolveHookArtifactPath, } from "./post-unit-hooks.js";
|
|
@@ -719,21 +719,21 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
719
719
|
}
|
|
720
720
|
}
|
|
721
721
|
// Evidence cross-reference (execute-task only)
|
|
722
|
-
//
|
|
723
|
-
//
|
|
724
|
-
//
|
|
725
|
-
// we can still detect units that claimed success but ran no commands.
|
|
722
|
+
// Only compare against concrete command evidence persisted by the task
|
|
723
|
+
// completion tool. A prose Verify field can be satisfied later by the
|
|
724
|
+
// host verification gate, so it is not enough to accuse the unit.
|
|
726
725
|
if (safetyConfig.evidence_cross_reference && s.currentUnit.type === "execute-task") {
|
|
727
726
|
try {
|
|
728
727
|
const actual = getEvidence();
|
|
729
728
|
const bashCalls = actual.filter(e => e.kind === "bash");
|
|
730
|
-
// If the task is marked complete but zero bash commands were run,
|
|
731
|
-
// it's suspicious — the LLM may have fabricated results.
|
|
732
729
|
if (sMid && sSid && sTid && isDbAvailable()) {
|
|
733
730
|
const taskRow = getTask(sMid, sSid, sTid);
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
731
|
+
const claimedCommands = getVerificationEvidence(sMid, sSid, sTid)
|
|
732
|
+
.map((row) => row.command)
|
|
733
|
+
.filter((command) => typeof command === "string" && command.trim().length > 0);
|
|
734
|
+
if (taskRow?.status === "complete" && claimedCommands.length > 0 && bashCalls.length === 0) {
|
|
735
|
+
logWarning("safety", "task claimed verification command evidence but no execution tool calls were recorded");
|
|
736
|
+
ctx.ui.notify(`Safety: task ${sTid} claimed command evidence but no execution tool calls were recorded`, "warning");
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
739
|
}
|