gsd-pi 2.81.0 → 2.82.0-dev.ed17d078d
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 +60 -30
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/gsd/auto/loop.js +111 -8
- package/dist/resources/extensions/gsd/auto/orchestrator.js +113 -6
- package/dist/resources/extensions/gsd/auto/phases.js +199 -97
- package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
- package/dist/resources/extensions/gsd/auto/session.js +9 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
- package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
- package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
- package/dist/resources/extensions/gsd/auto-start.js +20 -23
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
- package/dist/resources/extensions/gsd/auto-verification.js +12 -6
- package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
- package/dist/resources/extensions/gsd/auto.js +386 -106
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +13 -2
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/git-service.js +2 -1
- package/dist/resources/extensions/gsd/gsd-db.js +7 -23
- package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
- package/dist/resources/extensions/gsd/health-widget.js +4 -10
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -96
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
- package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
- package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
- package/dist/resources/extensions/gsd/session-lock.js +40 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
- package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
- package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
- package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
- package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
- package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
- package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
- 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 +6 -6
- 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/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- 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.js +2 -2
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- 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 +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/dist/welcome-screen.d.ts +0 -7
- package/dist/welcome-screen.js +60 -69
- package/package.json +3 -2
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +2 -0
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
- package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.js +9 -6
- package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
- package/packages/pi-tui/src/overlay-layout.ts +10 -7
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +105 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +27 -26
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
- package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
- package/src/resources/extensions/gsd/auto/loop.ts +113 -9
- package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
- package/src/resources/extensions/gsd/auto/phases.ts +158 -19
- package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
- package/src/resources/extensions/gsd/auto/session.ts +10 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
- package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +22 -22
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
- package/src/resources/extensions/gsd/auto-verification.ts +12 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
- package/src/resources/extensions/gsd/auto.ts +424 -106
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -2
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/git-service.ts +2 -0
- package/src/resources/extensions/gsd/gsd-db.ts +7 -23
- package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
- package/src/resources/extensions/gsd/health-widget.ts +6 -10
- package/src/resources/extensions/gsd/journal.ts +2 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
- package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
- package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
- package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
- package/src/resources/extensions/gsd/session-lock.ts +41 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
- package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
- package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +729 -176
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +20 -5
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
- package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
- package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
- package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
- package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
- package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// GSD-2 — ADR-005 Phase 3b: surface ProviderSwitchReport from pi-ai.
|
|
2
|
+
//
|
|
3
|
+
// pi-ai builds a ProviderSwitchReport on every cross-provider transform but
|
|
4
|
+
// only logs it to stderr when GSD_VERBOSE=1. This module installs a
|
|
5
|
+
// single-subscriber observer that surfaces non-empty reports through GSD's
|
|
6
|
+
// three usual telemetry surfaces:
|
|
7
|
+
//
|
|
8
|
+
// 1. UOK audit event (category model-policy, type provider-switch) — only
|
|
9
|
+
// when an auto trace is active.
|
|
10
|
+
// 2. Persistent notification (.gsd/notifications.jsonl, severity warning) —
|
|
11
|
+
// whenever the GSD basePath is known, so users see the loss in the
|
|
12
|
+
// dashboard / status surface without GSD_VERBOSE.
|
|
13
|
+
// 3. In-memory counter, exposed via getProviderSwitchStats() so any
|
|
14
|
+
// caller (dashboard, doctor, tests) can read the rollup.
|
|
15
|
+
import { setProviderSwitchObserver } from "@gsd/pi-ai";
|
|
16
|
+
import { autoSession } from "./auto-runtime-state.js";
|
|
17
|
+
import { appendNotification } from "./notification-store.js";
|
|
18
|
+
import { buildAuditEnvelope, emitUokAuditEvent } from "./uok/audit.js";
|
|
19
|
+
const INTERACTIVE_TRACE_KEY = "interactive";
|
|
20
|
+
let installed = false;
|
|
21
|
+
let totalSwitches = 0;
|
|
22
|
+
const totals = {
|
|
23
|
+
thinkingBlocksDropped: 0,
|
|
24
|
+
thinkingBlocksDowngraded: 0,
|
|
25
|
+
toolCallIdsRemapped: 0,
|
|
26
|
+
syntheticToolResultsInserted: 0,
|
|
27
|
+
thoughtSignaturesDropped: 0,
|
|
28
|
+
};
|
|
29
|
+
const byTrace = new Map();
|
|
30
|
+
let lastReport = null;
|
|
31
|
+
let lastAt = null;
|
|
32
|
+
/** Format a one-line summary suitable for a notification message. */
|
|
33
|
+
function summarize(report) {
|
|
34
|
+
const parts = [];
|
|
35
|
+
if (report.thinkingBlocksDropped > 0)
|
|
36
|
+
parts.push(`${report.thinkingBlocksDropped} thinking dropped`);
|
|
37
|
+
if (report.thinkingBlocksDowngraded > 0)
|
|
38
|
+
parts.push(`${report.thinkingBlocksDowngraded} thinking downgraded`);
|
|
39
|
+
if (report.toolCallIdsRemapped > 0)
|
|
40
|
+
parts.push(`${report.toolCallIdsRemapped} tool ids remapped`);
|
|
41
|
+
if (report.syntheticToolResultsInserted > 0)
|
|
42
|
+
parts.push(`${report.syntheticToolResultsInserted} synthetic tool results`);
|
|
43
|
+
if (report.thoughtSignaturesDropped > 0)
|
|
44
|
+
parts.push(`${report.thoughtSignaturesDropped} thought signatures dropped`);
|
|
45
|
+
return `Provider switch ${report.fromApi} → ${report.toApi}: ${parts.join(", ")}`;
|
|
46
|
+
}
|
|
47
|
+
function recordReport(report) {
|
|
48
|
+
const now = new Date().toISOString();
|
|
49
|
+
totalSwitches += 1;
|
|
50
|
+
totals.thinkingBlocksDropped += report.thinkingBlocksDropped;
|
|
51
|
+
totals.thinkingBlocksDowngraded += report.thinkingBlocksDowngraded;
|
|
52
|
+
totals.toolCallIdsRemapped += report.toolCallIdsRemapped;
|
|
53
|
+
totals.syntheticToolResultsInserted += report.syntheticToolResultsInserted;
|
|
54
|
+
totals.thoughtSignaturesDropped += report.thoughtSignaturesDropped;
|
|
55
|
+
lastReport = report;
|
|
56
|
+
lastAt = now;
|
|
57
|
+
const traceKey = autoSession.currentTraceId ?? INTERACTIVE_TRACE_KEY;
|
|
58
|
+
const existing = byTrace.get(traceKey);
|
|
59
|
+
if (existing) {
|
|
60
|
+
existing.switches += 1;
|
|
61
|
+
existing.lastReport = report;
|
|
62
|
+
existing.lastAt = now;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
byTrace.set(traceKey, { switches: 1, lastReport: report, lastAt: now });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function emitAudit(report) {
|
|
69
|
+
const traceId = autoSession.currentTraceId;
|
|
70
|
+
const basePath = autoSession.basePath;
|
|
71
|
+
if (!traceId || !basePath)
|
|
72
|
+
return;
|
|
73
|
+
try {
|
|
74
|
+
emitUokAuditEvent(basePath, buildAuditEnvelope({
|
|
75
|
+
traceId,
|
|
76
|
+
category: "model-policy",
|
|
77
|
+
type: "provider-switch",
|
|
78
|
+
payload: {
|
|
79
|
+
fromApi: report.fromApi,
|
|
80
|
+
toApi: report.toApi,
|
|
81
|
+
thinkingBlocksDropped: report.thinkingBlocksDropped,
|
|
82
|
+
thinkingBlocksDowngraded: report.thinkingBlocksDowngraded,
|
|
83
|
+
toolCallIdsRemapped: report.toolCallIdsRemapped,
|
|
84
|
+
syntheticToolResultsInserted: report.syntheticToolResultsInserted,
|
|
85
|
+
thoughtSignaturesDropped: report.thoughtSignaturesDropped,
|
|
86
|
+
},
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Audit emission is best-effort. Counter + notification still fire.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function emitNotification(report) {
|
|
94
|
+
try {
|
|
95
|
+
appendNotification(summarize(report), "warning", "workflow-logger");
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Notification persistence is best-effort.
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function handleReport(report) {
|
|
102
|
+
recordReport(report);
|
|
103
|
+
emitAudit(report);
|
|
104
|
+
emitNotification(report);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Install the pi-ai observer. Idempotent — calling more than once is a no-op
|
|
108
|
+
* after the first install.
|
|
109
|
+
*/
|
|
110
|
+
export function installProviderSwitchObserver() {
|
|
111
|
+
if (installed)
|
|
112
|
+
return;
|
|
113
|
+
setProviderSwitchObserver(handleReport);
|
|
114
|
+
installed = true;
|
|
115
|
+
}
|
|
116
|
+
/** Uninstall the observer. Intended for tests. */
|
|
117
|
+
export function uninstallProviderSwitchObserver() {
|
|
118
|
+
setProviderSwitchObserver(undefined);
|
|
119
|
+
installed = false;
|
|
120
|
+
}
|
|
121
|
+
/** Read-only snapshot of the in-memory rollup. */
|
|
122
|
+
export function getProviderSwitchStats() {
|
|
123
|
+
const trace = {};
|
|
124
|
+
for (const [key, value] of byTrace) {
|
|
125
|
+
trace[key] = { switches: value.switches, lastReport: { ...value.lastReport }, lastAt: value.lastAt };
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
totalSwitches,
|
|
129
|
+
totals: { ...totals },
|
|
130
|
+
byTrace: trace,
|
|
131
|
+
lastReport: lastReport ? { ...lastReport } : null,
|
|
132
|
+
lastAt,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/** Reset the in-memory rollup. Intended for tests. */
|
|
136
|
+
export function _resetProviderSwitchStats() {
|
|
137
|
+
totalSwitches = 0;
|
|
138
|
+
totals.thinkingBlocksDropped = 0;
|
|
139
|
+
totals.thinkingBlocksDowngraded = 0;
|
|
140
|
+
totals.toolCallIdsRemapped = 0;
|
|
141
|
+
totals.syntheticToolResultsInserted = 0;
|
|
142
|
+
totals.thoughtSignaturesDropped = 0;
|
|
143
|
+
byTrace.clear();
|
|
144
|
+
lastReport = null;
|
|
145
|
+
lastAt = null;
|
|
146
|
+
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
// Project/App: GSD-2
|
|
2
2
|
// File Purpose: ADR-015 Recovery Classification module for runtime failure taxonomy.
|
|
3
3
|
import { classifyError, isTransient } from "./error-classifier.js";
|
|
4
|
+
import { ReconciliationFailedError } from "./state-reconciliation.js";
|
|
4
5
|
export function classifyFailure(input) {
|
|
5
6
|
const message = errorMessage(input.error);
|
|
6
|
-
|
|
7
|
+
// ADR-017: ReconciliationFailedError is a typed throw from the State
|
|
8
|
+
// Reconciliation Module. Recognize it by class regardless of caller-supplied
|
|
9
|
+
// failureKind so the taxonomy stays consistent.
|
|
10
|
+
const failureKind = input.error instanceof ReconciliationFailedError
|
|
11
|
+
? "reconciliation-drift"
|
|
12
|
+
: input.failureKind ?? inferFailureKind(message);
|
|
7
13
|
switch (failureKind) {
|
|
8
14
|
case "tool-schema":
|
|
9
15
|
return {
|
|
@@ -45,6 +51,14 @@ export function classifyFailure(input) {
|
|
|
45
51
|
exitReason: "verification-drift",
|
|
46
52
|
remediation: "Inspect the verification artifact and reconcile the state snapshot before resuming.",
|
|
47
53
|
};
|
|
54
|
+
case "reconciliation-drift":
|
|
55
|
+
return {
|
|
56
|
+
failureKind,
|
|
57
|
+
action: "escalate",
|
|
58
|
+
reason: `Reconciliation drift${unitSuffix(input)}: ${message}`,
|
|
59
|
+
exitReason: "reconciliation-drift",
|
|
60
|
+
remediation: "Inspect the persistent or repair-failed drift kinds reported by the State Reconciliation Module before resuming.",
|
|
61
|
+
};
|
|
48
62
|
case "provider": {
|
|
49
63
|
const providerClass = classifyError(message, input.retryAfterMs);
|
|
50
64
|
return {
|
|
@@ -521,6 +521,46 @@ export function readSessionLockData(basePath) {
|
|
|
521
521
|
export function isSessionLockProcessAlive(data) {
|
|
522
522
|
return isPidAlive(data.pid);
|
|
523
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* ADR-017 raw primitive: remove orphaned lock artifacts (lock dir + lock file)
|
|
526
|
+
* when the recorded PID is dead or no metadata is present. Mirrors the
|
|
527
|
+
* pre-flight cleanup logic in acquireSessionLock so the stale-worker drift
|
|
528
|
+
* handler can clear the orphan proactively without going through the full
|
|
529
|
+
* acquire path. No-op when the lock is held by an alive process.
|
|
530
|
+
*
|
|
531
|
+
* Returns true when artifacts were removed (drift was present).
|
|
532
|
+
*/
|
|
533
|
+
export function removeStaleSessionLock(basePath) {
|
|
534
|
+
const lp = lockPath(basePath);
|
|
535
|
+
const gsdDir = gsdRoot(basePath);
|
|
536
|
+
const lockTarget = effectiveLockTarget(gsdDir);
|
|
537
|
+
const lockDir = lockTarget + ".lock";
|
|
538
|
+
const existingData = readExistingLockData(lp);
|
|
539
|
+
const isOrphan = !existingData ||
|
|
540
|
+
(typeof existingData.pid === "number" && !isPidAlive(existingData.pid));
|
|
541
|
+
if (!isOrphan)
|
|
542
|
+
return false;
|
|
543
|
+
let removed = false;
|
|
544
|
+
if (existsSync(lockDir)) {
|
|
545
|
+
try {
|
|
546
|
+
rmSync(lockDir, { recursive: true, force: true });
|
|
547
|
+
removed = true;
|
|
548
|
+
}
|
|
549
|
+
catch {
|
|
550
|
+
/* best-effort */
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (existsSync(lp)) {
|
|
554
|
+
try {
|
|
555
|
+
unlinkSync(lp);
|
|
556
|
+
removed = true;
|
|
557
|
+
}
|
|
558
|
+
catch {
|
|
559
|
+
/* best-effort */
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return removed;
|
|
563
|
+
}
|
|
524
564
|
/**
|
|
525
565
|
* Returns true if we currently hold a session lock for the given path.
|
|
526
566
|
*/
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: ADR-017 missing-completion-timestamp drift handler. Detects
|
|
3
|
+
// tasks/slices/milestones marked complete (status = 'complete' | 'done') in
|
|
4
|
+
// the DB but whose `completed_at` column is null, and where the on-disk
|
|
5
|
+
// SUMMARY.md attests to completion. Backfills `completed_at` from the
|
|
6
|
+
// SUMMARY.md mtime — deterministic and idempotent (re-running yields the
|
|
7
|
+
// same value).
|
|
8
|
+
import { existsSync, statSync } from "node:fs";
|
|
9
|
+
import { getMilestone, getMilestoneSlices, getSliceTasks, isDbAvailable, updateMilestoneStatus, updateSliceStatus, updateTaskStatus, } from "../../gsd-db.js";
|
|
10
|
+
import { resolveMilestoneFile, resolveSliceFile, resolveTaskFile, } from "../../paths.js";
|
|
11
|
+
const COMPLETE_STATUSES = new Set(["complete", "done"]);
|
|
12
|
+
function summaryMtimeIso(path) {
|
|
13
|
+
try {
|
|
14
|
+
return statSync(path).mtime.toISOString();
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function detectMissingCompletionTimestampDrift(state, ctx) {
|
|
21
|
+
if (!isDbAvailable())
|
|
22
|
+
return [];
|
|
23
|
+
const mid = state.activeMilestone?.id;
|
|
24
|
+
if (!mid)
|
|
25
|
+
return [];
|
|
26
|
+
const milestone = getMilestone(mid);
|
|
27
|
+
if (!milestone)
|
|
28
|
+
return [];
|
|
29
|
+
const drifts = [];
|
|
30
|
+
// Milestone-level
|
|
31
|
+
if (COMPLETE_STATUSES.has(milestone.status) &&
|
|
32
|
+
milestone.completed_at === null) {
|
|
33
|
+
const summary = resolveMilestoneFile(ctx.basePath, mid, "SUMMARY");
|
|
34
|
+
if (summary && existsSync(summary)) {
|
|
35
|
+
drifts.push({
|
|
36
|
+
kind: "missing-completion-timestamp",
|
|
37
|
+
entity: "milestone",
|
|
38
|
+
ids: [mid],
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Slice and task levels iterate independently — tasks can complete before
|
|
43
|
+
// the parent slice closes, so task drift must be checked even when the
|
|
44
|
+
// slice is still pending.
|
|
45
|
+
for (const slice of getMilestoneSlices(mid)) {
|
|
46
|
+
if (COMPLETE_STATUSES.has(slice.status) &&
|
|
47
|
+
slice.completed_at === null) {
|
|
48
|
+
const summary = resolveSliceFile(ctx.basePath, mid, slice.id, "SUMMARY");
|
|
49
|
+
if (summary && existsSync(summary)) {
|
|
50
|
+
drifts.push({
|
|
51
|
+
kind: "missing-completion-timestamp",
|
|
52
|
+
entity: "slice",
|
|
53
|
+
ids: [`${mid}/${slice.id}`],
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const task of getSliceTasks(mid, slice.id)) {
|
|
58
|
+
if (!COMPLETE_STATUSES.has(task.status))
|
|
59
|
+
continue;
|
|
60
|
+
if (task.completed_at !== null)
|
|
61
|
+
continue;
|
|
62
|
+
const taskSummary = resolveTaskFile(ctx.basePath, mid, slice.id, task.id, "SUMMARY");
|
|
63
|
+
if (taskSummary && existsSync(taskSummary)) {
|
|
64
|
+
drifts.push({
|
|
65
|
+
kind: "missing-completion-timestamp",
|
|
66
|
+
entity: "task",
|
|
67
|
+
ids: [`${mid}/${slice.id}/${task.id}`],
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return drifts;
|
|
73
|
+
}
|
|
74
|
+
export function repairMissingCompletionTimestamp(record, ctx) {
|
|
75
|
+
const composite = record.ids[0];
|
|
76
|
+
if (!composite)
|
|
77
|
+
return;
|
|
78
|
+
const parts = composite.split("/");
|
|
79
|
+
if (record.entity === "milestone") {
|
|
80
|
+
const [mid] = parts;
|
|
81
|
+
if (!mid)
|
|
82
|
+
return;
|
|
83
|
+
const milestone = getMilestone(mid);
|
|
84
|
+
if (!milestone ||
|
|
85
|
+
milestone.completed_at !== null ||
|
|
86
|
+
!COMPLETE_STATUSES.has(milestone.status))
|
|
87
|
+
return;
|
|
88
|
+
const summary = resolveMilestoneFile(ctx.basePath, mid, "SUMMARY");
|
|
89
|
+
const ts = summary ? summaryMtimeIso(summary) : null;
|
|
90
|
+
if (!ts)
|
|
91
|
+
return;
|
|
92
|
+
updateMilestoneStatus(mid, milestone.status, ts);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (record.entity === "slice") {
|
|
96
|
+
const [mid, sid] = parts;
|
|
97
|
+
if (!mid || !sid)
|
|
98
|
+
return;
|
|
99
|
+
const slice = getMilestoneSlices(mid).find((s) => s.id === sid);
|
|
100
|
+
if (!slice ||
|
|
101
|
+
slice.completed_at !== null ||
|
|
102
|
+
!COMPLETE_STATUSES.has(slice.status))
|
|
103
|
+
return;
|
|
104
|
+
const summary = resolveSliceFile(ctx.basePath, mid, sid, "SUMMARY");
|
|
105
|
+
const ts = summary ? summaryMtimeIso(summary) : null;
|
|
106
|
+
if (!ts)
|
|
107
|
+
return;
|
|
108
|
+
updateSliceStatus(mid, sid, slice.status, ts);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (record.entity === "task") {
|
|
112
|
+
const [mid, sid, tid] = parts;
|
|
113
|
+
if (!mid || !sid || !tid)
|
|
114
|
+
return;
|
|
115
|
+
const task = getSliceTasks(mid, sid).find((t) => t.id === tid);
|
|
116
|
+
if (!task ||
|
|
117
|
+
task.completed_at !== null ||
|
|
118
|
+
!COMPLETE_STATUSES.has(task.status))
|
|
119
|
+
return;
|
|
120
|
+
const summary = resolveTaskFile(ctx.basePath, mid, sid, tid, "SUMMARY");
|
|
121
|
+
const ts = summary ? summaryMtimeIso(summary) : null;
|
|
122
|
+
if (!ts)
|
|
123
|
+
return;
|
|
124
|
+
updateTaskStatus(mid, sid, tid, task.status, ts);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export const completionTimestampHandler = {
|
|
128
|
+
kind: "missing-completion-timestamp",
|
|
129
|
+
detect: detectMissingCompletionTimestampDrift,
|
|
130
|
+
repair: repairMissingCompletionTimestamp,
|
|
131
|
+
};
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: ADR-017 unmerged-merge-state drift handler. Relocated from
|
|
3
|
+
// auto-recovery.ts as part of issue #5701. Owns:
|
|
4
|
+
// - rebase/cherry-pick/revert leftover cleanup (#4980 HIGH-7)
|
|
5
|
+
// - MERGE_HEAD / SQUASH_MSG reconciliation with auto-resolve of .gsd/
|
|
6
|
+
// conflicts (#530, #2542)
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
8
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
9
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
10
|
+
import { getErrorMessage } from "../../error-utils.js";
|
|
11
|
+
import { nativeAddPaths, nativeCheckoutTheirs, nativeCommit, nativeConflictFiles, nativeMergeAbort, nativeRebaseAbort, nativeResetHard, } from "../../native-git-bridge.js";
|
|
12
|
+
import { logError, logWarning } from "../../workflow-logger.js";
|
|
13
|
+
const SILENT_NOTIFY = () => { };
|
|
14
|
+
function resolveGitDir(basePath) {
|
|
15
|
+
try {
|
|
16
|
+
const gitDir = execFileSync("git", ["rev-parse", "--git-dir"], {
|
|
17
|
+
cwd: basePath,
|
|
18
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
19
|
+
encoding: "utf-8",
|
|
20
|
+
}).trim();
|
|
21
|
+
if (gitDir.length > 0) {
|
|
22
|
+
return isAbsolute(gitDir) ? gitDir : resolve(basePath, gitDir);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
logWarning("recovery", `gitdir resolution failed: ${getErrorMessage(err)}`);
|
|
27
|
+
}
|
|
28
|
+
return join(basePath, ".git");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Best-effort abort of a pending merge/squash and hard-reset to HEAD.
|
|
32
|
+
* Handles both real merges (MERGE_HEAD) and squash merges (SQUASH_MSG).
|
|
33
|
+
*/
|
|
34
|
+
function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
|
|
35
|
+
if (hasMergeHead) {
|
|
36
|
+
try {
|
|
37
|
+
nativeMergeAbort(basePath);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
/* best-effort */
|
|
41
|
+
logWarning("recovery", `git merge-abort failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else if (squashMsgPath) {
|
|
45
|
+
try {
|
|
46
|
+
unlinkSync(squashMsgPath);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
/* best-effort */
|
|
50
|
+
logWarning("recovery", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
nativeResetHard(basePath);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
/* best-effort */
|
|
58
|
+
logError("recovery", `git reset failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Detect and abort other in-progress git operations left behind by a SIGKILL'd
|
|
63
|
+
* worker (rebase, cherry-pick, revert). Without this, a killed worker
|
|
64
|
+
* mid-rebase leaves `.git/rebase-merge/` or `.git/CHERRY_PICK_HEAD` and the
|
|
65
|
+
* worktree is wedged until the user manually runs the matching `--abort`.
|
|
66
|
+
*
|
|
67
|
+
* Called before merge-state reconciliation because these states block any
|
|
68
|
+
* subsequent merge/commit operation. (#4980 HIGH-7)
|
|
69
|
+
*/
|
|
70
|
+
function reconcileOtherInProgressGitOps(basePath, notify) {
|
|
71
|
+
const gitDir = resolveGitDir(basePath);
|
|
72
|
+
const states = [
|
|
73
|
+
{
|
|
74
|
+
label: "rebase",
|
|
75
|
+
indicators: [join(gitDir, "rebase-merge"), join(gitDir, "rebase-apply")],
|
|
76
|
+
abort: () => nativeRebaseAbort(basePath),
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
label: "cherry-pick",
|
|
80
|
+
indicators: [join(gitDir, "CHERRY_PICK_HEAD")],
|
|
81
|
+
abort: () => {
|
|
82
|
+
try {
|
|
83
|
+
execFileSync("git", ["cherry-pick", "--abort"], {
|
|
84
|
+
cwd: basePath,
|
|
85
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
86
|
+
encoding: "utf-8",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
throw new Error(`cherry-pick --abort failed: ${getErrorMessage(err)}`);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
label: "revert",
|
|
96
|
+
indicators: [join(gitDir, "REVERT_HEAD")],
|
|
97
|
+
abort: () => {
|
|
98
|
+
try {
|
|
99
|
+
execFileSync("git", ["revert", "--abort"], {
|
|
100
|
+
cwd: basePath,
|
|
101
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
102
|
+
encoding: "utf-8",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
throw new Error(`revert --abort failed: ${getErrorMessage(err)}`);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
let reconciled = false;
|
|
112
|
+
for (const s of states) {
|
|
113
|
+
const present = s.indicators.some((p) => existsSync(p));
|
|
114
|
+
if (!present)
|
|
115
|
+
continue;
|
|
116
|
+
try {
|
|
117
|
+
s.abort();
|
|
118
|
+
notify(`Detected leftover ${s.label} state from prior session — aborted.`, "warning");
|
|
119
|
+
reconciled = true;
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
logError("recovery", `${s.label} abort failed: ${getErrorMessage(err)}`);
|
|
123
|
+
notify(`Detected leftover ${s.label} state but auto-abort failed. ` +
|
|
124
|
+
`Run \`git ${s.label} --abort\` manually before retrying.`, "error");
|
|
125
|
+
return "blocked";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return reconciled ? "reconciled" : "clean";
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Core: detect leftover merge state and reconcile it. Takes a NotifyFn so the
|
|
132
|
+
* legacy reconcileMergeState(basePath, ctx) wrapper and the drift handler can
|
|
133
|
+
* both call it — the drift handler uses SILENT_NOTIFY.
|
|
134
|
+
*/
|
|
135
|
+
function reconcileMergeStateCore(basePath, notify) {
|
|
136
|
+
// First, abort any rebase/cherry-pick/revert left over from a SIGKILL'd
|
|
137
|
+
// worker. Doing this before the merge-state check unblocks any merge that
|
|
138
|
+
// would otherwise refuse with "you have unfinished operation". (HIGH-7)
|
|
139
|
+
const otherOpsResult = reconcileOtherInProgressGitOps(basePath, notify);
|
|
140
|
+
if (otherOpsResult === "blocked")
|
|
141
|
+
return "blocked";
|
|
142
|
+
const gitDir = resolveGitDir(basePath);
|
|
143
|
+
const mergeHeadPath = join(gitDir, "MERGE_HEAD");
|
|
144
|
+
const squashMsgPath = join(gitDir, "SQUASH_MSG");
|
|
145
|
+
const hasMergeHead = existsSync(mergeHeadPath);
|
|
146
|
+
const hasSquashMsg = existsSync(squashMsgPath);
|
|
147
|
+
if (!hasMergeHead && !hasSquashMsg) {
|
|
148
|
+
return otherOpsResult === "reconciled" ? "reconciled" : "clean";
|
|
149
|
+
}
|
|
150
|
+
const conflictedFiles = nativeConflictFiles(basePath);
|
|
151
|
+
if (conflictedFiles.length === 0) {
|
|
152
|
+
// All conflicts resolved — finalize the merge/squash commit
|
|
153
|
+
try {
|
|
154
|
+
const commitSha = nativeCommit(basePath, "chore(gsd): reconcile merge state");
|
|
155
|
+
if (commitSha) {
|
|
156
|
+
const mode = hasMergeHead ? "merge" : "squash commit";
|
|
157
|
+
notify(`Finalized leftover ${mode} from prior session.`, "info");
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
notify("No new commit needed for leftover merge/squash state — already committed.", "info");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
const errorMessage = getErrorMessage(err);
|
|
165
|
+
notify(`Failed to finalize leftover merge/squash commit: ${errorMessage}`, "error");
|
|
166
|
+
return "blocked";
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Still conflicted — try auto-resolving .gsd/ state file conflicts (#530)
|
|
171
|
+
const gsdConflicts = conflictedFiles.filter((f) => f.startsWith(".gsd/"));
|
|
172
|
+
const codeConflicts = conflictedFiles.filter((f) => !f.startsWith(".gsd/"));
|
|
173
|
+
if (gsdConflicts.length > 0 && codeConflicts.length === 0) {
|
|
174
|
+
let resolved = true;
|
|
175
|
+
try {
|
|
176
|
+
nativeCheckoutTheirs(basePath, gsdConflicts);
|
|
177
|
+
nativeAddPaths(basePath, gsdConflicts);
|
|
178
|
+
}
|
|
179
|
+
catch (e) {
|
|
180
|
+
logError("recovery", `auto-resolve .gsd/ conflicts failed: ${e.message}`);
|
|
181
|
+
resolved = false;
|
|
182
|
+
}
|
|
183
|
+
if (resolved) {
|
|
184
|
+
try {
|
|
185
|
+
nativeCommit(basePath, "chore: auto-resolve .gsd/ state file conflicts");
|
|
186
|
+
notify(`Auto-resolved ${gsdConflicts.length} .gsd/ state file conflict(s) from prior merge.`, "info");
|
|
187
|
+
}
|
|
188
|
+
catch (e) {
|
|
189
|
+
logError("recovery", `auto-commit .gsd/ conflict resolution failed: ${e.message}`);
|
|
190
|
+
resolved = false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (!resolved) {
|
|
194
|
+
abortAndResetMerge(basePath, hasMergeHead, squashMsgPath);
|
|
195
|
+
notify("Detected leftover merge state — auto-resolve failed, cleaned up. Re-deriving state.", "warning");
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// Code conflicts present — fail safe and preserve any manual resolution
|
|
200
|
+
// work instead of discarding it with merge --abort/reset --hard.
|
|
201
|
+
notify("Detected leftover merge state with unresolved code conflicts. Auto-mode will pause without modifying the worktree so manual conflict resolution is preserved.", "error");
|
|
202
|
+
return "blocked";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return "reconciled";
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Legacy entry point preserved for existing callers (auto.ts, auto/phases.ts
|
|
209
|
+
* via loop-deps, integration tests). New code prefers the drift handler.
|
|
210
|
+
*/
|
|
211
|
+
export function reconcileMergeState(basePath, ctx) {
|
|
212
|
+
return reconcileMergeStateCore(basePath, (message, severity) => ctx.ui.notify(message, severity));
|
|
213
|
+
}
|
|
214
|
+
function hasMergeStateLeftovers(basePath) {
|
|
215
|
+
const gitDir = resolveGitDir(basePath);
|
|
216
|
+
return (existsSync(join(gitDir, "MERGE_HEAD")) ||
|
|
217
|
+
existsSync(join(gitDir, "SQUASH_MSG")) ||
|
|
218
|
+
existsSync(join(gitDir, "rebase-merge")) ||
|
|
219
|
+
existsSync(join(gitDir, "rebase-apply")) ||
|
|
220
|
+
existsSync(join(gitDir, "CHERRY_PICK_HEAD")) ||
|
|
221
|
+
existsSync(join(gitDir, "REVERT_HEAD")));
|
|
222
|
+
}
|
|
223
|
+
export function detectMergeStateDrift(_state, ctx) {
|
|
224
|
+
if (hasMergeStateLeftovers(ctx.basePath)) {
|
|
225
|
+
return [{ kind: "unmerged-merge-state", basePath: ctx.basePath }];
|
|
226
|
+
}
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Repair: invoke the reconciliation core with a silent notify. If the
|
|
231
|
+
* underlying reconciliation reports "blocked" (e.g., unresolved code
|
|
232
|
+
* conflicts present), throw so reconcileBeforeDispatch surfaces the drift
|
|
233
|
+
* via ReconciliationFailedError.
|
|
234
|
+
*/
|
|
235
|
+
export function repairMergeStateDrift(record) {
|
|
236
|
+
const result = reconcileMergeStateCore(record.basePath, SILENT_NOTIFY);
|
|
237
|
+
if (result === "blocked") {
|
|
238
|
+
throw new Error(`Merge state reconciliation blocked for ${record.basePath} — likely unresolved code conflicts. Manual intervention required.`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
export const mergeStateHandler = {
|
|
242
|
+
kind: "unmerged-merge-state",
|
|
243
|
+
detect: detectMergeStateDrift,
|
|
244
|
+
repair: (record) => {
|
|
245
|
+
repairMergeStateDrift(record);
|
|
246
|
+
},
|
|
247
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: ADR-017 unregistered-milestone drift handler. Detects
|
|
3
|
+
// milestones whose on-disk directory has meaningful content (ROADMAP/
|
|
4
|
+
// CONTEXT/SUMMARY) but no DB row, then runs the markdown importer to
|
|
5
|
+
// reconcile. PROJECT.md is the human-facing index — the importer's source
|
|
6
|
+
// of truth is the .gsd/milestones/ directory tree.
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { getMilestone, isDbAvailable } from "../../gsd-db.js";
|
|
9
|
+
import { migrateHierarchyToDb } from "../../md-importer.js";
|
|
10
|
+
import { findMilestoneIds } from "../../milestone-ids.js";
|
|
11
|
+
import { resolveMilestoneFile } from "../../paths.js";
|
|
12
|
+
function milestoneHasContent(basePath, milestoneId) {
|
|
13
|
+
const roadmap = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
14
|
+
const context = resolveMilestoneFile(basePath, milestoneId, "CONTEXT");
|
|
15
|
+
const summary = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
|
|
16
|
+
return ((roadmap !== null && existsSync(roadmap)) ||
|
|
17
|
+
(context !== null && existsSync(context)) ||
|
|
18
|
+
(summary !== null && existsSync(summary)));
|
|
19
|
+
}
|
|
20
|
+
export function detectUnregisteredMilestoneDrift(_state, ctx) {
|
|
21
|
+
if (!isDbAvailable())
|
|
22
|
+
return [];
|
|
23
|
+
const drifts = [];
|
|
24
|
+
for (const milestoneId of findMilestoneIds(ctx.basePath)) {
|
|
25
|
+
if (getMilestone(milestoneId))
|
|
26
|
+
continue;
|
|
27
|
+
if (!milestoneHasContent(ctx.basePath, milestoneId))
|
|
28
|
+
continue;
|
|
29
|
+
drifts.push({ kind: "unregistered-milestone", milestoneId });
|
|
30
|
+
}
|
|
31
|
+
return drifts;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Repair: invoke the markdown importer. migrateHierarchyToDb walks the same
|
|
35
|
+
* findMilestoneIds list the detector uses and INSERTs OR IGNOREs every
|
|
36
|
+
* missing milestone (and its slices/tasks) — idempotent under cap=2 retry.
|
|
37
|
+
*
|
|
38
|
+
* Note: even though we receive one record at a time, the importer is a
|
|
39
|
+
* project-wide operation. Repeated invocation across multiple drift records
|
|
40
|
+
* in the same pass is wasteful but safe; a future optimization could
|
|
41
|
+
* coalesce by checking whether the importer has already run this pass.
|
|
42
|
+
*/
|
|
43
|
+
export function repairUnregisteredMilestone(_record, ctx) {
|
|
44
|
+
migrateHierarchyToDb(ctx.basePath);
|
|
45
|
+
}
|
|
46
|
+
export const unregisteredMilestoneHandler = {
|
|
47
|
+
kind: "unregistered-milestone",
|
|
48
|
+
detect: detectUnregisteredMilestoneDrift,
|
|
49
|
+
repair: repairUnregisteredMilestone,
|
|
50
|
+
};
|