gsd-pi 2.80.0-dev.b62439b9f → 2.80.0-dev.c5c38454b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{cli/cli-web-branch.d.ts → cli-web-branch.d.ts} +1 -1
- package/dist/{cli/cli-web-branch.js → cli-web-branch.js} +3 -3
- package/dist/{cli/cli.js → cli.js} +25 -25
- package/dist/{extension-runtime/extension-registry.js → extension-registry.js} +1 -1
- package/dist/{headless/headless-query.d.ts → headless-query.d.ts} +1 -1
- package/dist/{headless/headless-query.js → headless-query.js} +2 -3
- package/dist/{headless/headless-recover.js → headless-recover.js} +2 -3
- package/dist/{headless/headless.js → headless.js} +3 -3
- package/dist/loader.js +10 -10
- package/dist/{providers/models-resolver.js → models-resolver.js} +1 -1
- package/dist/{onboarding/onboarding.js → onboarding.js} +8 -8
- package/dist/{providers/remote-questions-config.js → remote-questions-config.js} +1 -1
- package/dist/{resource-runtime/resource-loader.d.ts → resource-loader.d.ts} +1 -1
- package/dist/{resource-runtime/resource-loader.js → resource-loader.js} +6 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/github-sync/templates.js +39 -8
- package/dist/resources/extensions/gsd/auto/loop.js +13 -9
- package/dist/resources/extensions/gsd/auto/run-unit.js +19 -15
- package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +154 -8
- package/dist/resources/extensions/gsd/auto-start.js +2 -3
- package/dist/resources/extensions/gsd/auto-worktree.js +6 -4
- package/dist/resources/extensions/gsd/auto.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +15 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
- package/dist/resources/extensions/gsd/db-base-schema.js +14 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +16 -0
- package/dist/resources/extensions/gsd/gsd-db.js +102 -2
- package/dist/resources/extensions/gsd/guided-flow.js +2 -2
- package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
- package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
- package/dist/{security/security-overrides.js → security-overrides.js} +1 -1
- package/dist/{startup/startup-model-validation.js → startup-model-validation.js} +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/{update/update-check.js → update-check.js} +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +3 -3
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.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.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/chunks/6897.js +12 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
- package/dist/{cli/web-mode.js → web-mode.js} +3 -3
- package/dist/{onboarding/welcome-screen.js → welcome-screen.js} +1 -1
- package/dist/{worktrees/worktree-cli.js → worktree-cli.js} +2 -3
- package/package.json +7 -3
- package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
- package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/fake-model.js +27 -0
- package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
- package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/index.js +8 -0
- package/packages/pi-ai/dist/models/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
- package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/fake.js +319 -0
- package/packages/pi-ai/dist/providers/fake.js.map +1 -0
- package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
- package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
- package/packages/pi-ai/src/models/fake-model.ts +30 -0
- package/packages/pi-ai/src/models/index.ts +9 -0
- package/packages/pi-ai/src/providers/fake.ts +376 -0
- package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +14 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +97 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +16 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -17
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +58 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +40 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +23 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +51 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +108 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +16 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +12 -0
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +118 -17
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +43 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +73 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +25 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
- package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +1 -2
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/index.d.ts +1 -0
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +2 -0
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/style.d.ts +41 -0
- package/packages/pi-tui/dist/style.d.ts.map +1 -0
- package/packages/pi-tui/dist/style.js +158 -0
- package/packages/pi-tui/dist/style.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts +1 -3
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +2 -3
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +1 -2
- package/packages/pi-tui/src/index.ts +9 -0
- package/packages/pi-tui/src/style.ts +225 -0
- package/packages/pi-tui/src/tui.ts +2 -3
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +18 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +36 -27
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/src/resources/extensions/github-sync/templates.ts +38 -8
- package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
- package/src/resources/extensions/gsd/auto/loop.ts +14 -10
- package/src/resources/extensions/gsd/auto/run-unit.ts +24 -14
- package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
- package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +153 -7
- package/src/resources/extensions/gsd/auto-start.ts +7 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +6 -4
- package/src/resources/extensions/gsd/auto.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
- package/src/resources/extensions/gsd/db-base-schema.ts +15 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +17 -0
- package/src/resources/extensions/gsd/gsd-db.ts +119 -1
- package/src/resources/extensions/gsd/guided-flow.ts +2 -2
- package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +83 -4
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +170 -1
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
- package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/headless-query.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
- package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
- package/dist/web/standalone/.next/server/chunks/7020.js +0 -12
- /package/dist/{app/app-paths.d.ts → app-paths.d.ts} +0 -0
- /package/dist/{app/app-paths.js → app-paths.js} +0 -0
- /package/dist/{extension-runtime/bundled-extension-paths.d.ts → bundled-extension-paths.d.ts} +0 -0
- /package/dist/{extension-runtime/bundled-extension-paths.js → bundled-extension-paths.js} +0 -0
- /package/dist/{extension-runtime/bundled-resource-path.d.ts → bundled-resource-path.d.ts} +0 -0
- /package/dist/{extension-runtime/bundled-resource-path.js → bundled-resource-path.js} +0 -0
- /package/dist/{startup/claude-cli-check.d.ts → claude-cli-check.d.ts} +0 -0
- /package/dist/{startup/claude-cli-check.js → claude-cli-check.js} +0 -0
- /package/dist/{cli/cli-auto-routing.d.ts → cli-auto-routing.d.ts} +0 -0
- /package/dist/{cli/cli-auto-routing.js → cli-auto-routing.js} +0 -0
- /package/dist/{cli/cli-policy.d.ts → cli-policy.d.ts} +0 -0
- /package/dist/{cli/cli-policy.js → cli-policy.js} +0 -0
- /package/dist/{cli/cli.d.ts → cli.d.ts} +0 -0
- /package/dist/{extension-runtime/extension-discovery.d.ts → extension-discovery.d.ts} +0 -0
- /package/dist/{extension-runtime/extension-discovery.js → extension-discovery.js} +0 -0
- /package/dist/{extension-runtime/extension-registry.d.ts → extension-registry.d.ts} +0 -0
- /package/dist/{extension-runtime/extension-sort.d.ts → extension-sort.d.ts} +0 -0
- /package/dist/{extension-runtime/extension-sort.js → extension-sort.js} +0 -0
- /package/dist/{extension-runtime/extension-validator.d.ts → extension-validator.d.ts} +0 -0
- /package/dist/{extension-runtime/extension-validator.js → extension-validator.js} +0 -0
- /package/dist/{headless/headless-answers.d.ts → headless-answers.d.ts} +0 -0
- /package/dist/{headless/headless-answers.js → headless-answers.js} +0 -0
- /package/dist/{headless/headless-context.d.ts → headless-context.d.ts} +0 -0
- /package/dist/{headless/headless-context.js → headless-context.js} +0 -0
- /package/dist/{headless/headless-events.d.ts → headless-events.d.ts} +0 -0
- /package/dist/{headless/headless-events.js → headless-events.js} +0 -0
- /package/dist/{headless/headless-recover.d.ts → headless-recover.d.ts} +0 -0
- /package/dist/{headless/headless-types.d.ts → headless-types.d.ts} +0 -0
- /package/dist/{headless/headless-types.js → headless-types.js} +0 -0
- /package/dist/{headless/headless-ui.d.ts → headless-ui.d.ts} +0 -0
- /package/dist/{headless/headless-ui.js → headless-ui.js} +0 -0
- /package/dist/{headless/headless.d.ts → headless.d.ts} +0 -0
- /package/dist/{cli/help-text.d.ts → help-text.d.ts} +0 -0
- /package/dist/{cli/help-text.js → help-text.js} +0 -0
- /package/dist/{cli/logo.d.ts → logo.d.ts} +0 -0
- /package/dist/{cli/logo.js → logo.js} +0 -0
- /package/dist/{mcp/mcp-server.d.ts → mcp-server.d.ts} +0 -0
- /package/dist/{mcp/mcp-server.js → mcp-server.js} +0 -0
- /package/dist/{providers/models-resolver.d.ts → models-resolver.d.ts} +0 -0
- /package/dist/{onboarding/onboarding.d.ts → onboarding.d.ts} +0 -0
- /package/dist/{providers/pi-migration.d.ts → pi-migration.d.ts} +0 -0
- /package/dist/{providers/pi-migration.js → pi-migration.js} +0 -0
- /package/dist/{app/project-sessions.d.ts → project-sessions.d.ts} +0 -0
- /package/dist/{app/project-sessions.js → project-sessions.js} +0 -0
- /package/dist/{providers/provider-migrations.d.ts → provider-migrations.d.ts} +0 -0
- /package/dist/{providers/provider-migrations.js → provider-migrations.js} +0 -0
- /package/dist/{providers/remote-questions-config.d.ts → remote-questions-config.d.ts} +0 -0
- /package/dist/{rtk/rtk-shared.d.ts → rtk-shared.d.ts} +0 -0
- /package/dist/{rtk/rtk-shared.js → rtk-shared.js} +0 -0
- /package/dist/{rtk/rtk.d.ts → rtk.d.ts} +0 -0
- /package/dist/{rtk/rtk.js → rtk.js} +0 -0
- /package/dist/{startup/runtime-checks.d.ts → runtime-checks.d.ts} +0 -0
- /package/dist/{startup/runtime-checks.js → runtime-checks.js} +0 -0
- /package/dist/{security/security-overrides.d.ts → security-overrides.d.ts} +0 -0
- /package/dist/{startup/startup-model-validation.d.ts → startup-model-validation.d.ts} +0 -0
- /package/dist/{startup/startup-timings.d.ts → startup-timings.d.ts} +0 -0
- /package/dist/{startup/startup-timings.js → startup-timings.js} +0 -0
- /package/dist/{app/tool-bootstrap.d.ts → tool-bootstrap.d.ts} +0 -0
- /package/dist/{app/tool-bootstrap.js → tool-bootstrap.js} +0 -0
- /package/dist/{update/update-check.d.ts → update-check.d.ts} +0 -0
- /package/dist/{update/update-cmd.d.ts → update-cmd.d.ts} +0 -0
- /package/dist/{update/update-cmd.js → update-cmd.js} +0 -0
- /package/dist/web/standalone/.next/static/{-WDXZiiJHGZDbYH75Mu6f → TCSim36ZpcPu2WgeoC45g}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{-WDXZiiJHGZDbYH75Mu6f → TCSim36ZpcPu2WgeoC45g}/_ssgManifest.js +0 -0
- /package/dist/{cli/web-mode.d.ts → web-mode.d.ts} +0 -0
- /package/dist/{onboarding/welcome-screen.d.ts → welcome-screen.d.ts} +0 -0
- /package/dist/{onboarding/wizard.d.ts → wizard.d.ts} +0 -0
- /package/dist/{onboarding/wizard.js → wizard.js} +0 -0
- /package/dist/{worktrees/worktree-cli.d.ts → worktree-cli.d.ts} +0 -0
- /package/dist/{worktrees/worktree-name-gen.d.ts → worktree-name-gen.d.ts} +0 -0
- /package/dist/{worktrees/worktree-name-gen.js → worktree-name-gen.js} +0 -0
- /package/dist/{worktrees/worktree-status-banner.d.ts → worktree-status-banner.d.ts} +0 -0
- /package/dist/{worktrees/worktree-status-banner.js → worktree-status-banner.js} +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Tests for the inlineCode markdown helper and its use in PR body templates.
|
|
3
|
+
|
|
4
|
+
import { describe, it } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { inlineCode, formatSwarmLanePRBody } from "../templates.ts";
|
|
7
|
+
|
|
8
|
+
describe("inlineCode", () => {
|
|
9
|
+
it("wraps a plain string in single backticks", () => {
|
|
10
|
+
assert.equal(inlineCode("hello"), "`hello`");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("uses a double-backtick fence when the input contains a single backtick", () => {
|
|
14
|
+
const out = inlineCode("a`b");
|
|
15
|
+
assert.equal(out, "``a`b``");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("uses a 4-backtick fence when the input contains a run of three backticks", () => {
|
|
19
|
+
const out = inlineCode("x```y");
|
|
20
|
+
assert.equal(out, "````x```y````");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("pads with a leading space when the input starts with a backtick", () => {
|
|
24
|
+
const out = inlineCode("`leading");
|
|
25
|
+
// longest run = 1 → fence length 2; leading backtick → pad both sides
|
|
26
|
+
assert.equal(out, "`` `leading ``");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("pads with a trailing space when the input ends with a backtick", () => {
|
|
30
|
+
const out = inlineCode("trailing`");
|
|
31
|
+
assert.equal(out, "`` trailing` ``");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("returns an empty string for empty input", () => {
|
|
35
|
+
// Documented invariant: empty input renders as nothing rather than as
|
|
36
|
+
// a literal pair of backticks (which GFM would render as the characters
|
|
37
|
+
// themselves, not as code).
|
|
38
|
+
assert.equal(inlineCode(""), "");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("escapes a branch with embedded backticks inside formatSwarmLanePRBody", () => {
|
|
42
|
+
const malicious = "feature`evil";
|
|
43
|
+
const body = formatSwarmLanePRBody({
|
|
44
|
+
lane: {
|
|
45
|
+
id: "workflow",
|
|
46
|
+
branch: malicious,
|
|
47
|
+
},
|
|
48
|
+
impactArea: "test",
|
|
49
|
+
transitionRisks: [],
|
|
50
|
+
rollbackPlan: [],
|
|
51
|
+
});
|
|
52
|
+
// The branch must appear inside a properly fenced inline-code span,
|
|
53
|
+
// i.e. wrapped in the helper's chosen fence (here a double backtick).
|
|
54
|
+
assert.ok(
|
|
55
|
+
body.includes("``feature`evil``"),
|
|
56
|
+
`expected double-backtick fenced branch, got body:\n${body}`,
|
|
57
|
+
);
|
|
58
|
+
// And there must be no markdown break-out: the substring "evil" should
|
|
59
|
+
// never appear unfenced as a bare word adjacent to a closing single
|
|
60
|
+
// backtick (the unpatched template produced "`feature`evil`").
|
|
61
|
+
assert.ok(
|
|
62
|
+
!body.includes("`feature`evil`\n") && !body.includes("`feature`evil` "),
|
|
63
|
+
`expected no inline-code break-out, got body:\n${body}`,
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -359,6 +359,20 @@ export async function autoLoop(
|
|
|
359
359
|
const prefs = deps.loadEffectiveGSDPreferences()?.preferences;
|
|
360
360
|
const uokFlags = resolveUokFlags(prefs);
|
|
361
361
|
|
|
362
|
+
// ── Check sidecar queue before deriveState ──
|
|
363
|
+
// NOTE: Sidecar dequeue MUST run before validateWorkflowSessionLock so a
|
|
364
|
+
// queued item is popped (and the `sidecar-dequeue` journal event emitted)
|
|
365
|
+
// even when the session lock invalidates this iteration. Inverting this
|
|
366
|
+
// order silently drops queued items on lock-loss. Refs #5308.
|
|
367
|
+
const sidecarItem = await dequeueSidecarItem({
|
|
368
|
+
queue: s.sidecarQueue,
|
|
369
|
+
executionGraphEnabled: uokFlags.executionGraph,
|
|
370
|
+
scheduleQueue: scheduleSidecarQueue,
|
|
371
|
+
warnSchedulingFailure: message => logWarning("dispatch", `sidecar queue scheduling failed: ${message}`),
|
|
372
|
+
logDequeue: payload => debugLog("autoLoop", { phase: "sidecar-dequeue", ...payload }),
|
|
373
|
+
emitDequeue: payload => journalReporter.emit("sidecar-dequeue", payload),
|
|
374
|
+
});
|
|
375
|
+
|
|
362
376
|
const sessionLockOutcome = validateWorkflowSessionLock({
|
|
363
377
|
active: s.active,
|
|
364
378
|
iteration,
|
|
@@ -382,16 +396,6 @@ export async function autoLoop(
|
|
|
382
396
|
break;
|
|
383
397
|
}
|
|
384
398
|
|
|
385
|
-
// ── Check sidecar queue before deriveState ──
|
|
386
|
-
const sidecarItem = await dequeueSidecarItem({
|
|
387
|
-
queue: s.sidecarQueue,
|
|
388
|
-
executionGraphEnabled: uokFlags.executionGraph,
|
|
389
|
-
scheduleQueue: scheduleSidecarQueue,
|
|
390
|
-
warnSchedulingFailure: message => logWarning("dispatch", `sidecar queue scheduling failed: ${message}`),
|
|
391
|
-
logDequeue: payload => debugLog("autoLoop", { phase: "sidecar-dequeue", ...payload }),
|
|
392
|
-
emitDequeue: payload => journalReporter.emit("sidecar-dequeue", payload),
|
|
393
|
-
});
|
|
394
|
-
|
|
395
399
|
const ic: IterationContext = { ctx, pi, s, deps, prefs, iteration, flowId, nextSeq };
|
|
396
400
|
journalReporter.emit("iteration-start", { iteration });
|
|
397
401
|
let iterData: IterationData;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// GSD-2 + src/resources/extensions/gsd/auto/run-unit.ts - Runs one GSD auto-mode unit from session creation through agent completion.
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* auto/run-unit.ts — Single unit execution: session create → prompt → await agent_end.
|
|
3
5
|
*
|
|
@@ -17,6 +19,7 @@ import {
|
|
|
17
19
|
import { debugLog } from "../debug-logger.js";
|
|
18
20
|
import { logWarning, logError } from "../workflow-logger.js";
|
|
19
21
|
import { resolveAutoSupervisorConfig } from "../preferences.js";
|
|
22
|
+
import { formatAutoUnitWorkingMessage } from "../working-output-messages.js";
|
|
20
23
|
|
|
21
24
|
// Tracks the latest session-switch attempt so a late timeout settlement from an
|
|
22
25
|
// older runUnit() call cannot clear the guard for a newer one.
|
|
@@ -184,30 +187,37 @@ export async function runUnit(
|
|
|
184
187
|
debugLog("runUnit", { phase: "send-message", unitType, unitId });
|
|
185
188
|
|
|
186
189
|
const requestDispatchedAt = Date.now();
|
|
187
|
-
|
|
188
|
-
{ customType: "gsd-auto", content: prompt, display: s.verbose },
|
|
189
|
-
{ triggerTurn: true },
|
|
190
|
-
);
|
|
190
|
+
ctx.ui.setWorkingMessage?.(formatAutoUnitWorkingMessage(unitType, unitId));
|
|
191
191
|
|
|
192
192
|
// ── Await agent_end with absolute timeout (H4 fix) ──
|
|
193
193
|
// If supervision fails to resolve unitPromise within 30s, treat as cancelled.
|
|
194
194
|
// Without this, a crashed agent that never emits agent_end hangs the loop (#3161).
|
|
195
|
-
debugLog("runUnit", { phase: "awaiting-agent-end", unitType, unitId });
|
|
196
195
|
const supervisor = resolveAutoSupervisorConfig();
|
|
197
196
|
const UNIT_HARD_TIMEOUT_MS = Math.max(
|
|
198
197
|
30_000,
|
|
199
198
|
((supervisor.hard_timeout_minutes ?? 30) * 60 * 1000) + 30_000,
|
|
200
199
|
);
|
|
201
200
|
let unitTimeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
201
|
+
let result: UnitResult;
|
|
202
|
+
try {
|
|
203
|
+
pi.sendMessage(
|
|
204
|
+
{ customType: "gsd-auto", content: prompt, display: s.verbose },
|
|
205
|
+
{ triggerTurn: true },
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
debugLog("runUnit", { phase: "awaiting-agent-end", unitType, unitId });
|
|
209
|
+
const timeoutResult = new Promise<UnitResult>((resolve) => {
|
|
210
|
+
unitTimeoutHandle = setTimeout(() => {
|
|
211
|
+
resolve({ status: "cancelled", errorContext: { message: "Unit hard timeout — supervision may have failed", category: "timeout", isTransient: true } });
|
|
212
|
+
}, UNIT_HARD_TIMEOUT_MS);
|
|
213
|
+
});
|
|
214
|
+
result = await runWithTurnGeneration(capturedTurnGen, () =>
|
|
215
|
+
Promise.race([unitPromise, timeoutResult]),
|
|
216
|
+
);
|
|
217
|
+
} finally {
|
|
218
|
+
if (unitTimeoutHandle) clearTimeout(unitTimeoutHandle);
|
|
219
|
+
ctx.ui.setWorkingMessage?.(undefined);
|
|
220
|
+
}
|
|
211
221
|
debugLog("runUnit", {
|
|
212
222
|
phase: "agent-end-received",
|
|
213
223
|
unitType,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// GSD-2 + src/resources/extensions/gsd/auto-dashboard.ts - Auto-mode progress widget rendering and dashboard helpers.
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Auto-mode Dashboard — progress widget rendering, elapsed time formatting,
|
|
3
5
|
* unit description helpers, and slice progress caching.
|
|
@@ -46,6 +48,7 @@ import {
|
|
|
46
48
|
import { logWarning } from "./workflow-logger.js";
|
|
47
49
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
48
50
|
import { homedir } from "node:os";
|
|
51
|
+
import { readUnitRuntimeRecord, type AutoUnitRuntimeRecord } from "./unit-runtime.js";
|
|
49
52
|
|
|
50
53
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
51
54
|
|
|
@@ -215,6 +218,36 @@ export function formatWidgetTokens(count: number): string {
|
|
|
215
218
|
return `${Math.round(count / 1000000)}M`;
|
|
216
219
|
}
|
|
217
220
|
|
|
221
|
+
export function formatRuntimeHealthSignal(
|
|
222
|
+
record: AutoUnitRuntimeRecord | null,
|
|
223
|
+
now = Date.now(),
|
|
224
|
+
): { level: "green" | "yellow"; summary: string; detail?: string } | null {
|
|
225
|
+
if (!record) return null;
|
|
226
|
+
const idleMs = Math.max(0, now - record.lastProgressAt);
|
|
227
|
+
const idleMinutes = Math.floor(idleMs / 60_000);
|
|
228
|
+
if ((record.recoveryAttempts ?? 0) > 0 || record.phase === "recovered" || record.lastProgressKind.includes("recovery")) {
|
|
229
|
+
return {
|
|
230
|
+
level: "yellow",
|
|
231
|
+
summary: "Recovering",
|
|
232
|
+
detail: `retry ${record.recoveryAttempts ?? 1} after ${record.lastRecoveryReason ?? "idle"} stall`,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
if (record.progressCount === 0 && idleMs >= 60_000) {
|
|
236
|
+
return {
|
|
237
|
+
level: "yellow",
|
|
238
|
+
summary: "Waiting on provider",
|
|
239
|
+
detail: `no output for ${idleMinutes}m`,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function shouldRenderRoadmapProgress(
|
|
246
|
+
progress: { total: number; activeSliceTasks?: { total: number } | null } | null,
|
|
247
|
+
): progress is { total: number; activeSliceTasks?: { total: number } | null } {
|
|
248
|
+
return !!progress && progress.total > 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
218
251
|
// ─── ETA Estimation ──────────────────────────────────────────────────────────
|
|
219
252
|
|
|
220
253
|
/**
|
|
@@ -622,6 +655,7 @@ export function updateProgressWidget(
|
|
|
622
655
|
let cachedLines: string[] | undefined;
|
|
623
656
|
let cachedWidth: number | undefined;
|
|
624
657
|
let cachedRtkLabel: string | null | undefined;
|
|
658
|
+
let cachedRuntimeRecord: AutoUnitRuntimeRecord | null = null;
|
|
625
659
|
|
|
626
660
|
const refreshRtkLabel = (): void => {
|
|
627
661
|
try {
|
|
@@ -634,7 +668,16 @@ export function updateProgressWidget(
|
|
|
634
668
|
}
|
|
635
669
|
};
|
|
636
670
|
|
|
671
|
+
const refreshRuntimeRecord = (): void => {
|
|
672
|
+
try {
|
|
673
|
+
cachedRuntimeRecord = readUnitRuntimeRecord(accessors.getBasePath(), unitType, unitId);
|
|
674
|
+
} catch {
|
|
675
|
+
cachedRuntimeRecord = null;
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
637
679
|
refreshRtkLabel();
|
|
680
|
+
refreshRuntimeRecord();
|
|
638
681
|
|
|
639
682
|
const pulseTimer = setInterval(() => {
|
|
640
683
|
pulseBright = !pulseBright;
|
|
@@ -652,6 +695,7 @@ export function updateProgressWidget(
|
|
|
652
695
|
updateSliceProgressCache(accessors.getBasePath(), mid.id, slice?.id);
|
|
653
696
|
}
|
|
654
697
|
refreshRtkLabel();
|
|
698
|
+
refreshRuntimeRecord();
|
|
655
699
|
cachedLines = undefined;
|
|
656
700
|
} catch (err) { /* non-fatal */
|
|
657
701
|
logWarning("dashboard", `DB status update failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -685,13 +729,16 @@ export function updateProgressWidget(
|
|
|
685
729
|
|
|
686
730
|
// Health indicator in header
|
|
687
731
|
const score = computeProgressScore();
|
|
688
|
-
const
|
|
689
|
-
|
|
732
|
+
const runtimeSignal = formatRuntimeHealthSignal(cachedRuntimeRecord);
|
|
733
|
+
const healthLevel = runtimeSignal?.level ?? score.level;
|
|
734
|
+
const healthSummary = runtimeSignal?.summary ?? score.summary;
|
|
735
|
+
const healthColor = healthLevel === "green" ? "success"
|
|
736
|
+
: healthLevel === "yellow" ? "warning"
|
|
690
737
|
: "error";
|
|
691
|
-
const healthIcon =
|
|
692
|
-
:
|
|
738
|
+
const healthIcon = healthLevel === "green" ? GLYPH.statusActive
|
|
739
|
+
: healthLevel === "yellow" ? "!"
|
|
693
740
|
: "x";
|
|
694
|
-
const healthStr = ` ${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor,
|
|
741
|
+
const healthStr = ` ${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor, healthSummary)}`;
|
|
695
742
|
|
|
696
743
|
const headerLeft = `${pad}${dot} ${theme.fg("accent", theme.bold("GSD"))} ${theme.fg("success", modeTag)}${healthStr}`;
|
|
697
744
|
|
|
@@ -706,7 +753,9 @@ export function updateProgressWidget(
|
|
|
706
753
|
lines.push(rightAlign(headerLeft, headerRight, width));
|
|
707
754
|
|
|
708
755
|
// Show health signal details when degraded (yellow/red)
|
|
709
|
-
if (
|
|
756
|
+
if (runtimeSignal?.detail && widgetMode !== "min") {
|
|
757
|
+
lines.push(`${pad} ${theme.fg("dim", runtimeSignal.detail)}`);
|
|
758
|
+
} else if (score.level !== "green" && score.signals.length > 0 && widgetMode !== "min") {
|
|
710
759
|
// Show up to 3 most relevant signals in compact form
|
|
711
760
|
const topSignals = score.signals
|
|
712
761
|
.filter(s => s.kind === "negative")
|
|
@@ -785,7 +834,7 @@ export function updateProgressWidget(
|
|
|
785
834
|
|
|
786
835
|
// Progress bar
|
|
787
836
|
const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
|
|
788
|
-
if (roadmapSlices) {
|
|
837
|
+
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
789
838
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
790
839
|
const barWidth = Math.max(6, Math.min(18, Math.floor(width * 0.25)));
|
|
791
840
|
const pct = total > 0 ? done / total : 0;
|
|
@@ -853,7 +902,7 @@ export function updateProgressWidget(
|
|
|
853
902
|
|
|
854
903
|
const leftLines: string[] = [];
|
|
855
904
|
|
|
856
|
-
if (roadmapSlices) {
|
|
905
|
+
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
857
906
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
858
907
|
const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
|
|
859
908
|
const pct = total > 0 ? done / total : 0;
|
|
@@ -211,6 +211,23 @@ export function hasPendingDeepStage(prefs: GSDPreferences | undefined, basePath:
|
|
|
211
211
|
return gate.status === "pending" || gate.status === "blocked";
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
export function shouldRunDeepProjectSetup(
|
|
215
|
+
state: Pick<GSDState, "phase">,
|
|
216
|
+
prefs: GSDPreferences | undefined,
|
|
217
|
+
basePath: string,
|
|
218
|
+
options: { hasSurvivorBranch?: boolean } = {},
|
|
219
|
+
): boolean {
|
|
220
|
+
if (options.hasSurvivorBranch === true) return false;
|
|
221
|
+
if (
|
|
222
|
+
state.phase !== "pre-planning" &&
|
|
223
|
+
state.phase !== "needs-discussion" &&
|
|
224
|
+
state.phase !== "planning"
|
|
225
|
+
) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
return hasPendingDeepStage(prefs, basePath);
|
|
229
|
+
}
|
|
230
|
+
|
|
214
231
|
function missingSliceStop(mid: string, phase: string): DispatchAction {
|
|
215
232
|
return {
|
|
216
233
|
action: "stop",
|
|
@@ -14,7 +14,7 @@ import { appendEvent } from "./workflow-events.js";
|
|
|
14
14
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
15
15
|
import { clearParseCache } from "./files.js";
|
|
16
16
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
17
|
-
import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk } from "./gsd-db.js";
|
|
17
|
+
import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk, getCompletedMilestoneTaskFileHints, getMilestoneCommitAttributionShas, recordMilestoneCommitAttribution } from "./gsd-db.js";
|
|
18
18
|
import { isValidationTerminal } from "./state.js";
|
|
19
19
|
import { getErrorMessage } from "./error-utils.js";
|
|
20
20
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
@@ -147,15 +147,29 @@ export function hasImplementationArtifacts(basePath: string, milestoneId?: strin
|
|
|
147
147
|
// milestone commits instead of treating the self-diff as proof of no work.
|
|
148
148
|
if (changedFiles.length === 0) {
|
|
149
149
|
if (milestoneId && currentBranch === integrationBranch) {
|
|
150
|
-
const
|
|
151
|
-
if (!
|
|
152
|
-
if (
|
|
150
|
+
const milestoneEvidence = getChangedFilesFromMilestoneEvidence(basePath, milestoneId);
|
|
151
|
+
if (!milestoneEvidence.ok) return "unknown";
|
|
152
|
+
if (milestoneEvidence.matched) return classifyImplementationFiles(milestoneEvidence.files);
|
|
153
153
|
}
|
|
154
154
|
if (currentBranch && currentBranch !== "HEAD") return "absent";
|
|
155
155
|
return "unknown";
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
const branchClassification = classifyImplementationFiles(changedFiles);
|
|
159
|
+
if (branchClassification === "present") return "present";
|
|
160
|
+
|
|
161
|
+
// A completing milestone branch can have a non-empty diff containing only
|
|
162
|
+
// .gsd/ closeout files after implementation commits already landed on the
|
|
163
|
+
// recorded integration branch. In that topology, the branch diff alone is
|
|
164
|
+
// insufficient; use the same milestone-tagged evidence fallback as the
|
|
165
|
+
// self-diff retry path before declaring the milestone implementation-free.
|
|
166
|
+
if (milestoneId) {
|
|
167
|
+
const milestoneEvidence = getChangedFilesFromMilestoneEvidence(basePath, milestoneId);
|
|
168
|
+
if (!milestoneEvidence.ok) return "unknown";
|
|
169
|
+
if (milestoneEvidence.matched) return classifyImplementationFiles(milestoneEvidence.files);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return "absent";
|
|
159
173
|
} catch (e) {
|
|
160
174
|
// Non-fatal — if git operations fail, return unknown so callers can decide
|
|
161
175
|
logWarning("recovery", `implementation artifact check failed: ${(e as Error).message}`);
|
|
@@ -185,6 +199,10 @@ function isImplementationPath(file: string): boolean {
|
|
|
185
199
|
return !file.startsWith(".gsd/") && !file.startsWith(".gsd\\");
|
|
186
200
|
}
|
|
187
201
|
|
|
202
|
+
function normalizeRepoPath(file: string): string {
|
|
203
|
+
return file.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
204
|
+
}
|
|
205
|
+
|
|
188
206
|
/**
|
|
189
207
|
* Detect the main/master branch name.
|
|
190
208
|
*/
|
|
@@ -263,7 +281,7 @@ function getChangedFilesFromMilestoneTaggedCommits(
|
|
|
263
281
|
"log", "--format=%H%x1f%B%x1e", "HEAD", "--", `.gsd/milestones/${milestoneId}`,
|
|
264
282
|
]);
|
|
265
283
|
if (!scoped.ok) return scoped;
|
|
266
|
-
if (scoped.matched) return scoped;
|
|
284
|
+
if (scoped.matched && classifyImplementationFiles(scoped.files) === "present") return scoped;
|
|
267
285
|
|
|
268
286
|
// Fallback (#5033): when .gsd/ is gitignored / external / untracked, the
|
|
269
287
|
// path-scoped scan matches no commits even though GSD-tagged commits
|
|
@@ -274,9 +292,137 @@ function getChangedFilesFromMilestoneTaggedCommits(
|
|
|
274
292
|
// Intentionally unbounded — symmetric with the primary scan, and avoids
|
|
275
293
|
// reintroducing the rolling-depth failure class removed in #4699 where
|
|
276
294
|
// milestone evidence aged out behind unrelated activity.
|
|
277
|
-
|
|
295
|
+
const unscoped = scanGsdTaggedCommits(basePath, milestoneId, [
|
|
278
296
|
"log", "--format=%H%x1f%B%x1e", "HEAD",
|
|
279
297
|
]);
|
|
298
|
+
if (!unscoped.ok) return scoped.matched ? scoped : unscoped;
|
|
299
|
+
if (!unscoped.matched) return scoped;
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
ok: true,
|
|
303
|
+
matched: true,
|
|
304
|
+
files: [...new Set([...scoped.files, ...unscoped.files])],
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function getChangedFilesFromMilestoneEvidence(
|
|
309
|
+
basePath: string,
|
|
310
|
+
milestoneId: string,
|
|
311
|
+
): { ok: boolean; matched: boolean; files: string[] } {
|
|
312
|
+
const tagged = getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId);
|
|
313
|
+
if (!tagged.ok) return tagged;
|
|
314
|
+
if (tagged.matched && classifyImplementationFiles(tagged.files) === "present") return tagged;
|
|
315
|
+
|
|
316
|
+
const attributed = getChangedFilesFromAttributedMilestoneCommits(basePath, milestoneId);
|
|
317
|
+
if (!attributed.ok) return tagged.matched ? tagged : attributed;
|
|
318
|
+
if (attributed.matched && classifyImplementationFiles(attributed.files) === "present") return attributed;
|
|
319
|
+
|
|
320
|
+
const backfilled = backfillChangedFilesFromUntaggedMilestoneCommits(basePath, milestoneId);
|
|
321
|
+
if (!backfilled.ok) return tagged.matched ? tagged : attributed.matched ? attributed : backfilled;
|
|
322
|
+
if (!backfilled.matched) {
|
|
323
|
+
if (tagged.matched) return tagged;
|
|
324
|
+
return attributed.matched ? attributed : backfilled;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
ok: true,
|
|
329
|
+
matched: true,
|
|
330
|
+
files: [...new Set([...tagged.files, ...attributed.files, ...backfilled.files])],
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function getChangedFilesFromAttributedMilestoneCommits(
|
|
335
|
+
basePath: string,
|
|
336
|
+
milestoneId: string,
|
|
337
|
+
): { ok: boolean; matched: boolean; files: string[] } {
|
|
338
|
+
try {
|
|
339
|
+
const shas = getMilestoneCommitAttributionShas(milestoneId);
|
|
340
|
+
if (shas.length === 0) return { ok: true, matched: false, files: [] };
|
|
341
|
+
|
|
342
|
+
const files = new Set<string>();
|
|
343
|
+
let matched = false;
|
|
344
|
+
for (const sha of shas) {
|
|
345
|
+
if (!isFullCommitSha(sha)) continue;
|
|
346
|
+
const commitFiles = getChangedFilesForCommit(basePath, sha);
|
|
347
|
+
if (commitFiles.length === 0) continue;
|
|
348
|
+
matched = true;
|
|
349
|
+
for (const file of commitFiles) files.add(file);
|
|
350
|
+
}
|
|
351
|
+
return { ok: true, matched, files: [...files] };
|
|
352
|
+
} catch (e) {
|
|
353
|
+
logWarning("recovery", `milestone attribution scan failed: ${(e as Error).message}`);
|
|
354
|
+
return { ok: false, matched: false, files: [] };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function backfillChangedFilesFromUntaggedMilestoneCommits(
|
|
359
|
+
basePath: string,
|
|
360
|
+
milestoneId: string,
|
|
361
|
+
): { ok: boolean; matched: boolean; files: string[] } {
|
|
362
|
+
try {
|
|
363
|
+
const milestone = getMilestone(milestoneId);
|
|
364
|
+
const milestoneStartedAt = milestone?.created_at ? Math.floor(Date.parse(milestone.created_at) / 1000) * 1000 : NaN;
|
|
365
|
+
if (!Number.isFinite(milestoneStartedAt)) return { ok: true, matched: false, files: [] };
|
|
366
|
+
|
|
367
|
+
const taskFileHints = getCompletedMilestoneTaskFileHints(milestoneId);
|
|
368
|
+
if (taskFileHints.length === 0) return { ok: true, matched: false, files: [] };
|
|
369
|
+
|
|
370
|
+
const hintSet = new Set(taskFileHints.map(normalizeRepoPath).filter(Boolean));
|
|
371
|
+
if (hintSet.size === 0) return { ok: true, matched: false, files: [] };
|
|
372
|
+
|
|
373
|
+
const records = getCommitRecords(basePath);
|
|
374
|
+
const files = new Set<string>();
|
|
375
|
+
let matched = false;
|
|
376
|
+
for (const record of records) {
|
|
377
|
+
if (!isFullCommitSha(record.hash)) continue;
|
|
378
|
+
if (Date.parse(record.committedAt) < milestoneStartedAt) continue;
|
|
379
|
+
if (record.parents.trim().split(/\s+/).filter(Boolean).length > 1) continue;
|
|
380
|
+
if (commitMessageHasGsdTrailer(record.message)) continue;
|
|
381
|
+
|
|
382
|
+
const commitFiles = getChangedFilesForCommit(basePath, record.hash);
|
|
383
|
+
const implementationFiles = commitFiles.map(normalizeRepoPath).filter(isImplementationPath);
|
|
384
|
+
if (implementationFiles.length === 0) continue;
|
|
385
|
+
if (!implementationFiles.some((file) => hintSet.has(file))) continue;
|
|
386
|
+
|
|
387
|
+
matched = true;
|
|
388
|
+
for (const file of implementationFiles) files.add(file);
|
|
389
|
+
recordMilestoneCommitAttribution({
|
|
390
|
+
commitSha: record.hash,
|
|
391
|
+
milestoneId,
|
|
392
|
+
source: "backfill",
|
|
393
|
+
confidence: 0.8,
|
|
394
|
+
files: implementationFiles,
|
|
395
|
+
createdAt: new Date().toISOString(),
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return { ok: true, matched, files: [...files] };
|
|
400
|
+
} catch (e) {
|
|
401
|
+
logWarning("recovery", `milestone attribution backfill failed: ${(e as Error).message}`);
|
|
402
|
+
return { ok: false, matched: false, files: [] };
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function getCommitRecords(basePath: string): Array<{ hash: string; parents: string; committedAt: string; message: string }> {
|
|
407
|
+
const logOutput = execFileSync("git", ["log", "--format=%H%x1f%P%x1f%cI%x1f%B%x1e", "HEAD"], {
|
|
408
|
+
cwd: basePath,
|
|
409
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
410
|
+
encoding: "utf-8",
|
|
411
|
+
});
|
|
412
|
+
return logOutput
|
|
413
|
+
.split("\x1e")
|
|
414
|
+
.map((record) => record.trim())
|
|
415
|
+
.filter(Boolean)
|
|
416
|
+
.flatMap((record) => {
|
|
417
|
+
const parts = record.split("\x1f");
|
|
418
|
+
if (parts.length < 4) return [];
|
|
419
|
+
const [hash, parents, committedAt, ...messageParts] = parts;
|
|
420
|
+
return [{ hash: hash.trim(), parents: parents.trim(), committedAt: committedAt.trim(), message: messageParts.join("\x1f") }];
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function isFullCommitSha(value: string): boolean {
|
|
425
|
+
return /^[0-9a-f]{40}$/i.test(value);
|
|
280
426
|
}
|
|
281
427
|
|
|
282
428
|
function scanGsdTaggedCommits(
|
|
@@ -664,12 +664,13 @@ export async function bootstrapAutoSession(
|
|
|
664
664
|
}
|
|
665
665
|
|
|
666
666
|
const effectivePrefs = loadEffectiveGSDPreferences(base)?.preferences;
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
667
|
+
const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
|
|
668
|
+
const deepProjectStagePending = shouldRunDeepProjectSetup(
|
|
669
|
+
state,
|
|
670
|
+
effectivePrefs,
|
|
671
|
+
base,
|
|
672
|
+
{ hasSurvivorBranch },
|
|
673
|
+
);
|
|
673
674
|
|
|
674
675
|
if (deepProjectStagePending) {
|
|
675
676
|
// Deep project-level setup runs before the first milestone exists. Let
|
|
@@ -275,13 +275,15 @@ function gitPathspecForWorktreePath(basePath: string, targetPath: string): strin
|
|
|
275
275
|
let target = targetPath;
|
|
276
276
|
try {
|
|
277
277
|
base = realpathSync.native(basePath);
|
|
278
|
-
} catch
|
|
279
|
-
|
|
278
|
+
} catch {
|
|
279
|
+
/* keep original */
|
|
280
|
+
void base;
|
|
280
281
|
}
|
|
281
282
|
try {
|
|
282
283
|
target = realpathSync.native(targetPath);
|
|
283
|
-
} catch
|
|
284
|
-
|
|
284
|
+
} catch {
|
|
285
|
+
/* keep original */
|
|
286
|
+
void target;
|
|
285
287
|
}
|
|
286
288
|
|
|
287
289
|
const rel = relative(base, target);
|
|
@@ -1949,15 +1949,15 @@ export async function startAuto(
|
|
|
1949
1949
|
// Re-sync managed resources on resume so long-lived auto sessions pick up
|
|
1950
1950
|
// bundled extension updates before resume-time verification/state logic runs.
|
|
1951
1951
|
// GSD_PKG_ROOT is set by loader.ts and points to the gsd-pi package root.
|
|
1952
|
-
// The relative import ("../../../resource-
|
|
1952
|
+
// The relative import ("../../../resource-loader.js") only works from the source
|
|
1953
1953
|
// tree; deployed extensions live at ~/.gsd/agent/extensions/gsd/ where the
|
|
1954
1954
|
// relative path resolves to ~/.gsd/agent/resource-loader.js which doesn't exist.
|
|
1955
1955
|
// Using GSD_PKG_ROOT constructs a correct absolute path in both contexts (#3949).
|
|
1956
1956
|
const agentDir = process.env.GSD_CODING_AGENT_DIR || join(gsdHome(), "agent");
|
|
1957
1957
|
const pkgRoot = process.env.GSD_PKG_ROOT;
|
|
1958
1958
|
const resourceLoaderPath = pkgRoot
|
|
1959
|
-
? pathToFileURL(join(pkgRoot, "dist", "resource-
|
|
1960
|
-
: new URL("../../../resource-
|
|
1959
|
+
? pathToFileURL(join(pkgRoot, "dist", "resource-loader.js")).href
|
|
1960
|
+
: new URL("../../../resource-loader.js", import.meta.url).href;
|
|
1961
1961
|
const { initResources } = await import(resourceLoaderPath);
|
|
1962
1962
|
initResources(agentDir);
|
|
1963
1963
|
// Open the project DB before rebuild/derive so resume uses DB-backed
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// GSD-2 + src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts - Handles provider and agent-end recovery for GSD auto-mode.
|
|
2
|
+
|
|
1
3
|
import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
2
4
|
|
|
3
5
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -12,7 +14,7 @@ import { clearPathCache } from "../paths.js";
|
|
|
12
14
|
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
|
|
13
15
|
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
14
16
|
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
15
|
-
import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto/resolve.js";
|
|
17
|
+
import { isSessionSwitchInFlight, resolveAgentEnd, resolveAgentEndCancelled } from "../auto/resolve.js";
|
|
16
18
|
import { resolveModelId } from "../auto-model-selection.js";
|
|
17
19
|
import { resolveProjectRoot } from "../worktree.js";
|
|
18
20
|
import { clearDiscussionFlowState } from "./write-gate.js";
|
|
@@ -69,6 +71,11 @@ export function _buildAbortedPauseContext(lastMsg: { errorMessage?: unknown }):
|
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
export function isUserInitiatedAbortMessage(message: string | undefined | null): boolean {
|
|
75
|
+
if (!message) return false;
|
|
76
|
+
return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user)\b/i.test(message);
|
|
77
|
+
}
|
|
78
|
+
|
|
72
79
|
async function pauseTransientWithBackoff(
|
|
73
80
|
cls: ErrorClass,
|
|
74
81
|
pi: ExtensionAPI,
|
|
@@ -180,6 +187,14 @@ export async function handleAgentEnd(
|
|
|
180
187
|
// is in the assistant message text content. Fall back to content when
|
|
181
188
|
// errorMessage looks uninformative.
|
|
182
189
|
const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
|
|
190
|
+
if (isUserInitiatedAbortMessage(rawErrorMsg)) {
|
|
191
|
+
resolveAgentEndCancelled({
|
|
192
|
+
message: rawErrorMsg,
|
|
193
|
+
category: "aborted",
|
|
194
|
+
isTransient: false,
|
|
195
|
+
});
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
183
198
|
const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
|
|
184
199
|
// #3588: When errorMessage is uninformative, extract the real error from
|
|
185
200
|
// the assistant message text content for display purposes only.
|