@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.738160b9
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 +1 -1
- package/dist/cli.js +17 -4
- package/dist/headless-answers.js +1 -1
- package/dist/headless-ui.d.ts +1 -1
- package/dist/headless-ui.js +1 -1
- package/dist/headless.js +1 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
- package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
- package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
- package/dist/resources/extensions/gsd/auto/session.js +11 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +1 -1
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
- package/dist/resources/extensions/gsd/auto-budget.js +5 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +34 -20
- package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +29 -14
- package/dist/resources/extensions/gsd/auto-recovery.js +9 -510
- package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
- package/dist/resources/extensions/gsd/auto-verification.js +5 -2
- package/dist/resources/extensions/gsd/auto.js +19 -10
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +39 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +11 -5
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +41 -21
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +96 -10
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +1 -1
- package/dist/resources/extensions/gsd/commands-context.js +19 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +17 -11
- package/dist/resources/extensions/gsd/commands-usage.js +1 -1
- package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
- package/dist/resources/extensions/gsd/db/engine.js +4 -1
- package/dist/resources/extensions/gsd/db/queries.js +60 -0
- package/dist/resources/extensions/gsd/db-memory-fts-schema.js +34 -0
- package/dist/resources/extensions/gsd/db-workspace.js +55 -3
- package/dist/resources/extensions/gsd/delegation-policy.js +1 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +192 -4
- package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +53 -11
- package/dist/resources/extensions/gsd/flat-phase-migration.js +45 -0
- package/dist/resources/extensions/gsd/forensics.js +2 -32
- package/dist/resources/extensions/gsd/git-service.js +61 -4
- package/dist/resources/extensions/gsd/gitignore.js +4 -1
- package/dist/resources/extensions/gsd/guided-flow-queue.js +66 -5
- package/dist/resources/extensions/gsd/health-widget.js +55 -29
- package/dist/resources/extensions/gsd/json-persistence.js +20 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +18 -11
- package/dist/resources/extensions/gsd/layout-policy.js +3 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +8 -9
- package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
- package/dist/resources/extensions/gsd/metrics.js +4 -4
- package/dist/resources/extensions/gsd/migrate-external.js +11 -2
- package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
- package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
- package/dist/resources/extensions/gsd/milestone-implementation-evidence.js +26 -20
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
- package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +3 -3
- package/dist/resources/extensions/gsd/quick.js +45 -2
- package/dist/resources/extensions/gsd/root-write-leak-guard.js +7 -1
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +8 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +16 -1
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +5 -2
- package/dist/resources/extensions/gsd/session-forensics.js +11 -1
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
- package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
- package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
- package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
- package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
- package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +45 -2
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
- package/dist/resources/extensions/gsd/state.js +12 -611
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +43 -14
- package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +59 -44
- package/dist/resources/extensions/gsd/tools/plan-task.js +28 -5
- package/dist/resources/extensions/gsd/undo.js +43 -6
- package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
- package/dist/resources/extensions/gsd/unit-registry.js +36 -6
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
- package/dist/resources/extensions/gsd/verification-gate.js +7 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +126 -13
- package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +30 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
- 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 +9 -9
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +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/page_client-reference-manifest.js +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/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- 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 → 2659.58e950899a9bb82f.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-6644fc6ee8ca1247.js → page-72a856634ad14c10.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +1 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +2 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +3 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts +41 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts +2 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +2 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
- package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
- package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -0
- 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 +25 -11
- 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-latency.d.ts +4 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
- 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 +26 -829
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts +58 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +258 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +23 -5
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/README.md +1 -1
- package/packages/mcp-server/dist/server.d.ts +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +3 -3
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +35 -21
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +3 -2
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +46 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +38 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/README.md +3 -2
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +11 -7
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme-schema.d.ts +75 -75
- package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/theme/theme-schema.js +1 -1
- package/pkg/dist/theme/theme-schema.js.map +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +11 -7
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
- package/src/resources/extensions/claude-code-cli/tests/index.test.ts +14 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
- package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
- package/src/resources/extensions/gsd/auto/session.ts +14 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +3 -1
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
- package/src/resources/extensions/gsd/auto-budget.ts +12 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +35 -24
- package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +41 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +13 -511
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
- package/src/resources/extensions/gsd/auto-verification.ts +5 -1
- package/src/resources/extensions/gsd/auto.ts +23 -8
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +44 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +11 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +52 -21
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +104 -10
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +1 -1
- package/src/resources/extensions/gsd/commands-context.ts +18 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -10
- package/src/resources/extensions/gsd/commands-usage.ts +1 -1
- package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
- package/src/resources/extensions/gsd/db/engine.ts +8 -1
- package/src/resources/extensions/gsd/db/queries.ts +79 -0
- package/src/resources/extensions/gsd/db-memory-fts-schema.ts +45 -0
- package/src/resources/extensions/gsd/db-workspace.ts +61 -3
- package/src/resources/extensions/gsd/delegation-policy.ts +1 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +233 -5
- package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
- package/src/resources/extensions/gsd/doctor-types.ts +3 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +56 -11
- package/src/resources/extensions/gsd/flat-phase-migration.ts +44 -0
- package/src/resources/extensions/gsd/forensics.ts +2 -33
- package/src/resources/extensions/gsd/git-service.ts +69 -5
- package/src/resources/extensions/gsd/gitignore.ts +4 -1
- package/src/resources/extensions/gsd/guided-flow-queue.ts +89 -4
- package/src/resources/extensions/gsd/health-widget.ts +69 -32
- package/src/resources/extensions/gsd/json-persistence.ts +20 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +16 -10
- package/src/resources/extensions/gsd/layout-policy.ts +2 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +8 -11
- package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
- package/src/resources/extensions/gsd/metrics.ts +4 -4
- package/src/resources/extensions/gsd/migrate-external.ts +8 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
- package/src/resources/extensions/gsd/milestone-implementation-evidence.ts +35 -21
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
- package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +3 -3
- package/src/resources/extensions/gsd/quick.ts +43 -2
- package/src/resources/extensions/gsd/root-write-leak-guard.ts +13 -1
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +9 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +16 -1
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +8 -2
- package/src/resources/extensions/gsd/session-forensics.ts +11 -1
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
- package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
- package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
- package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
- package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
- package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +81 -7
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
- package/src/resources/extensions/gsd/state.ts +32 -732
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +14 -5
- package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +182 -4
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +146 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
- package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +58 -3
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +143 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +239 -2
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +37 -2
- package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +130 -3
- package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
- package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/knowledge-cold-start.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +103 -4
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +195 -1
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +15 -3
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +32 -3
- package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
- package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +96 -15
- package/src/resources/extensions/gsd/tests/workflow-mcp-preflight.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +53 -15
- package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
- package/src/resources/extensions/gsd/tools/plan-slice.ts +60 -47
- package/src/resources/extensions/gsd/tools/plan-task.ts +30 -5
- package/src/resources/extensions/gsd/undo.ts +47 -6
- package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
- package/src/resources/extensions/gsd/unit-registry.ts +36 -6
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
- package/src/resources/extensions/gsd/verification-gate.ts +8 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +141 -7
- package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +31 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +0 -10
- package/dist/web/standalone/.next/static/chunks/webpack-f46ea08200a0227e.js +0 -1
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → 2A_WqqCS-EoYZxN9_v3d2}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → 2A_WqqCS-EoYZxN9_v3d2}/_ssgManifest.js +0 -0
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import { resolveExpectedArtifactPath } from "../auto-artifact-paths.ts";
|
|
37
37
|
import { AutoSession } from "../auto/session.ts";
|
|
38
38
|
import { acquireSessionLock, releaseSessionLock } from "../session-lock.ts";
|
|
39
|
+
import { clearGSDPreferencesCache } from "../preferences.ts";
|
|
39
40
|
import { invalidateAllCaches } from "../cache.ts";
|
|
40
41
|
import { invalidateStateCache } from "../state.ts";
|
|
41
42
|
import {
|
|
@@ -63,12 +64,15 @@ interface FixtureOptions {
|
|
|
63
64
|
dispatch?: UnifiedRule["where"];
|
|
64
65
|
/** Drop the gate_runs table after seeding so emitUokGate's insertGateRun throws (:538 path). */
|
|
65
66
|
dropGateRuns?: boolean;
|
|
67
|
+
/** Write project preferences that disable UOK gate telemetry. */
|
|
68
|
+
disableUokGates?: boolean;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
interface Fixture {
|
|
69
72
|
base: string;
|
|
70
73
|
session: AutoSession;
|
|
71
74
|
orchestrator: ReturnType<typeof createAutoOrchestrator>;
|
|
75
|
+
getAvailableCalls(): number;
|
|
72
76
|
cleanup(): void;
|
|
73
77
|
}
|
|
74
78
|
|
|
@@ -82,6 +86,7 @@ function makeFixture(opts: FixtureOptions = {}): Fixture {
|
|
|
82
86
|
|
|
83
87
|
invalidateAllCaches();
|
|
84
88
|
invalidateStateCache();
|
|
89
|
+
clearGSDPreferencesCache();
|
|
85
90
|
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
86
91
|
insertMilestone({ id: "M001", title: "Milestone", status: "active" });
|
|
87
92
|
insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "active", risk: "low", depends: [], demo: "", sequence: 1 });
|
|
@@ -100,6 +105,13 @@ function makeFixture(opts: FixtureOptions = {}): Fixture {
|
|
|
100
105
|
join(sliceDir, "S01-PLAN.md"),
|
|
101
106
|
["# S01: Slice", "", "**Goal:** g", "**Demo:** d", "", "## Tasks", "", "- [ ] **T01: Task** `est:1h`", ""].join("\n"),
|
|
102
107
|
);
|
|
108
|
+
if (opts.disableUokGates) {
|
|
109
|
+
writeFileSync(
|
|
110
|
+
join(base, ".gsd", "PREFERENCES.md"),
|
|
111
|
+
"---\nuok:\n gates:\n enabled: false\n---\n",
|
|
112
|
+
);
|
|
113
|
+
clearGSDPreferencesCache();
|
|
114
|
+
}
|
|
103
115
|
|
|
104
116
|
acquireSessionLock(base);
|
|
105
117
|
|
|
@@ -112,8 +124,19 @@ function makeFixture(opts: FixtureOptions = {}): Fixture {
|
|
|
112
124
|
session.currentMilestoneId = "M001";
|
|
113
125
|
session.resourceVersionOnStart = null;
|
|
114
126
|
|
|
127
|
+
let getAvailableCalls = 0;
|
|
115
128
|
const ctx: OrchestratorContext = {
|
|
116
|
-
ctx: {
|
|
129
|
+
ctx: {
|
|
130
|
+
model: {},
|
|
131
|
+
modelRegistry: {
|
|
132
|
+
getAll: () => [],
|
|
133
|
+
getAvailable: () => {
|
|
134
|
+
getAvailableCalls += 1;
|
|
135
|
+
return [];
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
ui: { notify() {} },
|
|
139
|
+
} as never,
|
|
117
140
|
pi: { getActiveTools: () => [] } as never,
|
|
118
141
|
dispatchBasePath: base,
|
|
119
142
|
runtimeBasePath: base,
|
|
@@ -140,8 +163,10 @@ function makeFixture(opts: FixtureOptions = {}): Fixture {
|
|
|
140
163
|
base,
|
|
141
164
|
session,
|
|
142
165
|
orchestrator,
|
|
166
|
+
getAvailableCalls: () => getAvailableCalls,
|
|
143
167
|
cleanup() {
|
|
144
168
|
resetRegistry();
|
|
169
|
+
clearGSDPreferencesCache();
|
|
145
170
|
try { releaseSessionLock(base); } catch { /* */ }
|
|
146
171
|
try { closeDatabase(); } catch { /* */ }
|
|
147
172
|
try { rmSync(base, { recursive: true, force: true }); } catch { /* */ }
|
|
@@ -210,6 +235,23 @@ test("advance() logs an engine warning when the uok gate emit fails (orchestrato
|
|
|
210
235
|
assert.ok(uokFail!.context?.gateId, "the failing gate id must be captured in context");
|
|
211
236
|
});
|
|
212
237
|
|
|
238
|
+
test("advance() resolves disabled uok gate flags once before gate emission", async (t) => {
|
|
239
|
+
const f = makeFixture({ dropGateRuns: true, disableUokGates: true });
|
|
240
|
+
t.after(() => f.cleanup());
|
|
241
|
+
|
|
242
|
+
const { logs } = await captureLogs(() => f.orchestrator.advance());
|
|
243
|
+
|
|
244
|
+
assert.equal(
|
|
245
|
+
logs.some((e) => e.component === "engine" && /uok gate emit failed/u.test(e.message)),
|
|
246
|
+
false,
|
|
247
|
+
"disabled uok gates must not construct the runner or write gate rows",
|
|
248
|
+
);
|
|
249
|
+
assert.ok(
|
|
250
|
+
f.getAvailableCalls() <= 2,
|
|
251
|
+
`uok gate preferences should be resolved once per advance, not once per emitted gate (getAvailable calls: ${f.getAvailableCalls()})`,
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
213
255
|
// orchestrator.ts:637 — mergePendingCompleteMilestone catches a
|
|
214
256
|
// rebuildMarkdownProjectionsFromDb failure after the system-owned milestone
|
|
215
257
|
// merge and logs `markdown projection rebuild after settlement merge failed`.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// gsd-pi + src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts
|
|
2
|
-
// Regression
|
|
3
|
-
//
|
|
2
|
+
// Regression coverage for orphaned gsd-preflight-stash entries from completed
|
|
3
|
+
// milestones: safe startup recovery for untracked work, manual warnings for
|
|
4
|
+
// tracked or dirty-tree cases that would silently mutate user state.
|
|
4
5
|
|
|
5
6
|
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
6
7
|
import assert from "node:assert/strict";
|
|
@@ -37,6 +38,13 @@ function pushPreflightStash(repo: string, milestoneId: string, fileName: string,
|
|
|
37
38
|
return marker;
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
function pushTrackedPreflightStash(repo: string, milestoneId: string, fileName: string, content: string): string {
|
|
42
|
+
writeFileSync(join(repo, fileName), content);
|
|
43
|
+
const marker = `gsd-preflight-stash:${milestoneId}:42:1700000000000:tracked`;
|
|
44
|
+
git(repo, "stash", "push", "-m", `gsd-preflight-stash [${marker}]`);
|
|
45
|
+
return marker;
|
|
46
|
+
}
|
|
47
|
+
|
|
40
48
|
describe("auditOrphanedPreflightStashes", () => {
|
|
41
49
|
let repo: string;
|
|
42
50
|
|
|
@@ -83,6 +91,23 @@ describe("auditOrphanedPreflightStashes", () => {
|
|
|
83
91
|
assert.match(list, /gsd-preflight-stash:M002:/);
|
|
84
92
|
});
|
|
85
93
|
|
|
94
|
+
test("does not auto-apply a tracked orphan preflight stash onto a clean working tree", () => {
|
|
95
|
+
pushTrackedPreflightStash(repo, "M006", "seed.txt", "seed\ntracked pre-merge work\n");
|
|
96
|
+
assert.equal(readFileSync(join(repo, "seed.txt"), "utf-8"), "seed\n");
|
|
97
|
+
|
|
98
|
+
const result = auditOrphanedPreflightStashes(repo, () => true);
|
|
99
|
+
|
|
100
|
+
assert.equal(result.applied.length, 0);
|
|
101
|
+
assert.equal(result.warnings.length, 1);
|
|
102
|
+
assert.match(result.warnings[0], /not auto-applied/);
|
|
103
|
+
assert.match(result.warnings[0], /stash modifies tracked files/);
|
|
104
|
+
assert.match(result.warnings[0], /git stash apply stash@\{\d+\}/);
|
|
105
|
+
assert.equal(readFileSync(join(repo, "seed.txt"), "utf-8"), "seed\n");
|
|
106
|
+
|
|
107
|
+
const list = git(repo, "stash", "list");
|
|
108
|
+
assert.match(list, /gsd-preflight-stash:M006:/);
|
|
109
|
+
});
|
|
110
|
+
|
|
86
111
|
test("ignores stashes whose milestone is not complete", () => {
|
|
87
112
|
pushPreflightStash(repo, "M003", "wip.txt", "still-working\n");
|
|
88
113
|
|
|
@@ -115,23 +140,25 @@ describe("auditOrphanedPreflightStashes", () => {
|
|
|
115
140
|
assert.match(result.warnings[0], /db unavailable/);
|
|
116
141
|
});
|
|
117
142
|
|
|
118
|
-
test("collects a warning
|
|
119
|
-
// Push a stash containing a change to seed.txt; then dirty seed.txt
|
|
120
|
-
//
|
|
143
|
+
test("collects a warning instead of applying when the working tree is not clean", () => {
|
|
144
|
+
// Push a stash containing a change to seed.txt; then dirty seed.txt before
|
|
145
|
+
// the audit runs. Startup recovery must leave the tree untouched and ask
|
|
146
|
+
// the user to apply the retained backup stash manually.
|
|
121
147
|
writeFileSync(join(repo, "seed.txt"), "stashed\n");
|
|
122
148
|
const marker = `gsd-preflight-stash:M005:42:1700:zz`;
|
|
123
149
|
git(repo, "stash", "push", "-m", `gsd-preflight-stash [${marker}]`);
|
|
124
150
|
|
|
125
|
-
// Dirty the working tree so apply will conflict.
|
|
126
151
|
writeFileSync(join(repo, "seed.txt"), "conflicting modification\n");
|
|
127
152
|
|
|
128
153
|
const result = auditOrphanedPreflightStashes(repo, () => true);
|
|
129
154
|
|
|
130
155
|
assert.equal(result.applied.length, 0);
|
|
131
156
|
assert.equal(result.warnings.length, 1);
|
|
132
|
-
assert.match(result.warnings[0], /
|
|
157
|
+
assert.match(result.warnings[0], /not auto-applied/);
|
|
158
|
+
assert.match(result.warnings[0], /working tree not clean/);
|
|
133
159
|
assert.match(result.warnings[0], /M005/);
|
|
134
160
|
assert.match(result.warnings[0], /git stash apply/);
|
|
161
|
+
assert.equal(readFileSync(join(repo, "seed.txt"), "utf-8"), "conflicting modification\n");
|
|
135
162
|
|
|
136
163
|
const list = git(repo, "stash", "list");
|
|
137
164
|
assert.match(list, /gsd-preflight-stash:M005:/);
|
|
@@ -169,6 +196,63 @@ describe("auditOrphanedPreflightStashes", () => {
|
|
|
169
196
|
"second run must NOT warn — files are already restored from first run",
|
|
170
197
|
);
|
|
171
198
|
});
|
|
199
|
+
|
|
200
|
+
test("warns instead of silently skipping when only some stash untracked files were restored", () => {
|
|
201
|
+
// Cursor Bugbot caught: isAlreadyRestoredUntrackedStatus treated a dirty
|
|
202
|
+
// tree as fully restored when every *current* untracked path appeared in
|
|
203
|
+
// the stash, without requiring every *stash* untracked path to be present.
|
|
204
|
+
// A partial restore (only some files recovered) was misread as the
|
|
205
|
+
// idempotent steady state, so the audit no-oped and the remaining pre-merge
|
|
206
|
+
// files stayed missing with no warning.
|
|
207
|
+
writeFileSync(join(repo, "first.txt"), "first\n");
|
|
208
|
+
writeFileSync(join(repo, "second.txt"), "second\n");
|
|
209
|
+
const marker = `gsd-preflight-stash:M007:42:1700000000000:partial`;
|
|
210
|
+
git(repo, "stash", "push", "--include-untracked", "-m", `gsd-preflight-stash [${marker}]`);
|
|
211
|
+
|
|
212
|
+
// Both files are stashed away.
|
|
213
|
+
assert.equal(existsSync(join(repo, "first.txt")), false);
|
|
214
|
+
assert.equal(existsSync(join(repo, "second.txt")), false);
|
|
215
|
+
|
|
216
|
+
// Simulate a partial restore: only first.txt came back; second.txt is still
|
|
217
|
+
// missing from the working tree.
|
|
218
|
+
writeFileSync(join(repo, "first.txt"), "first\n");
|
|
219
|
+
|
|
220
|
+
const result = auditOrphanedPreflightStashes(repo, () => true);
|
|
221
|
+
|
|
222
|
+
// Must NOT be treated as already-restored: second.txt is still missing, so
|
|
223
|
+
// the audit must surface a manual-recovery warning rather than no-op.
|
|
224
|
+
assert.equal(result.applied.length, 0);
|
|
225
|
+
assert.equal(result.warnings.length, 1, "partial restore must warn, not silently no-op");
|
|
226
|
+
assert.match(result.warnings[0], /not auto-applied/);
|
|
227
|
+
assert.match(result.warnings[0], /working tree not clean/);
|
|
228
|
+
assert.match(result.warnings[0], /M007/);
|
|
229
|
+
assert.match(result.warnings[0], /git stash apply/);
|
|
230
|
+
|
|
231
|
+
// The stash entry must remain so the user can recover second.txt manually.
|
|
232
|
+
const list = git(repo, "stash", "list");
|
|
233
|
+
assert.match(list, /gsd-preflight-stash:M007:/);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test("fully restored multi-file untracked stash stays a silent no-op", () => {
|
|
237
|
+
// Guards the other direction of the set-equality fix: when EVERY stash
|
|
238
|
+
// untracked file is present in the working tree, the genuine idempotent
|
|
239
|
+
// steady state must still be recognized and skipped without warning, even
|
|
240
|
+
// when the stash captured more than one file.
|
|
241
|
+
writeFileSync(join(repo, "alpha.txt"), "alpha\n");
|
|
242
|
+
writeFileSync(join(repo, "beta.txt"), "beta\n");
|
|
243
|
+
const marker = `gsd-preflight-stash:M008:42:1700000000000:multi`;
|
|
244
|
+
git(repo, "stash", "push", "--include-untracked", "-m", `gsd-preflight-stash [${marker}]`);
|
|
245
|
+
|
|
246
|
+
const first = auditOrphanedPreflightStashes(repo, () => true);
|
|
247
|
+
assert.equal(first.applied.length, 1, "first run applies both files");
|
|
248
|
+
assert.equal(first.warnings.length, 0);
|
|
249
|
+
assert.equal(existsSync(join(repo, "alpha.txt")), true);
|
|
250
|
+
assert.equal(existsSync(join(repo, "beta.txt")), true);
|
|
251
|
+
|
|
252
|
+
const second = auditOrphanedPreflightStashes(repo, () => true);
|
|
253
|
+
assert.equal(second.applied.length, 0, "second run skips");
|
|
254
|
+
assert.equal(second.warnings.length, 0, "fully restored multi-file stash must not warn");
|
|
255
|
+
});
|
|
172
256
|
});
|
|
173
257
|
|
|
174
258
|
test("_isAlreadyRestoredApplyError detects the git stash apply already-exists error", () => {
|
|
@@ -145,6 +145,32 @@ describe("parallel-research-slices dispatch rule", () => {
|
|
|
145
145
|
}
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
+
test("dispatches parallel research for S01 even when milestone research exists", async () => {
|
|
149
|
+
writeRoadmap(base, "M001", [
|
|
150
|
+
{ id: "S01", title: "Alpha" },
|
|
151
|
+
{ id: "S02", title: "Beta" },
|
|
152
|
+
]);
|
|
153
|
+
writeFileSync(
|
|
154
|
+
join(base, ".gsd", "milestones", "M001", "M001-RESEARCH.md"),
|
|
155
|
+
"# Milestone Research\n",
|
|
156
|
+
"utf-8",
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const action = await resolveDispatch({
|
|
160
|
+
basePath: base,
|
|
161
|
+
mid: "M001",
|
|
162
|
+
midTitle: "Parallel Research Milestone",
|
|
163
|
+
state: baseState(),
|
|
164
|
+
prefs: undefined,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
assert.equal(action.action, "dispatch");
|
|
168
|
+
if (action.action === "dispatch") {
|
|
169
|
+
assert.equal(action.unitType, "research-slice");
|
|
170
|
+
assert.equal(action.unitId, "M001/parallel-research");
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
148
174
|
test("does not dispatch parallel research with only one ready slice", async () => {
|
|
149
175
|
writeRoadmap(base, "M001", [{ id: "S01", title: "Alpha" }]);
|
|
150
176
|
|
|
@@ -54,9 +54,12 @@ const ALLOWED_IMPORTERS = new Set([
|
|
|
54
54
|
// explicit degraded-mode fallback when DB has no task rows (warns on use)
|
|
55
55
|
"gsd/reactive-graph.ts",
|
|
56
56
|
// recovery path: explicit pre-migration/DB-unavailable fallback branches
|
|
57
|
-
|
|
57
|
+
// (verifyExpectedArtifact extracted here from auto-recovery.ts)
|
|
58
|
+
"gsd/artifact-verification.ts",
|
|
58
59
|
// diagnostics-only surfaces: report on projections, make no dispatch decisions
|
|
59
60
|
"gsd/doctor.ts",
|
|
61
|
+
// diagnostics-only: compares PLAN.md task checkboxes against DB status
|
|
62
|
+
"gsd/doctor-engine-checks.ts",
|
|
60
63
|
// display/telemetry-only surfaces
|
|
61
64
|
"gsd/workspace-index.ts",
|
|
62
65
|
"gsd/visualizer-data.ts",
|
|
@@ -22,7 +22,7 @@ import { invalidateAllCaches } from "../cache.ts";
|
|
|
22
22
|
import type { GSDState } from "../types.ts";
|
|
23
23
|
|
|
24
24
|
const PARALLEL_RESEARCH_RULE = "planning (multiple slices need research) → parallel-research-slices";
|
|
25
|
-
const SINGLE_RESEARCH_RULE = "planning (no research
|
|
25
|
+
const SINGLE_RESEARCH_RULE = "planning (no research) → research-slice";
|
|
26
26
|
const VALIDATE_RULE = "validating-milestone → validate-milestone";
|
|
27
27
|
|
|
28
28
|
// ─── Fixture helpers ──────────────────────────────────────────────────────
|
|
@@ -94,6 +94,16 @@ test("plan-slice prompt: absence checks use negated quiet searches", () => {
|
|
|
94
94
|
assert.ok(result.includes("count commands exit 1 when they find zero matches"));
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
test("plan-slice prompt: npm package existence rule is stated during generation", () => {
|
|
98
|
+
const result = loadPrompt("plan-slice", { ...BASE_VARS, commitInstruction: "Do not commit." });
|
|
99
|
+
assert.ok(result.includes("reference only packages that exist on the public npm registry"));
|
|
100
|
+
assert.ok(result.includes("remove or correct any package name that is not real"));
|
|
101
|
+
// The post-unit pre-execution gate parses package names from require/import
|
|
102
|
+
// patterns too, not just install commands, so the rule must cover that scope.
|
|
103
|
+
assert.ok(result.includes("require('...')"));
|
|
104
|
+
assert.ok(result.includes("import ... from '...'"));
|
|
105
|
+
});
|
|
106
|
+
|
|
97
107
|
test("plan-slice prompt: footer references gsd_plan_slice tool, not direct write", () => {
|
|
98
108
|
const result = loadPrompt("plan-slice", { ...BASE_VARS, commitInstruction: "Do not commit." });
|
|
99
109
|
assert.ok(
|
|
@@ -8,6 +8,7 @@ import { tmpdir } from 'node:os';
|
|
|
8
8
|
|
|
9
9
|
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask, getSlice, getSliceTasks, getTask, getGateResults, updateTaskStatus } from '../gsd-db.ts';
|
|
10
10
|
import { handlePlanSlice } from '../tools/plan-slice.ts';
|
|
11
|
+
import { handlePlanTask } from '../tools/plan-task.ts';
|
|
11
12
|
import { parsePlan } from '../parsers-legacy.ts';
|
|
12
13
|
import { deriveState, invalidateStateCache } from '../state.ts';
|
|
13
14
|
|
|
@@ -511,15 +512,113 @@ test('handlePlanSlice leaves omitted enrichment fields empty instead of renderin
|
|
|
511
512
|
}
|
|
512
513
|
});
|
|
513
514
|
|
|
514
|
-
test('handlePlanSlice
|
|
515
|
+
test('handlePlanSlice accepts metadata-only payloads without deleting existing tasks', async () => {
|
|
515
516
|
const base = makeTmpBase();
|
|
516
517
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
517
518
|
|
|
518
519
|
try {
|
|
519
520
|
seedParentSlice();
|
|
520
|
-
const
|
|
521
|
-
assert.ok('error' in
|
|
522
|
-
assert.
|
|
521
|
+
const first = await handlePlanSlice(validParams(), base);
|
|
522
|
+
assert.ok(!('error' in first), `unexpected error: ${'error' in first ? first.error : ''}`);
|
|
523
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 2);
|
|
524
|
+
|
|
525
|
+
const second = await handlePlanSlice({
|
|
526
|
+
milestoneId: 'M001',
|
|
527
|
+
sliceId: 'S02',
|
|
528
|
+
goal: 'Persist updated slice metadata before incremental tasks.',
|
|
529
|
+
successCriteria: '- Metadata renders before task planning',
|
|
530
|
+
proofLevel: 'unit',
|
|
531
|
+
integrationClosure: 'Task details follow through gsd_plan_task.',
|
|
532
|
+
observabilityImpact: 'Progress survives between tool calls.',
|
|
533
|
+
}, base);
|
|
534
|
+
assert.ok(!('error' in second), `unexpected error: ${'error' in second ? second.error : ''}`);
|
|
535
|
+
assert.equal(getSlice('M001', 'S02')?.goal, 'Persist updated slice metadata before incremental tasks.');
|
|
536
|
+
assert.deepEqual(getSliceTasks('M001', 'S02').map((task) => task.id), ['T01', 'T02']);
|
|
537
|
+
|
|
538
|
+
const third = await handlePlanSlice({ ...validParams(), tasks: [] }, base);
|
|
539
|
+
assert.ok(!('error' in third), `unexpected error: ${'error' in third ? third.error : ''}`);
|
|
540
|
+
assert.deepEqual(getSliceTasks('M001', 'S02').map((task) => task.id), ['T01', 'T02']);
|
|
541
|
+
} finally {
|
|
542
|
+
cleanup(base);
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
test('handlePlanSlice metadata-only on a fresh sketch slice keeps is_sketch set and renders no PLAN.md (#1027)', async () => {
|
|
547
|
+
const base = makeTmpBase();
|
|
548
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
549
|
+
|
|
550
|
+
try {
|
|
551
|
+
insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
|
|
552
|
+
insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Planning slice', status: 'pending', demo: 'Rendered plans exist.', isSketch: true });
|
|
553
|
+
|
|
554
|
+
// The incremental flow's first call carries metadata only (no tasks). It
|
|
555
|
+
// must NOT error (renderPlanFromDb throws on a task-less slice), and it must
|
|
556
|
+
// NOT clear the sketch flag — clearing it without a PLAN.md would leave the
|
|
557
|
+
// slice out of refining with no plan artifact, breaking sketch/plan signaling.
|
|
558
|
+
const result = await handlePlanSlice({
|
|
559
|
+
milestoneId: 'M001',
|
|
560
|
+
sliceId: 'S02',
|
|
561
|
+
goal: 'Persist slice metadata before any tasks exist.',
|
|
562
|
+
}, base);
|
|
563
|
+
assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
|
|
564
|
+
assert.equal(getSlice('M001', 'S02')?.goal, 'Persist slice metadata before any tasks exist.');
|
|
565
|
+
assert.equal(getSliceTasks('M001', 'S02').length, 0);
|
|
566
|
+
assert.equal(getSlice('M001', 'S02')?.is_sketch, 1, 'sketch flag must stay set until a task-bearing plan renders');
|
|
567
|
+
|
|
568
|
+
const planPath = join(base, '.gsd', 'phases', '01-test', '01-02-PLAN.md');
|
|
569
|
+
assert.ok(!existsSync(planPath), 'no PLAN.md should be rendered until the first task is planned');
|
|
570
|
+
|
|
571
|
+
invalidateStateCache();
|
|
572
|
+
const after = await deriveState(base);
|
|
573
|
+
assert.equal(after.phase, 'refining', 'a task-less sketch slice stays in refining');
|
|
574
|
+
} finally {
|
|
575
|
+
cleanup(base);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
test('handlePlanTask materializes the slice PLAN.md and clears the sketch flag on the incremental path (#1027)', async () => {
|
|
580
|
+
const base = makeTmpBase();
|
|
581
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
582
|
+
|
|
583
|
+
try {
|
|
584
|
+
insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
|
|
585
|
+
insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Planning slice', status: 'pending', demo: 'Rendered plans exist.', isSketch: true });
|
|
586
|
+
|
|
587
|
+
const sliceResult = await handlePlanSlice({
|
|
588
|
+
milestoneId: 'M001',
|
|
589
|
+
sliceId: 'S02',
|
|
590
|
+
goal: 'Incrementally planned slice.',
|
|
591
|
+
successCriteria: '- The slice plan is built up one task at a time',
|
|
592
|
+
}, base);
|
|
593
|
+
assert.ok(!('error' in sliceResult), `unexpected error: ${'error' in sliceResult ? sliceResult.error : ''}`);
|
|
594
|
+
|
|
595
|
+
const taskResult = await handlePlanTask({
|
|
596
|
+
milestoneId: 'M001',
|
|
597
|
+
sliceId: 'S02',
|
|
598
|
+
taskId: 'T01',
|
|
599
|
+
title: 'First incremental task',
|
|
600
|
+
description: 'Implement the first task added through gsd_plan_task.',
|
|
601
|
+
estimate: '30m',
|
|
602
|
+
files: ['src/resources/extensions/gsd/tools/plan-task.ts'],
|
|
603
|
+
verify: 'node --test src/resources/extensions/gsd/tests/plan-task.test.ts',
|
|
604
|
+
inputs: ['src/resources/extensions/gsd/tools/plan-milestone.ts'],
|
|
605
|
+
expectedOutput: ['src/resources/extensions/gsd/tools/plan-task.ts'],
|
|
606
|
+
}, base);
|
|
607
|
+
assert.ok(!('error' in taskResult), `unexpected error: ${'error' in taskResult ? taskResult.error : ''}`);
|
|
608
|
+
|
|
609
|
+
// The first incremental task materializes the canonical slice PLAN.md with
|
|
610
|
+
// the task present, and clears the sketch flag now that a plan exists.
|
|
611
|
+
const planPath = join(base, '.gsd', 'phases', '01-test', '01-02-PLAN.md');
|
|
612
|
+
assert.ok(existsSync(planPath), 'slice PLAN.md should exist after the first task is planned');
|
|
613
|
+
const parsedPlan = parsePlan(readFileSync(planPath, 'utf-8'));
|
|
614
|
+
assert.equal(parsedPlan.goal, 'Incrementally planned slice.');
|
|
615
|
+
assert.equal(parsedPlan.tasks.length, 1);
|
|
616
|
+
assert.equal(parsedPlan.tasks[0]?.id, 'T01');
|
|
617
|
+
assert.equal(getSlice('M001', 'S02')?.is_sketch, 0, 'sketch flag must clear once the first task renders a plan');
|
|
618
|
+
|
|
619
|
+
invalidateStateCache();
|
|
620
|
+
const after = await deriveState(base);
|
|
621
|
+
assert.notEqual(after.phase, 'refining', 'a planned slice leaves refining');
|
|
523
622
|
} finally {
|
|
524
623
|
cleanup(base);
|
|
525
624
|
}
|
|
@@ -4,7 +4,7 @@ import { mkdtempSync, mkdirSync, rmSync, readFileSync, existsSync, writeFileSync
|
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { tmpdir } from 'node:os';
|
|
6
6
|
|
|
7
|
-
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask, getTask } from '../gsd-db.ts';
|
|
7
|
+
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask, getSlice, getTask, getGateResults } from '../gsd-db.ts';
|
|
8
8
|
import { handlePlanTask } from '../tools/plan-task.ts';
|
|
9
9
|
import { parseTaskPlanFile } from '../files.ts';
|
|
10
10
|
|
|
@@ -65,6 +65,25 @@ test('handlePlanTask writes planning state and renders task plan', async () => {
|
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
test('handlePlanTask seeds execute-task gate rows for incremental planning', async () => {
|
|
69
|
+
const base = makeTmpBase();
|
|
70
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
seedParent();
|
|
74
|
+
const result = await handlePlanTask(validParams(), base);
|
|
75
|
+
assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
|
|
76
|
+
|
|
77
|
+
const gateIds = getGateResults('M001', 'S02', 'task')
|
|
78
|
+
.filter((gate) => gate.task_id === 'T02')
|
|
79
|
+
.map((gate) => gate.gate_id)
|
|
80
|
+
.sort();
|
|
81
|
+
assert.deepEqual(gateIds, ['Q5', 'Q6', 'Q7']);
|
|
82
|
+
} finally {
|
|
83
|
+
cleanup(base);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
68
87
|
test('handlePlanTask rejects invalid payloads', async () => {
|
|
69
88
|
const base = makeTmpBase();
|
|
70
89
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -170,6 +189,30 @@ test('handlePlanTask surfaces render failures without changing parse-visible tas
|
|
|
170
189
|
}
|
|
171
190
|
});
|
|
172
191
|
|
|
192
|
+
test('handlePlanTask keeps the sketch flag set when the flat-phase slice plan sync fails (#1083)', async () => {
|
|
193
|
+
const base = makeTmpBase();
|
|
194
|
+
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
|
|
198
|
+
insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Planning slice', status: 'pending', demo: 'Rendered plans exist.', isSketch: true });
|
|
199
|
+
|
|
200
|
+
// The per-task render writes T02-PLAN.md and succeeds, but the flat-phase
|
|
201
|
+
// slice re-render (the canonical PLAN.md that embeds task checkboxes) targets
|
|
202
|
+
// phases/01-test/01-02-PLAN.md. Pre-creating that path as a directory forces
|
|
203
|
+
// EISDIR on the slice sync, so the canonical slice plan never reflects the
|
|
204
|
+
// task. The sketch flag must therefore stay set — the slice keeps refining —
|
|
205
|
+
// instead of leaving the slice out of refining over a stale plan.
|
|
206
|
+
mkdirSync(join(base, '.gsd', 'phases', '01-test', '01-02-PLAN.md'), { recursive: true });
|
|
207
|
+
|
|
208
|
+
const result = await handlePlanTask(validParams(), base);
|
|
209
|
+
assert.equal(getSlice('M001', 'S02')?.is_sketch, 1, 'sketch flag must stay set when the canonical slice plan could not sync');
|
|
210
|
+
assert.ok(getTask('M001', 'S02', 'T02'), 'the task itself is still persisted so the slice can re-sync on retry');
|
|
211
|
+
} finally {
|
|
212
|
+
cleanup(base);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
173
216
|
test('handlePlanTask reruns idempotently and refreshes parse-visible state', async () => {
|
|
174
217
|
const base = makeTmpBase();
|
|
175
218
|
openDatabase(join(base, '.gsd', 'gsd.db'));
|
|
@@ -10,7 +10,7 @@ import * as os from 'node:os';
|
|
|
10
10
|
import { openDatabase, closeDatabase } from '../gsd-db.ts';
|
|
11
11
|
import { handleCompleteTask } from '../tools/complete-task.ts';
|
|
12
12
|
import { readEvents } from '../workflow-events.ts';
|
|
13
|
-
import { readManifest } from '../workflow-manifest.ts';
|
|
13
|
+
import { flushManifest, readManifest } from '../workflow-manifest.ts';
|
|
14
14
|
|
|
15
15
|
function tempDir(): string {
|
|
16
16
|
return fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-post-hook-'));
|
|
@@ -115,8 +115,9 @@ test('post-mutation-hook: state-manifest.json exists after handleCompleteTask',
|
|
|
115
115
|
const result = await handleCompleteTask(makeCompleteTaskParams(), base);
|
|
116
116
|
assert.ok(!('error' in result), `handler should succeed, got: ${JSON.stringify(result)}`);
|
|
117
117
|
|
|
118
|
+
await flushManifest(base);
|
|
118
119
|
const manifestPath = path.join(base, '.gsd', 'state-manifest.json');
|
|
119
|
-
assert.ok(fs.existsSync(manifestPath), 'state-manifest.json should exist after
|
|
120
|
+
assert.ok(fs.existsSync(manifestPath), 'state-manifest.json should exist after manifest flush');
|
|
120
121
|
} finally {
|
|
121
122
|
closeDatabase();
|
|
122
123
|
cleanupDir(base);
|
|
@@ -131,6 +132,7 @@ test('post-mutation-hook: manifest has version 1 and includes completed task', a
|
|
|
131
132
|
|
|
132
133
|
try {
|
|
133
134
|
await handleCompleteTask(makeCompleteTaskParams(), base);
|
|
135
|
+
await flushManifest(base);
|
|
134
136
|
|
|
135
137
|
const manifest = readManifest(base);
|
|
136
138
|
assert.ok(manifest !== null, 'manifest should be readable');
|
|
@@ -6,7 +6,12 @@ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
buildCategorySummaries,
|
|
11
|
+
handlePrefsWizard,
|
|
12
|
+
serializePreferencesToFrontmatter,
|
|
13
|
+
} from "../commands-prefs-wizard.ts";
|
|
14
|
+
import { parsePreferencesMarkdown, validatePreferences } from "../preferences.ts";
|
|
10
15
|
import { KNOWN_PREFERENCE_KEYS } from "../preferences-types.ts";
|
|
11
16
|
|
|
12
17
|
const PREF_SAMPLE_VALUES: Record<string, unknown> = {
|
|
@@ -103,6 +108,54 @@ const PREF_SAMPLE_VALUES: Record<string, unknown> = {
|
|
|
103
108
|
},
|
|
104
109
|
};
|
|
105
110
|
|
|
111
|
+
test("prefs serializer preserves nested hook on_block objects", () => {
|
|
112
|
+
const frontmatter = serializePreferencesToFrontmatter({
|
|
113
|
+
post_unit_hooks: [{
|
|
114
|
+
name: "plan-review",
|
|
115
|
+
after: ["execute-task"],
|
|
116
|
+
prompt: "write PLAN-REVIEW.md",
|
|
117
|
+
artifact: "PLAN-REVIEW.md",
|
|
118
|
+
criticality: "blocking",
|
|
119
|
+
on_block: { action: "pause" },
|
|
120
|
+
}],
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
assert.doesNotMatch(frontmatter, /\[object Object\]/);
|
|
124
|
+
assert.ok(frontmatter.includes(" on_block:\n action: pause\n"));
|
|
125
|
+
|
|
126
|
+
const parsed = parsePreferencesMarkdown(`---\n${frontmatter}---\n`);
|
|
127
|
+
assert.notEqual(parsed, null);
|
|
128
|
+
|
|
129
|
+
const { errors, preferences } = validatePreferences(parsed!);
|
|
130
|
+
assert.deepEqual(errors, []);
|
|
131
|
+
assert.deepEqual(preferences.post_unit_hooks?.[0]?.on_block, { action: "pause" });
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("prefs serializer correctly indents nested object when it is the first array-item property", () => {
|
|
135
|
+
// on_block is the FIRST property — exercises the first-key-is-object branch
|
|
136
|
+
const frontmatter = serializePreferencesToFrontmatter({
|
|
137
|
+
post_unit_hooks: [{
|
|
138
|
+
on_block: { action: "pause" }, // first property — exercises the first-key-is-object branch
|
|
139
|
+
name: "gate", // required fields come after so on_block stays first
|
|
140
|
+
after: ["execute-task"],
|
|
141
|
+
prompt: "review output",
|
|
142
|
+
}],
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
assert.doesNotMatch(frontmatter, /\[object Object\]/);
|
|
146
|
+
// Children of on_block must be indented deeper than on_block itself (not siblings)
|
|
147
|
+
assert.ok(
|
|
148
|
+
frontmatter.includes(" - on_block:\n action: pause\n"),
|
|
149
|
+
`Expected on_block children indented as nested YAML, got:\n${frontmatter}`,
|
|
150
|
+
);
|
|
151
|
+
// Sanity: parse + validate round-trip
|
|
152
|
+
const parsed = parsePreferencesMarkdown(`---\n${frontmatter}---\n`);
|
|
153
|
+
assert.notEqual(parsed, null);
|
|
154
|
+
const { errors, preferences } = validatePreferences(parsed!);
|
|
155
|
+
assert.deepEqual(errors, []);
|
|
156
|
+
assert.deepEqual(preferences.post_unit_hooks?.[0]?.on_block, { action: "pause" });
|
|
157
|
+
});
|
|
158
|
+
|
|
106
159
|
test("prefs wizard save path preserves every known preference key", async () => {
|
|
107
160
|
const missingSamples = [...KNOWN_PREFERENCE_KEYS].filter((key) => !(key in PREF_SAMPLE_VALUES));
|
|
108
161
|
assert.deepEqual(missingSamples, [], "test fixture must cover every known preference key");
|