gsd-pi 2.73.1 → 2.74.0-dev.b741afb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-web-branch.d.ts +4 -3
- package/dist/cli-web-branch.js +10 -7
- package/dist/cli.js +184 -206
- package/dist/headless-query.js +4 -1
- package/dist/help-text.js +23 -0
- package/dist/logo.d.ts +1 -1
- package/dist/logo.js +1 -1
- package/dist/onboarding.js +59 -53
- package/dist/resource-loader.js +2 -2
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +68 -4
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
- package/dist/resources/extensions/gsd/auto/phases.js +60 -10
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +54 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +93 -57
- package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
- package/dist/resources/extensions/gsd/auto-start.js +23 -6
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
- package/dist/resources/extensions/gsd/auto-verification.js +88 -3
- package/dist/resources/extensions/gsd/auto.js +37 -10
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +21 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +20 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
- package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
- package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
- package/dist/resources/extensions/gsd/commands-do.js +79 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
- package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
- package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
- package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
- package/dist/resources/extensions/gsd/commands-ship.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +3 -5
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/graph-context.js +66 -0
- package/dist/resources/extensions/gsd/gsd-db.js +321 -0
- package/dist/resources/extensions/gsd/index.js +15 -2
- package/dist/resources/extensions/gsd/md-importer.js +3 -4
- package/dist/resources/extensions/gsd/memory-store.js +19 -51
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
- package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
- package/dist/resources/extensions/gsd/notification-widget.js +2 -2
- package/dist/resources/extensions/gsd/preferences-models.js +43 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +22 -0
- package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
- package/dist/resources/extensions/gsd/state.js +66 -15
- package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
- package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
- package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
- package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
- package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
- package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
- package/dist/tsconfig.extensions.tsbuildinfo +1 -0
- package/dist/update-check.d.ts +1 -0
- package/dist/update-check.js +13 -5
- package/dist/update-cmd.js +4 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- 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 +2 -2
- 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 +2 -2
- 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 +4 -4
- 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 +9 -9
- 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-manifest.json +5 -5
- 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-f1e30ab6bb269149.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/package.json +3 -3
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/index.d.ts +3 -0
- package/packages/mcp-server/dist/index.d.ts.map +1 -1
- package/packages/mcp-server/dist/index.js +3 -0
- package/packages/mcp-server/dist/index.js.map +1 -1
- package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
- package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/graph.js +548 -0
- package/packages/mcp-server/dist/readers/graph.js.map +1 -0
- package/packages/mcp-server/dist/readers/index.d.ts +2 -0
- package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
- package/packages/mcp-server/dist/readers/index.js +1 -0
- package/packages/mcp-server/dist/readers/index.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +65 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/index.ts +15 -0
- package/packages/mcp-server/src/readers/graph.test.ts +426 -0
- package/packages/mcp-server/src/readers/graph.ts +708 -0
- package/packages/mcp-server/src/readers/index.ts +12 -0
- package/packages/mcp-server/src/server.ts +83 -0
- package/packages/mcp-server/tsconfig.json +1 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
- package/packages/native/package.json +2 -2
- package/packages/native/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.json +1 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-ai/dist/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.js +12 -0
- package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +4 -0
- package/packages/pi-ai/src/utils/overflow.ts +14 -1
- package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
- package/packages/pi-ai/tsconfig.json +1 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +313 -8
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
- package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
- 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 +61 -28
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +9 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
- 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 +94 -16
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- 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 +11 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +355 -8
- package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
- package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +74 -32
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +113 -21
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +11 -3
- package/packages/pi-coding-agent/tsconfig.json +1 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +60 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +8 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +32 -3
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
- package/packages/pi-tui/src/tui.ts +31 -3
- package/packages/pi-tui/tsconfig.json +1 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.json +1 -0
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +107 -5
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +111 -2
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
- package/src/resources/extensions/gsd/auto/loop-deps.ts +6 -0
- package/src/resources/extensions/gsd/auto/phases.ts +90 -10
- package/src/resources/extensions/gsd/auto-dispatch.ts +10 -4
- package/src/resources/extensions/gsd/auto-model-selection.ts +85 -11
- package/src/resources/extensions/gsd/auto-post-unit.ts +107 -58
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
- package/src/resources/extensions/gsd/auto-start.ts +30 -6
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
- package/src/resources/extensions/gsd/auto-verification.ts +98 -3
- package/src/resources/extensions/gsd/auto.ts +38 -14
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +20 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
- package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
- package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
- package/src/resources/extensions/gsd/commands-do.ts +109 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
- package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
- package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
- package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
- package/src/resources/extensions/gsd/commands-ship.ts +219 -0
- package/src/resources/extensions/gsd/db-writer.ts +3 -5
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/graph-context.ts +85 -0
- package/src/resources/extensions/gsd/gsd-db.ts +467 -0
- package/src/resources/extensions/gsd/index.ts +18 -2
- package/src/resources/extensions/gsd/md-importer.ts +3 -5
- package/src/resources/extensions/gsd/memory-store.ts +31 -62
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
- package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
- package/src/resources/extensions/gsd/notification-widget.ts +2 -2
- package/src/resources/extensions/gsd/preferences-models.ts +41 -0
- package/src/resources/extensions/gsd/preferences-types.ts +12 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +23 -0
- package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
- package/src/resources/extensions/gsd/state.ts +80 -17
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
- package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
- package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +19 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
- package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
- package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
- package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
- package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
- package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
- package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.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/dist/web/standalone/.next/static/{Qr27MOHx0lxRGnJvlhxxu → XnHY5eXUsTCFmNodWHetD}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qr27MOHx0lxRGnJvlhxxu → XnHY5eXUsTCFmNodWHetD}/_ssgManifest.js +0 -0
|
@@ -104,6 +104,7 @@ import {
|
|
|
104
104
|
updateSliceProgressCache,
|
|
105
105
|
unitVerb,
|
|
106
106
|
hideFooter,
|
|
107
|
+
describeNextUnit,
|
|
107
108
|
} from "./auto-dashboard.js";
|
|
108
109
|
import { existsSync, unlinkSync } from "node:fs";
|
|
109
110
|
import { join } from "node:path";
|
|
@@ -233,6 +234,18 @@ export function detectRogueFileWrites(
|
|
|
233
234
|
return rogues;
|
|
234
235
|
}
|
|
235
236
|
|
|
237
|
+
export const STEP_COMPLETE_FALLBACK_MESSAGE =
|
|
238
|
+
"Step complete. Run /clear, then /gsd to continue (or /gsd auto to run continuously).";
|
|
239
|
+
|
|
240
|
+
export function buildStepCompleteMessage(nextState: import("./types.js").GSDState): string {
|
|
241
|
+
if (nextState.phase === "complete") {
|
|
242
|
+
return "Step complete — milestone finished. Run /gsd status to review, or start the next milestone.";
|
|
243
|
+
}
|
|
244
|
+
const next = describeNextUnit(nextState);
|
|
245
|
+
return `Step complete. Next: ${next.label}\n`
|
|
246
|
+
+ `Run /clear, then /gsd to continue (or /gsd auto to run continuously).`;
|
|
247
|
+
}
|
|
248
|
+
|
|
236
249
|
export interface PreVerificationOpts {
|
|
237
250
|
skipSettleDelay?: boolean;
|
|
238
251
|
skipWorktreeSync?: boolean;
|
|
@@ -249,6 +262,65 @@ export interface PostUnitContext {
|
|
|
249
262
|
updateProgressWidget: (ctx: ExtensionContext, unitType: string, unitId: string, state: import("./types.js").GSDState) => void;
|
|
250
263
|
}
|
|
251
264
|
|
|
265
|
+
export async function autoCommitUnit(
|
|
266
|
+
basePath: string,
|
|
267
|
+
unitType: string,
|
|
268
|
+
unitId: string,
|
|
269
|
+
ctx?: ExtensionContext,
|
|
270
|
+
): Promise<string | null> {
|
|
271
|
+
try {
|
|
272
|
+
let taskContext: TaskCommitContext | undefined;
|
|
273
|
+
|
|
274
|
+
if (unitType === "execute-task") {
|
|
275
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
276
|
+
if (mid && sid && tid) {
|
|
277
|
+
const summaryPath = resolveTaskFile(basePath, mid, sid, tid, "SUMMARY");
|
|
278
|
+
if (summaryPath) {
|
|
279
|
+
try {
|
|
280
|
+
const summaryContent = await loadFile(summaryPath);
|
|
281
|
+
if (summaryContent) {
|
|
282
|
+
const summary = parseSummary(summaryContent);
|
|
283
|
+
let ghIssueNumber: number | undefined;
|
|
284
|
+
try {
|
|
285
|
+
const { getTaskIssueNumberForCommit } = await import("../github-sync/sync.js");
|
|
286
|
+
ghIssueNumber = getTaskIssueNumberForCommit(basePath, mid, sid, tid) ?? undefined;
|
|
287
|
+
} catch (err) {
|
|
288
|
+
logWarning("engine", `GitHub issue lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
taskContext = {
|
|
292
|
+
taskId: `${sid}/${tid}`,
|
|
293
|
+
taskTitle: summary.title?.replace(/^T\d+:\s*/, "") || tid,
|
|
294
|
+
oneLiner: summary.oneLiner || undefined,
|
|
295
|
+
keyFiles: summary.frontmatter.key_files?.filter(f => !f.includes("{{")) || undefined,
|
|
296
|
+
issueNumber: ghIssueNumber,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
} catch (e) {
|
|
300
|
+
debugLog("postUnit", { phase: "task-summary-parse", error: String(e) });
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
_resetHasChangesCache();
|
|
307
|
+
|
|
308
|
+
if (LIFECYCLE_ONLY_UNITS.has(unitType)) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const commitMsg = autoCommitCurrentBranch(basePath, unitType, unitId, taskContext);
|
|
313
|
+
if (commitMsg) {
|
|
314
|
+
ctx?.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
|
|
315
|
+
}
|
|
316
|
+
return commitMsg;
|
|
317
|
+
} catch (e) {
|
|
318
|
+
debugLog("postUnit", { phase: "auto-commit", error: String(e) });
|
|
319
|
+
ctx?.ui.notify(`Auto-commit failed: ${String(e).split("\n")[0]}`, "warning");
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
252
324
|
/**
|
|
253
325
|
* Pre-verification processing: parallel worker signal check, cache invalidation,
|
|
254
326
|
* auto-commit, doctor run, state rebuild, worktree sync, artifact verification.
|
|
@@ -288,63 +360,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
288
360
|
// Auto-commit
|
|
289
361
|
if (s.currentUnit) {
|
|
290
362
|
const unit = s.currentUnit;
|
|
291
|
-
|
|
292
|
-
let taskContext: TaskCommitContext | undefined;
|
|
293
|
-
|
|
294
|
-
if (s.currentUnit.type === "execute-task") {
|
|
295
|
-
const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
|
|
296
|
-
if (mid && sid && tid) {
|
|
297
|
-
const summaryPath = resolveTaskFile(s.basePath, mid, sid, tid, "SUMMARY");
|
|
298
|
-
if (summaryPath) {
|
|
299
|
-
try {
|
|
300
|
-
const summaryContent = await loadFile(summaryPath);
|
|
301
|
-
if (summaryContent) {
|
|
302
|
-
const summary = parseSummary(summaryContent);
|
|
303
|
-
// Look up GitHub issue number for commit linking
|
|
304
|
-
let ghIssueNumber: number | undefined;
|
|
305
|
-
try {
|
|
306
|
-
const { getTaskIssueNumberForCommit } = await import("../github-sync/sync.js");
|
|
307
|
-
ghIssueNumber = getTaskIssueNumberForCommit(s.basePath, mid, sid, tid) ?? undefined;
|
|
308
|
-
} catch (err) {
|
|
309
|
-
// GitHub sync not available — skip
|
|
310
|
-
logWarning("engine", `GitHub issue lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
taskContext = {
|
|
314
|
-
taskId: `${sid}/${tid}`,
|
|
315
|
-
taskTitle: summary.title?.replace(/^T\d+:\s*/, "") || tid,
|
|
316
|
-
oneLiner: summary.oneLiner || undefined,
|
|
317
|
-
keyFiles: summary.frontmatter.key_files?.filter(f => !f.includes("{{")) || undefined,
|
|
318
|
-
issueNumber: ghIssueNumber,
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
} catch (e) {
|
|
322
|
-
debugLog("postUnit", { phase: "task-summary-parse", error: String(e) });
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Invalidate the nativeHasChanges cache before auto-commit (#1853).
|
|
329
|
-
// The cache has a 10-second TTL and is keyed by basePath. A stale
|
|
330
|
-
// `false` result causes autoCommit to skip staging entirely, leaving
|
|
331
|
-
// code files only in the working tree where they are destroyed by
|
|
332
|
-
// `git worktree remove --force` during teardown.
|
|
333
|
-
_resetHasChangesCache();
|
|
334
|
-
|
|
335
|
-
// Skip auto-commit for lifecycle-only units (#2553) — they only touch
|
|
336
|
-
// `.gsd/` internal state files. Those files are picked up by the next
|
|
337
|
-
// actual task commit via smartStage().
|
|
338
|
-
if (!LIFECYCLE_ONLY_UNITS.has(s.currentUnit.type)) {
|
|
339
|
-
const commitMsg = autoCommitCurrentBranch(s.basePath, s.currentUnit.type, s.currentUnit.id, taskContext);
|
|
340
|
-
if (commitMsg) {
|
|
341
|
-
ctx.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
} catch (e) {
|
|
345
|
-
debugLog("postUnit", { phase: "auto-commit", error: String(e) });
|
|
346
|
-
ctx.ui.notify(`Auto-commit failed: ${String(e).split("\n")[0]}`, "warning");
|
|
347
|
-
}
|
|
363
|
+
await autoCommitUnit(s.basePath, unit.type, unit.id, ctx);
|
|
348
364
|
|
|
349
365
|
// GitHub sync (non-blocking, opt-in)
|
|
350
366
|
await runSafely("postUnit", "github-sync", async () => {
|
|
@@ -619,6 +635,30 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
619
635
|
s.verificationRetryCount.set(retryKey, attempt);
|
|
620
636
|
|
|
621
637
|
if (attempt > MAX_VERIFICATION_RETRIES) {
|
|
638
|
+
// #4175: For complete-milestone, a blocker placeholder is harmful —
|
|
639
|
+
// the stub SUMMARY has no recovery value (milestone is terminal),
|
|
640
|
+
// it does not update DB status (so deriveState never advances),
|
|
641
|
+
// and it fools stopAuto's presence check into merging a milestone
|
|
642
|
+
// that was never legitimately completed. Pause auto-mode with a
|
|
643
|
+
// clear single failure signal and preserve the worktree branch.
|
|
644
|
+
if (s.currentUnit.type === "complete-milestone") {
|
|
645
|
+
debugLog("postUnit", {
|
|
646
|
+
phase: "artifact-verify-pause-complete-milestone",
|
|
647
|
+
unitType: s.currentUnit.type,
|
|
648
|
+
unitId: s.currentUnit.id,
|
|
649
|
+
attempt,
|
|
650
|
+
maxRetries: MAX_VERIFICATION_RETRIES,
|
|
651
|
+
});
|
|
652
|
+
s.verificationRetryCount.delete(retryKey);
|
|
653
|
+
s.pendingVerificationRetry = null;
|
|
654
|
+
ctx.ui.notify(
|
|
655
|
+
`Milestone ${s.currentUnit.id} verification failed after ${MAX_VERIFICATION_RETRIES} retries — worktree branch preserved. Re-run /gsd auto once blockers are resolved.`,
|
|
656
|
+
"error",
|
|
657
|
+
);
|
|
658
|
+
await pauseAuto(ctx, pi);
|
|
659
|
+
return "dispatched";
|
|
660
|
+
}
|
|
661
|
+
|
|
622
662
|
// Retries exhausted — write a blocker placeholder so the pipeline
|
|
623
663
|
// can advance past this stuck unit (#2653).
|
|
624
664
|
debugLog("postUnit", {
|
|
@@ -1025,8 +1065,17 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
1025
1065
|
}
|
|
1026
1066
|
}
|
|
1027
1067
|
|
|
1028
|
-
// Step mode → show wizard instead of dispatch
|
|
1068
|
+
// Step mode → show wizard instead of dispatch.
|
|
1069
|
+
// Without this notify(), /gsd in step mode finishes a unit and silently
|
|
1070
|
+
// exits the loop, leaving the user with no hint to /clear and /gsd again.
|
|
1029
1071
|
if (s.stepMode) {
|
|
1072
|
+
try {
|
|
1073
|
+
const nextState = await deriveState(s.basePath);
|
|
1074
|
+
ctx.ui.notify(buildStepCompleteMessage(nextState), "info");
|
|
1075
|
+
} catch (e) {
|
|
1076
|
+
debugLog("postUnit", { phase: "step-wizard-notify", error: String(e) });
|
|
1077
|
+
ctx.ui.notify(STEP_COMPLETE_FALLBACK_MESSAGE, "info");
|
|
1078
|
+
}
|
|
1030
1079
|
return "step-wizard";
|
|
1031
1080
|
}
|
|
1032
1081
|
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
|
|
35
35
|
import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
|
|
36
36
|
import { logWarning } from "./workflow-logger.js";
|
|
37
|
+
import { inlineGraphSubgraph } from "./graph-context.js";
|
|
37
38
|
|
|
38
39
|
// ─── Preamble Cap ─────────────────────────────────────────────────────────────
|
|
39
40
|
|
|
@@ -1175,6 +1176,10 @@ export async function buildResearchSlicePrompt(
|
|
|
1175
1176
|
const knowledgeInlineRS = await inlineKnowledgeScoped(base, keywords);
|
|
1176
1177
|
if (knowledgeInlineRS) inlined.push(knowledgeInlineRS);
|
|
1177
1178
|
|
|
1179
|
+
// Knowledge graph: subgraph for this slice (graceful — skipped if no graph.json)
|
|
1180
|
+
const graphBlockRS = await inlineGraphSubgraph(base, `${sid} ${sTitle}`, { budget: 3000 });
|
|
1181
|
+
if (graphBlockRS) inlined.push(graphBlockRS);
|
|
1182
|
+
|
|
1178
1183
|
inlined.push(inlineTemplate("research", "Research"));
|
|
1179
1184
|
|
|
1180
1185
|
const depContent = await inlineDependencySummaries(mid, sid, base);
|
|
@@ -1250,6 +1255,10 @@ export async function buildPlanSlicePrompt(
|
|
|
1250
1255
|
const knowledgeInlinePS = await inlineKnowledgeScoped(base, keywordsPS);
|
|
1251
1256
|
if (knowledgeInlinePS) inlined.push(knowledgeInlinePS);
|
|
1252
1257
|
|
|
1258
|
+
// Knowledge graph: subgraph for this slice (graceful — skipped if no graph.json)
|
|
1259
|
+
const graphBlockPS = await inlineGraphSubgraph(base, `${sid} ${sTitle}`, { budget: 3000 });
|
|
1260
|
+
if (graphBlockPS) inlined.push(graphBlockPS);
|
|
1261
|
+
|
|
1253
1262
|
inlined.push(inlineTemplate("plan", "Slice Plan"));
|
|
1254
1263
|
if (inlineLevel === "full") {
|
|
1255
1264
|
inlined.push(inlineTemplate("task-plan", "Task Plan"));
|
|
@@ -1366,12 +1375,16 @@ export async function buildExecuteTaskPrompt(
|
|
|
1366
1375
|
// Only include if it has content (not a "not found" result)
|
|
1367
1376
|
const knowledgeContent = knowledgeInlineET && !knowledgeInlineET.includes("not found") ? knowledgeInlineET : null;
|
|
1368
1377
|
|
|
1378
|
+
// Knowledge graph: tight subgraph for this task (graceful — skipped if no graph.json)
|
|
1379
|
+
const graphBlockET = await inlineGraphSubgraph(base, `${tid} ${tTitle}`, { budget: 2000 });
|
|
1380
|
+
|
|
1369
1381
|
const inlinedTemplates = inlineLevel === "minimal"
|
|
1370
1382
|
? inlineTemplate("task-summary", "Task Summary")
|
|
1371
1383
|
: [
|
|
1372
1384
|
inlineTemplate("task-summary", "Task Summary"),
|
|
1373
1385
|
inlineTemplate("decisions", "Decisions"),
|
|
1374
1386
|
...(knowledgeContent ? [knowledgeContent] : []),
|
|
1387
|
+
...(graphBlockET ? [graphBlockET] : []),
|
|
1375
1388
|
].join("\n\n---\n\n");
|
|
1376
1389
|
|
|
1377
1390
|
const taskSummaryPath = join(base, `${relSlicePath(base, mid, sid)}/tasks/${tid}-SUMMARY.md`);
|
|
@@ -83,7 +83,11 @@ import { join } from "node:path";
|
|
|
83
83
|
import { sep as pathSep } from "node:path";
|
|
84
84
|
|
|
85
85
|
import { resolveProjectRootDbPath } from "./bootstrap/dynamic-tools.js";
|
|
86
|
-
import {
|
|
86
|
+
import {
|
|
87
|
+
isCustomProvider,
|
|
88
|
+
resolveDefaultSessionModel,
|
|
89
|
+
resolveDynamicRoutingConfig,
|
|
90
|
+
} from "./preferences-models.js";
|
|
87
91
|
import type { WorktreeResolver } from "./worktree-resolver.js";
|
|
88
92
|
import { getSessionModelOverride } from "./session-model-override.js";
|
|
89
93
|
|
|
@@ -274,8 +278,18 @@ export async function bootstrapAutoSession(
|
|
|
274
278
|
//
|
|
275
279
|
// This preserves #3517 defaults while honoring explicit runtime model
|
|
276
280
|
// selection for subsequent /gsd runs in the same session.
|
|
281
|
+
//
|
|
282
|
+
// Exception (#4122): when the session provider is a custom provider declared
|
|
283
|
+
// in ~/.gsd/agent/models.json (Ollama, vLLM, OpenAI-compatible proxy, etc.),
|
|
284
|
+
// PREFERENCES.md is skipped entirely. PREFERENCES.md cannot reference custom
|
|
285
|
+
// providers, so honoring it would silently reroute auto-mode to a built-in
|
|
286
|
+
// provider the user is not logged into and surface as "Not logged in · Please
|
|
287
|
+
// run /login" before pausing and resetting to claude-code/claude-sonnet-4-6.
|
|
277
288
|
const manualSessionOverride = getSessionModelOverride(ctx.sessionManager.getSessionId());
|
|
278
|
-
const
|
|
289
|
+
const sessionProviderIsCustom = isCustomProvider(ctx.model?.provider);
|
|
290
|
+
const preferredModel = sessionProviderIsCustom
|
|
291
|
+
? null
|
|
292
|
+
: resolveDefaultSessionModel(ctx.model?.provider);
|
|
279
293
|
// Validate the preferred model against the live registry + provider auth so
|
|
280
294
|
// an unconfigured PREFERENCES.md entry (no API key / OAuth) can't become the
|
|
281
295
|
// start-model snapshot. Without this, every subsequent unit would try to
|
|
@@ -792,6 +806,9 @@ export async function bootstrapAutoSession(
|
|
|
792
806
|
|
|
793
807
|
ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
|
|
794
808
|
ctx.ui.setFooter(hideFooter);
|
|
809
|
+
// Hide gsd-health during AUTO — gsd-progress is the single source of truth
|
|
810
|
+
// for last-commit / cost / health signal while auto is running.
|
|
811
|
+
ctx.ui.setWidget("gsd-health", undefined);
|
|
795
812
|
const modeLabel = s.stepMode ? "Step-mode" : "Auto-mode";
|
|
796
813
|
const pendingCount = (state.registry ?? []).filter(
|
|
797
814
|
(m) => m.status !== "complete" && m.status !== "parked",
|
|
@@ -811,12 +828,19 @@ export async function bootstrapAutoSession(
|
|
|
811
828
|
? `${s.autoModeStartModel.provider}/${s.autoModeStartModel.id}`
|
|
812
829
|
: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : "default";
|
|
813
830
|
|
|
814
|
-
// Flat-rate providers (e.g. GitHub Copilot, claude-code
|
|
815
|
-
//
|
|
816
|
-
|
|
831
|
+
// Flat-rate providers (e.g. GitHub Copilot, claude-code, user-declared
|
|
832
|
+
// subscription proxies, externalCli CLIs) suppress routing at dispatch
|
|
833
|
+
// time (#3453) — reflect that in the banner. Thread the same
|
|
834
|
+
// FlatRateContext used by selectAndApplyModel so user-declared
|
|
835
|
+
// flat-rate providers and externalCli auto-detection are respected.
|
|
836
|
+
const { isFlatRateProvider, buildFlatRateContext } = await import("./auto-model-selection.js");
|
|
837
|
+
const bannerPrefs = loadEffectiveGSDPreferences()?.preferences;
|
|
817
838
|
const effectiveProvider = s.autoModeStartModel?.provider ?? ctx.model?.provider;
|
|
818
839
|
const effectivelyEnabled = routingConfig.enabled
|
|
819
|
-
&& !(effectiveProvider && isFlatRateProvider(
|
|
840
|
+
&& !(effectiveProvider && isFlatRateProvider(
|
|
841
|
+
effectiveProvider,
|
|
842
|
+
buildFlatRateContext(effectiveProvider, ctx, bannerPrefs),
|
|
843
|
+
));
|
|
820
844
|
|
|
821
845
|
// The actual ceiling may come from tier_models.heavy, not the start model.
|
|
822
846
|
const effectiveCeiling = (routingConfig.enabled && routingConfig.tier_models?.heavy)
|
|
@@ -230,6 +230,23 @@ export async function recoverTimedOutUnit(
|
|
|
230
230
|
return "recovered";
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
// #4175: For complete-milestone, never write a blocker placeholder — a stub
|
|
234
|
+
// SUMMARY has no recovery value (milestone is terminal), it does not update
|
|
235
|
+
// DB status, and downstream merge paths can treat the stub as a legitimate
|
|
236
|
+
// completion signal. Pause instead so the worktree branch is preserved.
|
|
237
|
+
if (unitType === "complete-milestone") {
|
|
238
|
+
writeUnitRuntimeRecord(basePath, unitType, unitId, currentUnitStartedAt, {
|
|
239
|
+
phase: "paused",
|
|
240
|
+
recoveryAttempts: recoveryAttempts + 1,
|
|
241
|
+
lastRecoveryReason: reason,
|
|
242
|
+
});
|
|
243
|
+
ctx.ui.notify(
|
|
244
|
+
`Milestone ${unitId} ${reason}-recovery exhausted ${maxRecoveryAttempts} attempt(s) — worktree branch preserved. Re-run /gsd auto once blockers are resolved.`,
|
|
245
|
+
"error",
|
|
246
|
+
);
|
|
247
|
+
return "paused";
|
|
248
|
+
}
|
|
249
|
+
|
|
233
250
|
// Retries exhausted — write a blocker placeholder and advance the pipeline
|
|
234
251
|
// instead of silently stalling.
|
|
235
252
|
const placeholder = writeBlockerPlaceholder(
|
|
@@ -12,10 +12,15 @@
|
|
|
12
12
|
|
|
13
13
|
import type { ExtensionContext, ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
14
14
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
15
|
-
import { resolveSliceFile, resolveSlicePath } from "./paths.js";
|
|
15
|
+
import { resolveSliceFile, resolveSlicePath, resolveMilestoneFile } from "./paths.js";
|
|
16
16
|
import { parseUnitId } from "./unit-id.js";
|
|
17
|
-
import { isDbAvailable, getTask, getSliceTasks, type TaskRow } from "./gsd-db.js";
|
|
17
|
+
import { isDbAvailable, getTask, getSliceTasks, getMilestoneSlices, type TaskRow } from "./gsd-db.js";
|
|
18
18
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
19
|
+
import { extractVerdict } from "./verdict-parser.js";
|
|
20
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
21
|
+
import { loadFile } from "./files.js";
|
|
22
|
+
import { parseRoadmap } from "./parsers-legacy.js";
|
|
23
|
+
import { isMilestoneComplete } from "./state.js";
|
|
19
24
|
import {
|
|
20
25
|
runVerificationGate,
|
|
21
26
|
formatFailureContext,
|
|
@@ -43,6 +48,88 @@ function isInfraVerificationFailure(stderr: string): boolean {
|
|
|
43
48
|
);
|
|
44
49
|
}
|
|
45
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Post-unit guard for `validate-milestone` units (#4094).
|
|
53
|
+
*
|
|
54
|
+
* When validate-milestone writes verdict=needs-remediation, the agent is
|
|
55
|
+
* expected to also call gsd_reassess_roadmap in the same turn to add
|
|
56
|
+
* remediation slices. If they don't, the state machine re-derives
|
|
57
|
+
* `phase: validating-milestone` indefinitely (all slices still complete +
|
|
58
|
+
* verdict still needs-remediation), wasting ~3 dispatches before the stuck
|
|
59
|
+
* detector fires.
|
|
60
|
+
*
|
|
61
|
+
* This guard fires immediately on the first occurrence: if VALIDATION.md
|
|
62
|
+
* verdict is needs-remediation and no incomplete slices exist for the
|
|
63
|
+
* milestone, pause the auto-loop with a clear blocker.
|
|
64
|
+
*/
|
|
65
|
+
async function runValidateMilestonePostCheck(
|
|
66
|
+
vctx: VerificationContext,
|
|
67
|
+
pauseAuto: (ctx?: ExtensionContext, pi?: ExtensionAPI) => Promise<void>,
|
|
68
|
+
): Promise<VerificationResult> {
|
|
69
|
+
const { s, ctx, pi } = vctx;
|
|
70
|
+
if (!s.currentUnit) return "continue";
|
|
71
|
+
|
|
72
|
+
const { milestone: mid } = parseUnitId(s.currentUnit.id);
|
|
73
|
+
if (!mid) return "continue";
|
|
74
|
+
|
|
75
|
+
const validationFile = resolveMilestoneFile(s.basePath, mid, "VALIDATION");
|
|
76
|
+
if (!validationFile) return "continue";
|
|
77
|
+
|
|
78
|
+
const validationContent = await loadFile(validationFile);
|
|
79
|
+
if (!validationContent) return "continue";
|
|
80
|
+
|
|
81
|
+
const verdict = extractVerdict(validationContent);
|
|
82
|
+
if (verdict !== "needs-remediation") return "continue";
|
|
83
|
+
|
|
84
|
+
const incompleteSliceCount = await countIncompleteSlices(s.basePath, mid);
|
|
85
|
+
|
|
86
|
+
// If any non-closed slices exist, the agent successfully queued remediation
|
|
87
|
+
// work — proceed normally. The state machine will execute those slices and
|
|
88
|
+
// re-validate per the #3596/#3670 fix.
|
|
89
|
+
if (incompleteSliceCount > 0) return "continue";
|
|
90
|
+
|
|
91
|
+
ctx.ui.notify(
|
|
92
|
+
`Milestone ${mid} validation returned verdict=needs-remediation but no remediation slices were added. Pausing for human review.`,
|
|
93
|
+
"error",
|
|
94
|
+
);
|
|
95
|
+
process.stderr.write(
|
|
96
|
+
`validate-milestone: pausing — verdict=needs-remediation with no incomplete slices for ${mid}. ` +
|
|
97
|
+
`The agent must call gsd_reassess_roadmap to add remediation slices before re-validation.\n`,
|
|
98
|
+
);
|
|
99
|
+
await pauseAuto(ctx, pi);
|
|
100
|
+
return "pause";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Count slices for a milestone that are not in a closed status.
|
|
105
|
+
* DB-backed projects are authoritative (#4094 peer review); falls back to
|
|
106
|
+
* roadmap parsing only when the DB is unavailable.
|
|
107
|
+
*/
|
|
108
|
+
async function countIncompleteSlices(basePath: string, milestoneId: string): Promise<number> {
|
|
109
|
+
if (isDbAvailable()) {
|
|
110
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
111
|
+
if (slices.length === 0) {
|
|
112
|
+
// No DB rows — treat as "unknown", do not pause.
|
|
113
|
+
return 1;
|
|
114
|
+
}
|
|
115
|
+
return slices.filter((slice) => !isClosedStatus(slice.status)).length;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Filesystem fallback: parse the roadmap markdown.
|
|
119
|
+
try {
|
|
120
|
+
const roadmapFile = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
121
|
+
if (!roadmapFile) return 1;
|
|
122
|
+
const roadmapContent = await loadFile(roadmapFile);
|
|
123
|
+
if (!roadmapContent) return 1;
|
|
124
|
+
const roadmap = parseRoadmap(roadmapContent);
|
|
125
|
+
if (roadmap.slices.length === 0) return 1;
|
|
126
|
+
return isMilestoneComplete(roadmap) ? 0 : 1;
|
|
127
|
+
} catch {
|
|
128
|
+
// Parsing failures should not cause false-positive pauses.
|
|
129
|
+
return 1;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
46
133
|
/**
|
|
47
134
|
* Run the verification gate for the current execute-task unit.
|
|
48
135
|
* Returns:
|
|
@@ -56,7 +143,15 @@ export async function runPostUnitVerification(
|
|
|
56
143
|
): Promise<VerificationResult> {
|
|
57
144
|
const { s, ctx, pi } = vctx;
|
|
58
145
|
|
|
59
|
-
if (!s.currentUnit
|
|
146
|
+
if (!s.currentUnit) {
|
|
147
|
+
return "continue";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (s.currentUnit.type === "validate-milestone") {
|
|
151
|
+
return await runValidateMilestonePostCheck(vctx, pauseAuto);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (s.currentUnit.type !== "execute-task") {
|
|
60
155
|
return "continue";
|
|
61
156
|
}
|
|
62
157
|
|
|
@@ -187,7 +187,7 @@ import {
|
|
|
187
187
|
deregisterSigtermHandler as _deregisterSigtermHandler,
|
|
188
188
|
detectWorkingTreeActivity,
|
|
189
189
|
} from "./auto-supervisor.js";
|
|
190
|
-
import { isDbAvailable } from "./gsd-db.js";
|
|
190
|
+
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
191
191
|
import { countPendingCaptures } from "./captures.js";
|
|
192
192
|
import { clearCmuxSidebar, logCmuxEvent, syncCmuxSidebar } from "../cmux/index.js";
|
|
193
193
|
|
|
@@ -195,10 +195,12 @@ import { clearCmuxSidebar, logCmuxEvent, syncCmuxSidebar } from "../cmux/index.j
|
|
|
195
195
|
import { startUnitSupervision } from "./auto-timers.js";
|
|
196
196
|
import { runPostUnitVerification } from "./auto-verification.js";
|
|
197
197
|
import {
|
|
198
|
+
autoCommitUnit,
|
|
198
199
|
postUnitPreVerification,
|
|
199
200
|
postUnitPostVerification,
|
|
200
201
|
} from "./auto-post-unit.js";
|
|
201
202
|
import { bootstrapAutoSession, openProjectDbIfPresent, type BootstrapDeps } from "./auto-start.js";
|
|
203
|
+
import { initHealthWidget } from "./health-widget.js";
|
|
202
204
|
import { autoLoop, resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight, type LoopDeps, type ErrorContext } from "./auto-loop.js";
|
|
203
205
|
// Slice-level parallelism (#2340)
|
|
204
206
|
import { getEligibleSlices } from "./slice-parallel-eligibility.js";
|
|
@@ -650,6 +652,7 @@ function handleLostSessionLock(
|
|
|
650
652
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
651
653
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
652
654
|
ctx?.ui.setFooter(undefined);
|
|
655
|
+
if (ctx) initHealthWidget(ctx);
|
|
653
656
|
}
|
|
654
657
|
|
|
655
658
|
/**
|
|
@@ -684,6 +687,7 @@ function cleanupAfterLoopExit(ctx: ExtensionContext): void {
|
|
|
684
687
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
685
688
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
686
689
|
ctx.ui.setFooter(undefined);
|
|
690
|
+
initHealthWidget(ctx);
|
|
687
691
|
}
|
|
688
692
|
|
|
689
693
|
// Restore CWD out of worktree back to original project root
|
|
@@ -758,24 +762,36 @@ export async function stopAuto(
|
|
|
758
762
|
: { notify: () => {} };
|
|
759
763
|
const resolver = buildResolver();
|
|
760
764
|
|
|
761
|
-
// Check if the milestone is complete
|
|
765
|
+
// Check if the milestone is complete. DB status is the authoritative
|
|
766
|
+
// signal — only a successful gsd_complete_milestone call flips it to
|
|
767
|
+
// "complete" (tools/complete-milestone.ts). SUMMARY file presence is
|
|
768
|
+
// NOT sufficient: a blocker placeholder stub or a partial write can
|
|
769
|
+
// leave a file behind without the milestone actually being done,
|
|
770
|
+
// which previously caused stopAuto to merge a failed milestone and
|
|
771
|
+
// emit a misleading metadata-only merge warning (#4175).
|
|
772
|
+
// DB-unavailable projects fall back to SUMMARY-file presence.
|
|
762
773
|
let milestoneComplete = false;
|
|
763
774
|
try {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
// Also check in the worktree path (SUMMARY may not be synced yet)
|
|
771
|
-
const wtSummaryPath = resolveMilestoneFile(
|
|
772
|
-
s.basePath,
|
|
775
|
+
if (isDbAvailable()) {
|
|
776
|
+
const dbRow = getMilestone(s.currentMilestoneId);
|
|
777
|
+
milestoneComplete = dbRow?.status === "complete";
|
|
778
|
+
} else {
|
|
779
|
+
const summaryPath = resolveMilestoneFile(
|
|
780
|
+
s.originalBasePath || s.basePath,
|
|
773
781
|
s.currentMilestoneId,
|
|
774
782
|
"SUMMARY",
|
|
775
783
|
);
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
784
|
+
if (!summaryPath) {
|
|
785
|
+
// Also check in the worktree path (SUMMARY may not be synced yet)
|
|
786
|
+
const wtSummaryPath = resolveMilestoneFile(
|
|
787
|
+
s.basePath,
|
|
788
|
+
s.currentMilestoneId,
|
|
789
|
+
"SUMMARY",
|
|
790
|
+
);
|
|
791
|
+
milestoneComplete = wtSummaryPath !== null;
|
|
792
|
+
} else {
|
|
793
|
+
milestoneComplete = true;
|
|
794
|
+
}
|
|
779
795
|
}
|
|
780
796
|
} catch (err) {
|
|
781
797
|
// Non-fatal — fall through to preserveBranch path
|
|
@@ -943,6 +959,7 @@ export async function stopAuto(
|
|
|
943
959
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
944
960
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
945
961
|
ctx?.ui.setFooter(undefined);
|
|
962
|
+
if (ctx) initHealthWidget(ctx);
|
|
946
963
|
restoreProjectRootEnv();
|
|
947
964
|
restoreMilestoneLockEnv();
|
|
948
965
|
|
|
@@ -1044,6 +1061,7 @@ export async function pauseAuto(
|
|
|
1044
1061
|
ctx?.ui.setStatus("gsd-auto", "paused");
|
|
1045
1062
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
1046
1063
|
ctx?.ui.setFooter(undefined);
|
|
1064
|
+
if (ctx) initHealthWidget(ctx);
|
|
1047
1065
|
const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
|
|
1048
1066
|
ctx?.ui.notify(
|
|
1049
1067
|
`${s.stepMode ? "Step" : "Auto"}-mode paused (Escape). Type to interact, or ${resumeCmd} to resume.`,
|
|
@@ -1163,6 +1181,7 @@ function buildLoopDeps(): LoopDeps {
|
|
|
1163
1181
|
getMainBranch,
|
|
1164
1182
|
// Unit closeout + runtime records
|
|
1165
1183
|
closeoutUnit,
|
|
1184
|
+
autoCommitUnit,
|
|
1166
1185
|
recordOutcome,
|
|
1167
1186
|
writeLock,
|
|
1168
1187
|
captureAvailableSkills,
|
|
@@ -1383,6 +1402,11 @@ export async function startAuto(
|
|
|
1383
1402
|
s.stepMode = requestedStepMode;
|
|
1384
1403
|
s.cmdCtx = ctx;
|
|
1385
1404
|
s.basePath = base;
|
|
1405
|
+
// Ensure the workflow-logger audit log is pinned to the project root
|
|
1406
|
+
// even when auto-mode is entered via a path that bypasses the
|
|
1407
|
+
// bootstrap/dynamic-tools ensureDbOpen() → setLogBasePath() chain
|
|
1408
|
+
// (e.g. /clear resume, hot-reload).
|
|
1409
|
+
setLogBasePath(base);
|
|
1386
1410
|
s.unitDispatchCount.clear();
|
|
1387
1411
|
s.unitLifetimeDispatches.clear();
|
|
1388
1412
|
if (!getLedger()) initMetrics(base);
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
4
4
|
|
|
5
|
-
import { registerGSDCommand } from "../commands.js";
|
|
6
5
|
import { registerExitCommand } from "../exit-command.js";
|
|
7
6
|
import { registerWorktreeCommand } from "../worktree-command.js";
|
|
8
7
|
import { registerDbTools } from "./db-tools.js";
|
|
@@ -12,6 +11,7 @@ import { registerQueryTools } from "./query-tools.js";
|
|
|
12
11
|
import { registerHooks } from "./register-hooks.js";
|
|
13
12
|
import { registerShortcuts } from "./register-shortcuts.js";
|
|
14
13
|
import { writeCrashLog } from "./crash-log.js";
|
|
14
|
+
import { logWarning } from "../workflow-logger.js";
|
|
15
15
|
|
|
16
16
|
export { writeCrashLog } from "./crash-log.js";
|
|
17
17
|
|
|
@@ -58,7 +58,8 @@ function installEpipeGuard(): void {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
61
|
-
registerGSDCommand
|
|
61
|
+
// Note: registerGSDCommand is called by index.ts before this function,
|
|
62
|
+
// so we intentionally skip it here to avoid double-registration.
|
|
62
63
|
registerWorktreeCommand(pi);
|
|
63
64
|
registerExitCommand(pi);
|
|
64
65
|
|
|
@@ -71,10 +72,25 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
|
71
72
|
},
|
|
72
73
|
});
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
// Wrap non-critical registrations individually so one failure
|
|
76
|
+
// doesn't prevent the others from loading.
|
|
77
|
+
const nonCriticalRegistrations: Array<[string, () => void]> = [
|
|
78
|
+
["dynamic-tools", () => registerDynamicTools(pi)],
|
|
79
|
+
["db-tools", () => registerDbTools(pi)],
|
|
80
|
+
["journal-tools", () => registerJournalTools(pi)],
|
|
81
|
+
["query-tools", () => registerQueryTools(pi)],
|
|
82
|
+
["shortcuts", () => registerShortcuts(pi)],
|
|
83
|
+
["hooks", () => registerHooks(pi)],
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
for (const [name, register] of nonCriticalRegistrations) {
|
|
87
|
+
try {
|
|
88
|
+
register();
|
|
89
|
+
} catch (err) {
|
|
90
|
+
logWarning(
|
|
91
|
+
"bootstrap",
|
|
92
|
+
`Failed to register ${name}: ${err instanceof Error ? err.message : String(err)}`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
80
96
|
}
|