gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.3065f7bfa
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/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +178 -108
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +20 -30
- package/dist/resources/extensions/gsd/auto/session.js +8 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -4
- package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
- package/dist/resources/extensions/gsd/auto-start.js +197 -6
- 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-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +86 -26
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +42 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +49 -36
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +15 -5
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +33 -20
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +7 -1
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +9 -3
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +8 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +259 -28
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
- package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
- package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
- 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/ecosystem/gsd-extension-api.js +2 -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 +99 -38
- 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/native-git-bridge.js +32 -8
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -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/replan-slice.md +2 -2
- 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/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/workflow-protocol.js +131 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +68 -21
- 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 +15 -15
- 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 +15 -15
- 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-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -0
- 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/dist/index.d.ts +1 -0
- package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/index.js +2 -0
- package/packages/pi-agent-core/dist/index.js.map +1 -1
- package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
- package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
- package/packages/pi-agent-core/dist/token-audit.js +221 -0
- package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
- package/packages/pi-agent-core/dist/types.d.ts +9 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
- package/packages/pi-agent-core/src/agent-loop.ts +4 -1
- package/packages/pi-agent-core/src/agent.ts +8 -0
- package/packages/pi-agent-core/src/index.ts +2 -0
- package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
- package/packages/pi-agent-core/src/token-audit.ts +287 -0
- package/packages/pi-agent-core/src/types.ts +14 -0
- package/packages/pi-agent-core/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-tool-refresh.test.js +18 -0
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +44 -7
- 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 +3 -1
- 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/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -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 +6 -6
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +5 -3
- 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 +39 -1
- 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/hooks-runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
- package/packages/pi-coding-agent/dist/core/sdk.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/core/skill-tool.test.js +22 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
- package/packages/pi-coding-agent/dist/core/system-prompt.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 +13 -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-tool-refresh.test.ts +25 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +48 -7
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
- 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/loader.ts +10 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
- package/packages/pi-coding-agent/src/core/extensions/types.ts +42 -1
- package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
- package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
- 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 +22 -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/extensions/gsd/auto/loop-deps.ts +2 -2
- package/src/resources/extensions/gsd/auto/loop.ts +50 -8
- package/src/resources/extensions/gsd/auto/phases.ts +251 -172
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +25 -30
- package/src/resources/extensions/gsd/auto/session.ts +8 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
- package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
- package/src/resources/extensions/gsd/auto-start.ts +230 -9
- 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-worktree.ts +123 -0
- package/src/resources/extensions/gsd/auto.ts +98 -21
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +49 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +50 -36
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +16 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +34 -19
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +8 -1
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +10 -3
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +9 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +305 -28
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
- package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
- package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
- 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/ecosystem/gsd-extension-api.ts +3 -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 +123 -45
- 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/native-git-bridge.ts +39 -6
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -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 +16 -13
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -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/replan-slice.md +2 -2
- 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/tests/artifact-retry-cap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +417 -10
- 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/auto-wrapup-inflight-guard.test.ts +168 -6
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -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/custom-engine-loop-integration.test.ts +5 -1
- 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/execute-task-rendering.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
- package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +239 -1
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -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/milestone-merge-stash-restore.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -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 +45 -5
- package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -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/query-tools-db-open.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +38 -17
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -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 +55 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -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/unstructured-continue-context-injection.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
- package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +167 -4
- 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/workflow-protocol.ts +160 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +85 -19
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +0 -97
- /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_ssgManifest.js +0 -0
|
@@ -165,6 +165,9 @@ test("executeMilestoneStatus returns milestone metadata and slice counts", async
|
|
|
165
165
|
assert.equal(parsed.sliceCount, 1);
|
|
166
166
|
assert.equal(parsed.slices[0].id, "S01");
|
|
167
167
|
assert.equal(parsed.slices[0].taskCounts.pending, 1);
|
|
168
|
+
assert.equal(result.details.status, "active");
|
|
169
|
+
assert.equal(result.details.title, "Milestone One");
|
|
170
|
+
assert.deepEqual(result.details.slices, parsed.slices);
|
|
168
171
|
} finally {
|
|
169
172
|
closeDatabase();
|
|
170
173
|
cleanup(base);
|
|
@@ -39,6 +39,7 @@ function makeDeps(
|
|
|
39
39
|
getAutoWorktreePath: () => null,
|
|
40
40
|
autoCommitCurrentBranch: () => {},
|
|
41
41
|
getCurrentBranch: () => "main",
|
|
42
|
+
checkoutBranch: () => {},
|
|
42
43
|
autoWorktreeBranch: (milestoneId: string) => `milestone/${milestoneId}`,
|
|
43
44
|
resolveMilestoneFile: (_basePath: string, milestoneId: string) =>
|
|
44
45
|
`/project/.gsd/milestones/${milestoneId}/${milestoneId}-ROADMAP.md`,
|
|
@@ -79,7 +79,7 @@ async function waitFor(condition: () => boolean, label: string): Promise<void> {
|
|
|
79
79
|
assert.fail(`Timed out waiting for ${label} after ${timeoutMs}ms`);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
test("runUnit
|
|
82
|
+
test("runUnit passes basePath as workspaceRoot without changing process cwd", async (t) => {
|
|
83
83
|
_resetPendingResolve();
|
|
84
84
|
|
|
85
85
|
const originalCwd = process.cwd();
|
|
@@ -93,13 +93,15 @@ test("runUnit changes cwd to basePath before creating a new session", async (t)
|
|
|
93
93
|
|
|
94
94
|
process.chdir(drifted);
|
|
95
95
|
|
|
96
|
+
let newSessionWorkspaceRoot: string | undefined;
|
|
96
97
|
let cwdAtNewSession: string | undefined;
|
|
97
98
|
const session = {
|
|
98
99
|
active: true,
|
|
99
100
|
basePath: base,
|
|
100
101
|
verbose: false,
|
|
101
102
|
cmdCtx: {
|
|
102
|
-
newSession: () => {
|
|
103
|
+
newSession: (options?: { workspaceRoot?: string }) => {
|
|
104
|
+
newSessionWorkspaceRoot = options?.workspaceRoot;
|
|
103
105
|
cwdAtNewSession = process.cwd();
|
|
104
106
|
return Promise.resolve({ cancelled: false });
|
|
105
107
|
},
|
|
@@ -119,10 +121,12 @@ test("runUnit changes cwd to basePath before creating a new session", async (t)
|
|
|
119
121
|
|
|
120
122
|
const result = await resultPromise;
|
|
121
123
|
assert.equal(result.status, "completed");
|
|
122
|
-
assert.equal(
|
|
124
|
+
assert.equal(newSessionWorkspaceRoot, base);
|
|
125
|
+
assert.equal(cwdAtNewSession, drifted);
|
|
126
|
+
assert.equal(process.cwd(), drifted);
|
|
123
127
|
});
|
|
124
128
|
|
|
125
|
-
test("runUnit
|
|
129
|
+
test("runUnit does not chdir or cancel when basePath is not a live directory", async (t) => {
|
|
126
130
|
_resetPendingResolve();
|
|
127
131
|
|
|
128
132
|
const originalCwd = process.cwd();
|
|
@@ -136,14 +140,14 @@ test("runUnit cancels before creating a session when basePath chdir fails", asyn
|
|
|
136
140
|
|
|
137
141
|
process.chdir(drifted);
|
|
138
142
|
|
|
139
|
-
let
|
|
143
|
+
let newSessionWorkspaceRoot: string | undefined;
|
|
140
144
|
const session = {
|
|
141
145
|
active: true,
|
|
142
146
|
basePath: base,
|
|
143
147
|
verbose: false,
|
|
144
148
|
cmdCtx: {
|
|
145
|
-
newSession: () => {
|
|
146
|
-
|
|
149
|
+
newSession: (options?: { workspaceRoot?: string }) => {
|
|
150
|
+
newSessionWorkspaceRoot = options?.workspaceRoot;
|
|
147
151
|
return Promise.resolve({ cancelled: false });
|
|
148
152
|
},
|
|
149
153
|
},
|
|
@@ -156,15 +160,14 @@ test("runUnit cancels before creating a session when basePath chdir fails", asyn
|
|
|
156
160
|
} as any;
|
|
157
161
|
const ctx = { ui: { notify: () => {} }, model: { id: "test-model" } } as any;
|
|
158
162
|
|
|
159
|
-
const
|
|
163
|
+
const resultPromise = runUnit(ctx, pi, session, "task", "T01", "prompt");
|
|
164
|
+
await waitFor(() => pi.calls.length === 1, "runUnit dispatch");
|
|
165
|
+
resolveAgentEnd({ messages: [{ role: "assistant" }] });
|
|
160
166
|
|
|
161
|
-
|
|
162
|
-
assert.equal(result.
|
|
163
|
-
assert.equal(
|
|
164
|
-
assert.
|
|
165
|
-
assert.ok(result.errorContext?.message.includes(base), "error should include the failed basePath");
|
|
166
|
-
assert.equal(newSessionCalled, false, "newSession must not run after chdir failure");
|
|
167
|
-
assert.equal(pi.calls.length, 0, "unit must not dispatch after chdir failure");
|
|
167
|
+
const result = await resultPromise;
|
|
168
|
+
assert.equal(result.status, "completed");
|
|
169
|
+
assert.equal(newSessionWorkspaceRoot, base);
|
|
170
|
+
assert.equal(process.cwd(), drifted);
|
|
168
171
|
});
|
|
169
172
|
|
|
170
173
|
test("direct dispatch redirects to the canonical milestone worktree before newSession", async (t) => {
|
|
@@ -185,12 +188,12 @@ test("direct dispatch redirects to the canonical milestone worktree before newSe
|
|
|
185
188
|
|
|
186
189
|
process.chdir(drifted);
|
|
187
190
|
|
|
188
|
-
let
|
|
191
|
+
let newSessionWorkspaceRoot: string | undefined;
|
|
189
192
|
let sentPrompt: string | undefined;
|
|
190
193
|
const ctx = {
|
|
191
194
|
ui: { notify: () => {} },
|
|
192
|
-
newSession: async () => {
|
|
193
|
-
|
|
195
|
+
newSession: async (options?: { workspaceRoot?: string }) => {
|
|
196
|
+
newSessionWorkspaceRoot = options?.workspaceRoot;
|
|
194
197
|
return { cancelled: false };
|
|
195
198
|
},
|
|
196
199
|
} as any;
|
|
@@ -202,7 +205,7 @@ test("direct dispatch redirects to the canonical milestone worktree before newSe
|
|
|
202
205
|
|
|
203
206
|
await dispatchDirectPhase(ctx, pi, "research-milestone", base);
|
|
204
207
|
|
|
205
|
-
assert.equal(
|
|
208
|
+
assert.equal(newSessionWorkspaceRoot, worktreeRoot);
|
|
206
209
|
assert.equal(process.cwd(), drifted);
|
|
207
210
|
assert.ok(sentPrompt?.includes(worktreeRoot), "prompt should name the canonical worktree root");
|
|
208
211
|
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// GSD-2 + Worktree dispatch guard: degrade empty worktrees over real project roots.
|
|
2
|
+
|
|
3
|
+
import { describe, test } from "node:test";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
|
|
6
|
+
import { shouldDegradeEmptyWorktreeToProjectRoot } from "../auto/phases.ts";
|
|
7
|
+
import type { ProjectClassification } from "../detection.ts";
|
|
8
|
+
|
|
9
|
+
function classification(kind: ProjectClassification["kind"]): ProjectClassification {
|
|
10
|
+
return {
|
|
11
|
+
kind,
|
|
12
|
+
signals: {
|
|
13
|
+
detectedFiles: [],
|
|
14
|
+
isGitRepo: true,
|
|
15
|
+
isMonorepo: false,
|
|
16
|
+
xcodePlatforms: [],
|
|
17
|
+
hasCI: false,
|
|
18
|
+
hasTests: false,
|
|
19
|
+
verificationCommands: [],
|
|
20
|
+
},
|
|
21
|
+
trackedFiles: [],
|
|
22
|
+
untrackedFiles: [],
|
|
23
|
+
contentFiles: [],
|
|
24
|
+
markers: [],
|
|
25
|
+
reason: kind,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("worktree project-root degradation", () => {
|
|
30
|
+
test("degrades when worktree is greenfield but project root has content", () => {
|
|
31
|
+
assert.equal(
|
|
32
|
+
shouldDegradeEmptyWorktreeToProjectRoot(
|
|
33
|
+
classification("greenfield"),
|
|
34
|
+
classification("typed-existing"),
|
|
35
|
+
),
|
|
36
|
+
true,
|
|
37
|
+
);
|
|
38
|
+
assert.equal(
|
|
39
|
+
shouldDegradeEmptyWorktreeToProjectRoot(
|
|
40
|
+
classification("greenfield"),
|
|
41
|
+
classification("untyped-existing"),
|
|
42
|
+
),
|
|
43
|
+
true,
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("keeps true greenfield worktrees in worktree mode", () => {
|
|
48
|
+
assert.equal(
|
|
49
|
+
shouldDegradeEmptyWorktreeToProjectRoot(
|
|
50
|
+
classification("greenfield"),
|
|
51
|
+
classification("greenfield"),
|
|
52
|
+
),
|
|
53
|
+
false,
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("does not degrade when project root classification is invalid", () => {
|
|
58
|
+
assert.equal(
|
|
59
|
+
shouldDegradeEmptyWorktreeToProjectRoot(
|
|
60
|
+
classification("greenfield"),
|
|
61
|
+
classification("invalid-repo"),
|
|
62
|
+
),
|
|
63
|
+
false,
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: WorktreeResolver unit and regression tests.
|
|
1
3
|
import test from "node:test";
|
|
2
4
|
import assert from "node:assert/strict";
|
|
3
5
|
import { mkdtempSync, rmSync, mkdirSync, realpathSync } from "node:fs";
|
|
@@ -9,6 +11,17 @@ import {
|
|
|
9
11
|
type NotifyCtx,
|
|
10
12
|
} from "../worktree-resolver.js";
|
|
11
13
|
import { AutoSession } from "../auto/session.js";
|
|
14
|
+
import {
|
|
15
|
+
closeDatabase,
|
|
16
|
+
insertMilestone,
|
|
17
|
+
openDatabase,
|
|
18
|
+
} from "../gsd-db.js";
|
|
19
|
+
import { registerAutoWorker } from "../db/auto-workers.js";
|
|
20
|
+
import {
|
|
21
|
+
claimMilestoneLease,
|
|
22
|
+
getMilestoneLease,
|
|
23
|
+
releaseMilestoneLease,
|
|
24
|
+
} from "../db/milestone-leases.js";
|
|
12
25
|
|
|
13
26
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
14
27
|
|
|
@@ -19,11 +32,12 @@ interface CallLog {
|
|
|
19
32
|
}
|
|
20
33
|
|
|
21
34
|
function makeSession(
|
|
22
|
-
overrides?: Partial<
|
|
35
|
+
overrides?: Partial<AutoSession>,
|
|
23
36
|
): AutoSession {
|
|
24
37
|
const s = new AutoSession();
|
|
25
38
|
s.basePath = overrides?.basePath ?? "/project";
|
|
26
39
|
s.originalBasePath = overrides?.originalBasePath ?? "/project";
|
|
40
|
+
Object.assign(s, overrides);
|
|
27
41
|
return s;
|
|
28
42
|
}
|
|
29
43
|
|
|
@@ -104,6 +118,9 @@ function makeDeps(
|
|
|
104
118
|
calls.push({ fn: "getCurrentBranch", args: [basePath] });
|
|
105
119
|
return "main";
|
|
106
120
|
},
|
|
121
|
+
checkoutBranch: (basePath: string, branch: string) => {
|
|
122
|
+
calls.push({ fn: "checkoutBranch", args: [basePath, branch] });
|
|
123
|
+
},
|
|
107
124
|
autoWorktreeBranch: (milestoneId: string) => {
|
|
108
125
|
calls.push({ fn: "autoWorktreeBranch", args: [milestoneId] });
|
|
109
126
|
return `milestone/${milestoneId}`;
|
|
@@ -182,6 +199,17 @@ function findCalls(calls: CallLog[], fn: string): CallLog[] {
|
|
|
182
199
|
return calls.filter((c) => c.fn === fn);
|
|
183
200
|
}
|
|
184
201
|
|
|
202
|
+
function makeDbBase(): string {
|
|
203
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-worktree-resolver-"));
|
|
204
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
205
|
+
return base;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function cleanupDbBase(base: string): void {
|
|
209
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
210
|
+
try { rmSync(base, { recursive: true, force: true }); } catch { /* noop */ }
|
|
211
|
+
}
|
|
212
|
+
|
|
185
213
|
// ─── Getter Tests ────────────────────────────────────────────────────────────
|
|
186
214
|
|
|
187
215
|
test("workPath returns s.basePath", () => {
|
|
@@ -371,6 +399,43 @@ test("enterMilestone does not create double-nested worktree when originalBasePat
|
|
|
371
399
|
);
|
|
372
400
|
});
|
|
373
401
|
|
|
402
|
+
test("enterMilestone reacquires a released same-milestone lease before worktree entry", (t) => {
|
|
403
|
+
const base = makeDbBase();
|
|
404
|
+
t.after(() => cleanupDbBase(base));
|
|
405
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
406
|
+
insertMilestone({ id: "M001", title: "Test milestone", status: "active" });
|
|
407
|
+
|
|
408
|
+
const workerId = registerAutoWorker({ projectRootRealpath: base });
|
|
409
|
+
const originalClaim = claimMilestoneLease(workerId, "M001");
|
|
410
|
+
assert.equal(originalClaim.ok, true);
|
|
411
|
+
if (!originalClaim.ok) throw new Error("expected test lease claim");
|
|
412
|
+
assert.equal(releaseMilestoneLease(workerId, "M001", originalClaim.token), true);
|
|
413
|
+
|
|
414
|
+
const s = makeSession({
|
|
415
|
+
basePath: base,
|
|
416
|
+
originalBasePath: base,
|
|
417
|
+
workerId,
|
|
418
|
+
currentMilestoneId: "M001",
|
|
419
|
+
milestoneLeaseToken: originalClaim.token,
|
|
420
|
+
});
|
|
421
|
+
const deps = makeDeps({
|
|
422
|
+
createAutoWorktree: (basePath: string, milestoneId: string) => join(basePath, ".gsd", "worktrees", milestoneId),
|
|
423
|
+
});
|
|
424
|
+
const ctx = makeNotifyCtx();
|
|
425
|
+
const resolver = new WorktreeResolver(s, deps);
|
|
426
|
+
|
|
427
|
+
resolver.enterMilestone("M001", ctx);
|
|
428
|
+
|
|
429
|
+
const row = getMilestoneLease("M001");
|
|
430
|
+
assert.ok(row);
|
|
431
|
+
assert.equal(row.worker_id, workerId);
|
|
432
|
+
assert.equal(row.status, "held");
|
|
433
|
+
assert.equal(row.fencing_token, originalClaim.token + 1);
|
|
434
|
+
assert.equal(s.milestoneLeaseToken, originalClaim.token + 1);
|
|
435
|
+
assert.equal(s.basePath, join(base, ".gsd", "worktrees", "M001"));
|
|
436
|
+
assert.equal(ctx.messages.some((m) => m.level === "error"), false);
|
|
437
|
+
});
|
|
438
|
+
|
|
374
439
|
// ─── enterMilestone Tests (branch mode) ──────────────────────────────────────
|
|
375
440
|
|
|
376
441
|
test("enterMilestone in branch mode calls enterBranchModeForMilestone and rebuilds GitService", () => {
|
|
@@ -740,21 +805,92 @@ test("mergeAndExit in branch mode merges when on milestone branch", () => {
|
|
|
740
805
|
assert.ok(ctx.messages.some((m) => m.msg.includes("branch mode")));
|
|
741
806
|
});
|
|
742
807
|
|
|
743
|
-
test("mergeAndExit in branch mode
|
|
808
|
+
test("mergeAndExit in branch mode checks out the milestone branch and merges (#5538-followup)", () => {
|
|
809
|
+
// Regression: previously this case silently returned without merging,
|
|
810
|
+
// stranding the milestone's commits on the branch (the test12345 repro).
|
|
811
|
+
// The fix forces a checkout first; merge proceeds when checkout succeeds.
|
|
744
812
|
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
813
|
+
let currentBranch = "main";
|
|
814
|
+
const checkoutInvocations: Array<{ basePath: string; branch: string }> = [];
|
|
745
815
|
const deps = makeDeps({
|
|
746
816
|
isInAutoWorktree: () => false,
|
|
747
817
|
getIsolationMode: () => "branch",
|
|
748
|
-
getCurrentBranch: () =>
|
|
818
|
+
getCurrentBranch: () => currentBranch,
|
|
749
819
|
autoWorktreeBranch: () => "milestone/M001",
|
|
820
|
+
checkoutBranch: (basePath: string, branch: string) => {
|
|
821
|
+
checkoutInvocations.push({ basePath, branch });
|
|
822
|
+
currentBranch = branch;
|
|
823
|
+
},
|
|
750
824
|
});
|
|
751
825
|
const ctx = makeNotifyCtx();
|
|
752
826
|
const resolver = new WorktreeResolver(s, deps);
|
|
753
827
|
|
|
754
828
|
resolver.mergeAndExit("M001", ctx);
|
|
755
829
|
|
|
830
|
+
assert.equal(checkoutInvocations.length, 1, "must attempt checkout when on wrong branch");
|
|
831
|
+
assert.deepEqual(checkoutInvocations[0], { basePath: "/project", branch: "milestone/M001" });
|
|
832
|
+
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1);
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
test("mergeAndExit in branch mode throws when checkout fails", () => {
|
|
836
|
+
// Regression for the silent-skip bug: if the working tree is on the wrong
|
|
837
|
+
// branch and checkout fails, we must throw so the caller pauses auto-mode
|
|
838
|
+
// — never silently advance with the milestone unmerged.
|
|
839
|
+
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
840
|
+
const deps = makeDeps({
|
|
841
|
+
isInAutoWorktree: () => false,
|
|
842
|
+
getIsolationMode: () => "branch",
|
|
843
|
+
getCurrentBranch: () => "main",
|
|
844
|
+
autoWorktreeBranch: () => "milestone/M001",
|
|
845
|
+
checkoutBranch: () => {
|
|
846
|
+
throw new Error("dirty working tree blocks checkout");
|
|
847
|
+
},
|
|
848
|
+
});
|
|
849
|
+
const ctx = makeNotifyCtx();
|
|
850
|
+
const resolver = new WorktreeResolver(s, deps);
|
|
851
|
+
|
|
852
|
+
assert.throws(
|
|
853
|
+
() => resolver.mergeAndExit("M001", ctx),
|
|
854
|
+
/dirty working tree blocks checkout/,
|
|
855
|
+
);
|
|
856
|
+
assert.equal(
|
|
857
|
+
findCalls(deps.calls, "mergeMilestoneToMain").length,
|
|
858
|
+
0,
|
|
859
|
+
"merge must not run when checkout failed",
|
|
860
|
+
);
|
|
861
|
+
const errorNotify = ctx.messages.find((m) => m.level === "error");
|
|
862
|
+
assert.ok(errorNotify, "an error notification must be emitted");
|
|
863
|
+
assert.match(errorNotify!.msg, /milestone\/M001 failed/);
|
|
864
|
+
assert.match(errorNotify!.msg, /Resolve manually/);
|
|
865
|
+
assert.equal(
|
|
866
|
+
ctx.messages.some((m) => m.level === "warning" && m.msg.includes("Milestone merge failed")),
|
|
867
|
+
false,
|
|
868
|
+
"checkout failures with explicit recovery guidance must not emit a duplicate warning",
|
|
869
|
+
);
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
test("mergeAndExit in branch mode throws when checkout reports success but HEAD is still wrong", () => {
|
|
873
|
+
// Defense in depth: even if checkoutBranch returns without throwing, we
|
|
874
|
+
// re-verify and throw if HEAD didn't actually move. Prevents merging on
|
|
875
|
+
// top of the wrong branch on platforms where the checkout is a no-op.
|
|
876
|
+
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
877
|
+
const deps = makeDeps({
|
|
878
|
+
isInAutoWorktree: () => false,
|
|
879
|
+
getIsolationMode: () => "branch",
|
|
880
|
+
getCurrentBranch: () => "main", // never changes — simulates no-op checkout
|
|
881
|
+
autoWorktreeBranch: () => "milestone/M001",
|
|
882
|
+
checkoutBranch: () => {
|
|
883
|
+
// Pretend success — but getCurrentBranch will still return "main".
|
|
884
|
+
},
|
|
885
|
+
});
|
|
886
|
+
const ctx = makeNotifyCtx();
|
|
887
|
+
const resolver = new WorktreeResolver(s, deps);
|
|
888
|
+
|
|
889
|
+
assert.throws(
|
|
890
|
+
() => resolver.mergeAndExit("M001", ctx),
|
|
891
|
+
/reported success but current branch is main/,
|
|
892
|
+
);
|
|
756
893
|
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
|
|
757
|
-
assert.equal(ctx.messages.length, 0);
|
|
758
894
|
});
|
|
759
895
|
|
|
760
896
|
test("mergeAndExit in branch mode handles merge failure gracefully", () => {
|
|
@@ -977,6 +1113,33 @@ test("mergeAndEnterNext enters next milestone even if merge fails", () => {
|
|
|
977
1113
|
);
|
|
978
1114
|
});
|
|
979
1115
|
|
|
1116
|
+
test("mergeAndEnterNext halts after branch-mode user-notified checkout failure", () => {
|
|
1117
|
+
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
1118
|
+
const deps = makeDeps({
|
|
1119
|
+
isInAutoWorktree: () => false,
|
|
1120
|
+
getIsolationMode: () => "branch",
|
|
1121
|
+
getCurrentBranch: () => "main",
|
|
1122
|
+
autoWorktreeBranch: () => "milestone/M001",
|
|
1123
|
+
checkoutBranch: () => {
|
|
1124
|
+
throw new Error("dirty working tree blocks checkout");
|
|
1125
|
+
},
|
|
1126
|
+
});
|
|
1127
|
+
const ctx = makeNotifyCtx();
|
|
1128
|
+
const resolver = new WorktreeResolver(s, deps);
|
|
1129
|
+
|
|
1130
|
+
assert.throws(
|
|
1131
|
+
() => resolver.mergeAndEnterNext("M001", "M002", ctx),
|
|
1132
|
+
/dirty working tree blocks checkout/,
|
|
1133
|
+
);
|
|
1134
|
+
assert.equal(
|
|
1135
|
+
findCalls(deps.calls, "enterBranchModeForMilestone").length,
|
|
1136
|
+
0,
|
|
1137
|
+
"must not enter the next milestone after a user-notified branch-mode failure",
|
|
1138
|
+
);
|
|
1139
|
+
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
|
|
1140
|
+
assert.ok(ctx.messages.some((m) => m.level === "error" && m.msg.includes("Resolve manually")));
|
|
1141
|
+
});
|
|
1142
|
+
|
|
980
1143
|
// ─── GitService Rebuild Atomicity ────────────────────────────────────────────
|
|
981
1144
|
|
|
982
1145
|
test("GitService is rebuilt with the NEW basePath after enterMilestone", () => {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Shared Context Mode tool result helpers.
|
|
3
|
+
|
|
4
|
+
export interface ToolExecutionResult {
|
|
5
|
+
content: Array<{ type: "text"; text: string }>;
|
|
6
|
+
details: Record<string, unknown>;
|
|
7
|
+
isError?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type ContextModeToolName = "gsd_exec" | "gsd_exec_search" | "gsd_resume";
|
|
11
|
+
|
|
12
|
+
export function contextModeDisabledResult(operation: ContextModeToolName): ToolExecutionResult {
|
|
13
|
+
return {
|
|
14
|
+
content: [
|
|
15
|
+
{
|
|
16
|
+
type: "text",
|
|
17
|
+
text:
|
|
18
|
+
`${operation} is disabled by \`context_mode.enabled: false\` in preferences. ` +
|
|
19
|
+
"Remove that override or set it to true to re-enable Context Mode tools.",
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
details: { operation, error: "context_mode_disabled" },
|
|
23
|
+
isError: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// re-discover past runs without re-executing. Read-only; no DB writes.
|
|
5
5
|
|
|
6
6
|
import { searchExecHistory, type ExecSearchOptions } from "../exec-history.js";
|
|
7
|
+
import { isContextModeEnabled, type ContextModeConfig } from "../preferences-types.js";
|
|
8
|
+
import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
|
|
7
9
|
|
|
8
10
|
export interface ExecSearchToolParams {
|
|
9
11
|
query?: string;
|
|
@@ -12,16 +14,14 @@ export interface ExecSearchToolParams {
|
|
|
12
14
|
limit?: number;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
export interface ToolExecutionResult {
|
|
16
|
-
content: Array<{ type: "text"; text: string }>;
|
|
17
|
-
details: Record<string, unknown>;
|
|
18
|
-
isError?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
17
|
export function executeExecSearch(
|
|
22
18
|
params: ExecSearchToolParams,
|
|
23
|
-
opts: { baseDir: string },
|
|
19
|
+
opts: { baseDir: string; preferences?: { context_mode?: ContextModeConfig } | null },
|
|
24
20
|
): ToolExecutionResult {
|
|
21
|
+
if (!isContextModeEnabled(opts.preferences)) {
|
|
22
|
+
return contextModeDisabledResult("gsd_exec_search");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
25
|
const searchOpts: ExecSearchOptions = {
|
|
26
26
|
query: typeof params.query === "string" ? params.query : undefined,
|
|
27
27
|
runtime: params.runtime,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type ExecSandboxResult,
|
|
13
13
|
} from "../exec-sandbox.js";
|
|
14
14
|
import { isContextModeEnabled, type ContextModeConfig } from "../preferences-types.js";
|
|
15
|
+
import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
|
|
15
16
|
|
|
16
17
|
export interface ExecToolParams {
|
|
17
18
|
runtime: ExecSandboxRequest["runtime"];
|
|
@@ -20,17 +21,12 @@ export interface ExecToolParams {
|
|
|
20
21
|
timeout_ms?: number;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export interface ToolExecutionResult {
|
|
24
|
-
content: Array<{ type: "text"; text: string }>;
|
|
25
|
-
details: Record<string, unknown>;
|
|
26
|
-
isError?: boolean;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
24
|
export interface ExecToolDeps {
|
|
30
25
|
baseDir: string;
|
|
31
26
|
preferences: { context_mode?: ContextModeConfig } | null;
|
|
32
27
|
/** Optional override for testing. */
|
|
33
28
|
run?: (req: ExecSandboxRequest, opts: ExecSandboxOptions) => Promise<ExecSandboxResult>;
|
|
29
|
+
env?: NodeJS.ProcessEnv;
|
|
34
30
|
now?: () => Date;
|
|
35
31
|
generateId?: () => string;
|
|
36
32
|
}
|
|
@@ -77,21 +73,6 @@ function isEnabled(prefs: ExecToolDeps["preferences"]): boolean {
|
|
|
77
73
|
return isContextModeEnabled(prefs);
|
|
78
74
|
}
|
|
79
75
|
|
|
80
|
-
function disabledResult(): ToolExecutionResult {
|
|
81
|
-
return {
|
|
82
|
-
content: [
|
|
83
|
-
{
|
|
84
|
-
type: "text",
|
|
85
|
-
text:
|
|
86
|
-
"gsd_exec is disabled by `context_mode.enabled: false` in preferences. Remove that " +
|
|
87
|
-
"override (or set it to true) to re-enable sandboxed tool-output execution.",
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
details: { operation: "gsd_exec", error: "context_mode_disabled" },
|
|
91
|
-
isError: true,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
76
|
function paramError(message: string): ToolExecutionResult {
|
|
96
77
|
return {
|
|
97
78
|
content: [{ type: "text", text: `Error: ${message}` }],
|
|
@@ -104,7 +85,7 @@ export async function executeGsdExec(
|
|
|
104
85
|
params: ExecToolParams,
|
|
105
86
|
deps: ExecToolDeps,
|
|
106
87
|
): Promise<ToolExecutionResult> {
|
|
107
|
-
if (!isEnabled(deps.preferences)) return
|
|
88
|
+
if (!isEnabled(deps.preferences)) return contextModeDisabledResult("gsd_exec");
|
|
108
89
|
|
|
109
90
|
const runtime = params.runtime;
|
|
110
91
|
if (runtime !== "bash" && runtime !== "node" && runtime !== "python") {
|
|
@@ -121,7 +102,7 @@ export async function executeGsdExec(
|
|
|
121
102
|
const opts = buildExecOptions(
|
|
122
103
|
deps.baseDir,
|
|
123
104
|
deps.preferences?.context_mode,
|
|
124
|
-
{ now: deps.now, generateId: deps.generateId },
|
|
105
|
+
{ env: deps.env, now: deps.now, generateId: deps.generateId },
|
|
125
106
|
);
|
|
126
107
|
const run = deps.run ?? runExecSandbox;
|
|
127
108
|
|
|
@@ -308,6 +308,7 @@ function includeSupersededMemories(rankedActive: Memory[]): Memory[] {
|
|
|
308
308
|
scope: (row["scope"] as string) ?? "project",
|
|
309
309
|
tags,
|
|
310
310
|
structured_fields: structuredFields,
|
|
311
|
+
last_hit_at: (row["last_hit_at"] as string | null) ?? null,
|
|
311
312
|
};
|
|
312
313
|
});
|
|
313
314
|
} catch {
|
|
@@ -18,6 +18,7 @@ import { renderAllProjections } from "../workflow-projections.js";
|
|
|
18
18
|
import { writeManifest } from "../workflow-manifest.js";
|
|
19
19
|
import { appendEvent } from "../workflow-events.js";
|
|
20
20
|
import { logWarning } from "../workflow-logger.js";
|
|
21
|
+
import { validatePlanningPathScope } from "../planning-path-scope.js";
|
|
21
22
|
|
|
22
23
|
export interface PlanSliceTaskInput {
|
|
23
24
|
taskId: string;
|
|
@@ -141,6 +142,18 @@ export async function handlePlanSlice(
|
|
|
141
142
|
return { error: `validation failed: ${(err as Error).message}` };
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
const pathScopeError = validatePlanningPathScope(
|
|
146
|
+
basePath,
|
|
147
|
+
params.tasks.flatMap((task, index) => [
|
|
148
|
+
{ field: `tasks[${index}].files`, values: task.files },
|
|
149
|
+
{ field: `tasks[${index}].inputs`, values: task.inputs },
|
|
150
|
+
{ field: `tasks[${index}].expectedOutput`, values: task.expectedOutput },
|
|
151
|
+
]),
|
|
152
|
+
);
|
|
153
|
+
if (pathScopeError) {
|
|
154
|
+
return { error: `validation failed: ${pathScopeError}` };
|
|
155
|
+
}
|
|
156
|
+
|
|
144
157
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
145
158
|
// Guards must be inside the transaction so the state they check cannot
|
|
146
159
|
// change between the read and the write (#2723).
|
|
@@ -8,6 +8,7 @@ import { renderAllProjections } from "../workflow-projections.js";
|
|
|
8
8
|
import { writeManifest } from "../workflow-manifest.js";
|
|
9
9
|
import { appendEvent } from "../workflow-events.js";
|
|
10
10
|
import { logWarning } from "../workflow-logger.js";
|
|
11
|
+
import { validatePlanningPathScope } from "../planning-path-scope.js";
|
|
11
12
|
|
|
12
13
|
export interface PlanTaskParams {
|
|
13
14
|
milestoneId: string;
|
|
@@ -66,6 +67,15 @@ export async function handlePlanTask(
|
|
|
66
67
|
return { error: `validation failed: ${(err as Error).message}` };
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
const pathScopeError = validatePlanningPathScope(basePath, [
|
|
71
|
+
{ field: "files", values: params.files },
|
|
72
|
+
{ field: "inputs", values: params.inputs },
|
|
73
|
+
{ field: "expectedOutput", values: params.expectedOutput },
|
|
74
|
+
]);
|
|
75
|
+
if (pathScopeError) {
|
|
76
|
+
return { error: `validation failed: ${pathScopeError}` };
|
|
77
|
+
}
|
|
78
|
+
|
|
69
79
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
70
80
|
// Guards must be inside the transaction so the state they check cannot
|
|
71
81
|
// change between the read and the write (#2723).
|
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
// re-deriving project memory state.
|
|
4
4
|
|
|
5
5
|
import { readCompactionSnapshot } from "../compaction-snapshot.js";
|
|
6
|
+
import { isContextModeEnabled, type ContextModeConfig } from "../preferences-types.js";
|
|
7
|
+
import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
|
|
6
8
|
|
|
7
9
|
export interface ResumeToolParams {
|
|
8
10
|
/** Ignored — reserved for future variant (e.g. dated snapshots). */
|
|
9
11
|
_variant?: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export interface ToolExecutionResult {
|
|
13
|
-
content: Array<{ type: "text"; text: string }>;
|
|
14
|
-
details: Record<string, unknown>;
|
|
15
|
-
isError?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
export function executeResume(
|
|
19
15
|
_params: ResumeToolParams,
|
|
20
|
-
opts: { baseDir: string },
|
|
16
|
+
opts: { baseDir: string; preferences?: { context_mode?: ContextModeConfig } | null },
|
|
21
17
|
): ToolExecutionResult {
|
|
18
|
+
if (!isContextModeEnabled(opts.preferences)) {
|
|
19
|
+
return contextModeDisabledResult("gsd_resume");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
22
|
const snapshot = readCompactionSnapshot(opts.baseDir);
|
|
23
23
|
if (snapshot == null) {
|
|
24
24
|
return {
|
|
@@ -813,7 +813,7 @@ export async function executeMilestoneStatus(
|
|
|
813
813
|
|
|
814
814
|
return {
|
|
815
815
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
816
|
-
details: { operation: "milestone_status",
|
|
816
|
+
details: { operation: "milestone_status", ...result },
|
|
817
817
|
};
|
|
818
818
|
});
|
|
819
819
|
} catch (err) {
|