@opengsd/gsd-pi 1.0.2-dev.867e002 → 1.0.2-dev.a271e2d
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/onboarding.js +22 -3
- package/dist/resource-loader.js +3 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/context7/index.js +12 -2
- package/dist/resources/extensions/get-secrets-from-user.js +16 -16
- package/dist/resources/extensions/google-cli/index.js +30 -0
- package/dist/resources/extensions/google-cli/models.js +55 -0
- package/dist/resources/extensions/google-cli/package.json +11 -0
- package/dist/resources/extensions/google-cli/readiness.js +12 -0
- package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
- package/dist/resources/extensions/gsd/auto/loop.js +62 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +37 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
- package/dist/resources/extensions/gsd/auto-post-unit.js +21 -11
- package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-start.js +232 -49
- package/dist/resources/extensions/gsd/auto.js +6 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
- package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
- package/dist/resources/extensions/gsd/commands-usage.js +105 -1
- package/dist/resources/extensions/gsd/config-overlay.js +20 -14
- package/dist/resources/extensions/gsd/context-overlay.js +22 -16
- package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
- package/dist/resources/extensions/gsd/doctor.js +6 -1
- package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
- package/dist/resources/extensions/gsd/guided-flow.js +5 -6
- package/dist/resources/extensions/gsd/key-manager.js +45 -13
- package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
- package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
- package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
- package/dist/resources/extensions/gsd/preferences.js +14 -2
- package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -3
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
- package/dist/resources/extensions/gsd/repository-registry.js +3 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +11 -4
- package/dist/resources/extensions/gsd/skill-activation.js +233 -0
- package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
- package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
- package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
- package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
- package/dist/resources/extensions/gsd/skill-scope.js +52 -0
- package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
- package/dist/resources/extensions/gsd/skills.js +60 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +42 -8
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
- package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
- package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
- package/dist/resources/extensions/gsd/vision-ask.js +22 -0
- package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
- package/dist/resources/extensions/search-the-web/native-search.js +57 -8
- package/dist/resources/extensions/shared/confirm-ui.js +9 -6
- package/dist/resources/extensions/shared/dialog-frame.js +42 -0
- package/dist/resources/extensions/shared/interview-ui.js +42 -30
- package/dist/resources/extensions/shared/next-action-ui.js +6 -6
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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/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 +6 -6
- package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-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/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.test.js +5 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +7 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +8 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/dist/workflow.test.js +1 -0
- package/packages/contracts/dist/workflow.test.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +28 -5
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/skills.js +6 -0
- package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
- package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
- package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +8 -59
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +21 -72
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +50 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
- package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/README.md +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +3 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/context7/index.ts +15 -2
- package/src/resources/extensions/get-secrets-from-user.ts +17 -16
- package/src/resources/extensions/google-cli/index.ts +34 -0
- package/src/resources/extensions/google-cli/models.ts +57 -0
- package/src/resources/extensions/google-cli/package.json +11 -0
- package/src/resources/extensions/google-cli/readiness.ts +15 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
- package/src/resources/extensions/gsd/auto/loop.ts +74 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +46 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
- package/src/resources/extensions/gsd/auto-post-unit.ts +43 -14
- package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
- package/src/resources/extensions/gsd/auto-start.ts +307 -56
- package/src/resources/extensions/gsd/auto.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +9 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
- package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
- package/src/resources/extensions/gsd/commands-usage.ts +110 -5
- package/src/resources/extensions/gsd/config-overlay.ts +19 -16
- package/src/resources/extensions/gsd/context-overlay.ts +24 -19
- package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/doctor.ts +6 -1
- package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
- package/src/resources/extensions/gsd/guided-flow.ts +5 -6
- package/src/resources/extensions/gsd/key-manager.ts +57 -14
- package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
- package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
- package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
- package/src/resources/extensions/gsd/preferences.ts +17 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -3
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
- package/src/resources/extensions/gsd/repository-registry.ts +3 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -4
- package/src/resources/extensions/gsd/skill-activation.ts +292 -0
- package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
- package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
- package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
- package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
- package/src/resources/extensions/gsd/skill-scope.ts +63 -0
- package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
- package/src/resources/extensions/gsd/skills.ts +75 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
- package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
- package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +74 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +42 -10
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
- package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
- package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
- package/src/resources/extensions/gsd/vision-ask.ts +28 -0
- package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
- package/src/resources/extensions/search-the-web/native-search.ts +60 -8
- package/src/resources/extensions/shared/confirm-ui.ts +8 -12
- package/src/resources/extensions/shared/dialog-frame.ts +71 -0
- package/src/resources/extensions/shared/interview-ui.ts +43 -42
- package/src/resources/extensions/shared/next-action-ui.ts +6 -6
- package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
- package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → QKed8_bmMc7zc3WLM7MW9}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → QKed8_bmMc7zc3WLM7MW9}/_ssgManifest.js +0 -0
|
@@ -21,7 +21,7 @@ import { invalidateAllCaches } from "./cache.js";
|
|
|
21
21
|
import { writeLock, clearLock, readCrashLock, isLockProcessAlive } from "./crash-recovery.js";
|
|
22
22
|
import { acquireSessionLock, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
|
|
23
23
|
import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
|
|
24
|
-
import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeBranchList, nativeBranchExists, nativeBranchListMerged, nativeBranchDelete, nativeWorktreeRemove, nativeCommitCountBetween, } from "./native-git-bridge.js";
|
|
24
|
+
import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeBranchList, nativeBranchExists, nativeBranchListMerged, nativeBranchDelete, nativeWorktreeRemove, nativeCommitCountBetween, nativeHasChanges, } from "./native-git-bridge.js";
|
|
25
25
|
import { GitServiceImpl } from "./git-service.js";
|
|
26
26
|
import { captureIntegrationBranch, detectWorktreeName, setActiveMilestoneId, } from "./worktree.js";
|
|
27
27
|
import { getAutoWorktreePath, checkoutBranchWithStashGuard } from "./auto-worktree.js";
|
|
@@ -126,17 +126,68 @@ export function resolveSurvivorRecoveryIsolationMode(isolationMode, phase) {
|
|
|
126
126
|
return "branch";
|
|
127
127
|
return isolationMode;
|
|
128
128
|
}
|
|
129
|
-
|
|
129
|
+
function isBlockingStrandedWorkAction(action) {
|
|
130
|
+
return action.kind === "in-progress-stranded-work" && action.blocksAuto;
|
|
131
|
+
}
|
|
132
|
+
function detectWorktreeEvidence(basePath, milestoneId, hasChanges) {
|
|
133
|
+
const wtDir = getWorktreeDir(basePath, milestoneId);
|
|
134
|
+
const wtPath = getAutoWorktreePath(basePath, milestoneId);
|
|
135
|
+
let dirty = false;
|
|
136
|
+
if (wtPath) {
|
|
137
|
+
try {
|
|
138
|
+
dirty = hasChanges(wtPath);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
dirty = false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
path: wtPath,
|
|
146
|
+
dirExists: existsSync(wtDir),
|
|
147
|
+
dirty,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function strandedWorkMessage(args) {
|
|
151
|
+
const evidence = [];
|
|
152
|
+
if (args.branch && args.commitsAhead > 0) {
|
|
153
|
+
evidence.push(`branch ${args.branch} has ${args.commitsAhead} commit(s) ahead of ${args.mainBranch}`);
|
|
154
|
+
}
|
|
155
|
+
if (args.dirtyWorktree) {
|
|
156
|
+
evidence.push("the worktree has uncommitted changes");
|
|
157
|
+
}
|
|
158
|
+
if (evidence.length === 0) {
|
|
159
|
+
evidence.push("physical git evidence exists");
|
|
160
|
+
}
|
|
161
|
+
const wtSuffix = args.worktreeDirExists
|
|
162
|
+
? ` Worktree directory at .gsd/worktrees/${args.milestoneId}/ holds live work.`
|
|
163
|
+
: "";
|
|
164
|
+
const recovery = args.recoveryMode === "worktree"
|
|
165
|
+
? "Recovering will adopt the existing worktree."
|
|
166
|
+
: "Recovering will adopt the milestone branch.";
|
|
167
|
+
return (`Stranded work for in-progress milestone ${args.milestoneId}: ${evidence.join("; ")}.` +
|
|
168
|
+
wtSuffix +
|
|
169
|
+
` ${recovery} Park or discard explicitly if abandoning.`);
|
|
170
|
+
}
|
|
171
|
+
export function auditOrphanedMilestoneBranches(basePath, _isolationMode, gitDeps = {}) {
|
|
130
172
|
const recovered = [];
|
|
131
173
|
const warnings = [];
|
|
174
|
+
const actions = [];
|
|
132
175
|
const branchList = gitDeps.branchList ?? nativeBranchList;
|
|
133
176
|
const branchExists = gitDeps.branchExists ?? nativeBranchExists;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
177
|
+
const hasChanges = gitDeps.hasChanges ?? nativeHasChanges;
|
|
178
|
+
const pushAction = (action) => {
|
|
179
|
+
actions.push(action);
|
|
180
|
+
if (action.severity === "info") {
|
|
181
|
+
recovered.push(action.message);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
warnings.push(action.message);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
137
187
|
// Skip if DB not available — can't determine completion status
|
|
138
|
-
if (!isDbAvailable())
|
|
139
|
-
return { recovered, warnings };
|
|
188
|
+
if (!isDbAvailable()) {
|
|
189
|
+
return { recovered, warnings, actions, blockingStrandedWork: null };
|
|
190
|
+
}
|
|
140
191
|
let milestoneBranches;
|
|
141
192
|
let milestoneBranchListAvailable = true;
|
|
142
193
|
try {
|
|
@@ -170,6 +221,7 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode, gitDeps
|
|
|
170
221
|
if (!milestone)
|
|
171
222
|
continue;
|
|
172
223
|
const isMerged = mergedBranches.has(branch);
|
|
224
|
+
const worktreeEvidence = detectWorktreeEvidence(basePath, milestoneId, hasChanges);
|
|
173
225
|
// #4762 — in-progress milestone branch with unmerged commits ahead of
|
|
174
226
|
// main. This is the pre-completion orphan case: auto-mode exited without
|
|
175
227
|
// completing the milestone (pause, stop, crash, merge error, blocker) and
|
|
@@ -181,32 +233,45 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode, gitDeps
|
|
|
181
233
|
// Parked/other closed statuses go through the legacy complete/unmerged
|
|
182
234
|
// path below where appropriate.
|
|
183
235
|
if (!isClosedStatus(milestone.status)) {
|
|
184
|
-
if (isMerged)
|
|
185
|
-
continue; // nothing to recover
|
|
186
236
|
let commitsAhead = 0;
|
|
187
237
|
try {
|
|
188
238
|
commitsAhead = nativeCommitCountBetween(basePath, mainBranch, branch);
|
|
189
239
|
}
|
|
190
240
|
catch {
|
|
191
|
-
|
|
192
|
-
continue;
|
|
241
|
+
commitsAhead = 0;
|
|
193
242
|
}
|
|
194
|
-
if (commitsAhead === 0)
|
|
243
|
+
if ((isMerged || commitsAhead === 0) && !worktreeEvidence.dirty)
|
|
195
244
|
continue;
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
245
|
+
const recoveryMode = worktreeEvidence.path
|
|
246
|
+
? "worktree"
|
|
247
|
+
: "branch";
|
|
248
|
+
const message = strandedWorkMessage({
|
|
249
|
+
milestoneId,
|
|
250
|
+
branch,
|
|
251
|
+
commitsAhead,
|
|
252
|
+
mainBranch,
|
|
253
|
+
dirtyWorktree: worktreeEvidence.dirty,
|
|
254
|
+
worktreeDirExists: worktreeEvidence.dirExists,
|
|
255
|
+
recoveryMode,
|
|
256
|
+
});
|
|
257
|
+
pushAction({
|
|
258
|
+
kind: "in-progress-stranded-work",
|
|
259
|
+
milestoneId,
|
|
260
|
+
branch,
|
|
261
|
+
commitsAhead,
|
|
262
|
+
dirtyWorktree: worktreeEvidence.dirty,
|
|
263
|
+
worktreeDirExists: worktreeEvidence.dirExists,
|
|
264
|
+
recoveryMode,
|
|
265
|
+
message,
|
|
266
|
+
severity: "warning",
|
|
267
|
+
blocksAuto: true,
|
|
268
|
+
});
|
|
204
269
|
// #4764 telemetry
|
|
205
270
|
try {
|
|
206
271
|
emitWorktreeOrphaned(basePath, milestoneId, {
|
|
207
272
|
reason: "in-progress-unmerged",
|
|
208
273
|
commitsAhead,
|
|
209
|
-
worktreeDirExists:
|
|
274
|
+
worktreeDirExists: worktreeEvidence.dirExists,
|
|
210
275
|
});
|
|
211
276
|
}
|
|
212
277
|
catch (err) {
|
|
@@ -223,7 +288,14 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode, gitDeps
|
|
|
223
288
|
// Branch is merged — safe to delete branch and clean up worktree dir
|
|
224
289
|
try {
|
|
225
290
|
nativeBranchDelete(basePath, branch, true);
|
|
226
|
-
|
|
291
|
+
pushAction({
|
|
292
|
+
kind: "complete-merged-branch",
|
|
293
|
+
milestoneId,
|
|
294
|
+
branch,
|
|
295
|
+
message: `Deleted merged branch ${branch} for completed milestone ${milestoneId}.`,
|
|
296
|
+
severity: "info",
|
|
297
|
+
blocksAuto: false,
|
|
298
|
+
});
|
|
227
299
|
}
|
|
228
300
|
catch (err) {
|
|
229
301
|
warnings.push(`Failed to delete merged branch ${branch}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -246,7 +318,15 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode, gitDeps
|
|
|
246
318
|
if (isInsideWorktreesDir(basePath, wtDir)) {
|
|
247
319
|
try {
|
|
248
320
|
rmSync(wtDir, { recursive: true, force: true });
|
|
249
|
-
|
|
321
|
+
pushAction({
|
|
322
|
+
kind: "complete-merged-worktree",
|
|
323
|
+
milestoneId,
|
|
324
|
+
branch,
|
|
325
|
+
worktreeDirExists: true,
|
|
326
|
+
message: `Removed orphaned worktree directory for ${milestoneId}.`,
|
|
327
|
+
severity: "info",
|
|
328
|
+
blocksAuto: false,
|
|
329
|
+
});
|
|
250
330
|
}
|
|
251
331
|
catch (err2) {
|
|
252
332
|
warnings.push(`Failed to remove worktree directory for ${milestoneId}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
@@ -257,14 +337,30 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode, gitDeps
|
|
|
257
337
|
}
|
|
258
338
|
}
|
|
259
339
|
else {
|
|
260
|
-
|
|
340
|
+
pushAction({
|
|
341
|
+
kind: "complete-merged-worktree",
|
|
342
|
+
milestoneId,
|
|
343
|
+
branch,
|
|
344
|
+
worktreeDirExists: true,
|
|
345
|
+
message: `Removed orphaned worktree directory for ${milestoneId}.`,
|
|
346
|
+
severity: "info",
|
|
347
|
+
blocksAuto: false,
|
|
348
|
+
});
|
|
261
349
|
}
|
|
262
350
|
}
|
|
263
351
|
}
|
|
264
352
|
else {
|
|
265
353
|
// Branch is NOT merged — preserve for safety, warn the user
|
|
266
|
-
|
|
267
|
-
|
|
354
|
+
pushAction({
|
|
355
|
+
kind: "complete-unmerged-branch",
|
|
356
|
+
milestoneId,
|
|
357
|
+
branch,
|
|
358
|
+
worktreeDirExists: worktreeEvidence.dirExists,
|
|
359
|
+
message: `Branch ${branch} exists for completed milestone ${milestoneId} but is NOT merged into ${mainBranch}. ` +
|
|
360
|
+
`This may contain unmerged work. Merge manually or run \`/gsd doctor fix\` to resolve.`,
|
|
361
|
+
severity: "warning",
|
|
362
|
+
blocksAuto: false,
|
|
363
|
+
});
|
|
268
364
|
// #4764 telemetry
|
|
269
365
|
try {
|
|
270
366
|
emitWorktreeOrphaned(basePath, milestoneId, {
|
|
@@ -300,6 +396,43 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode, gitDeps
|
|
|
300
396
|
completedMilestones = [];
|
|
301
397
|
}
|
|
302
398
|
for (const m of completedMilestones) {
|
|
399
|
+
if (!isClosedStatus(m.status)) {
|
|
400
|
+
if (seenMilestoneIds.has(m.id))
|
|
401
|
+
continue;
|
|
402
|
+
const worktreeEvidence = detectWorktreeEvidence(basePath, m.id, hasChanges);
|
|
403
|
+
if (!worktreeEvidence.dirty)
|
|
404
|
+
continue;
|
|
405
|
+
const message = strandedWorkMessage({
|
|
406
|
+
milestoneId: m.id,
|
|
407
|
+
commitsAhead: 0,
|
|
408
|
+
mainBranch,
|
|
409
|
+
dirtyWorktree: true,
|
|
410
|
+
worktreeDirExists: worktreeEvidence.dirExists,
|
|
411
|
+
recoveryMode: "worktree",
|
|
412
|
+
});
|
|
413
|
+
pushAction({
|
|
414
|
+
kind: "in-progress-stranded-work",
|
|
415
|
+
milestoneId: m.id,
|
|
416
|
+
commitsAhead: 0,
|
|
417
|
+
dirtyWorktree: true,
|
|
418
|
+
worktreeDirExists: worktreeEvidence.dirExists,
|
|
419
|
+
recoveryMode: "worktree",
|
|
420
|
+
message,
|
|
421
|
+
severity: "warning",
|
|
422
|
+
blocksAuto: true,
|
|
423
|
+
});
|
|
424
|
+
try {
|
|
425
|
+
emitWorktreeOrphaned(basePath, m.id, {
|
|
426
|
+
reason: "in-progress-unmerged",
|
|
427
|
+
commitsAhead: 0,
|
|
428
|
+
worktreeDirExists: worktreeEvidence.dirExists,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
catch (err) {
|
|
432
|
+
logWarning("engine", `worktree-orphaned telemetry failed for ${m.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
433
|
+
}
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
303
436
|
if (m.status !== "complete")
|
|
304
437
|
continue;
|
|
305
438
|
if (seenMilestoneIds.has(m.id))
|
|
@@ -332,17 +465,36 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode, gitDeps
|
|
|
332
465
|
if (existsSync(wtDir)) {
|
|
333
466
|
try {
|
|
334
467
|
rmSync(wtDir, { recursive: true, force: true });
|
|
335
|
-
|
|
468
|
+
pushAction({
|
|
469
|
+
kind: "complete-branchless-worktree",
|
|
470
|
+
milestoneId: m.id,
|
|
471
|
+
worktreeDirExists: true,
|
|
472
|
+
message: `Removed orphaned worktree directory for ${m.id} (branch already deleted).`,
|
|
473
|
+
severity: "info",
|
|
474
|
+
blocksAuto: false,
|
|
475
|
+
});
|
|
336
476
|
}
|
|
337
477
|
catch (err) {
|
|
338
478
|
warnings.push(`Failed to remove orphaned worktree directory for ${m.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
339
479
|
}
|
|
340
480
|
}
|
|
341
481
|
else {
|
|
342
|
-
|
|
482
|
+
pushAction({
|
|
483
|
+
kind: "complete-branchless-worktree",
|
|
484
|
+
milestoneId: m.id,
|
|
485
|
+
worktreeDirExists: true,
|
|
486
|
+
message: `Removed orphaned worktree directory for ${m.id} (branch already deleted).`,
|
|
487
|
+
severity: "info",
|
|
488
|
+
blocksAuto: false,
|
|
489
|
+
});
|
|
343
490
|
}
|
|
344
491
|
}
|
|
345
|
-
return {
|
|
492
|
+
return {
|
|
493
|
+
recovered,
|
|
494
|
+
warnings,
|
|
495
|
+
actions,
|
|
496
|
+
blockingStrandedWork: actions.find(isBlockingStrandedWorkAction) ?? null,
|
|
497
|
+
};
|
|
346
498
|
}
|
|
347
499
|
/**
|
|
348
500
|
* Pure decision function for picking which orphan milestone the auto-loop
|
|
@@ -679,17 +831,27 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
679
831
|
// was lost due to session ending between completion and teardown.
|
|
680
832
|
// Must run after DB open and before worktree entry.
|
|
681
833
|
let orphanAuditRecovered = false;
|
|
834
|
+
let strandedRecoveryActions = [];
|
|
835
|
+
let strandedRecoveryAction = null;
|
|
682
836
|
try {
|
|
683
837
|
const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode(base));
|
|
838
|
+
strandedRecoveryActions = auditResult.actions.filter(isBlockingStrandedWorkAction);
|
|
839
|
+
strandedRecoveryAction = strandedRecoveryActions[0] ?? null;
|
|
684
840
|
for (const msg of auditResult.recovered) {
|
|
685
841
|
ctx.ui.notify(`Orphan audit: ${msg}`, "info");
|
|
686
842
|
}
|
|
687
843
|
for (const msg of auditResult.warnings) {
|
|
688
|
-
|
|
844
|
+
const prefix = msg.startsWith("Stranded work") ? "" : "Orphan audit: ";
|
|
845
|
+
ctx.ui.notify(`${prefix}${msg}`, "warning");
|
|
689
846
|
}
|
|
690
847
|
if (auditResult.recovered.length > 0) {
|
|
691
848
|
orphanAuditRecovered = true;
|
|
692
|
-
debugLog("orphan-audit", {
|
|
849
|
+
debugLog("orphan-audit", {
|
|
850
|
+
recovered: auditResult.recovered,
|
|
851
|
+
warnings: auditResult.warnings,
|
|
852
|
+
strandedRecoveryAction,
|
|
853
|
+
strandedRecoveryActions,
|
|
854
|
+
});
|
|
693
855
|
}
|
|
694
856
|
}
|
|
695
857
|
catch (err) {
|
|
@@ -724,13 +886,6 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
724
886
|
logWarning("bootstrap", `orphaned preflight-stash audit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
725
887
|
}
|
|
726
888
|
let state = await deriveState(base);
|
|
727
|
-
if (process.env.GSD_HEADLESS === "1" &&
|
|
728
|
-
orphanAuditRecovered &&
|
|
729
|
-
!state.activeMilestone &&
|
|
730
|
-
state.phase === "complete") {
|
|
731
|
-
ctx.ui.notify("Auto-mode stopped (Recovered completed milestone cleanup; all milestones complete).", "info");
|
|
732
|
-
return releaseLockAndReturn();
|
|
733
|
-
}
|
|
734
889
|
// Stale worktree state recovery (#654)
|
|
735
890
|
if (state.activeMilestone &&
|
|
736
891
|
shouldUseWorktreeIsolation(base) &&
|
|
@@ -740,6 +895,28 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
740
895
|
state = await deriveState(wtPath);
|
|
741
896
|
}
|
|
742
897
|
}
|
|
898
|
+
const blockingStrandedRecoveryAction = state.activeMilestone
|
|
899
|
+
? strandedRecoveryActions.find((action) => action.milestoneId !== state.activeMilestone?.id) ?? strandedRecoveryAction
|
|
900
|
+
: strandedRecoveryAction;
|
|
901
|
+
if (blockingStrandedRecoveryAction) {
|
|
902
|
+
if (!state.activeMilestone) {
|
|
903
|
+
ctx.ui.notify(`Stranded work for ${blockingStrandedRecoveryAction.milestoneId} blocks auto-mode, but that milestone is not active in project state. Park or discard it explicitly before continuing.`, "error");
|
|
904
|
+
return releaseLockAndReturn();
|
|
905
|
+
}
|
|
906
|
+
if (state.activeMilestone.id !== blockingStrandedRecoveryAction.milestoneId) {
|
|
907
|
+
ctx.ui.notify(`Stranded work for ${blockingStrandedRecoveryAction.milestoneId} blocks auto-mode before ${state.activeMilestone.id}. Recover, park, or discard ${blockingStrandedRecoveryAction.milestoneId} explicitly before continuing.`, "error");
|
|
908
|
+
return releaseLockAndReturn();
|
|
909
|
+
}
|
|
910
|
+
strandedRecoveryAction = blockingStrandedRecoveryAction;
|
|
911
|
+
ctx.ui.notify(`Recovering stranded work for ${strandedRecoveryAction.milestoneId} before dispatching new units.`, "info");
|
|
912
|
+
}
|
|
913
|
+
if (process.env.GSD_HEADLESS === "1" &&
|
|
914
|
+
orphanAuditRecovered &&
|
|
915
|
+
!state.activeMilestone &&
|
|
916
|
+
state.phase === "complete") {
|
|
917
|
+
ctx.ui.notify("Auto-mode stopped (Recovered completed milestone cleanup; all milestones complete).", "info");
|
|
918
|
+
return releaseLockAndReturn();
|
|
919
|
+
}
|
|
743
920
|
// Milestone branch recovery (#601, #2358)
|
|
744
921
|
// Detect survivor milestone branches in both pre-planning and complete phases.
|
|
745
922
|
// In phase=complete, the milestone artifacts exist but finalization (merge,
|
|
@@ -768,7 +945,8 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
768
945
|
// The worktree/branch was created but the milestone only has CONTEXT-DRAFT.md.
|
|
769
946
|
// Route to the interactive discussion handler instead of falling through to
|
|
770
947
|
// auto-mode, which would immediately stop with "needs discussion".
|
|
771
|
-
if (
|
|
948
|
+
if (!strandedRecoveryAction &&
|
|
949
|
+
decideSurvivorAction(hasSurvivorBranch, state.phase) === "discuss") {
|
|
772
950
|
const { showSmartEntry } = await import("./guided-flow.js");
|
|
773
951
|
await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
|
|
774
952
|
invalidateAllCaches();
|
|
@@ -848,14 +1026,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
848
1026
|
const effectivePrefs = loadEffectiveGSDPreferences(base)?.preferences;
|
|
849
1027
|
const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
|
|
850
1028
|
const deepProjectStagePending = shouldRunDeepProjectSetup(state, effectivePrefs, base, { hasSurvivorBranch });
|
|
851
|
-
if (deepProjectStagePending) {
|
|
1029
|
+
if (deepProjectStagePending && !strandedRecoveryAction) {
|
|
852
1030
|
// Deep project-level setup runs before the first milestone exists. Let
|
|
853
1031
|
// the auto loop dispatch workflow-preferences / project / requirements
|
|
854
1032
|
// units instead of recursing back through showSmartEntry while this
|
|
855
1033
|
// bootstrap still holds the session lock.
|
|
856
1034
|
s.currentMilestoneId = null;
|
|
857
1035
|
}
|
|
858
|
-
if (!hasSurvivorBranch && !deepProjectStagePending) {
|
|
1036
|
+
if (!hasSurvivorBranch && !deepProjectStagePending && !strandedRecoveryAction) {
|
|
859
1037
|
// No active work — start a new milestone via discuss flow
|
|
860
1038
|
if (!state.activeMilestone || state.phase === "complete") {
|
|
861
1039
|
// Guard against recursive dialog loop (#1348):
|
|
@@ -917,7 +1095,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
917
1095
|
}
|
|
918
1096
|
}
|
|
919
1097
|
// Unreachable safety check
|
|
920
|
-
if (!state.activeMilestone && !deepProjectStagePending) {
|
|
1098
|
+
if (!state.activeMilestone && !deepProjectStagePending && !strandedRecoveryAction) {
|
|
921
1099
|
const { showSmartEntry } = await import("./guided-flow.js");
|
|
922
1100
|
await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
|
|
923
1101
|
return releaseLockAndReturn();
|
|
@@ -952,7 +1130,9 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
952
1130
|
s.resourceVersionOnStart = readResourceVersion();
|
|
953
1131
|
s.pendingQuickTasks = [];
|
|
954
1132
|
s.currentUnit = null;
|
|
955
|
-
s.currentMilestoneId ??=
|
|
1133
|
+
s.currentMilestoneId ??=
|
|
1134
|
+
strandedRecoveryAction?.milestoneId ??
|
|
1135
|
+
(deepProjectStagePending ? null : state.activeMilestone?.id ?? null);
|
|
956
1136
|
s.originalModelId = startModelSnapshot?.id ?? ctx.model?.id ?? null;
|
|
957
1137
|
s.originalModelProvider = startModelSnapshot?.provider ?? ctx.model?.provider ?? null;
|
|
958
1138
|
s.originalThinkingLevel = startThinkingSnapshot ?? null;
|
|
@@ -960,7 +1140,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
960
1140
|
registerSigtermHandler(base);
|
|
961
1141
|
// Capture integration branch
|
|
962
1142
|
if (s.currentMilestoneId) {
|
|
963
|
-
if (getIsolationMode(base) !== "none") {
|
|
1143
|
+
if (getIsolationMode(base) !== "none" || strandedRecoveryAction) {
|
|
964
1144
|
captureIntegrationBranch(base, s.currentMilestoneId);
|
|
965
1145
|
}
|
|
966
1146
|
setActiveMilestoneId(base, s.currentMilestoneId);
|
|
@@ -970,7 +1150,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
970
1150
|
// milestone/<MID>. Auto-checkout back to the integration branch.
|
|
971
1151
|
const isolationMode = getIsolationMode(base);
|
|
972
1152
|
const isRepo = nativeIsRepo(base);
|
|
973
|
-
if (isolationMode === "none" && isRepo) {
|
|
1153
|
+
if (isolationMode === "none" && isRepo && !strandedRecoveryAction) {
|
|
974
1154
|
try {
|
|
975
1155
|
const currentBranch = nativeGetCurrentBranch(base);
|
|
976
1156
|
const integrationBranch = nativeDetectMainBranch(base);
|
|
@@ -1001,12 +1181,15 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
1001
1181
|
return symlinkRe.test(p);
|
|
1002
1182
|
};
|
|
1003
1183
|
if (s.currentMilestoneId &&
|
|
1004
|
-
getIsolationMode(base) !== "none" &&
|
|
1184
|
+
(getIsolationMode(base) !== "none" || strandedRecoveryAction?.recoveryMode) &&
|
|
1005
1185
|
!detectWorktreeName(base) &&
|
|
1006
1186
|
!isUnderGsdWorktrees(base)) {
|
|
1007
|
-
const
|
|
1008
|
-
|
|
1009
|
-
|
|
1187
|
+
const lifecycle = buildLifecycle();
|
|
1188
|
+
const enterResult = strandedRecoveryAction?.recoveryMode
|
|
1189
|
+
? lifecycle.adoptStrandedMilestone(s.currentMilestoneId, base, { notify: ctx.ui.notify.bind(ctx.ui) }, { mode: strandedRecoveryAction.recoveryMode })
|
|
1190
|
+
: lifecycle.enterMilestone(s.currentMilestoneId, {
|
|
1191
|
+
notify: ctx.ui.notify.bind(ctx.ui),
|
|
1192
|
+
});
|
|
1010
1193
|
if (!enterResult.ok) {
|
|
1011
1194
|
s.active = false;
|
|
1012
1195
|
if (enterResult.reason === "lease-conflict") {
|
|
@@ -37,6 +37,8 @@ import { runGSDDoctor, rebuildState } from "./doctor.js";
|
|
|
37
37
|
import { preDispatchHealthGate, recordHealthSnapshot, resetProactiveHealing, setLevelChangeCallback, } from "./doctor-proactive.js";
|
|
38
38
|
import { clearSkillSnapshot } from "./skill-discovery.js";
|
|
39
39
|
import { captureAvailableSkills, resetSkillTelemetry, } from "./skill-telemetry.js";
|
|
40
|
+
import { getInstalledSkillNames } from "./skills.js";
|
|
41
|
+
import { effectiveSkillNamesForUnit } from "./skill-scope.js";
|
|
40
42
|
import { getRtkSessionSavings } from "../shared/rtk-session-stats.js";
|
|
41
43
|
import { deactivateGSD } from "../shared/gsd-phase-state.js";
|
|
42
44
|
import { initMetrics, resetMetrics, getLedger, getProjectTotals, filterUnitsForMilestone, formatCost, formatTokenCount, } from "./metrics.js";
|
|
@@ -2040,7 +2042,10 @@ function buildLoopDeps(pi) {
|
|
|
2040
2042
|
autoCommitUnit,
|
|
2041
2043
|
recordOutcome,
|
|
2042
2044
|
writeLock,
|
|
2043
|
-
captureAvailableSkills
|
|
2045
|
+
captureAvailableSkills: () => {
|
|
2046
|
+
const unitType = s.currentUnit?.type;
|
|
2047
|
+
captureAvailableSkills(effectiveSkillNamesForUnit(unitType, getInstalledSkillNames()));
|
|
2048
|
+
},
|
|
2044
2049
|
ensurePreconditions,
|
|
2045
2050
|
updateSliceProgressCache,
|
|
2046
2051
|
// Model selection + supervision
|
|
@@ -678,8 +678,9 @@ export function registerDbTools(pi) {
|
|
|
678
678
|
promptSnippet: "Complete a GSD task (DB write + summary render + checkbox toggle)",
|
|
679
679
|
promptGuidelines: [
|
|
680
680
|
"Use gsd_task_complete (or gsd_complete_task) when a task is finished and needs to be recorded.",
|
|
681
|
-
"
|
|
682
|
-
"
|
|
681
|
+
"Include verification whenever possible. If verification is omitted, the executor derives it from verificationEvidence when possible.",
|
|
682
|
+
"verificationEvidence is an array of objects with command, exitCode, verdict, durationMs.",
|
|
683
|
+
"The tool validates required fields and returns an error message if verification cannot be derived.",
|
|
683
684
|
"On success, returns the summaryPath where the SUMMARY.md was written.",
|
|
684
685
|
"Idempotent — calling with the same params twice will upsert (INSERT OR REPLACE) without error.",
|
|
685
686
|
],
|
|
@@ -690,7 +691,7 @@ export function registerDbTools(pi) {
|
|
|
690
691
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
691
692
|
oneLiner: Type.String({ description: "One-line summary of what was accomplished" }),
|
|
692
693
|
narrative: Type.String({ description: "Detailed narrative of what happened during the task" }),
|
|
693
|
-
verification: Type.String({ description: "What was verified and how — commands run, tests passed, behavior confirmed" }),
|
|
694
|
+
verification: Type.Optional(Type.String({ description: "What was verified and how — commands run, tests passed, behavior confirmed. If omitted, derived from verificationEvidence when possible." })),
|
|
694
695
|
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
695
696
|
deviations: Type.Optional(Type.String({ description: "Deviations from the task plan, or 'None.'" })),
|
|
696
697
|
knownIssues: Type.Optional(Type.String({ description: "Known issues discovered but not fixed, or 'None.'" })),
|
|
@@ -36,8 +36,13 @@ export function registerExecTools(pi) {
|
|
|
36
36
|
"Need persisted output? Read the stdout_path returned in details (file on local disk).",
|
|
37
37
|
],
|
|
38
38
|
parameters: Type.Object({
|
|
39
|
-
runtime: Type.
|
|
40
|
-
|
|
39
|
+
runtime: Type.Optional(Type.String({
|
|
40
|
+
description: "Optional interpreter. Defaults to bash. Supported: bash, node, python; sh/shell, js/nodejs, and py/python3 aliases are accepted.",
|
|
41
|
+
})),
|
|
42
|
+
script: Type.Optional(Type.String({ description: "Script body. Keep output small (log the finding, not the data)." })),
|
|
43
|
+
command: Type.Optional(Type.String({ description: "Alias for script; defaults to bash when runtime is omitted." })),
|
|
44
|
+
cmd: Type.Optional(Type.String({ description: "Short alias for script." })),
|
|
45
|
+
code: Type.Optional(Type.String({ description: "Alias for script, useful for node/python snippets." })),
|
|
41
46
|
purpose: Type.Optional(Type.String({ description: "Short label recorded in meta.json for later review." })),
|
|
42
47
|
timeout_ms: Type.Optional(Type.Number({
|
|
43
48
|
description: "Per-invocation timeout (ms). Capped at 600000. Default from preferences.",
|
|
@@ -21,6 +21,31 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
21
21
|
// EventEmitter does not buffer events for late subscribers.
|
|
22
22
|
import { initCmuxEventListeners } from "../../cmux/index.js";
|
|
23
23
|
export { writeCrashLog } from "./crash-log.js";
|
|
24
|
+
// Pipe-closed storm guard. #99/#101 stopped EPIPE from flooding ~/.gsd/crash,
|
|
25
|
+
// but a persistently-broken output pipe whose `destroyed`/`writableEnded` flags
|
|
26
|
+
// never flip is still swallowed on every write — a tight, progress-free CPU
|
|
27
|
+
// spin. If the pipe-closed error fires in a tight loop the pipe is gone for
|
|
28
|
+
// good; exit cleanly instead.
|
|
29
|
+
const EPIPE_STORM_THRESHOLD = 100;
|
|
30
|
+
const EPIPE_STORM_WINDOW_MS = 10_000;
|
|
31
|
+
let epipeCount = 0;
|
|
32
|
+
let epipeWindowStart = 0;
|
|
33
|
+
/** Write to stderr without ever re-throwing — stderr can EPIPE too, which would
|
|
34
|
+
* re-enter this handler and re-loop. */
|
|
35
|
+
function safeStderr(msg) {
|
|
36
|
+
try {
|
|
37
|
+
process.stderr.write(msg);
|
|
38
|
+
}
|
|
39
|
+
catch { /* stderr is also broken; nothing we can do */ }
|
|
40
|
+
}
|
|
41
|
+
/** A peer closing the read end of a pipe mid-write surfaces differently per
|
|
42
|
+
* platform: POSIX throws `EPIPE`; Windows throws `Error: write EOF` (or
|
|
43
|
+
* `read EOF`) with no `code` set, from node:internal/stream_base_commons.
|
|
44
|
+
* Both are the same logical condition and must be treated as recoverable —
|
|
45
|
+
* otherwise the Windows EOF variant escapes to the uncaught-exception path
|
|
46
|
+
* and crashes auto-mode workers mid-iteration (#181). ECONNRESET is NOT
|
|
47
|
+
* included here: it commonly comes from network sockets (#182 follow-up) and
|
|
48
|
+
* is a real error that should surface rather than be silently swallowed. */
|
|
24
49
|
function isPipeClosedError(err) {
|
|
25
50
|
const errno = err.code;
|
|
26
51
|
if (errno === "EPIPE")
|
|
@@ -30,7 +55,7 @@ function isPipeClosedError(err) {
|
|
|
30
55
|
}
|
|
31
56
|
export function handleRecoverableExtensionProcessError(err) {
|
|
32
57
|
if (err.message.includes("ProcessTransport is not ready for writing")) {
|
|
33
|
-
|
|
58
|
+
safeStderr(`[gsd] swallowed dead transport control write: ${err.message}\n`);
|
|
34
59
|
return true;
|
|
35
60
|
}
|
|
36
61
|
if (isPipeClosedError(err)) {
|
|
@@ -40,24 +65,33 @@ export function handleRecoverableExtensionProcessError(err) {
|
|
|
40
65
|
if (stdoutGone) {
|
|
41
66
|
process.exit(0);
|
|
42
67
|
}
|
|
43
|
-
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
if (now - epipeWindowStart > EPIPE_STORM_WINDOW_MS) {
|
|
70
|
+
epipeWindowStart = now;
|
|
71
|
+
epipeCount = 0;
|
|
72
|
+
}
|
|
73
|
+
if (++epipeCount > EPIPE_STORM_THRESHOLD) {
|
|
74
|
+
safeStderr(`[gsd] ${tag} storm (${epipeCount} within ${EPIPE_STORM_WINDOW_MS}ms) — output pipe is gone; exiting.\n`);
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
safeStderr(`[gsd] swallowed ${tag} (syscall=${err.syscall ?? "?"})\n`);
|
|
44
78
|
return true;
|
|
45
79
|
}
|
|
46
80
|
if (err.code === "EIO") {
|
|
47
81
|
const syscall = err.syscall;
|
|
48
82
|
if (syscall === "read") {
|
|
49
|
-
|
|
83
|
+
safeStderr(`[gsd] EIO: ${err.message}\n`);
|
|
50
84
|
return true;
|
|
51
85
|
}
|
|
52
86
|
}
|
|
53
87
|
if (err.code === "ENOENT") {
|
|
54
88
|
const syscall = err.syscall;
|
|
55
89
|
if (syscall?.startsWith("spawn")) {
|
|
56
|
-
|
|
90
|
+
safeStderr(`[gsd] spawn ENOENT: ${err.path ?? "unknown"} — command not found\n`);
|
|
57
91
|
return true;
|
|
58
92
|
}
|
|
59
93
|
if (syscall === "uv_cwd") {
|
|
60
|
-
|
|
94
|
+
safeStderr(`[gsd] ENOENT (${syscall}): ${err.message}\n`);
|
|
61
95
|
return true;
|
|
62
96
|
}
|
|
63
97
|
}
|