@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
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { clearParseCache } from "../files.js";
|
|
2
2
|
import { isClosedStatus } from "../status-guards.js";
|
|
3
3
|
import { isNonEmptyString, validateStringArray } from "../validation.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getGateIdsForTurn } from "../gate-registry.js";
|
|
5
|
+
import { transaction, getSlice, getTask, insertTask, upsertTaskPlanning, insertGateRow, setSliceSketchFlag } from "../gsd-db.js";
|
|
5
6
|
import { invalidateStateCache } from "../state.js";
|
|
6
7
|
import { renderTaskPlanFromDb, renderPlanFromDb } from "../markdown-renderer.js";
|
|
7
|
-
import {
|
|
8
|
+
import { resolveTasksDir } from "../paths.js";
|
|
8
9
|
import { flushWorkflowProjections } from "../projection-flush.js";
|
|
9
10
|
import { writeManifest } from "../workflow-manifest.js";
|
|
10
11
|
import { appendEvent } from "../workflow-events.js";
|
|
11
12
|
import { logWarning } from "../workflow-logger.js";
|
|
13
|
+
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
12
14
|
import { validatePathOnlyPlanningFields, validatePlanningPathScope } from "../planning-path-scope.js";
|
|
15
|
+
import type { GateId } from "../types.js";
|
|
13
16
|
|
|
14
17
|
export interface PlanTaskParams {
|
|
15
18
|
milestoneId: string;
|
|
@@ -57,6 +60,12 @@ function validateParams(params: PlanTaskParams): PlanTaskParams {
|
|
|
57
60
|
};
|
|
58
61
|
}
|
|
59
62
|
|
|
63
|
+
function resolveTaskGates(basePath: string): GateId[] {
|
|
64
|
+
const loaded = loadEffectiveGSDPreferences(basePath);
|
|
65
|
+
if (loaded?.preferences?.gate_evaluation?.task_gates === false) return [];
|
|
66
|
+
return [...getGateIdsForTurn("execute-task")];
|
|
67
|
+
}
|
|
68
|
+
|
|
60
69
|
export async function handlePlanTask(
|
|
61
70
|
rawParams: PlanTaskParams,
|
|
62
71
|
basePath: string,
|
|
@@ -84,6 +93,14 @@ export async function handlePlanTask(
|
|
|
84
93
|
return { error: `validation failed: ${pathScopeError}` };
|
|
85
94
|
}
|
|
86
95
|
|
|
96
|
+
let taskGates: GateId[];
|
|
97
|
+
try {
|
|
98
|
+
taskGates = resolveTaskGates(basePath);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
101
|
+
return { error: `validation failed: ${message}` };
|
|
102
|
+
}
|
|
103
|
+
|
|
87
104
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
88
105
|
// Guards must be inside the transaction so the state they check cannot
|
|
89
106
|
// change between the read and the write (#2723).
|
|
@@ -127,6 +144,9 @@ export async function handlePlanTask(
|
|
|
127
144
|
observabilityImpact: params.observabilityImpact ?? "",
|
|
128
145
|
fullPlanMd: params.fullPlanMd,
|
|
129
146
|
});
|
|
147
|
+
for (const gid of taskGates) {
|
|
148
|
+
insertGateRow({ milestoneId: params.milestoneId, sliceId: params.sliceId, gateId: gid, scope: "task", taskId: params.taskId });
|
|
149
|
+
}
|
|
130
150
|
});
|
|
131
151
|
} catch (err) {
|
|
132
152
|
return { error: `db write failed: ${(err as Error).message}` };
|
|
@@ -142,17 +162,22 @@ export async function handlePlanTask(
|
|
|
142
162
|
// Flat-phase: tasks live as checkboxes in the slice plan's <tasks> block,
|
|
143
163
|
// not as standalone TID-PLAN.md files. Re-render the slice plan so the
|
|
144
164
|
// new/updated task appears in the plan file that gsd-core reads.
|
|
145
|
-
// Guard: resolveTasksDir is null in flat-phase (no tasks/ subdir exists)
|
|
146
|
-
|
|
165
|
+
// Guard: resolveTasksDir is null in flat-phase (no tasks/ subdir exists).
|
|
166
|
+
let slicePlanSynced = false;
|
|
147
167
|
try {
|
|
148
168
|
const tDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
|
|
149
|
-
if (!tDir
|
|
169
|
+
if (!tDir) {
|
|
150
170
|
await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
171
|
+
slicePlanSynced = true;
|
|
151
172
|
}
|
|
152
173
|
} catch (syncErr) {
|
|
153
174
|
logWarning("tool", `plan-task: slice-plan sync failed: ${(syncErr as Error).message}`);
|
|
154
175
|
}
|
|
155
176
|
|
|
177
|
+
if (slicePlanSynced) {
|
|
178
|
+
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
179
|
+
}
|
|
180
|
+
|
|
156
181
|
invalidateStateCache();
|
|
157
182
|
clearParseCache();
|
|
158
183
|
|
|
@@ -15,6 +15,7 @@ import { gsdRoot, resolveTasksDir, resolveSlicePath, resolveSliceFile, resolveTa
|
|
|
15
15
|
import { sendDesktopNotification } from "./notifications.js";
|
|
16
16
|
import { getTask, getSlice, getSliceTasks, updateTaskStatus, resetSliceCascade } from "./gsd-db.js";
|
|
17
17
|
import { renderPlanCheckboxes, renderRoadmapCheckboxes } from "./markdown-renderer.js";
|
|
18
|
+
import { UNIT_REGISTRY } from "./unit-registry.js";
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Undo the last completed unit: revert git commits,
|
|
@@ -42,16 +43,20 @@ export async function handleUndo(args: string, ctx: ExtensionCommandContext, _pi
|
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
// Extract unit type and ID from the most recent activity log filename
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
// Extract unit type and ID from the most recent activity log filename.
|
|
47
|
+
// Both the unit type and the unit ID may contain hyphens, so anchor on the
|
|
48
|
+
// known unit-type vocabulary instead of guessing the unit-ID shape: a regex
|
|
49
|
+
// tuned to milestone-shaped IDs rejects project-level units whose IDs are
|
|
50
|
+
// symbolic (e.g. discuss-project uses PROJECT, workflow-preferences uses
|
|
51
|
+
// WORKFLOW-PREFS).
|
|
52
|
+
const parsed = parseActivityLogFilename(files[0]);
|
|
53
|
+
if (!parsed) {
|
|
49
54
|
ctx.ui.notify("Nothing to undo — could not parse latest activity log.", "warning");
|
|
50
55
|
return;
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
const unitType =
|
|
54
|
-
const unitId =
|
|
58
|
+
const unitType = parsed.unitType;
|
|
59
|
+
const unitId = parsed.unitId.replace(/-/g, "/");
|
|
55
60
|
|
|
56
61
|
if (!force) {
|
|
57
62
|
ctx.ui.notify(
|
|
@@ -100,6 +105,11 @@ export async function handleUndo(args: string, ctx: ExtensionCommandContext, _pi
|
|
|
100
105
|
if (unitType === "execute-task" && task !== undefined && slice !== undefined) {
|
|
101
106
|
const [mid, sid, tid] = [milestone, slice, task];
|
|
102
107
|
planUpdated = uncheckTaskInPlan(basePath, mid, sid, tid);
|
|
108
|
+
if (getTask(mid, sid, tid)) {
|
|
109
|
+
updateTaskStatus(mid, sid, tid, "pending");
|
|
110
|
+
await renderPlanCheckboxes(basePath, mid, sid);
|
|
111
|
+
planUpdated = true;
|
|
112
|
+
}
|
|
103
113
|
}
|
|
104
114
|
|
|
105
115
|
// 3. Try to revert git commits from activity log
|
|
@@ -379,6 +389,37 @@ export async function handleResetSlice(
|
|
|
379
389
|
|
|
380
390
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
381
391
|
|
|
392
|
+
// Known unit types sorted longest-first so a more specific type (e.g.
|
|
393
|
+
// "execute-task-simple") matches before a prefix of it ("execute-task") when
|
|
394
|
+
// splitting "<seq>-<unitType>-<unitId>.jsonl".
|
|
395
|
+
const UNIT_TYPES_BY_LENGTH_DESC: readonly string[] = Object.keys(UNIT_REGISTRY).sort(
|
|
396
|
+
(a, b) => b.length - a.length,
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Parse an activity-log filename of the form `<seq>-<unitType>-<unitId>.jsonl`
|
|
401
|
+
* (the format written by activity-log.ts). Both the unit type and the unit ID
|
|
402
|
+
* may contain hyphens, so we anchor on the known unit-type vocabulary rather
|
|
403
|
+
* than guessing the ID shape. This keeps non-milestone IDs (e.g. PROJECT,
|
|
404
|
+
* WORKFLOW-PREFS) parseable. Returns null when the name has no sequence prefix
|
|
405
|
+
* or does not start with a recognised unit type.
|
|
406
|
+
*/
|
|
407
|
+
export function parseActivityLogFilename(
|
|
408
|
+
filename: string,
|
|
409
|
+
): { unitType: string; unitId: string } | null {
|
|
410
|
+
const seqMatch = filename.match(/^\d+-(.+)\.jsonl$/);
|
|
411
|
+
if (!seqMatch) return null;
|
|
412
|
+
const rest = seqMatch[1];
|
|
413
|
+
for (const unitType of UNIT_TYPES_BY_LENGTH_DESC) {
|
|
414
|
+
const prefix = `${unitType}-`;
|
|
415
|
+
if (rest.startsWith(prefix)) {
|
|
416
|
+
const unitId = rest.slice(prefix.length);
|
|
417
|
+
if (unitId.length > 0) return { unitType, unitId };
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
|
|
382
423
|
export function uncheckTaskInPlan(basePath: string, mid: string, sid: string, tid: string): boolean {
|
|
383
424
|
const slicePath = resolveSlicePath(basePath, mid, sid);
|
|
384
425
|
if (!slicePath) return false;
|
|
@@ -135,14 +135,38 @@ const CONTEXT_MODE_GUIDANCE_BY_LANE: Record<Exclude<ContextModePolicy, "none">,
|
|
|
135
135
|
"Use `gsd_resume` for prior context, `gsd_exec_search` for saved evidence, and `gsd_exec` for noisy doc validation commands.",
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
-
// Per-unit overrides win over the lane default.
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
// Per-unit overrides win over the lane default. Some units intentionally run
|
|
139
|
+
// with narrower tool contracts than their shared Context Mode lane, so their
|
|
140
|
+
// guidance must name only tools the unit can actually call.
|
|
141
|
+
export const CONTEXT_MODE_GUIDANCE_BY_UNIT: Readonly<Record<string, string>> = {
|
|
142
|
+
"discuss-milestone":
|
|
143
|
+
"Use `ask_user_questions` to continue the milestone interview, then persist outcomes with `gsd_summary_save`, `gsd_decision_save`, `gsd_requirement_save`, `gsd_requirement_update`, `gsd_plan_milestone`, or `gsd_milestone_generate_id` as appropriate.",
|
|
144
|
+
"discuss-slice":
|
|
145
|
+
"Use `ask_user_questions` to continue the slice interview, then persist outcomes with `gsd_summary_save` or `gsd_decision_save` as appropriate.",
|
|
146
|
+
"discuss-project":
|
|
147
|
+
"Use `ask_user_questions` to continue the project interview, then persist outcomes with `gsd_summary_save`, `gsd_decision_save`, or `gsd_requirement_save` as appropriate.",
|
|
148
|
+
"discuss-requirements":
|
|
149
|
+
"Use `ask_user_questions` to continue the requirements interview, then persist outcomes with `gsd_requirement_save` or `gsd_summary_save` as appropriate.",
|
|
150
|
+
"replan-slice":
|
|
151
|
+
"Use `gsd_replan_slice` to persist the revised slice plan, and `gsd_decision_save` for planning decisions that need durable rationale.",
|
|
152
|
+
"reassess-roadmap":
|
|
153
|
+
"Use `gsd_milestone_status` to inspect current milestone state, then `gsd_reassess_roadmap` to persist the roadmap reassessment.",
|
|
144
154
|
"run-uat":
|
|
145
155
|
"Use `gsd_uat_exec` for acceptance checks so evidence is typed as UAT-owned, and `gsd_resume` after compaction or resume.",
|
|
156
|
+
"research-project":
|
|
157
|
+
"Dispatch parallel scout subagents for stack, features, architecture, and pitfalls research; each writes one file under `.gsd/research/` (`STACK.md`, `FEATURES.md`, `ARCHITECTURE.md`, `PITFALLS.md`).",
|
|
158
|
+
"gate-evaluate":
|
|
159
|
+
"Use `subagent` to dispatch tester agents, then persist each gate with `gsd_save_gate_result`; rely on testers for verification evidence.",
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Per-unit guidance for the nested render mode (renderMode: "nested"), used when this
|
|
163
|
+
// unit's Context Mode line is embedded into a subagent prompt — e.g. the tester prompts
|
|
164
|
+
// dispatched by gate-evaluate. Must instruct the subagent on what IT should do, not
|
|
165
|
+
// re-state the parent coordinator's dispatch instructions. Falls back to
|
|
166
|
+
// CONTEXT_MODE_GUIDANCE_BY_UNIT then the lane default when no nested entry exists.
|
|
167
|
+
export const CONTEXT_MODE_NESTED_GUIDANCE_BY_UNIT: Readonly<Record<string, string>> = {
|
|
168
|
+
"gate-evaluate":
|
|
169
|
+
"Run verification checks to answer the gate question, then persist the verdict with `gsd_save_gate_result`.",
|
|
146
170
|
};
|
|
147
171
|
|
|
148
172
|
/**
|
|
@@ -160,7 +184,9 @@ export function composeContextModeInstructions(
|
|
|
160
184
|
|
|
161
185
|
const lane = CONTEXT_MODE_LANE_LABELS[manifest.contextMode];
|
|
162
186
|
const guidance =
|
|
163
|
-
|
|
187
|
+
(opts.renderMode === "nested" ? CONTEXT_MODE_NESTED_GUIDANCE_BY_UNIT[unitType] : undefined)
|
|
188
|
+
?? CONTEXT_MODE_GUIDANCE_BY_UNIT[unitType]
|
|
189
|
+
?? CONTEXT_MODE_GUIDANCE_BY_LANE[manifest.contextMode];
|
|
164
190
|
if (opts.renderMode === "nested") {
|
|
165
191
|
return `Context Mode (${lane} lane): ${guidance}`;
|
|
166
192
|
}
|
|
@@ -98,7 +98,13 @@ export const UNIT_REGISTRY = {
|
|
|
98
98
|
scopeClass: "standard",
|
|
99
99
|
phaseChain: ["research"],
|
|
100
100
|
toolContract: {
|
|
101
|
-
allowedGsdTools: [
|
|
101
|
+
allowedGsdTools: [
|
|
102
|
+
"gsd_summary_save",
|
|
103
|
+
"gsd_decision_save",
|
|
104
|
+
"gsd_exec",
|
|
105
|
+
"gsd_exec_search",
|
|
106
|
+
"gsd_resume",
|
|
107
|
+
],
|
|
102
108
|
requiredWorkflowTools: ["gsd_summary_save"],
|
|
103
109
|
},
|
|
104
110
|
},
|
|
@@ -111,10 +117,11 @@ export const UNIT_REGISTRY = {
|
|
|
111
117
|
"gsd_milestone_status",
|
|
112
118
|
"gsd_plan_milestone",
|
|
113
119
|
"gsd_plan_slice",
|
|
120
|
+
"gsd_plan_task",
|
|
114
121
|
"gsd_decision_save",
|
|
115
122
|
"gsd_requirement_update",
|
|
116
123
|
],
|
|
117
|
-
requiredWorkflowTools: ["gsd_milestone_status", "gsd_plan_milestone", "gsd_plan_slice"],
|
|
124
|
+
requiredWorkflowTools: ["gsd_milestone_status", "gsd_plan_milestone", "gsd_plan_slice", "gsd_plan_task"],
|
|
118
125
|
},
|
|
119
126
|
},
|
|
120
127
|
"discuss-milestone": {
|
|
@@ -154,7 +161,15 @@ export const UNIT_REGISTRY = {
|
|
|
154
161
|
scopeClass: "section-close",
|
|
155
162
|
phaseChain: ["validation", "planning"],
|
|
156
163
|
toolContract: {
|
|
157
|
-
allowedGsdTools: [
|
|
164
|
+
allowedGsdTools: [
|
|
165
|
+
"gsd_milestone_status",
|
|
166
|
+
"gsd_exec",
|
|
167
|
+
"gsd_exec_search",
|
|
168
|
+
"gsd_resume",
|
|
169
|
+
"gsd_validate_milestone",
|
|
170
|
+
"gsd_reassess_roadmap",
|
|
171
|
+
"subagent",
|
|
172
|
+
],
|
|
158
173
|
requiredWorkflowTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap"],
|
|
159
174
|
},
|
|
160
175
|
},
|
|
@@ -165,6 +180,9 @@ export const UNIT_REGISTRY = {
|
|
|
165
180
|
toolContract: {
|
|
166
181
|
allowedGsdTools: [
|
|
167
182
|
"gsd_milestone_status",
|
|
183
|
+
"gsd_exec",
|
|
184
|
+
"gsd_exec_search",
|
|
185
|
+
"gsd_resume",
|
|
168
186
|
"gsd_requirement_update",
|
|
169
187
|
"gsd_summary_save",
|
|
170
188
|
"gsd_complete_milestone",
|
|
@@ -202,13 +220,14 @@ export const UNIT_REGISTRY = {
|
|
|
202
220
|
allowedGsdTools: [
|
|
203
221
|
"gsd_milestone_status",
|
|
204
222
|
"gsd_plan_slice",
|
|
223
|
+
"gsd_plan_task",
|
|
205
224
|
"gsd_reassess_roadmap",
|
|
206
225
|
"gsd_decision_save",
|
|
207
226
|
"gsd_exec",
|
|
208
227
|
"gsd_exec_search",
|
|
209
228
|
"gsd_resume",
|
|
210
229
|
],
|
|
211
|
-
requiredWorkflowTools: ["gsd_plan_slice", "gsd_reassess_roadmap"],
|
|
230
|
+
requiredWorkflowTools: ["gsd_plan_slice", "gsd_plan_task", "gsd_reassess_roadmap"],
|
|
212
231
|
},
|
|
213
232
|
},
|
|
214
233
|
"refine-slice": {
|
|
@@ -244,6 +263,8 @@ export const UNIT_REGISTRY = {
|
|
|
244
263
|
allowedGsdTools: [
|
|
245
264
|
"gsd_milestone_status",
|
|
246
265
|
"gsd_exec",
|
|
266
|
+
"gsd_exec_search",
|
|
267
|
+
"gsd_resume",
|
|
247
268
|
"gsd_slice_complete",
|
|
248
269
|
"gsd_task_reopen",
|
|
249
270
|
"gsd_replan_slice",
|
|
@@ -326,7 +347,13 @@ export const UNIT_REGISTRY = {
|
|
|
326
347
|
scopeClass: "execute-task",
|
|
327
348
|
phaseChain: ["execution"],
|
|
328
349
|
toolContract: {
|
|
329
|
-
allowedGsdTools: [
|
|
350
|
+
allowedGsdTools: [
|
|
351
|
+
"gsd_milestone_status",
|
|
352
|
+
"gsd_task_complete",
|
|
353
|
+
"gsd_exec",
|
|
354
|
+
"gsd_summary_save",
|
|
355
|
+
"gsd_decision_save",
|
|
356
|
+
],
|
|
330
357
|
requiredWorkflowTools: ["gsd_task_complete", "gsd_summary_save"],
|
|
331
358
|
},
|
|
332
359
|
},
|
|
@@ -413,12 +440,15 @@ export const UNIT_REGISTRY = {
|
|
|
413
440
|
requiredWorkflowTools: ["ask_user_questions"],
|
|
414
441
|
},
|
|
415
442
|
},
|
|
443
|
+
// research-project dispatches 4 parallel scout subagents (Task calls); each scout
|
|
444
|
+
// writes one file under .gsd/research/ directly. The parent coordinator does not
|
|
445
|
+
// call gsd_summary_save or gsd_decision_save — the scouts own their own output.
|
|
416
446
|
"research-project": {
|
|
417
447
|
kind: "primary",
|
|
418
448
|
scopeClass: "standard",
|
|
419
449
|
phaseChain: ["research"],
|
|
420
450
|
toolContract: {
|
|
421
|
-
allowedGsdTools: [
|
|
451
|
+
allowedGsdTools: [],
|
|
422
452
|
requiredWorkflowTools: [],
|
|
423
453
|
},
|
|
424
454
|
},
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Block new workflow entry when completed milestone branches are still unmerged.
|
|
3
3
|
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
|
|
4
6
|
import {
|
|
5
7
|
nativeBranchExists,
|
|
6
8
|
nativeDetectMainBranch,
|
|
@@ -12,17 +14,23 @@ import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
|
12
14
|
import { getAllMilestones } from "./gsd-db.js";
|
|
13
15
|
import { resolveMilestoneIntegrationBranch } from "./git-service.js";
|
|
14
16
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
15
|
-
import { captureRootDirtySnapshot, type RootDirtyEntry } from "./root-write-leak-guard.js";
|
|
16
17
|
import { isClosedStatus } from "./status-guards.js";
|
|
17
18
|
|
|
19
|
+
export interface UnmergedMilestoneDirtyEntry {
|
|
20
|
+
path: string;
|
|
21
|
+
status: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
export interface UnmergedMilestoneBlocker {
|
|
19
25
|
milestoneId: string;
|
|
20
26
|
branch: string;
|
|
21
27
|
integrationBranch: string;
|
|
22
28
|
files: string[];
|
|
23
|
-
dirtyOverlap:
|
|
29
|
+
dirtyOverlap: UnmergedMilestoneDirtyEntry[];
|
|
24
30
|
}
|
|
25
31
|
|
|
32
|
+
type UnmergedMilestoneDirtySnapshot = Map<string, UnmergedMilestoneDirtyEntry>;
|
|
33
|
+
|
|
26
34
|
const BLOCKED_COMMANDS = new Set([
|
|
27
35
|
"auto",
|
|
28
36
|
"next",
|
|
@@ -67,6 +75,32 @@ function isRuntimePath(path: string): boolean {
|
|
|
67
75
|
return path === ".gsd" || path.startsWith(".gsd/");
|
|
68
76
|
}
|
|
69
77
|
|
|
78
|
+
function captureDirtyPathStatusSnapshot(rootPath: string): UnmergedMilestoneDirtySnapshot {
|
|
79
|
+
const snapshot: UnmergedMilestoneDirtySnapshot = new Map();
|
|
80
|
+
let status = "";
|
|
81
|
+
try {
|
|
82
|
+
status = execFileSync("git", ["status", "--porcelain", "--untracked-files=all"], {
|
|
83
|
+
cwd: rootPath,
|
|
84
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
85
|
+
encoding: "utf-8",
|
|
86
|
+
});
|
|
87
|
+
} catch {
|
|
88
|
+
return snapshot;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const line of status.split("\n")) {
|
|
92
|
+
if (!line.trim()) continue;
|
|
93
|
+
const code = line.slice(0, 2);
|
|
94
|
+
const path = line.slice(3).replace(/^"|"$/g, "");
|
|
95
|
+
if (!path || isRuntimePath(path)) continue;
|
|
96
|
+
snapshot.set(path, {
|
|
97
|
+
path,
|
|
98
|
+
status: code.trim() || code,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return snapshot;
|
|
102
|
+
}
|
|
103
|
+
|
|
70
104
|
function formatCommandLabel(attemptedCommand: string): string {
|
|
71
105
|
const trimmed = attemptedCommand.trim();
|
|
72
106
|
return trimmed ? `/gsd ${trimmed}` : "/gsd";
|
|
@@ -132,7 +166,7 @@ export async function findUnmergedCompletedMilestones(base: string): Promise<Unm
|
|
|
132
166
|
await ensureDbOpen(base);
|
|
133
167
|
|
|
134
168
|
const blockers: UnmergedMilestoneBlocker[] = [];
|
|
135
|
-
|
|
169
|
+
let dirtyByPath: UnmergedMilestoneDirtySnapshot | null = null;
|
|
136
170
|
|
|
137
171
|
for (const milestone of getAllMilestones()) {
|
|
138
172
|
if (!isClosedStatus(milestone.status)) continue;
|
|
@@ -158,14 +192,16 @@ export async function findUnmergedCompletedMilestones(base: string): Promise<Unm
|
|
|
158
192
|
const uniqueFiles = [...new Set(files)].sort();
|
|
159
193
|
if (uniqueFiles.length === 0) continue;
|
|
160
194
|
|
|
195
|
+
if (!dirtyByPath) dirtyByPath = captureDirtyPathStatusSnapshot(base);
|
|
196
|
+
const dirtySnapshot = dirtyByPath;
|
|
161
197
|
blockers.push({
|
|
162
198
|
milestoneId: milestone.id,
|
|
163
199
|
branch,
|
|
164
200
|
integrationBranch,
|
|
165
201
|
files: uniqueFiles,
|
|
166
202
|
dirtyOverlap: uniqueFiles
|
|
167
|
-
.map((path) =>
|
|
168
|
-
.filter((entry): entry is
|
|
203
|
+
.map((path) => dirtySnapshot.get(path))
|
|
204
|
+
.filter((entry): entry is UnmergedMilestoneDirtyEntry => Boolean(entry)),
|
|
169
205
|
});
|
|
170
206
|
}
|
|
171
207
|
|
|
@@ -7,7 +7,7 @@ import { getAutoWorktreePath, isInAutoWorktree } from "./auto-worktree.js";
|
|
|
7
7
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
8
8
|
import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
|
|
9
9
|
import { getIsolationMode } from "./preferences.js";
|
|
10
|
-
import { deriveState } from "./state.js";
|
|
10
|
+
import { deriveState, invalidateStateCache } from "./state.js";
|
|
11
11
|
import type { GSDState } from "./types.js";
|
|
12
12
|
import { detectWorktreeName } from "./worktree.js";
|
|
13
13
|
|
|
@@ -133,12 +133,7 @@ export function formatValidationBlockedMessage(
|
|
|
133
133
|
].join("\n\n");
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
base: string,
|
|
138
|
-
attemptedCommand = "",
|
|
139
|
-
): Promise<string | null> {
|
|
140
|
-
await ensureDbOpen(base);
|
|
141
|
-
refreshWorkflowDatabaseFromDisk();
|
|
136
|
+
async function deriveValidationBlockState(base: string): Promise<GSDState> {
|
|
142
137
|
let state = await deriveState(base);
|
|
143
138
|
|
|
144
139
|
if (
|
|
@@ -153,5 +148,16 @@ export async function getValidationBlockMessageForBase(
|
|
|
153
148
|
}
|
|
154
149
|
}
|
|
155
150
|
|
|
151
|
+
return state;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export async function getValidationBlockMessageForBase(
|
|
155
|
+
base: string,
|
|
156
|
+
attemptedCommand = "",
|
|
157
|
+
): Promise<string | null> {
|
|
158
|
+
await ensureDbOpen(base);
|
|
159
|
+
refreshWorkflowDatabaseFromDisk();
|
|
160
|
+
invalidateStateCache();
|
|
161
|
+
const state = await deriveValidationBlockState(base);
|
|
156
162
|
return formatValidationBlockedMessage(state, attemptedCommand);
|
|
157
163
|
}
|
|
@@ -244,6 +244,14 @@ export function formatFailureContext(result: VerificationResult): string {
|
|
|
244
244
|
return header + body;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
export function formatFailureSignature(result: VerificationResult): string {
|
|
248
|
+
return result.checks
|
|
249
|
+
.filter((check) => check.exitCode !== 0)
|
|
250
|
+
.map((check) => `${check.command.trim()}#${check.exitCode}`)
|
|
251
|
+
.sort()
|
|
252
|
+
.join("\n");
|
|
253
|
+
}
|
|
254
|
+
|
|
247
255
|
// ─── Gate Execution ─────────────────────────────────────────────────────────
|
|
248
256
|
|
|
249
257
|
/** Characters that indicate shell control syntax when unquoted in a command string. */
|
|
@@ -10,11 +10,12 @@ import type { ArtifactRow, MilestoneRow } from "./db-milestone-artifact-rows.js"
|
|
|
10
10
|
import type { SliceRow, TaskRow } from "./db-task-slice-rows.js";
|
|
11
11
|
import type { VerificationEvidenceRow } from "./db-verification-evidence-rows.js";
|
|
12
12
|
import type { Decision, GateRow, Requirement } from "./types.js";
|
|
13
|
-
import { atomicWriteSync } from "./atomic-write.js";
|
|
13
|
+
import { atomicWriteAsync, atomicWriteSync } from "./atomic-write.js";
|
|
14
14
|
import { getAllDecisionsFromMemories } from "./context-store.js";
|
|
15
15
|
import { backfillDecisionsToMemories } from "./memory-backfill.js";
|
|
16
16
|
import { invalidateAllCaches } from "./cache.js";
|
|
17
|
-
import {
|
|
17
|
+
import { logWarning } from "./workflow-logger.js";
|
|
18
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
18
19
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
19
20
|
|
|
20
21
|
// ─── Manifest Types ──────────────────────────────────────────────────────
|
|
@@ -349,16 +350,146 @@ export function snapshotState(): StateManifest {
|
|
|
349
350
|
|
|
350
351
|
// ─── writeManifest ───────────────────────────────────────────────────────
|
|
351
352
|
|
|
353
|
+
interface ManifestWriteState {
|
|
354
|
+
filePath: string;
|
|
355
|
+
latestJson: string | null;
|
|
356
|
+
inFlightJson: string | null;
|
|
357
|
+
/** Set by sync exit flush so an in-flight async write cannot leave stale data on disk. */
|
|
358
|
+
syncFlushJson: string | null;
|
|
359
|
+
active: Promise<void> | null;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const manifestWrites = new Map<string, ManifestWriteState>();
|
|
363
|
+
let processTeardownFlushInstalled = false;
|
|
364
|
+
let beforeExitFlushStarted = false;
|
|
365
|
+
|
|
366
|
+
function manifestWriteKey(basePath: string): string {
|
|
367
|
+
return resolve(basePath);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function manifestFilePath(basePath: string): string {
|
|
371
|
+
return join(resolve(basePath), ".gsd", "state-manifest.json");
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function describeError(err: unknown): string {
|
|
375
|
+
return err instanceof Error ? err.message : String(err);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function logManifestWriteFailure(filePath: string, err: unknown): void {
|
|
379
|
+
logWarning("manifest", `state manifest write failed: ${describeError(err)}`, { file: filePath });
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async function drainManifestWrites(key: string, state: ManifestWriteState): Promise<void> {
|
|
383
|
+
let lastWriteError: unknown = null;
|
|
384
|
+
try {
|
|
385
|
+
while (state.latestJson !== null && state.syncFlushJson === null) {
|
|
386
|
+
const json = state.latestJson;
|
|
387
|
+
state.latestJson = null;
|
|
388
|
+
state.inFlightJson = json;
|
|
389
|
+
try {
|
|
390
|
+
await atomicWriteAsync(state.filePath, json);
|
|
391
|
+
if (state.syncFlushJson !== null) {
|
|
392
|
+
atomicWriteSync(state.filePath, state.syncFlushJson);
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
lastWriteError = null;
|
|
396
|
+
} catch (err) {
|
|
397
|
+
lastWriteError = err;
|
|
398
|
+
logManifestWriteFailure(state.filePath, err);
|
|
399
|
+
} finally {
|
|
400
|
+
state.inFlightJson = null;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
} finally {
|
|
404
|
+
state.active = null;
|
|
405
|
+
if (state.latestJson === null && state.inFlightJson === null) {
|
|
406
|
+
manifestWrites.delete(key);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (lastWriteError !== null && state.syncFlushJson === null) {
|
|
410
|
+
throw lastWriteError;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function enqueueManifestWrite(basePath: string, json: string): void {
|
|
415
|
+
const key = manifestWriteKey(basePath);
|
|
416
|
+
let state = manifestWrites.get(key);
|
|
417
|
+
if (!state) {
|
|
418
|
+
state = {
|
|
419
|
+
filePath: manifestFilePath(basePath),
|
|
420
|
+
latestJson: null,
|
|
421
|
+
inFlightJson: null,
|
|
422
|
+
syncFlushJson: null,
|
|
423
|
+
active: null,
|
|
424
|
+
};
|
|
425
|
+
manifestWrites.set(key, state);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
state.latestJson = json;
|
|
429
|
+
if (!state.active) {
|
|
430
|
+
const active = drainManifestWrites(key, state);
|
|
431
|
+
void active.catch(() => {});
|
|
432
|
+
state.active = active;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
352
436
|
/**
|
|
353
|
-
*
|
|
437
|
+
* Queue current DB state for an async atomic write to .gsd/state-manifest.json.
|
|
354
438
|
* Uses JSON.stringify with 2-space indent for git three-way merge friendliness.
|
|
355
439
|
*/
|
|
356
440
|
export function writeManifest(basePath: string): void {
|
|
357
441
|
const manifest = snapshotState();
|
|
358
442
|
const json = JSON.stringify(manifest, null, 2);
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
443
|
+
enqueueManifestWrite(basePath, json);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
async function flushManifestByKey(key: string): Promise<void> {
|
|
447
|
+
for (;;) {
|
|
448
|
+
const active = manifestWrites.get(key)?.active;
|
|
449
|
+
if (!active) return;
|
|
450
|
+
await active;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Wait for any queued manifest write for this base path to become durable.
|
|
456
|
+
*/
|
|
457
|
+
export async function flushManifest(basePath: string): Promise<void> {
|
|
458
|
+
await flushManifestByKey(manifestWriteKey(basePath));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export async function flushAllManifests(): Promise<void> {
|
|
462
|
+
await Promise.all(Array.from(manifestWrites.keys(), key => flushManifestByKey(key)));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function flushAllManifestsSync(): void {
|
|
466
|
+
for (const [key, state] of manifestWrites) {
|
|
467
|
+
const json = state.latestJson ?? state.inFlightJson;
|
|
468
|
+
if (json === null) continue;
|
|
469
|
+
try {
|
|
470
|
+
atomicWriteSync(state.filePath, json);
|
|
471
|
+
state.latestJson = null;
|
|
472
|
+
state.inFlightJson = null;
|
|
473
|
+
state.syncFlushJson = json;
|
|
474
|
+
manifestWrites.delete(key);
|
|
475
|
+
} catch (err) {
|
|
476
|
+
logManifestWriteFailure(state.filePath, err);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export function installManifestFlushOnProcessTeardown(): void {
|
|
482
|
+
if (processTeardownFlushInstalled) return;
|
|
483
|
+
processTeardownFlushInstalled = true;
|
|
484
|
+
|
|
485
|
+
process.once("beforeExit", () => {
|
|
486
|
+
if (beforeExitFlushStarted) return;
|
|
487
|
+
beforeExitFlushStarted = true;
|
|
488
|
+
void flushAllManifests();
|
|
489
|
+
});
|
|
490
|
+
process.once("exit", () => {
|
|
491
|
+
flushAllManifestsSync();
|
|
492
|
+
});
|
|
362
493
|
}
|
|
363
494
|
|
|
364
495
|
// ─── readManifest ────────────────────────────────────────────────────────
|
|
@@ -414,9 +545,12 @@ function restoreArtifactProjections(basePath: string, manifest: StateManifest):
|
|
|
414
545
|
if (manifest.artifacts === undefined) return;
|
|
415
546
|
|
|
416
547
|
for (const artifact of manifest.artifacts) {
|
|
548
|
+
const content = artifact.full_content ?? "";
|
|
549
|
+
if (content === "") continue;
|
|
550
|
+
|
|
417
551
|
atomicWriteSync(
|
|
418
552
|
artifactProjectionPath(basePath, artifact.path),
|
|
419
|
-
|
|
553
|
+
content,
|
|
420
554
|
);
|
|
421
555
|
}
|
|
422
556
|
}
|