gsd-pi 2.80.0-dev.c5f2443b3 → 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/github-sync/templates.js +39 -8
- package/dist/resources/extensions/gsd/auto/loop.js +48 -10
- 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 +32 -16
- package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
- 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 +197 -9
- package/dist/resources/extensions/gsd/auto-start.js +2 -3
- 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 +36 -3
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
- 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/commands-extract-learnings.js +17 -12
- 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/custom-workflow-engine.js +22 -2
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +18 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +22 -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/graph.js +9 -3
- package/dist/resources/extensions/gsd/gsd-db.js +146 -13
- package/dist/resources/extensions/gsd/guided-flow.js +82 -16
- 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/pr-evidence.js +57 -16
- 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/working-output-messages.js +64 -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 +10 -10
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- 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/api/onboarding/route.js +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 +10 -10
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-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/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
- package/package.json +12 -8
- package/packages/contracts/package.json +1 -1
- 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-ai/dist/models/fake-model.d.ts +12 -0
- package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/fake-model.js +27 -0
- package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
- package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/index.js +8 -0
- package/packages/pi-ai/dist/models/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
- package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/fake.js +319 -0
- package/packages/pi-ai/dist/providers/fake.js.map +1 -0
- package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
- package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
- package/packages/pi-ai/src/models/fake-model.ts +30 -0
- package/packages/pi-ai/src/models/index.ts +9 -0
- package/packages/pi-ai/src/providers/fake.ts +376 -0
- package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
- package/packages/pi-ai/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 +76 -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 +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 +17 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +99 -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/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +24 -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 +33 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +17 -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 +109 -17
- 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 +69 -2
- 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 +93 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
- 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 +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
- 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 +89 -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 +110 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -1
- package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +51 -1
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +122 -17
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +99 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +92 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -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/__tests__/style.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
- package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/index.d.ts +1 -0
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +2 -0
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/style.d.ts +41 -0
- package/packages/pi-tui/dist/style.d.ts.map +1 -0
- package/packages/pi-tui/dist/style.js +158 -0
- package/packages/pi-tui/dist/style.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts +0 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +21 -16
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
- package/packages/pi-tui/src/index.ts +9 -0
- package/packages/pi-tui/src/style.ts +225 -0
- package/packages/pi-tui/src/tui.ts +23 -16
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +18 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +36 -27
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/github-sync/templates.ts +38 -8
- package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +67 -18
- 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 +42 -15
- package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
- package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
- 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 +207 -7
- package/src/resources/extensions/gsd/auto-start.ts +7 -6
- 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 +37 -2
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
- 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/commands-extract-learnings.ts +17 -12
- 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/custom-workflow-engine.ts +24 -1
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +19 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +25 -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/graph.ts +12 -5
- package/src/resources/extensions/gsd/gsd-db.ts +168 -13
- package/src/resources/extensions/gsd/guided-flow.ts +98 -16
- 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/pr-evidence.ts +63 -5
- 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-abort-pause-regression.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +155 -5
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +184 -2
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
- 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/custom-engine-loop-integration.test.ts +112 -6
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
- package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
- package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
- 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/fixtures/pr-body/commands-ship-basic.md +52 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
- 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/pr-evidence-equivalence.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -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/uok-plan-v2-wiring.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -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/tests/worktree-write-gate.test.ts +179 -0
- 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/working-output-messages.ts +120 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
- package/src/resources/extensions/gsd/worktree-resolver.ts +36 -15
- package/packages/contracts/tsconfig.tsbuildinfo +0 -1
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → -5nHJWzSdG-WkPMul_khA}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → -5nHJWzSdG-WkPMul_khA}/_ssgManifest.js +0 -0
|
@@ -44,4 +44,13 @@ describe('status opens DB before deriveState (#3691)', () => {
|
|
|
44
44
|
assert.match(quickSrc, /getIsolationMode\(\)\s*!==\s*"none"/,
|
|
45
45
|
'quick.ts should compare isolation mode against "none"');
|
|
46
46
|
});
|
|
47
|
+
|
|
48
|
+
test('quick task prompt handles external .gsd without staging quick files', () => {
|
|
49
|
+
assert.match(quickSrc, /isExternalGsdRoot/,
|
|
50
|
+
'quick.ts should detect whether .gsd resolves outside the project repo');
|
|
51
|
+
assert.match(quickSrc, /do not stage or commit `\.gsd\/quick\/\.\.\.`/,
|
|
52
|
+
'external-state quick tasks must tell the agent not to stage .gsd/quick files');
|
|
53
|
+
assert.match(quickSrc, /nothing in the project repo to commit/,
|
|
54
|
+
'external-state quick tasks should allow summary-only work without a git commit');
|
|
55
|
+
});
|
|
47
56
|
});
|
|
@@ -21,12 +21,18 @@ import type {
|
|
|
21
21
|
ComputedArtifactRegistry,
|
|
22
22
|
UnitContextManifest,
|
|
23
23
|
} from "../unit-context-manifest.ts";
|
|
24
|
-
import { UNIT_MANIFESTS } from "../unit-context-manifest.ts";
|
|
25
|
-
import {
|
|
24
|
+
import { KNOWN_UNIT_TYPES, UNIT_MANIFESTS } from "../unit-context-manifest.ts";
|
|
25
|
+
import {
|
|
26
|
+
buildExecuteTaskPrompt,
|
|
27
|
+
buildGateEvaluatePrompt,
|
|
28
|
+
buildReassessRoadmapPrompt,
|
|
29
|
+
buildWorkflowPreferencesPrompt,
|
|
30
|
+
} from "../auto-prompts.ts";
|
|
26
31
|
import { invalidateAllCaches } from "../cache.ts";
|
|
27
32
|
import {
|
|
28
33
|
openDatabase,
|
|
29
34
|
closeDatabase,
|
|
35
|
+
insertGateRow,
|
|
30
36
|
insertMilestone,
|
|
31
37
|
upsertMilestonePlanning,
|
|
32
38
|
insertSlice,
|
|
@@ -121,7 +127,7 @@ test("Context Mode composer: standalone output starts with heading and includes
|
|
|
121
127
|
assert.ok(out.startsWith("## Context Mode"));
|
|
122
128
|
assert.match(out, /execution lane/i);
|
|
123
129
|
assert.match(out, /`gsd_exec`/);
|
|
124
|
-
assert.match(out, /
|
|
130
|
+
assert.match(out, /builds, tests, and diagnostics/);
|
|
125
131
|
assert.match(out, /`gsd_exec_search`/);
|
|
126
132
|
assert.match(out, /before reruns/);
|
|
127
133
|
assert.match(out, /`gsd_resume`/);
|
|
@@ -136,7 +142,45 @@ test("Context Mode composer: nested output is compact single sentence", () => {
|
|
|
136
142
|
assert.match(out, /`gsd_exec`/);
|
|
137
143
|
assert.match(out, /`gsd_exec_search`/);
|
|
138
144
|
assert.match(out, /`gsd_resume`/);
|
|
139
|
-
assert.ok(out.length <
|
|
145
|
+
assert.ok(out.length < 240, `nested guidance should stay compact, got ${out.length} chars`);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const laneLabelByMode: Record<string, string> = {
|
|
149
|
+
interview: "interview",
|
|
150
|
+
research: "research",
|
|
151
|
+
planning: "planning",
|
|
152
|
+
execution: "execution",
|
|
153
|
+
verification: "verification",
|
|
154
|
+
orchestration: "orchestration",
|
|
155
|
+
docs: "documentation",
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
test("Context Mode composer: every known eligible unit renders its configured lane and required tools", () => {
|
|
159
|
+
for (const unitType of KNOWN_UNIT_TYPES) {
|
|
160
|
+
const manifest = UNIT_MANIFESTS[unitType];
|
|
161
|
+
assert.ok(manifest, `missing manifest for ${unitType}`);
|
|
162
|
+
const out = composeContextModeInstructions(unitType, { enabled: true, renderMode: "standalone" });
|
|
163
|
+
if (manifest.contextMode === "none") {
|
|
164
|
+
assert.strictEqual(out, "", `${unitType} should not render Context Mode`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
assert.ok(out.startsWith("## Context Mode"), `${unitType} should render standalone Context Mode heading`);
|
|
168
|
+
assert.match(out, new RegExp(`Lane: \\*\\*${laneLabelByMode[manifest.contextMode]} lane\\*\\*\\.`, "i"));
|
|
169
|
+
assert.match(out, /`gsd_exec`/, `${unitType} should mention gsd_exec`);
|
|
170
|
+
assert.match(out, /`gsd_exec_search`/, `${unitType} should mention gsd_exec_search`);
|
|
171
|
+
assert.match(out, /`gsd_resume`/, `${unitType} should mention gsd_resume`);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("Context Mode composer: workflow-preferences and research-decision render no Context Mode block", () => {
|
|
176
|
+
assert.strictEqual(
|
|
177
|
+
composeContextModeInstructions("workflow-preferences", { enabled: true, renderMode: "standalone" }),
|
|
178
|
+
"",
|
|
179
|
+
);
|
|
180
|
+
assert.strictEqual(
|
|
181
|
+
composeContextModeInstructions("research-decision", { enabled: true, renderMode: "standalone" }),
|
|
182
|
+
"",
|
|
183
|
+
);
|
|
140
184
|
});
|
|
141
185
|
|
|
142
186
|
// ─── Integration: migrated buildReassessRoadmapPrompt ─────────────────────
|
|
@@ -220,6 +264,94 @@ test("#4782 phase 2: buildReassessRoadmapPrompt emits composer-shaped context wi
|
|
|
220
264
|
assert.ok(!prompt.includes("Slice Context (from discussion)"));
|
|
221
265
|
});
|
|
222
266
|
|
|
267
|
+
test("Context Mode resume injection: eligible prompts include one bounded snapshot block above inlined context", async (t) => {
|
|
268
|
+
const base = makeFixtureBase();
|
|
269
|
+
t.after(() => cleanup(base));
|
|
270
|
+
invalidateAllCaches();
|
|
271
|
+
|
|
272
|
+
seed(base, "M001");
|
|
273
|
+
writeArtifacts(base);
|
|
274
|
+
writeFileSync(
|
|
275
|
+
join(base, ".gsd", "last-snapshot.md"),
|
|
276
|
+
"# GSD context snapshot\n\nResume evidence.\n",
|
|
277
|
+
"utf-8",
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
281
|
+
|
|
282
|
+
assert.equal(prompt.match(/## Context Snapshot/g)?.length, 1);
|
|
283
|
+
assert.match(prompt, /Source: `\.gsd\/last-snapshot\.md`/);
|
|
284
|
+
assert.match(prompt, /Resume evidence/);
|
|
285
|
+
assert.ok(prompt.indexOf("## Context Mode") < prompt.indexOf("## Context Snapshot"));
|
|
286
|
+
assert.ok(prompt.indexOf("## Context Snapshot") < prompt.indexOf("## Inlined Context"));
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("Context Mode resume injection: missing snapshot does not add an empty block", async (t) => {
|
|
290
|
+
const base = makeFixtureBase();
|
|
291
|
+
t.after(() => cleanup(base));
|
|
292
|
+
invalidateAllCaches();
|
|
293
|
+
|
|
294
|
+
seed(base, "M001");
|
|
295
|
+
writeArtifacts(base);
|
|
296
|
+
|
|
297
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
298
|
+
|
|
299
|
+
assert.match(prompt, /## Context Mode/);
|
|
300
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("Context Mode resume injection: disabled mode suppresses guidance and snapshot reads", async (t) => {
|
|
304
|
+
const base = makeFixtureBase();
|
|
305
|
+
t.after(() => cleanup(base));
|
|
306
|
+
invalidateAllCaches();
|
|
307
|
+
|
|
308
|
+
seed(base, "M001");
|
|
309
|
+
writeArtifacts(base);
|
|
310
|
+
writeFileSync(join(base, ".gsd", "PREFERENCES.md"), "---\ncontext_mode:\n enabled: false\n---\n", "utf-8");
|
|
311
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nDo not inject.\n", "utf-8");
|
|
312
|
+
|
|
313
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
314
|
+
|
|
315
|
+
assert.doesNotMatch(prompt, /## Context Mode/);
|
|
316
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
317
|
+
assert.doesNotMatch(prompt, /Do not inject/);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("Context Mode resume injection: none-mode units do not inject snapshots", async () => {
|
|
321
|
+
const base = makeFixtureBase();
|
|
322
|
+
try {
|
|
323
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nNo lane.\n", "utf-8");
|
|
324
|
+
const prompt = await buildWorkflowPreferencesPrompt(base);
|
|
325
|
+
assert.doesNotMatch(prompt, /## Context Mode/);
|
|
326
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
327
|
+
assert.doesNotMatch(prompt, /No lane/);
|
|
328
|
+
} finally {
|
|
329
|
+
cleanup(base);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("Context Mode prompt suppression: disabled inlined, phase-anchor, and nested prompts omit Context Mode", async (t) => {
|
|
334
|
+
const base = makeFixtureBase();
|
|
335
|
+
t.after(() => cleanup(base));
|
|
336
|
+
invalidateAllCaches();
|
|
337
|
+
|
|
338
|
+
seed(base, "M001");
|
|
339
|
+
writeArtifacts(base);
|
|
340
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
341
|
+
writeFileSync(join(base, ".gsd", "PREFERENCES.md"), "---\ncontext_mode:\n enabled: false\n---\n", "utf-8");
|
|
342
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nDo not inject.\n", "utf-8");
|
|
343
|
+
|
|
344
|
+
const inlinedPrompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
345
|
+
assert.doesNotMatch(inlinedPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
346
|
+
|
|
347
|
+
const phaseAnchorPrompt = await buildExecuteTaskPrompt("M001", "S01", "First", "T01", "Task", base);
|
|
348
|
+
assert.doesNotMatch(phaseAnchorPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
349
|
+
|
|
350
|
+
const nestedPrompt = await buildGateEvaluatePrompt("M001", "Test", "S01", "First", base);
|
|
351
|
+
assert.match(nestedPrompt, /Use this as the prompt for a `subagent` call/);
|
|
352
|
+
assert.doesNotMatch(nestedPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
353
|
+
});
|
|
354
|
+
|
|
223
355
|
// ─── v2 surface (#4924) ───────────────────────────────────────────────────
|
|
224
356
|
|
|
225
357
|
const fakeBase: BaseResolverContext = {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
markFailed,
|
|
22
22
|
markStuck,
|
|
23
23
|
markCanceled,
|
|
24
|
+
markLatestActiveForWorkerCanceled,
|
|
24
25
|
getRecentForUnit,
|
|
25
26
|
getLatestForUnit,
|
|
26
27
|
} from "../db/unit-dispatches.ts";
|
|
@@ -196,6 +197,35 @@ test("markStuck and markCanceled set their respective statuses", (t) => {
|
|
|
196
197
|
assert.equal(getLatestForUnit("M001/S01/T01")!.status, "canceled");
|
|
197
198
|
});
|
|
198
199
|
|
|
200
|
+
test("markLatestActiveForWorkerCanceled cancels only the latest active dispatch for a worker", (t) => {
|
|
201
|
+
const base = makeBase();
|
|
202
|
+
t.after(() => cleanup(base));
|
|
203
|
+
const { workerId, leaseToken } = setup(base);
|
|
204
|
+
|
|
205
|
+
const first = recordDispatchClaim({
|
|
206
|
+
traceId: "tc-1", workerId, milestoneLeaseToken: leaseToken,
|
|
207
|
+
milestoneId: "M001", unitType: "plan-slice", unitId: "M001/S01",
|
|
208
|
+
});
|
|
209
|
+
assert.equal(first.ok, true);
|
|
210
|
+
if (!first.ok) return;
|
|
211
|
+
markCompleted(first.dispatchId);
|
|
212
|
+
|
|
213
|
+
const second = recordDispatchClaim({
|
|
214
|
+
traceId: "tc-2", workerId, milestoneLeaseToken: leaseToken,
|
|
215
|
+
milestoneId: "M001", unitType: "run-task", unitId: "M001/S01/T01",
|
|
216
|
+
});
|
|
217
|
+
assert.equal(second.ok, true);
|
|
218
|
+
if (!second.ok) return;
|
|
219
|
+
markRunning(second.dispatchId);
|
|
220
|
+
|
|
221
|
+
assert.equal(markLatestActiveForWorkerCanceled(workerId, "signal-exit"), true);
|
|
222
|
+
assert.equal(getLatestForUnit("M001/S01")!.status, "completed");
|
|
223
|
+
const latest = getLatestForUnit("M001/S01/T01")!;
|
|
224
|
+
assert.equal(latest.status, "canceled");
|
|
225
|
+
assert.equal(latest.exit_reason, "signal-exit");
|
|
226
|
+
assert.equal(markLatestActiveForWorkerCanceled(workerId, "signal-exit"), false);
|
|
227
|
+
});
|
|
228
|
+
|
|
199
229
|
test("terminal transitions do not overwrite an already terminal dispatch", (t) => {
|
|
200
230
|
const base = makeBase();
|
|
201
231
|
t.after(() => cleanup(base));
|
|
@@ -5,9 +5,11 @@ import {
|
|
|
5
5
|
clearUnitRuntimeRecord,
|
|
6
6
|
formatExecuteTaskRecoveryStatus,
|
|
7
7
|
inspectExecuteTaskDurability,
|
|
8
|
+
isInFlightRuntimePhase,
|
|
8
9
|
readUnitRuntimeRecord,
|
|
9
10
|
writeUnitRuntimeRecord,
|
|
10
11
|
} from "../unit-runtime.ts";
|
|
12
|
+
import { closeDatabase, insertMilestone, insertSlice, insertTask, openDatabase } from "../gsd-db.ts";
|
|
11
13
|
import { clearPathCache } from '../paths.ts';
|
|
12
14
|
import { test } from 'node:test';
|
|
13
15
|
import assert from 'node:assert/strict';
|
|
@@ -22,6 +24,12 @@ writeFileSync(
|
|
|
22
24
|
"utf-8",
|
|
23
25
|
);
|
|
24
26
|
|
|
27
|
+
console.log("\n=== in-flight runtime phases ===");
|
|
28
|
+
{
|
|
29
|
+
assert.equal(isInFlightRuntimePhase("crashed"), true, "crashed records remain recoverable");
|
|
30
|
+
assert.equal(isInFlightRuntimePhase("finalized"), false, "finalized records are terminal");
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
console.log("\n=== runtime record write/read/update ===");
|
|
26
34
|
{
|
|
27
35
|
const first = writeUnitRuntimeRecord(base, "execute-task", "M100/S02/T09", 1000, { phase: "dispatched" });
|
|
@@ -65,6 +73,35 @@ console.log("\n=== runtime record cleanup ===");
|
|
|
65
73
|
assert.deepStrictEqual(loaded, null, "record removed");
|
|
66
74
|
}
|
|
67
75
|
|
|
76
|
+
console.log("\n=== execute-task durability trusts closed DB task status ===");
|
|
77
|
+
{
|
|
78
|
+
const dbBase = mkdtempSync(join(tmpdir(), "gsd-unit-runtime-db-test-"));
|
|
79
|
+
mkdirSync(join(dbBase, ".gsd", "milestones", "M300", "slices", "S01", "tasks"), { recursive: true });
|
|
80
|
+
try {
|
|
81
|
+
openDatabase(join(dbBase, ".gsd", "gsd.db"));
|
|
82
|
+
insertMilestone({ id: "M300", title: "DB Milestone", status: "active" });
|
|
83
|
+
insertSlice({ id: "S01", milestoneId: "M300", title: "DB Slice", status: "in_progress" });
|
|
84
|
+
insertTask({ id: "T01", milestoneId: "M300", sliceId: "S01", title: "DB Task", status: "complete" });
|
|
85
|
+
writeFileSync(
|
|
86
|
+
join(dbBase, ".gsd", "milestones", "M300", "slices", "S01", "S01-PLAN.md"),
|
|
87
|
+
"# S01\n\n## Tasks\n\n- [ ] **T01: DB Task** `est:10m`\n",
|
|
88
|
+
"utf-8",
|
|
89
|
+
);
|
|
90
|
+
writeFileSync(join(dbBase, ".gsd", "STATE.md"), "## Next Action\nExecute T01 for S01: DB task\n", "utf-8");
|
|
91
|
+
|
|
92
|
+
const status = await inspectExecuteTaskDurability(dbBase, "M300/S01/T01");
|
|
93
|
+
assert.ok(status !== null, "db-complete: status exists");
|
|
94
|
+
assert.equal(status!.dbComplete, true, "db-complete: closed DB status is captured");
|
|
95
|
+
assert.equal(status!.summaryExists, false, "db-complete: summary can still be missing");
|
|
96
|
+
assert.equal(status!.taskChecked, false, "db-complete: checkbox can still be unchecked");
|
|
97
|
+
assert.equal(status!.nextActionAdvanced, false, "db-complete: next action can still point at task");
|
|
98
|
+
assert.equal(formatExecuteTaskRecoveryStatus(status!), "DB task status is closed");
|
|
99
|
+
} finally {
|
|
100
|
+
closeDatabase();
|
|
101
|
+
rmSync(dbBase, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
68
105
|
console.log("\n=== hook unit type sanitization (slash in unitType) ===");
|
|
69
106
|
{
|
|
70
107
|
// Hook units have unitType like "hook/code-review" with a slash
|
|
@@ -118,7 +118,7 @@ test("guided flow checks pending deep setup before plan-v2 gate", () => {
|
|
|
118
118
|
const source = readFileSync(join(gsdDir, "guided-flow.ts"), "utf-8");
|
|
119
119
|
const showSmartEntryIdx = source.indexOf("export async function showSmartEntry");
|
|
120
120
|
assert.notEqual(showSmartEntryIdx, -1);
|
|
121
|
-
const deepIdx = source.indexOf("
|
|
121
|
+
const deepIdx = source.indexOf("shouldRunDeepProjectSetup(state, prefs, basePath)", showSmartEntryIdx);
|
|
122
122
|
const planIdx = source.indexOf("runPlanV2Gate(ctx, basePath, state)", showSmartEntryIdx);
|
|
123
123
|
assert.ok(
|
|
124
124
|
deepIdx > -1 && planIdx > -1 && deepIdx < planIdx,
|
|
@@ -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);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// GSD-2 + src/resources/extensions/gsd/tests/working-output-messages.test.ts - Regression coverage for user-facing working-state message quality.
|
|
2
|
+
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
evaluateWorkingOutputMessage,
|
|
8
|
+
evaluateWorkingOutputMessages,
|
|
9
|
+
formatAutoUnitWorkingMessage,
|
|
10
|
+
} from "../working-output-messages.ts";
|
|
11
|
+
|
|
12
|
+
test("auto unit loader messages name the active work", () => {
|
|
13
|
+
assert.equal(
|
|
14
|
+
formatAutoUnitWorkingMessage("research-milestone", "M001"),
|
|
15
|
+
"Researching M001: waiting for provider response",
|
|
16
|
+
);
|
|
17
|
+
assert.equal(
|
|
18
|
+
evaluateWorkingOutputMessage({
|
|
19
|
+
surface: "loader",
|
|
20
|
+
message: formatAutoUnitWorkingMessage("research-milestone", "M001"),
|
|
21
|
+
context: { unitType: "research-milestone", unitId: "M001", health: "waiting" },
|
|
22
|
+
}).length,
|
|
23
|
+
0,
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("generic working messages are flagged", () => {
|
|
28
|
+
const findings = evaluateWorkingOutputMessage({
|
|
29
|
+
surface: "loader",
|
|
30
|
+
message: "Working...",
|
|
31
|
+
context: { health: "waiting" },
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
assert.deepEqual(findings.map(f => f.code), ["generic-working-message"]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("dashboard messages cannot claim healthy progress while recovering", () => {
|
|
38
|
+
const findings = evaluateWorkingOutputMessage({
|
|
39
|
+
surface: "dashboard",
|
|
40
|
+
message: "GSD AUTO Progressing well",
|
|
41
|
+
context: { health: "recovering", recoveryAttempts: 1 },
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
assert.deepEqual(findings.map(f => f.code), ["misleading-healthy-message"]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("pre-roadmap zero-slice counters are flagged", () => {
|
|
48
|
+
const findings = evaluateWorkingOutputMessage({
|
|
49
|
+
surface: "dashboard",
|
|
50
|
+
message: "0/0 slices",
|
|
51
|
+
context: { health: "waiting" },
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
assert.deepEqual(findings.map(f => f.code), ["fake-zero-progress"]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("stalled/provider-error/timeout messages need an action", () => {
|
|
58
|
+
const noAction = evaluateWorkingOutputMessage({
|
|
59
|
+
surface: "notification",
|
|
60
|
+
message: "Provider stalled after 2m",
|
|
61
|
+
context: { health: "stalled" },
|
|
62
|
+
});
|
|
63
|
+
assert.deepEqual(noAction.map(f => f.code), ["missing-action"]);
|
|
64
|
+
|
|
65
|
+
const withAction = evaluateWorkingOutputMessage({
|
|
66
|
+
surface: "notification",
|
|
67
|
+
message: "Provider stalled after 2m. Type /gsd stop or wait for retry.",
|
|
68
|
+
context: { health: "stalled" },
|
|
69
|
+
});
|
|
70
|
+
assert.equal(withAction.length, 0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("current fixed research working surfaces pass the audit", () => {
|
|
74
|
+
const findings = evaluateWorkingOutputMessages([
|
|
75
|
+
{
|
|
76
|
+
surface: "loader",
|
|
77
|
+
message: "Researching M001: waiting for provider response",
|
|
78
|
+
context: { unitType: "research-milestone", unitId: "M001", health: "waiting" },
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
surface: "dashboard",
|
|
82
|
+
message: "Recovering\nretry 1 after idle stall",
|
|
83
|
+
context: { unitType: "research-milestone", unitId: "M001", health: "recovering", recoveryAttempts: 1 },
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
surface: "notification",
|
|
87
|
+
message: "Auto-mode stopped - User requested stop.",
|
|
88
|
+
context: { health: "stopped" },
|
|
89
|
+
},
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
assert.equal(findings.length, 0);
|
|
93
|
+
});
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
11
11
|
import assert from "node:assert/strict";
|
|
12
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readdirSync } from "node:fs";
|
|
12
|
+
import { existsSync, mkdtempSync, mkdirSync, readFileSync, writeFileSync, rmSync, readdirSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import { tmpdir } from "node:os";
|
|
15
15
|
import { execSync } from "node:child_process";
|
|
16
16
|
|
|
17
|
-
import { PROJECT_FILES } from "../detection.js";
|
|
17
|
+
import { PROJECT_FILES, classifyProject } from "../detection.js";
|
|
18
18
|
|
|
19
19
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
20
20
|
|
|
@@ -30,6 +30,14 @@ function createGitRepo(): string {
|
|
|
30
30
|
return dir;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
function createEmptyGitRepo(): string {
|
|
34
|
+
const dir = mkdtempSync(join(tmpdir(), "wt-dispatch-test-empty-"));
|
|
35
|
+
execSync("git init", { cwd: dir, stdio: "ignore" });
|
|
36
|
+
execSync("git config user.email test@test.com", { cwd: dir, stdio: "ignore" });
|
|
37
|
+
execSync("git config user.name Test", { cwd: dir, stdio: "ignore" });
|
|
38
|
+
return dir;
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
/**
|
|
34
42
|
* Simulate the health check logic from auto/phases.ts.
|
|
35
43
|
*
|
|
@@ -64,8 +72,6 @@ function hasXcodeBundle(basePath: string): boolean {
|
|
|
64
72
|
} catch { return false; }
|
|
65
73
|
}
|
|
66
74
|
|
|
67
|
-
import { existsSync } from "node:fs";
|
|
68
|
-
|
|
69
75
|
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
70
76
|
|
|
71
77
|
test("PROJECT_FILES is exported and contains expected multi-ecosystem entries", () => {
|
|
@@ -80,6 +86,21 @@ test("PROJECT_FILES is exported and contains expected multi-ecosystem entries",
|
|
|
80
86
|
assert.ok(PROJECT_FILES.includes("Package.swift"), "includes Swift marker");
|
|
81
87
|
});
|
|
82
88
|
|
|
89
|
+
test("runUnitPhase fails closed when classification returns invalid-repo", () => {
|
|
90
|
+
const source = readFileSync(join(process.cwd(), "src/resources/extensions/gsd/auto/phases.ts"), "utf-8");
|
|
91
|
+
const invalidRepoBranch = source.slice(
|
|
92
|
+
source.indexOf('projectClassification.kind === "invalid-repo"'),
|
|
93
|
+
source.indexOf('projectClassification.kind === "greenfield"'),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
assert.match(invalidRepoBranch, /projectClassification\.reason === "missing \.git" && hasGit/);
|
|
97
|
+
assert.match(invalidRepoBranch, /project classification could not confirm \.git/);
|
|
98
|
+
assert.match(invalidRepoBranch, /ctx\.ui\.notify\(msg,\s*"error"\)/);
|
|
99
|
+
assert.match(invalidRepoBranch, /await deps\.stopAuto\(ctx,\s*pi,\s*msg\)/);
|
|
100
|
+
assert.match(invalidRepoBranch, /return \{ action: "break", reason: "worktree-invalid" \}/);
|
|
101
|
+
assert.match(invalidRepoBranch, /classified as invalid-repo/);
|
|
102
|
+
});
|
|
103
|
+
|
|
83
104
|
describe("health check with git repo", () => {
|
|
84
105
|
let dir: string;
|
|
85
106
|
beforeEach(() => { dir = createGitRepo(); });
|
|
@@ -132,8 +153,18 @@ describe("health check with git repo", () => {
|
|
|
132
153
|
});
|
|
133
154
|
|
|
134
155
|
test("health check passes for empty git repo (greenfield project)", () => {
|
|
135
|
-
|
|
136
|
-
|
|
156
|
+
const empty = createEmptyGitRepo();
|
|
157
|
+
try {
|
|
158
|
+
assert.ok(wouldPassHealthCheck(empty, existsSync), "empty git repo should pass health check (greenfield)");
|
|
159
|
+
assert.equal(classifyProject(empty).kind, "greenfield");
|
|
160
|
+
} finally {
|
|
161
|
+
rmSync(empty, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("health check classifies README-only repo as untyped existing, not greenfield", () => {
|
|
166
|
+
assert.ok(wouldPassHealthCheck(dir, existsSync), "README-only repo should pass health check");
|
|
167
|
+
assert.equal(classifyProject(dir).kind, "untyped-existing");
|
|
137
168
|
});
|
|
138
169
|
});
|
|
139
170
|
|
|
@@ -235,4 +235,11 @@ describe("removeWorktree — missing worktree", () => {
|
|
|
235
235
|
"should not throw when worktree does not exist",
|
|
236
236
|
);
|
|
237
237
|
});
|
|
238
|
+
|
|
239
|
+
test("deleteBranch is quiet when the branch is already gone", () => {
|
|
240
|
+
assert.doesNotThrow(
|
|
241
|
+
() => removeWorktree(base, "nonexistent", { deleteBranch: true }),
|
|
242
|
+
"missing branch should be treated as already cleaned up",
|
|
243
|
+
);
|
|
244
|
+
});
|
|
238
245
|
});
|
|
@@ -56,11 +56,11 @@ test("#2616: findNestedGitDirs ignores .git files (worktree pointers)", (t) => {
|
|
|
56
56
|
);
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
test("#2616: findNestedGitDirs skips excluded directories (node_modules, .gsd, target)", (t) => {
|
|
59
|
+
test("#2616: findNestedGitDirs skips excluded directories (node_modules, .gsd, .bg-shell, target)", (t) => {
|
|
60
60
|
const root = makeRoot(t);
|
|
61
61
|
|
|
62
62
|
// All three of these contain a .git *directory*, but the scan must skip them.
|
|
63
|
-
for (const excluded of ["node_modules", ".gsd", "target"]) {
|
|
63
|
+
for (const excluded of ["node_modules", ".gsd", ".bg-shell", "target"]) {
|
|
64
64
|
const inside = join(root, excluded, "vendored-pkg");
|
|
65
65
|
mkdirSync(join(inside, ".git"), { recursive: true });
|
|
66
66
|
}
|
|
@@ -73,6 +73,13 @@ test("#2616: findNestedGitDirs skips excluded directories (node_modules, .gsd, t
|
|
|
73
73
|
);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
test("#2616: findNestedGitDirs ignores normal missing child .git probes", (t) => {
|
|
77
|
+
const root = makeRoot(t);
|
|
78
|
+
mkdirSync(join(root, "plain-dir"), { recursive: true });
|
|
79
|
+
|
|
80
|
+
assert.deepEqual(findNestedGitDirs(root), []);
|
|
81
|
+
});
|
|
82
|
+
|
|
76
83
|
test("#2616: findNestedGitDirs finds deeply nested repos", (t) => {
|
|
77
84
|
const root = makeRoot(t);
|
|
78
85
|
const deep = join(root, "a", "b", "c", "scaffolded");
|
|
@@ -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
|
|
|
@@ -182,6 +196,17 @@ function findCalls(calls: CallLog[], fn: string): CallLog[] {
|
|
|
182
196
|
return calls.filter((c) => c.fn === fn);
|
|
183
197
|
}
|
|
184
198
|
|
|
199
|
+
function makeDbBase(): string {
|
|
200
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-worktree-resolver-"));
|
|
201
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
202
|
+
return base;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function cleanupDbBase(base: string): void {
|
|
206
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
207
|
+
try { rmSync(base, { recursive: true, force: true }); } catch { /* noop */ }
|
|
208
|
+
}
|
|
209
|
+
|
|
185
210
|
// ─── Getter Tests ────────────────────────────────────────────────────────────
|
|
186
211
|
|
|
187
212
|
test("workPath returns s.basePath", () => {
|
|
@@ -371,6 +396,43 @@ test("enterMilestone does not create double-nested worktree when originalBasePat
|
|
|
371
396
|
);
|
|
372
397
|
});
|
|
373
398
|
|
|
399
|
+
test("enterMilestone reacquires a released same-milestone lease before worktree entry", (t) => {
|
|
400
|
+
const base = makeDbBase();
|
|
401
|
+
t.after(() => cleanupDbBase(base));
|
|
402
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
403
|
+
insertMilestone({ id: "M001", title: "Test milestone", status: "active" });
|
|
404
|
+
|
|
405
|
+
const workerId = registerAutoWorker({ projectRootRealpath: base });
|
|
406
|
+
const originalClaim = claimMilestoneLease(workerId, "M001");
|
|
407
|
+
assert.equal(originalClaim.ok, true);
|
|
408
|
+
if (!originalClaim.ok) throw new Error("expected test lease claim");
|
|
409
|
+
assert.equal(releaseMilestoneLease(workerId, "M001", originalClaim.token), true);
|
|
410
|
+
|
|
411
|
+
const s = makeSession({
|
|
412
|
+
basePath: base,
|
|
413
|
+
originalBasePath: base,
|
|
414
|
+
workerId,
|
|
415
|
+
currentMilestoneId: "M001",
|
|
416
|
+
milestoneLeaseToken: originalClaim.token,
|
|
417
|
+
});
|
|
418
|
+
const deps = makeDeps({
|
|
419
|
+
createAutoWorktree: (basePath: string, milestoneId: string) => join(basePath, ".gsd", "worktrees", milestoneId),
|
|
420
|
+
});
|
|
421
|
+
const ctx = makeNotifyCtx();
|
|
422
|
+
const resolver = new WorktreeResolver(s, deps);
|
|
423
|
+
|
|
424
|
+
resolver.enterMilestone("M001", ctx);
|
|
425
|
+
|
|
426
|
+
const row = getMilestoneLease("M001");
|
|
427
|
+
assert.ok(row);
|
|
428
|
+
assert.equal(row.worker_id, workerId);
|
|
429
|
+
assert.equal(row.status, "held");
|
|
430
|
+
assert.equal(row.fencing_token, originalClaim.token + 1);
|
|
431
|
+
assert.equal(s.milestoneLeaseToken, originalClaim.token + 1);
|
|
432
|
+
assert.equal(s.basePath, join(base, ".gsd", "worktrees", "M001"));
|
|
433
|
+
assert.equal(ctx.messages.some((m) => m.level === "error"), false);
|
|
434
|
+
});
|
|
435
|
+
|
|
374
436
|
// ─── enterMilestone Tests (branch mode) ──────────────────────────────────────
|
|
375
437
|
|
|
376
438
|
test("enterMilestone in branch mode calls enterBranchModeForMilestone and rebuilds GitService", () => {
|