@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.955e4da0
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/dist/cli-web-branch.d.ts +2 -0
- package/dist/cli-web-branch.js +9 -2
- package/dist/help-text.js +5 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +78 -23
- package/dist/resources/extensions/bg-shell/utilities.js +2 -2
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +92 -230
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
- package/dist/resources/extensions/github-sync/templates.js +3 -3
- package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
- package/dist/resources/extensions/gsd/auto/loop.js +74 -56
- package/dist/resources/extensions/gsd/auto/orchestrator.js +142 -15
- package/dist/resources/extensions/gsd/auto/phases.js +34 -4
- package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
- package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
- package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +12 -9
- package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
- package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
- package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
- package/dist/resources/extensions/gsd/auto-start.js +20 -36
- package/dist/resources/extensions/gsd/auto-timers.js +16 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
- package/dist/resources/extensions/gsd/auto-verification.js +7 -7
- package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +34 -289
- package/dist/resources/extensions/gsd/auto.js +15 -14
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +20 -43
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +131 -140
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +89 -8
- package/dist/resources/extensions/gsd/captures.js +5 -13
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
- package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
- package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
- package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
- package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
- package/dist/resources/extensions/gsd/commands-ship.js +2 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
- package/dist/resources/extensions/gsd/db/engine.js +755 -0
- package/dist/resources/extensions/gsd/db/queries.js +372 -0
- package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
- package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
- package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
- package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
- package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
- package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
- package/dist/resources/extensions/gsd/db-workspace.js +103 -0
- package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
- package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +8 -10
- package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +9 -2
- package/dist/resources/extensions/gsd/doctor.js +16 -9
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
- package/dist/resources/extensions/gsd/git-service.js +1 -0
- package/dist/resources/extensions/gsd/gitignore.js +3 -0
- package/dist/resources/extensions/gsd/gsd-db.js +183 -2048
- package/dist/resources/extensions/gsd/guided-flow.js +68 -471
- package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
- package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
- package/dist/resources/extensions/gsd/md-importer.js +4 -3
- package/dist/resources/extensions/gsd/migrate/safety.js +19 -11
- package/dist/resources/extensions/gsd/migration-auto-check.js +27 -5
- package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
- package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
- package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
- package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
- package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
- package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
- package/dist/resources/extensions/gsd/model-router.js +3 -0
- package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +7 -5
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/paths.js +10 -24
- package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
- package/dist/resources/extensions/gsd/preferences.js +161 -29
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
- package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
- package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
- package/dist/resources/extensions/gsd/question-transport.js +86 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +12 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
- package/dist/resources/extensions/gsd/state.js +13 -5
- package/dist/resources/extensions/gsd/status-guards.js +56 -8
- package/dist/resources/extensions/gsd/templates/plan.md +7 -0
- package/dist/resources/extensions/gsd/templates/project.md +1 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/dist/resources/extensions/gsd/templates/uat.md +5 -1
- package/dist/resources/extensions/gsd/tool-contract.js +52 -8
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
- package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
- package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -5
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
- package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
- package/dist/resources/extensions/gsd/uat-policy.js +16 -10
- package/dist/resources/extensions/gsd/uat-run.js +9 -14
- package/dist/resources/extensions/gsd/undo.js +8 -7
- package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
- package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
- package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
- package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
- package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
- package/dist/resources/extensions/gsd/worktree-git-recovery.js +287 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
- package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
- package/dist/resources/extensions/gsd/worktree-root.js +17 -6
- package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
- package/dist/resources/extensions/gsd/worktree-session-state.js +12 -10
- package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
- package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
- package/dist/resources/extensions/shared/interview-ui.js +2 -2
- package/dist/resources/shared/claude-runtime-floor.js +182 -0
- package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/update-cmd.js +20 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- 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 +8 -8
- 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/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +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 +12 -12
- package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/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/2659.b7b129ee6a769448.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
- package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
- package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +20 -8
- package/dist/worktree-status-banner.js +7 -3
- package/package.json +2 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts +10 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +8 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +32 -22
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
- package/packages/pi-ai/dist/image-models.generated.js +6 -6
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +295 -98
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +309 -154
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/components/input.js +1 -1
- package/packages/pi-tui/dist/components/input.js.map +1 -1
- package/packages/pi-tui/dist/keys.d.ts.map +1 -1
- package/packages/pi-tui/dist/keys.js +39 -30
- package/packages/pi-tui/dist/keys.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +22 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +87 -24
- package/src/resources/extensions/bg-shell/utilities.ts +2 -2
- package/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +114 -281
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +268 -0
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
- package/src/resources/extensions/github-sync/templates.ts +3 -3
- package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
- package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +3 -1
- package/src/resources/extensions/gsd/auto/loop.ts +83 -61
- package/src/resources/extensions/gsd/auto/orchestrator.ts +164 -17
- package/src/resources/extensions/gsd/auto/phases.ts +45 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
- package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +16 -8
- package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
- package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
- package/src/resources/extensions/gsd/auto-start.ts +25 -34
- package/src/resources/extensions/gsd/auto-timers.ts +16 -2
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
- package/src/resources/extensions/gsd/auto-verification.ts +7 -8
- package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +53 -306
- package/src/resources/extensions/gsd/auto.ts +27 -17
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +20 -43
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +147 -153
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +132 -6
- package/src/resources/extensions/gsd/captures.ts +5 -14
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
- package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
- package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
- package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
- package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
- package/src/resources/extensions/gsd/commands-ship.ts +2 -2
- package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
- package/src/resources/extensions/gsd/db/engine.ts +809 -0
- package/src/resources/extensions/gsd/db/queries.ts +453 -0
- package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
- package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
- package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
- package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
- package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
- package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
- package/src/resources/extensions/gsd/db-workspace.ts +170 -0
- package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
- package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +8 -11
- package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +10 -3
- package/src/resources/extensions/gsd/doctor.ts +15 -5
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
- package/src/resources/extensions/gsd/git-service.ts +1 -0
- package/src/resources/extensions/gsd/gitignore.ts +3 -0
- package/src/resources/extensions/gsd/gsd-db.ts +185 -2373
- package/src/resources/extensions/gsd/guided-flow.ts +81 -561
- package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
- package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
- package/src/resources/extensions/gsd/md-importer.ts +3 -3
- package/src/resources/extensions/gsd/migrate/safety.ts +17 -9
- package/src/resources/extensions/gsd/migration-auto-check.ts +30 -5
- package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
- package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
- package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
- package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
- package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
- package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
- package/src/resources/extensions/gsd/model-router.ts +3 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
- package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -5
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/paths.ts +9 -22
- package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +191 -28
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
- package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
- package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
- package/src/resources/extensions/gsd/question-transport.ts +138 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +14 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
- package/src/resources/extensions/gsd/state.ts +15 -5
- package/src/resources/extensions/gsd/status-guards.ts +59 -8
- package/src/resources/extensions/gsd/templates/plan.md +7 -0
- package/src/resources/extensions/gsd/templates/project.md +1 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/src/resources/extensions/gsd/templates/uat.md +5 -1
- package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +444 -5
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +143 -1
- package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +185 -1
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +121 -0
- package/src/resources/extensions/gsd/tool-contract.ts +86 -8
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
- package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
- package/src/resources/extensions/gsd/tools/exec-tool.ts +5 -5
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
- package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
- package/src/resources/extensions/gsd/uat-policy.ts +19 -10
- package/src/resources/extensions/gsd/uat-run.ts +10 -14
- package/src/resources/extensions/gsd/undo.ts +9 -8
- package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
- package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
- package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
- package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
- package/src/resources/extensions/gsd/worktree-git-recovery.ts +308 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +17 -17
- package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
- package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
- package/src/resources/extensions/gsd/worktree-root.ts +17 -6
- package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
- package/src/resources/extensions/gsd/worktree-session-state.ts +12 -10
- package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
- package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
- package/src/resources/extensions/shared/interview-ui.ts +15 -2
- package/src/resources/shared/claude-runtime-floor.ts +248 -0
- package/src/resources/skills/gsd-browser/SKILL.md +1 -1
- package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
- package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
- package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
- package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
- package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_ssgManifest.js +0 -0
|
@@ -33,6 +33,8 @@ import type { UnifiedRule } from "../rule-types.js";
|
|
|
33
33
|
import { supportsStructuredQuestions } from "../workflow-mcp.js";
|
|
34
34
|
import {
|
|
35
35
|
closeDatabase,
|
|
36
|
+
insertAssessment,
|
|
37
|
+
insertGateRow,
|
|
36
38
|
insertMilestone,
|
|
37
39
|
insertSlice,
|
|
38
40
|
insertTask,
|
|
@@ -302,6 +304,46 @@ test("advance() sets active unit and is reflected in status", async (t) => {
|
|
|
302
304
|
});
|
|
303
305
|
});
|
|
304
306
|
|
|
307
|
+
test("advance() blocks source dispatch when an earlier slice is incomplete", async (t) => {
|
|
308
|
+
const f = makeFixture({
|
|
309
|
+
dispatch: () => ({
|
|
310
|
+
action: "dispatch",
|
|
311
|
+
unitType: "execute-task",
|
|
312
|
+
unitId: "M001/S02/T01",
|
|
313
|
+
prompt: "fixture-prompt",
|
|
314
|
+
}),
|
|
315
|
+
});
|
|
316
|
+
t.after(() => f.cleanup());
|
|
317
|
+
|
|
318
|
+
insertSlice({
|
|
319
|
+
id: "S02",
|
|
320
|
+
milestoneId: "M001",
|
|
321
|
+
title: "Second slice",
|
|
322
|
+
status: "active",
|
|
323
|
+
risk: "low",
|
|
324
|
+
depends: [],
|
|
325
|
+
demo: "",
|
|
326
|
+
sequence: 2,
|
|
327
|
+
});
|
|
328
|
+
insertTask({
|
|
329
|
+
id: "T01",
|
|
330
|
+
sliceId: "S02",
|
|
331
|
+
milestoneId: "M001",
|
|
332
|
+
title: "Second task",
|
|
333
|
+
status: "active",
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const result = await f.orchestrator.advance();
|
|
337
|
+
|
|
338
|
+
assert.equal(result.kind, "blocked");
|
|
339
|
+
if (result.kind !== "blocked") return;
|
|
340
|
+
assert.equal(result.action, "stop");
|
|
341
|
+
assert.match(result.reason, /earlier slice M001\/S01 is not complete/);
|
|
342
|
+
assert.equal(f.session.pendingOrchestrationDispatch, null);
|
|
343
|
+
assert.deepEqual(f.orchestrator.getStatus().activeUnit, undefined);
|
|
344
|
+
assert.ok(f.journalNames().includes("advance-blocked"));
|
|
345
|
+
});
|
|
346
|
+
|
|
305
347
|
test("getStatus() returns defensive copy of activeUnit", async (t) => {
|
|
306
348
|
const f = makeFixture();
|
|
307
349
|
t.after(() => f.cleanup());
|
|
@@ -374,10 +416,65 @@ test("advance() reports completion when complete state has no next unit", async
|
|
|
374
416
|
|
|
375
417
|
assert.equal(result.kind, "stopped");
|
|
376
418
|
if (result.kind !== "stopped") return;
|
|
377
|
-
assert.equal(result.reason, "
|
|
419
|
+
assert.equal(result.reason, "All milestones complete");
|
|
420
|
+
assert.equal(result.terminalOutcome?.code, "all-complete");
|
|
378
421
|
assert.equal(f.orchestrator.getStatus().phase, "stopped");
|
|
379
422
|
});
|
|
380
423
|
|
|
424
|
+
test("advance() blocks all-complete stop when completed milestone is still unmerged in a worktree", async (t) => {
|
|
425
|
+
const f = makeFixture({ complete: true, noTask: true });
|
|
426
|
+
t.after(() => f.cleanup());
|
|
427
|
+
|
|
428
|
+
insertSlice({
|
|
429
|
+
id: "S01",
|
|
430
|
+
milestoneId: "M001",
|
|
431
|
+
title: "Slice",
|
|
432
|
+
status: "complete",
|
|
433
|
+
risk: "low",
|
|
434
|
+
depends: [],
|
|
435
|
+
demo: "",
|
|
436
|
+
sequence: 1,
|
|
437
|
+
});
|
|
438
|
+
insertAssessment({
|
|
439
|
+
path: "milestones/M001/M001-VALIDATION.md",
|
|
440
|
+
milestoneId: "M001",
|
|
441
|
+
status: "pass",
|
|
442
|
+
scope: "milestone-validation",
|
|
443
|
+
fullContent: "verdict: pass",
|
|
444
|
+
});
|
|
445
|
+
insertGateRow({
|
|
446
|
+
milestoneId: "M001",
|
|
447
|
+
sliceId: "S01",
|
|
448
|
+
gateId: "Q3",
|
|
449
|
+
scope: "slice",
|
|
450
|
+
status: "pending",
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
const worktreePath = join(f.base, ".gsd", "worktrees", "M001");
|
|
454
|
+
mkdirSync(join(f.base, ".gsd", "worktrees"), { recursive: true });
|
|
455
|
+
execFileSync("git", ["worktree", "add", "-b", "milestone/M001", worktreePath], { cwd: f.base, stdio: "ignore" });
|
|
456
|
+
mkdirSync(join(worktreePath, ".gsd", "milestones", "M001"), { recursive: true });
|
|
457
|
+
writeFileSync(join(worktreePath, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\n");
|
|
458
|
+
f.session.basePath = worktreePath;
|
|
459
|
+
f.session.originalBasePath = f.base;
|
|
460
|
+
f.session.currentMilestoneId = "M001";
|
|
461
|
+
f.session.milestoneMergedInPhases = false;
|
|
462
|
+
|
|
463
|
+
const result = await f.orchestrator.advance();
|
|
464
|
+
|
|
465
|
+
assert.equal(result.kind, "blocked");
|
|
466
|
+
if (result.kind !== "blocked") return;
|
|
467
|
+
assert.equal(result.action, "pause");
|
|
468
|
+
assert.equal(result.terminalOutcome?.code, "settlement-blocked");
|
|
469
|
+
assert.match(result.reason, /worktree branch has not been merged to main/);
|
|
470
|
+
assert.doesNotMatch(result.reason, /quality gate Q3 is still pending/);
|
|
471
|
+
assert.equal(f.orchestrator.getStatus().phase, "paused");
|
|
472
|
+
assert.equal(f.session.milestoneSettlement?.ok, false);
|
|
473
|
+
const names = f.journalNames();
|
|
474
|
+
assert.ok(names.includes("advance-blocked"));
|
|
475
|
+
assert.ok(!names.includes("advance-stopped"));
|
|
476
|
+
});
|
|
477
|
+
|
|
381
478
|
test("advance() stopped clears previous activeUnit and resets idempotent lock", async (t) => {
|
|
382
479
|
// First advance dispatches; then we make the milestone resolve to no unit by
|
|
383
480
|
// closing it on disk + DB and re-deriving. Simpler: drive a fixture that
|
|
@@ -696,7 +793,10 @@ test("stuck-loop: start() resets the ring so a fresh saturation cycle is require
|
|
|
696
793
|
assert.equal(next.kind, "advanced");
|
|
697
794
|
});
|
|
698
795
|
|
|
699
|
-
test("stuck-loop: resume()
|
|
796
|
+
test("stuck-loop: resume() preserves ring so detection accumulates across pause/resume", async (t) => {
|
|
797
|
+
// Regression for #572: resume() must NOT reset dispatchKeyWindow. Before the
|
|
798
|
+
// fix, a pause/resume cycle cleared the window, letting a stuck loop silently
|
|
799
|
+
// re-accumulate STUCK_WINDOW_SIZE dispatches before being detected again.
|
|
700
800
|
const f = makeFixture();
|
|
701
801
|
t.after(() => f.cleanup());
|
|
702
802
|
|
|
@@ -707,11 +807,39 @@ test("stuck-loop: resume() resets the ring", async (t) => {
|
|
|
707
807
|
const resumed = await f.orchestrator.resume();
|
|
708
808
|
assert.equal(resumed.kind, "resumed");
|
|
709
809
|
|
|
810
|
+
// The ring is preserved, so the next advance pushes it to STUCK_WINDOW_SIZE
|
|
811
|
+
// and triggers stuck-loop detection — not a fresh dispatch.
|
|
710
812
|
const next = await f.orchestrator.advance();
|
|
711
|
-
assert.equal(next.kind, "
|
|
813
|
+
assert.equal(next.kind, "blocked");
|
|
814
|
+
if (next.kind !== "blocked") return;
|
|
815
|
+
assert.equal(next.action, "stop");
|
|
816
|
+
assert.ok(next.reason.startsWith("stuck-loop:"), `expected stuck-loop reason, got: ${next.reason}`);
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
test("stuck-loop: stop('pause') preserves ring across the stop/resume cycle", async (t) => {
|
|
820
|
+
// Regression for #572: stop("pause") must behave the same as resume() —
|
|
821
|
+
// the window must survive so detection accumulates across pause/resume pairs.
|
|
822
|
+
const f = makeFixture();
|
|
823
|
+
t.after(() => f.cleanup());
|
|
824
|
+
|
|
825
|
+
for (let i = 0; i < STUCK_WINDOW_SIZE - 1; i++) {
|
|
826
|
+
await f.orchestrator.advance();
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const stopped = await f.orchestrator.stop("pause");
|
|
830
|
+
assert.equal(stopped.kind, "stopped");
|
|
831
|
+
|
|
832
|
+
const resumed = await f.orchestrator.resume();
|
|
833
|
+
assert.equal(resumed.kind, "resumed");
|
|
834
|
+
|
|
835
|
+
const next = await f.orchestrator.advance();
|
|
836
|
+
assert.equal(next.kind, "blocked");
|
|
837
|
+
if (next.kind !== "blocked") return;
|
|
838
|
+
assert.equal(next.action, "stop");
|
|
839
|
+
assert.ok(next.reason.startsWith("stuck-loop:"), `expected stuck-loop reason, got: ${next.reason}`);
|
|
712
840
|
});
|
|
713
841
|
|
|
714
|
-
test("stuck-loop: stop() resets the ring", async (t) => {
|
|
842
|
+
test("stuck-loop: stop('user-request') resets the ring (hard stop)", async (t) => {
|
|
715
843
|
const f = makeFixture();
|
|
716
844
|
t.after(() => f.cleanup());
|
|
717
845
|
|
|
@@ -722,6 +850,7 @@ test("stuck-loop: stop() resets the ring", async (t) => {
|
|
|
722
850
|
const stopped = await f.orchestrator.stop("user-request");
|
|
723
851
|
assert.equal(stopped.kind, "stopped");
|
|
724
852
|
|
|
853
|
+
// Hard stop clears the ring, so the next advance dispatches fresh.
|
|
725
854
|
const next = await f.orchestrator.advance();
|
|
726
855
|
assert.equal(next.kind, "advanced");
|
|
727
856
|
});
|
|
@@ -306,7 +306,9 @@ test("pauseAuto records the expected worktree path when paused from project root
|
|
|
306
306
|
|
|
307
307
|
const meta = readPausedSessionMetadata(base);
|
|
308
308
|
assert.ok(meta);
|
|
309
|
-
|
|
309
|
+
// No worktree exists yet, so the recorded path is the canonical
|
|
310
|
+
// .gsd-worktrees/ creation location (worktree-placement seam).
|
|
311
|
+
assert.equal(meta.worktreePath, join(base, ".gsd-worktrees", "M001"));
|
|
310
312
|
} finally {
|
|
311
313
|
autoSession.reset();
|
|
312
314
|
try {
|
|
@@ -88,3 +88,49 @@ test("detects session execution tools supported by the evidence collector", () =
|
|
|
88
88
|
|
|
89
89
|
assert.equal(_hasExecutionToolCallsInSessionForTest(entries), true);
|
|
90
90
|
});
|
|
91
|
+
|
|
92
|
+
test("detects execution tool calls in bare agent-end messages (no session-entry wrapper)", () => {
|
|
93
|
+
// The auto loop passes opts.agentEndMessages as bare {role, content}
|
|
94
|
+
// messages — not {type: "message", message} session-manager entries.
|
|
95
|
+
const entries = [
|
|
96
|
+
{
|
|
97
|
+
role: "assistant",
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: "toolCall",
|
|
101
|
+
name: "Bash",
|
|
102
|
+
arguments: { command: "test -s index.html && grep -q localStorage index.html" },
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
assert.equal(_hasExecutionToolCallsInSessionForTest(entries), true);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("does not suppress for bare agent-end messages without execution tools", () => {
|
|
112
|
+
const entries = [
|
|
113
|
+
{
|
|
114
|
+
role: "assistant",
|
|
115
|
+
content: [
|
|
116
|
+
{ type: "text", text: "Task complete." },
|
|
117
|
+
{ type: "toolCall", name: "Write", arguments: { file_path: "index.html" } },
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
assert.equal(_hasExecutionToolCallsInSessionForTest(entries), false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("ignores bare user messages with toolCall-shaped content", () => {
|
|
126
|
+
const entries = [
|
|
127
|
+
{
|
|
128
|
+
role: "user",
|
|
129
|
+
content: [
|
|
130
|
+
{ type: "toolCall", name: "bash", arguments: { command: "echo hi" } },
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
assert.equal(_hasExecutionToolCallsInSessionForTest(entries), false);
|
|
136
|
+
});
|
|
@@ -6,12 +6,15 @@ import assert from "node:assert/strict";
|
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
autoSession,
|
|
9
|
+
clearAutoToolSurfaceSnapshot,
|
|
9
10
|
clearToolInvocationError,
|
|
10
11
|
getAutoRuntimeSnapshot,
|
|
12
|
+
recordAutoToolSurfaceSnapshot,
|
|
11
13
|
} from "../auto-runtime-state.ts";
|
|
12
14
|
|
|
13
15
|
test("getAutoRuntimeSnapshot includes orchestration phase when available", () => {
|
|
14
16
|
autoSession.reset();
|
|
17
|
+
clearAutoToolSurfaceSnapshot();
|
|
15
18
|
autoSession.active = true;
|
|
16
19
|
autoSession.basePath = "/tmp/project";
|
|
17
20
|
autoSession.orchestration = {
|
|
@@ -33,10 +36,40 @@ test("getAutoRuntimeSnapshot includes orchestration phase when available", () =>
|
|
|
33
36
|
assert.equal(snap.orchestrationPhase, "running");
|
|
34
37
|
assert.equal(snap.orchestrationTransitionCount, 3);
|
|
35
38
|
assert.equal(snap.orchestrationLastTransitionAt, 123);
|
|
39
|
+
assert.equal(snap.toolSurface, null);
|
|
36
40
|
|
|
37
41
|
autoSession.reset();
|
|
38
42
|
});
|
|
39
43
|
|
|
44
|
+
test("getAutoRuntimeSnapshot includes the active typed tool-surface snapshot", () => {
|
|
45
|
+
autoSession.reset();
|
|
46
|
+
clearAutoToolSurfaceSnapshot();
|
|
47
|
+
autoSession.active = true;
|
|
48
|
+
|
|
49
|
+
recordAutoToolSurfaceSnapshot({
|
|
50
|
+
source: "dispatch-scope",
|
|
51
|
+
unitType: "run-uat",
|
|
52
|
+
modelFacingToolNames: ["read", "read", "gsd_uat_exec"],
|
|
53
|
+
registeredToolNames: ["read", "browser_navigate"],
|
|
54
|
+
scopedToolNames: ["read", "browser_navigate"],
|
|
55
|
+
presentedToolNames: ["gsd_uat_exec"],
|
|
56
|
+
capturedAt: 123,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const snap = getAutoRuntimeSnapshot();
|
|
60
|
+
|
|
61
|
+
assert.equal(snap.toolSurface?.source, "dispatch-scope");
|
|
62
|
+
assert.equal(snap.toolSurface?.unitType, "run-uat");
|
|
63
|
+
assert.deepEqual(snap.toolSurface?.modelFacingToolNames, ["read", "gsd_uat_exec"]);
|
|
64
|
+
assert.deepEqual(snap.toolSurface?.registeredToolNames, ["read", "browser_navigate"]);
|
|
65
|
+
assert.deepEqual(snap.toolSurface?.scopedToolNames, ["read", "browser_navigate"]);
|
|
66
|
+
assert.deepEqual(snap.toolSurface?.presentedToolNames, ["gsd_uat_exec"]);
|
|
67
|
+
assert.equal(snap.toolSurface?.capturedAt, 123);
|
|
68
|
+
|
|
69
|
+
autoSession.reset();
|
|
70
|
+
clearAutoToolSurfaceSnapshot();
|
|
71
|
+
});
|
|
72
|
+
|
|
40
73
|
test("clearToolInvocationError clears stale tool error state for active auto sessions", () => {
|
|
41
74
|
autoSession.reset();
|
|
42
75
|
autoSession.active = true;
|
|
@@ -56,4 +89,5 @@ test("getAutoRuntimeSnapshot omits orchestration phase when seam not wired", ()
|
|
|
56
89
|
assert.equal(snap.orchestrationPhase, undefined);
|
|
57
90
|
assert.equal(snap.orchestrationTransitionCount, undefined);
|
|
58
91
|
assert.equal(snap.orchestrationLastTransitionAt, undefined);
|
|
92
|
+
assert.equal(snap.toolSurface, null);
|
|
59
93
|
});
|
|
@@ -184,7 +184,7 @@ describe("auto-worktree workspace registry", () => {
|
|
|
184
184
|
git(["commit", "-m", "add milestone"], tempDir);
|
|
185
185
|
|
|
186
186
|
createAutoWorktree(tempDir, "M003");
|
|
187
|
-
const wtDir = join(tempDir, ".gsd
|
|
187
|
+
const wtDir = join(tempDir, ".gsd-worktrees", "M003");
|
|
188
188
|
writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
|
|
189
189
|
git(["add", "feature.txt"], wtDir);
|
|
190
190
|
git(["commit", "-m", "feat: implement M003"], wtDir);
|
|
@@ -216,7 +216,7 @@ describe("auto-worktree workspace registry", () => {
|
|
|
216
216
|
git(["commit", "-m", "add milestone"], tempDir);
|
|
217
217
|
|
|
218
218
|
createAutoWorktree(tempDir, "M004");
|
|
219
|
-
const wtDir = join(tempDir, ".gsd
|
|
219
|
+
const wtDir = join(tempDir, ".gsd-worktrees", "M004");
|
|
220
220
|
writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
|
|
221
221
|
git(["add", "feature.txt"], wtDir);
|
|
222
222
|
git(["commit", "-m", "feat: implement M004"], wtDir);
|
|
@@ -35,7 +35,8 @@ test("repair target accepts a missing expected milestone worktree", () => {
|
|
|
35
35
|
|
|
36
36
|
assert.equal(result.ok, true);
|
|
37
37
|
if (result.ok) {
|
|
38
|
-
|
|
38
|
+
// No worktree exists yet, so the expected path is the canonical container.
|
|
39
|
+
assert.equal(result.expectedPath, join(base, ".gsd-worktrees", "M001"));
|
|
39
40
|
}
|
|
40
41
|
} finally {
|
|
41
42
|
cleanup(base);
|
|
@@ -192,7 +193,8 @@ test("paused metadata path resolves to the expected worktree while paused at pro
|
|
|
192
193
|
baseIsAutoWorktree: false,
|
|
193
194
|
});
|
|
194
195
|
|
|
195
|
-
|
|
196
|
+
// No worktree exists yet, so resolution lands at the canonical container.
|
|
197
|
+
assert.equal(result, join(base, ".gsd-worktrees", "M001"));
|
|
196
198
|
} finally {
|
|
197
199
|
cleanup(base);
|
|
198
200
|
}
|
|
@@ -17,6 +17,7 @@ import { tmpdir } from "node:os";
|
|
|
17
17
|
import { randomUUID } from "node:crypto";
|
|
18
18
|
|
|
19
19
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.ts";
|
|
20
|
+
import { resolveCloseoutArtifactProjection } from "../artifact-projection.ts";
|
|
20
21
|
|
|
21
22
|
function makeTmpBase(): string {
|
|
22
23
|
const base = join(tmpdir(), `gsd-canon-test-${randomUUID()}`);
|
|
@@ -106,3 +107,22 @@ test("only returns the worktree for the requested milestone, not siblings", () =
|
|
|
106
107
|
cleanup(base);
|
|
107
108
|
}
|
|
108
109
|
});
|
|
110
|
+
|
|
111
|
+
test("resolveCloseoutArtifactProjection names project and canonical artifact roots", () => {
|
|
112
|
+
const base = makeTmpBase();
|
|
113
|
+
try {
|
|
114
|
+
const wtPath = makeLiveWorktree(base, "M001");
|
|
115
|
+
const projection = resolveCloseoutArtifactProjection({
|
|
116
|
+
milestoneId: "M001",
|
|
117
|
+
basePath: wtPath,
|
|
118
|
+
originalBasePath: base,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
assert.equal(projection.projectRoot, base);
|
|
122
|
+
assert.equal(projection.canonicalMilestoneRoot, wtPath);
|
|
123
|
+
assert.equal(projection.summaryArtifactBasePath, wtPath);
|
|
124
|
+
assert.equal(projection.gateEvidenceBasePath, wtPath);
|
|
125
|
+
} finally {
|
|
126
|
+
cleanup(base);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
@@ -73,4 +73,26 @@ describe("clear stale pending auto-start (#3667)", () => {
|
|
|
73
73
|
"pending auto-start gate must clear stale map entries for completed discussions",
|
|
74
74
|
);
|
|
75
75
|
});
|
|
76
|
+
|
|
77
|
+
test("guided-flow does not treat a live discuss turn as a stale pending entry", () => {
|
|
78
|
+
const source = readFileSync(join(__dirname, "..", "guided-flow.ts"), "utf-8");
|
|
79
|
+
assert.ok(
|
|
80
|
+
source.includes("!isAgentTurnInFlight(ctx)"),
|
|
81
|
+
"stale-entry deletion must be gated on no agent turn being in flight — a dispatched " +
|
|
82
|
+
"discuss turn can think for over 30s before writing its first artifact, and deleting " +
|
|
83
|
+
"its entry re-dispatches the workflow (duplicate interview + duplicate completion message)",
|
|
84
|
+
);
|
|
85
|
+
assert.ok(
|
|
86
|
+
source.includes('const milestoneHasDraft = !!resolveMilestoneFile(basePath, entry.milestoneId, "CONTEXT-DRAFT");'),
|
|
87
|
+
"stale-entry check must treat an existing CONTEXT-DRAFT as proof of an in-progress interview",
|
|
88
|
+
);
|
|
89
|
+
assert.ok(
|
|
90
|
+
source.includes("!milestoneHasDraft"),
|
|
91
|
+
"stale-entry deletion must require the CONTEXT-DRAFT to be absent",
|
|
92
|
+
);
|
|
93
|
+
assert.ok(
|
|
94
|
+
source.includes("ctx.hasPendingMessages"),
|
|
95
|
+
"in-flight detection must also cover dispatched-but-not-yet-started queued messages",
|
|
96
|
+
);
|
|
97
|
+
});
|
|
76
98
|
});
|
|
@@ -696,3 +696,25 @@ test("ensureCodebaseMapFresh: does not rewrite expired metadata when fingerprint
|
|
|
696
696
|
cleanup(base);
|
|
697
697
|
}
|
|
698
698
|
});
|
|
699
|
+
|
|
700
|
+
test("ensureCodebaseMapFresh: detects file changes within the TTL window", () => {
|
|
701
|
+
const base = makeTmpRepo();
|
|
702
|
+
try {
|
|
703
|
+
addFile(base, "src/main.ts");
|
|
704
|
+
// Generate initial map with a long TTL so the cache is still active.
|
|
705
|
+
const initial = ensureCodebaseMapFresh(base, undefined, { ttlMs: 60_000 });
|
|
706
|
+
assert.equal(initial.status, "generated");
|
|
707
|
+
|
|
708
|
+
// Add a new tracked file while the TTL is still active.
|
|
709
|
+
addFile(base, "src/new.ts");
|
|
710
|
+
|
|
711
|
+
// Must detect the change even though the TTL has not expired.
|
|
712
|
+
const refreshed = ensureCodebaseMapFresh(base, undefined, { ttlMs: 60_000 });
|
|
713
|
+
assert.equal(refreshed.status, "updated");
|
|
714
|
+
assert.equal(refreshed.reason, "files-changed");
|
|
715
|
+
const written = readCodebaseMap(base);
|
|
716
|
+
assert.ok(written?.includes("`src/new.ts`"));
|
|
717
|
+
} finally {
|
|
718
|
+
cleanup(base);
|
|
719
|
+
}
|
|
720
|
+
});
|
|
@@ -64,3 +64,14 @@ test("getWorkspaceGitBlockMessageForBase allows doctor on product conflicts", as
|
|
|
64
64
|
cleanup(base);
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
|
+
|
|
68
|
+
test("getWorkspaceGitBlockMessageForBase allows forensics on product conflicts", async () => {
|
|
69
|
+
const base = makeTempRepo("gsd-dispatch-ws-git-forensics-");
|
|
70
|
+
try {
|
|
71
|
+
seedProductConflict(base);
|
|
72
|
+
const blocked = await getWorkspaceGitBlockMessageForBase(base, "forensics");
|
|
73
|
+
assert.equal(blocked, null);
|
|
74
|
+
} finally {
|
|
75
|
+
cleanup(base);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import test from "node:test";
|
|
12
12
|
import assert from "node:assert/strict";
|
|
13
|
-
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
14
14
|
import { join } from "node:path";
|
|
15
15
|
import { tmpdir } from "node:os";
|
|
16
16
|
import { randomUUID } from "node:crypto";
|
|
@@ -486,3 +486,40 @@ test("state.ts needs-remediation blocker messages reference /gsd verdict", async
|
|
|
486
486
|
`expected at least 2 references to /gsd verdict in state.ts blockers, found ${occurrences.length}`,
|
|
487
487
|
);
|
|
488
488
|
});
|
|
489
|
+
|
|
490
|
+
// ─── WAL checkpoint regression (#563) ───────────────────────────────────
|
|
491
|
+
|
|
492
|
+
test("handleVerdict pass checkpoints WAL so subsequent processes see the updated verdict (#563)", async () => {
|
|
493
|
+
// Regression: before the fix, executeValidateMilestone wrote the assessment
|
|
494
|
+
// only into the WAL file. The next /gsd auto invocation (a new process)
|
|
495
|
+
// opened gsd.db directly and saw stale pre-verdict data because the WAL
|
|
496
|
+
// had not been flushed. The fix adds checkpointDatabase() after a
|
|
497
|
+
// successful verdict so the WAL is truncated and gsd.db is self-contained.
|
|
498
|
+
const base = makeBase();
|
|
499
|
+
try {
|
|
500
|
+
openTestDb(base);
|
|
501
|
+
seedMilestone("M001", "Checkpoint Test Milestone");
|
|
502
|
+
seedSlice("M001", "S01", "complete");
|
|
503
|
+
writeValidation(base, "M001", "needs-attention");
|
|
504
|
+
|
|
505
|
+
const { ctx } = makeMockCtx();
|
|
506
|
+
await handleVerdict("pass --milestone M001", ctx, base);
|
|
507
|
+
|
|
508
|
+
// After handleVerdict succeeds, PRAGMA wal_checkpoint(TRUNCATE) must have
|
|
509
|
+
// run. The WAL file is truncated to zero bytes — a new process reading
|
|
510
|
+
// gsd.db directly sees the updated verdict without needing the WAL.
|
|
511
|
+
const walPath = join(base, ".gsd", "gsd.db-wal");
|
|
512
|
+
if (existsSync(walPath)) {
|
|
513
|
+
const { size } = statSync(walPath);
|
|
514
|
+
assert.equal(
|
|
515
|
+
size,
|
|
516
|
+
0,
|
|
517
|
+
"WAL must be zero bytes after handleVerdict pass — checkpointDatabase() was not called (#563)",
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
} finally {
|
|
521
|
+
closeDatabase();
|
|
522
|
+
invalidateStateCache();
|
|
523
|
+
cleanup(base);
|
|
524
|
+
}
|
|
525
|
+
});
|
|
@@ -14,7 +14,15 @@ import { execFileSync } from "node:child_process";
|
|
|
14
14
|
|
|
15
15
|
import { DISPATCH_RULES, resolveDispatch, type DispatchContext } from "../auto-dispatch.ts";
|
|
16
16
|
import { AutoSession } from "../auto/session.ts";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
closeDatabase,
|
|
19
|
+
getPendingGates,
|
|
20
|
+
insertAssessment,
|
|
21
|
+
insertGateRow,
|
|
22
|
+
insertMilestone,
|
|
23
|
+
insertSlice,
|
|
24
|
+
openDatabase,
|
|
25
|
+
} from "../gsd-db.ts";
|
|
18
26
|
|
|
19
27
|
function makeBase(): string {
|
|
20
28
|
const base = mkdtempSync(join(tmpdir(), "gsd-complete-dispatch-"));
|
|
@@ -243,7 +251,7 @@ describe("complete phase dispatch guard (#5683)", () => {
|
|
|
243
251
|
assert.equal(result?.reason, "All milestones complete.");
|
|
244
252
|
});
|
|
245
253
|
|
|
246
|
-
test("
|
|
254
|
+
test("closes stale pending gates from milestone validation before terminal stop", async () => {
|
|
247
255
|
base = makeBase();
|
|
248
256
|
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
249
257
|
insertMilestone({ id: "M001", title: "Milestone One", status: "complete" });
|
|
@@ -268,10 +276,33 @@ describe("complete phase dispatch guard (#5683)", () => {
|
|
|
268
276
|
|
|
269
277
|
const result = await rule.match(ctx);
|
|
270
278
|
|
|
279
|
+
assert.equal(result?.action, "stop");
|
|
280
|
+
assert.equal(result?.reason, "All milestones complete.");
|
|
281
|
+
assert.deepEqual(getPendingGates("M001", "S01"), []);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test("blocks terminal stop when pending gates have no closeout evidence", async () => {
|
|
285
|
+
base = makeBase();
|
|
286
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
287
|
+
insertMilestone({ id: "M001", title: "Milestone One", status: "complete" });
|
|
288
|
+
insertSlice({ milestoneId: "M001", id: "S01", title: "Done", status: "complete" });
|
|
289
|
+
insertGateRow({
|
|
290
|
+
milestoneId: "M001",
|
|
291
|
+
sliceId: "S01",
|
|
292
|
+
gateId: "Q3",
|
|
293
|
+
scope: "slice",
|
|
294
|
+
status: "pending",
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
const ctx = buildDispatchCtx(base);
|
|
298
|
+
ctx.state.phase = "complete";
|
|
299
|
+
|
|
300
|
+
const result = await rule.match(ctx);
|
|
301
|
+
|
|
271
302
|
assert.equal(result?.action, "stop");
|
|
272
303
|
assert.equal(result?.level, "warning");
|
|
273
304
|
assert.match(result?.reason ?? "", /closeout-consistency-blocked/);
|
|
274
|
-
assert.match(result?.reason ?? "", /
|
|
305
|
+
assert.match(result?.reason ?? "", /latest milestone validation is "absent"/);
|
|
275
306
|
});
|
|
276
307
|
});
|
|
277
308
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Regression coverage for run-uat browser tool availability checks.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
|
|
10
|
+
import { DISPATCH_RULES, type DispatchContext } from "../auto-dispatch.ts";
|
|
11
|
+
import type { GSDState } from "../types.ts";
|
|
12
|
+
|
|
13
|
+
type DispatchRuleEntry = (typeof DISPATCH_RULES)[number];
|
|
14
|
+
|
|
15
|
+
function runUatRule(): DispatchRuleEntry {
|
|
16
|
+
const rule = DISPATCH_RULES.find((entry) => entry.name === "run-uat (post-completion)");
|
|
17
|
+
assert.ok(rule, "run-uat dispatch rule must exist");
|
|
18
|
+
return rule;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function makeState(): GSDState {
|
|
22
|
+
return {
|
|
23
|
+
activeMilestone: { id: "M001", title: "Browser UAT" },
|
|
24
|
+
activeSlice: { id: "S02", title: "Next Slice" },
|
|
25
|
+
activeTask: null,
|
|
26
|
+
phase: "verifying",
|
|
27
|
+
recentDecisions: [],
|
|
28
|
+
blockers: [],
|
|
29
|
+
nextAction: "",
|
|
30
|
+
registry: [],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function scaffoldRunUatProject(basePath: string): void {
|
|
35
|
+
const milestoneDir = join(basePath, ".gsd", "milestones", "M001");
|
|
36
|
+
const sliceDir = join(milestoneDir, "slices", "S01");
|
|
37
|
+
mkdirSync(sliceDir, { recursive: true });
|
|
38
|
+
|
|
39
|
+
writeFileSync(join(milestoneDir, "M001-ROADMAP.md"), [
|
|
40
|
+
"# M001: Browser UAT",
|
|
41
|
+
"",
|
|
42
|
+
"## Slices",
|
|
43
|
+
"",
|
|
44
|
+
"- [x] **S01: Completed browser slice** `risk:low` `depends:[]`",
|
|
45
|
+
"- [ ] **S02: Next slice** `risk:low` `depends:[S01]`",
|
|
46
|
+
"",
|
|
47
|
+
].join("\n"), "utf-8");
|
|
48
|
+
|
|
49
|
+
writeFileSync(join(sliceDir, "S01-SUMMARY.md"), "# S01 Summary\n\nDone.\n", "utf-8");
|
|
50
|
+
writeFileSync(join(sliceDir, "S01-UAT.md"), [
|
|
51
|
+
"# S01 UAT",
|
|
52
|
+
"",
|
|
53
|
+
"## UAT Type",
|
|
54
|
+
"- UAT mode: human-experience",
|
|
55
|
+
"",
|
|
56
|
+
"Open the app in a browser and verify the completed user flow.",
|
|
57
|
+
"",
|
|
58
|
+
].join("\n"), "utf-8");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function makeContext(basePath: string, overrides: Partial<DispatchContext> = {}): DispatchContext {
|
|
62
|
+
return {
|
|
63
|
+
basePath,
|
|
64
|
+
mid: "M001",
|
|
65
|
+
midTitle: "Browser UAT",
|
|
66
|
+
state: makeState(),
|
|
67
|
+
prefs: undefined,
|
|
68
|
+
activeTools: ["read", "gsd_uat_exec", "gsd_uat_result_save"],
|
|
69
|
+
...overrides,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
test("run-uat browser preflight uses registered tools when the active surface is scoped", async (t) => {
|
|
74
|
+
const basePath = mkdtempSync(join(tmpdir(), "gsd-run-uat-browser-tools-"));
|
|
75
|
+
t.after(() => rmSync(basePath, { recursive: true, force: true }));
|
|
76
|
+
scaffoldRunUatProject(basePath);
|
|
77
|
+
|
|
78
|
+
const blocked = await runUatRule().match(makeContext(basePath));
|
|
79
|
+
assert.equal(blocked?.action, "stop");
|
|
80
|
+
assert.match(blocked?.action === "stop" ? blocked.reason : "", /run-uat tool surface has none/);
|
|
81
|
+
|
|
82
|
+
const dispatched = await runUatRule().match(makeContext(basePath, {
|
|
83
|
+
registeredTools: ["browser_navigate"],
|
|
84
|
+
}));
|
|
85
|
+
assert.equal(dispatched?.action, "dispatch");
|
|
86
|
+
assert.equal(dispatched?.action === "dispatch" ? dispatched.unitType : undefined, "run-uat");
|
|
87
|
+
assert.equal(dispatched?.action === "dispatch" ? dispatched.unitId : undefined, "M001/S01");
|
|
88
|
+
});
|