@opengsd/gsd-pi 1.0.2-dev.867e002 → 1.0.2-dev.cce3612
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/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 +18 -2
- 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/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/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/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 +8 -8
- 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 +8 -8
- 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/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.js +1 -1
- 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 +37 -2
- 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/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/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-recovery.test.ts +41 -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/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/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 → orfEoZqDIo6Be_Z9ZFipD}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{praHP_OATcjBkvAVejjGK → orfEoZqDIo6Be_Z9ZFipD}/_ssgManifest.js +0 -0
|
@@ -15,16 +15,15 @@ import { delimiter, join } from "node:path";
|
|
|
15
15
|
import { AuthStorage } from "@gsd/pi-coding-agent";
|
|
16
16
|
import { getEnvApiKey } from "@gsd/pi-ai";
|
|
17
17
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
18
|
-
import { getAuthPath, PROVIDER_REGISTRY } from "./key-manager.js";
|
|
18
|
+
import { getAuthPath, PROVIDER_REGISTRY, supportsBrowserOAuth } from "./key-manager.js";
|
|
19
19
|
import { homedir } from "node:os";
|
|
20
20
|
// ── Provider routing constants ────────────────────────────────────────────────
|
|
21
21
|
/**
|
|
22
22
|
* Providers that use external CLI authentication (not API keys).
|
|
23
|
-
*
|
|
23
|
+
* When explicitly selected, the provider's own CLI/session owns auth.
|
|
24
24
|
*/
|
|
25
25
|
const CLI_AUTH_PROVIDERS = new Set([
|
|
26
26
|
"claude-code",
|
|
27
|
-
"openai-codex",
|
|
28
27
|
"google-gemini-cli",
|
|
29
28
|
"google-antigravity",
|
|
30
29
|
]);
|
|
@@ -126,23 +125,26 @@ function collectConfiguredModelProviders() {
|
|
|
126
125
|
* Used for lightweight binary-presence checks (PATH scan, no subprocess).
|
|
127
126
|
*/
|
|
128
127
|
const CLI_BINARY_MAP = {
|
|
129
|
-
"claude-code": "claude",
|
|
130
|
-
"
|
|
131
|
-
"google-
|
|
132
|
-
"google-antigravity": "antigravity",
|
|
128
|
+
"claude-code": ["claude", "claude-code"],
|
|
129
|
+
"google-gemini-cli": ["gemini"],
|
|
130
|
+
"google-antigravity": ["agy"],
|
|
133
131
|
};
|
|
132
|
+
const CLI_AUTH_PATH_CHECK_PROVIDERS = new Set([
|
|
133
|
+
"google-gemini-cli",
|
|
134
|
+
"google-antigravity",
|
|
135
|
+
]);
|
|
134
136
|
/**
|
|
135
137
|
* Check if a CLI provider's binary exists anywhere in PATH.
|
|
136
138
|
* Fast filesystem scan — no subprocess, no network, sub-1ms.
|
|
137
139
|
*/
|
|
138
140
|
function isCliBinaryInPath(providerId) {
|
|
139
|
-
const
|
|
140
|
-
if (!
|
|
141
|
+
const binaries = CLI_BINARY_MAP[providerId];
|
|
142
|
+
if (!binaries)
|
|
141
143
|
return false;
|
|
142
144
|
const pathDirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
143
145
|
// On Windows, command shims are commonly installed as .cmd/.exe/.bat/.com.
|
|
144
146
|
// Scan PATHEXT candidates in addition to the bare binary name.
|
|
145
|
-
const executableNames = [
|
|
147
|
+
const executableNames = [...binaries];
|
|
146
148
|
if (process.platform === "win32") {
|
|
147
149
|
const rawPathExt = process.env.PATHEXT
|
|
148
150
|
?.split(";")
|
|
@@ -150,10 +152,12 @@ function isCliBinaryInPath(providerId) {
|
|
|
150
152
|
.filter(Boolean) ?? [];
|
|
151
153
|
const normalizedPathExt = rawPathExt.map(ext => ext.startsWith(".") ? ext.toLowerCase() : `.${ext.toLowerCase()}`);
|
|
152
154
|
const defaultExt = [".exe", ".cmd", ".bat", ".com"];
|
|
153
|
-
for (const
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
executableNames.
|
|
155
|
+
for (const binary of binaries) {
|
|
156
|
+
for (const ext of [...normalizedPathExt, ...defaultExt]) {
|
|
157
|
+
const candidate = `${binary}${ext}`;
|
|
158
|
+
if (!executableNames.includes(candidate))
|
|
159
|
+
executableNames.push(candidate);
|
|
160
|
+
}
|
|
157
161
|
}
|
|
158
162
|
}
|
|
159
163
|
return pathDirs.some(dir => executableNames.some(name => existsSync(join(dir, name))));
|
|
@@ -185,11 +189,6 @@ function hasModelsJsonApiKey(providerId) {
|
|
|
185
189
|
}
|
|
186
190
|
function resolveKey(providerId) {
|
|
187
191
|
const info = PROVIDER_REGISTRY.find(p => p.id === providerId);
|
|
188
|
-
// claude-code never stores credentials in auth.json — GSD delegates entirely to
|
|
189
|
-
// the local CLI binary. Presence of the binary in PATH is the only signal.
|
|
190
|
-
if (providerId === "claude-code") {
|
|
191
|
-
return { found: isCliBinaryInPath("claude-code"), source: "env", backedOff: false };
|
|
192
|
-
}
|
|
193
192
|
if (providerId === "anthropic-vertex" && process.env.ANTHROPIC_VERTEX_PROJECT_ID) {
|
|
194
193
|
return { found: true, source: "env", backedOff: false };
|
|
195
194
|
}
|
|
@@ -201,7 +200,16 @@ function resolveKey(providerId) {
|
|
|
201
200
|
const creds = auth.getCredentialsForProvider(providerId);
|
|
202
201
|
if (creds.length > 0) {
|
|
203
202
|
// Filter out empty placeholder keys (from skipped onboarding)
|
|
204
|
-
const hasRealKey = creds.some(c =>
|
|
203
|
+
const hasRealKey = creds.some(c => {
|
|
204
|
+
if (c.type === "oauth")
|
|
205
|
+
return true;
|
|
206
|
+
if (c.type !== "api_key")
|
|
207
|
+
return false;
|
|
208
|
+
const key = c.key?.trim();
|
|
209
|
+
if (!key)
|
|
210
|
+
return false;
|
|
211
|
+
return !(CLI_AUTH_PROVIDERS.has(providerId) && key === "cli");
|
|
212
|
+
});
|
|
205
213
|
if (hasRealKey) {
|
|
206
214
|
return {
|
|
207
215
|
found: true,
|
|
@@ -229,6 +237,11 @@ function resolveKey(providerId) {
|
|
|
229
237
|
if (hasModelsJsonApiKey(providerId)) {
|
|
230
238
|
return { found: true, source: "models.json", backedOff: false };
|
|
231
239
|
}
|
|
240
|
+
// Cross-provider routes can use a local CLI when it is installed. Explicit
|
|
241
|
+
// external CLI provider selections are handled in checkLlmProviders() below.
|
|
242
|
+
if (CLI_AUTH_PROVIDERS.has(providerId) && isCliBinaryInPath(providerId)) {
|
|
243
|
+
return { found: true, source: "env", backedOff: false };
|
|
244
|
+
}
|
|
232
245
|
return { found: false, source: "none", backedOff: false };
|
|
233
246
|
}
|
|
234
247
|
// ── Individual check groups ────────────────────────────────────────────────────
|
|
@@ -236,15 +249,32 @@ function checkLlmProviders() {
|
|
|
236
249
|
const required = collectConfiguredModelProviders();
|
|
237
250
|
const results = [];
|
|
238
251
|
for (const providerId of required) {
|
|
239
|
-
// CLI-authenticated providers don't need API keys
|
|
252
|
+
// CLI-authenticated providers don't need API keys. The provider's own
|
|
253
|
+
// request path validates CLI sessions when it is used.
|
|
240
254
|
if (CLI_AUTH_PROVIDERS.has(providerId)) {
|
|
241
255
|
const info = PROVIDER_REGISTRY.find(p => p.id === providerId);
|
|
256
|
+
const label = info?.label ?? providerId;
|
|
257
|
+
if (CLI_AUTH_PATH_CHECK_PROVIDERS.has(providerId) && !isCliBinaryInPath(providerId)) {
|
|
258
|
+
const binaries = CLI_BINARY_MAP[providerId]?.map(binary => `\`${binary}\``).join(" or ");
|
|
259
|
+
results.push({
|
|
260
|
+
name: providerId,
|
|
261
|
+
label,
|
|
262
|
+
category: "llm",
|
|
263
|
+
status: "error",
|
|
264
|
+
message: `${label} — CLI not found`,
|
|
265
|
+
detail: binaries
|
|
266
|
+
? `Install ${label} and ensure ${binaries} is on PATH`
|
|
267
|
+
: `Install ${label} and ensure its CLI is on PATH`,
|
|
268
|
+
required: true,
|
|
269
|
+
});
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
242
272
|
results.push({
|
|
243
273
|
name: providerId,
|
|
244
|
-
label
|
|
274
|
+
label,
|
|
245
275
|
category: "llm",
|
|
246
276
|
status: "ok",
|
|
247
|
-
message: `${
|
|
277
|
+
message: `${label} — CLI auth (no key needed)`,
|
|
248
278
|
required: true,
|
|
249
279
|
});
|
|
250
280
|
continue;
|
|
@@ -282,7 +312,7 @@ function checkLlmProviders() {
|
|
|
282
312
|
message: `${label} — not configured`,
|
|
283
313
|
detail: providerId === "anthropic-vertex"
|
|
284
314
|
? "Set ANTHROPIC_VERTEX_PROJECT_ID and authenticate with Google ADC"
|
|
285
|
-
: info
|
|
315
|
+
: info && supportsBrowserOAuth(info)
|
|
286
316
|
? `Run /gsd keys to authenticate`
|
|
287
317
|
: `Set ${envVar} or run /gsd keys`,
|
|
288
318
|
required: true,
|
|
@@ -480,13 +480,18 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
480
480
|
catch {
|
|
481
481
|
continue;
|
|
482
482
|
}
|
|
483
|
+
if (entry === "parallel-research")
|
|
484
|
+
continue;
|
|
483
485
|
if (!knownSliceIds.has(entry)) {
|
|
486
|
+
const quarantineExample = `.gsd/quarantine/milestones/${milestoneId}/slices/${entry}-manual-review`;
|
|
484
487
|
issues.push({
|
|
485
488
|
severity: "warning",
|
|
486
489
|
code: "orphaned_slice_directory",
|
|
487
490
|
scope: "milestone",
|
|
488
491
|
unitId: milestoneId,
|
|
489
|
-
message: `Directory "${entry}" exists in ${milestoneId}/slices/ but is not referenced in the roadmap
|
|
492
|
+
message: `Directory "${entry}" exists in ${milestoneId}/slices/ but is not referenced in the roadmap or DB. ` +
|
|
493
|
+
`Review it; if stale, move or delete it. To preserve it, move it under ${quarantineExample}. ` +
|
|
494
|
+
"If it contains work to keep, copy or merge that content into a DB-backed slice before resuming.",
|
|
490
495
|
file: `${relMilestonePath(basePath, milestoneId)}/slices/${entry}`,
|
|
491
496
|
fixable: false,
|
|
492
497
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// File Purpose: Detect and reconcile unresolved Git conflict state before automation runs.
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
|
-
import { join } from "node:path";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
6
|
import { autoResolveSafeConflictPaths } from "./git-conflict-resolve.js";
|
|
7
7
|
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
8
8
|
import { abortAndReset } from "./git-self-heal.js";
|
|
@@ -10,6 +10,23 @@ import { logWarning } from "./workflow-logger.js";
|
|
|
10
10
|
function splitZeroDelimited(output) {
|
|
11
11
|
return output.split("\0").filter(Boolean);
|
|
12
12
|
}
|
|
13
|
+
function hasGitMarker(basePath) {
|
|
14
|
+
try {
|
|
15
|
+
let dir = resolve(basePath);
|
|
16
|
+
for (let i = 0; i < 30; i++) {
|
|
17
|
+
if (existsSync(join(dir, ".git")))
|
|
18
|
+
return true;
|
|
19
|
+
const parent = dirname(dir);
|
|
20
|
+
if (parent === dir)
|
|
21
|
+
break;
|
|
22
|
+
dir = parent;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Fall through to the git probes, which will report unknown on failure.
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
13
30
|
export function listUnmergedGitPaths(basePath) {
|
|
14
31
|
try {
|
|
15
32
|
const output = spawnSync("git", ["diff", "--name-only", "--diff-filter=U", "-z"], {
|
|
@@ -57,6 +74,14 @@ export function listMergeStateBlockers(basePath) {
|
|
|
57
74
|
return MERGE_STATE_MARKERS.filter((marker) => existsSync(join(gitDir, marker)));
|
|
58
75
|
}
|
|
59
76
|
export function probeGitConflictState(basePath) {
|
|
77
|
+
if (!hasGitMarker(basePath)) {
|
|
78
|
+
return {
|
|
79
|
+
status: "clean",
|
|
80
|
+
unmerged: [],
|
|
81
|
+
checkFailures: [],
|
|
82
|
+
mergeStateBlockers: [],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
60
85
|
const unmerged = listUnmergedGitPaths(basePath);
|
|
61
86
|
if (unmerged === null) {
|
|
62
87
|
return {
|
|
@@ -934,7 +934,7 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType,
|
|
|
934
934
|
if (unitType)
|
|
935
935
|
setGuidedUnitContext(projectRoot, unitType);
|
|
936
936
|
try {
|
|
937
|
-
pi.sendMessage({
|
|
937
|
+
await pi.sendMessage({
|
|
938
938
|
customType,
|
|
939
939
|
content: buildWorkflowDispatchContent({ workflow, workflowPath, task: note }),
|
|
940
940
|
display: false,
|
|
@@ -946,10 +946,9 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType,
|
|
|
946
946
|
}
|
|
947
947
|
}
|
|
948
948
|
finally {
|
|
949
|
-
// Restore full tool
|
|
950
|
-
//
|
|
951
|
-
//
|
|
952
|
-
// block ensures restoration even if sendMessage throws.
|
|
949
|
+
// Restore full tool/skill surface after the turn completes. Awaiting
|
|
950
|
+
// sendMessage ensures scoped skills stay in _baseSystemPrompt through
|
|
951
|
+
// before_agent_start (#3628, skill token savings).
|
|
953
952
|
restoreGsdWorkflowTools(pi, savedTools);
|
|
954
953
|
}
|
|
955
954
|
}
|
|
@@ -1045,7 +1044,7 @@ function buildHeadlessDiscussPrompt(nextId, seedContext, _basePath) {
|
|
|
1045
1044
|
* Run preparation phase if enabled, then build the discuss prompt.
|
|
1046
1045
|
* Preparation analyzes the codebase and prior context, injecting the results
|
|
1047
1046
|
* as supplementary context into the standard discuss template. The discuss
|
|
1048
|
-
* template drives the conversation
|
|
1047
|
+
* template drives the conversation with a variable vision opener, while
|
|
1049
1048
|
* the preparation briefs give the agent grounding in the existing codebase.
|
|
1050
1049
|
*
|
|
1051
1050
|
* @param ctx - Extension command context with UI for progress notifications
|
|
@@ -12,18 +12,18 @@ import { getErrorMessage } from "./error-utils.js";
|
|
|
12
12
|
import { gsdHome } from "./gsd-home.js";
|
|
13
13
|
export const PROVIDER_REGISTRY = [
|
|
14
14
|
// LLM Providers
|
|
15
|
-
{ id: "anthropic", label: "Anthropic (Claude)", category: "llm", envVar: "ANTHROPIC_API_KEY", prefixes: ["sk-ant-"],
|
|
15
|
+
{ id: "anthropic", label: "Anthropic (Claude)", category: "llm", envVar: "ANTHROPIC_API_KEY", prefixes: ["sk-ant-"], authMode: "apiKey", dashboardUrl: "console.anthropic.com" },
|
|
16
16
|
// Claude Code CLI: routes through the local `claude` binary — no API key,
|
|
17
17
|
// authentication is handled by the CLI's own OAuth flow.
|
|
18
18
|
// Referenced by doctor-providers.ts, auto-model-selection.ts, and others;
|
|
19
19
|
// must be in the canonical registry so all consumers see the same catalog.
|
|
20
20
|
// See: https://github.com/open-gsd/gsd-pi/issues/4541
|
|
21
|
-
{ id: "claude-code", label: "Claude Code CLI", category: "llm",
|
|
21
|
+
{ id: "claude-code", label: "Claude Code CLI", category: "llm", authMode: "externalCli" },
|
|
22
22
|
{ id: "openai", label: "OpenAI", category: "llm", envVar: "OPENAI_API_KEY", prefixes: ["sk-"], dashboardUrl: "platform.openai.com/api-keys" },
|
|
23
|
-
{ id: "github-copilot", label: "GitHub Copilot", category: "llm", envVar: "GITHUB_TOKEN",
|
|
24
|
-
{ id: "openai-codex", label: "ChatGPT Plus/Pro (Codex)", category: "llm",
|
|
25
|
-
{ id: "google-gemini-cli", label: "Google Gemini CLI", category: "llm",
|
|
26
|
-
{ id: "google-antigravity", label: "Antigravity", category: "llm",
|
|
23
|
+
{ id: "github-copilot", label: "GitHub Copilot", category: "llm", envVar: "GITHUB_TOKEN", authMode: "browserOAuth" },
|
|
24
|
+
{ id: "openai-codex", label: "ChatGPT Plus/Pro (Codex)", category: "llm", authMode: "browserOAuth" },
|
|
25
|
+
{ id: "google-gemini-cli", label: "Google Gemini CLI", category: "llm", authMode: "externalCli" },
|
|
26
|
+
{ id: "google-antigravity", label: "Antigravity", category: "llm", authMode: "externalCli" },
|
|
27
27
|
{ id: "google", label: "Google (Gemini)", category: "llm", envVar: "GEMINI_API_KEY", dashboardUrl: "aistudio.google.com/apikey" },
|
|
28
28
|
{ id: "groq", label: "Groq", category: "llm", envVar: "GROQ_API_KEY", dashboardUrl: "console.groq.com" },
|
|
29
29
|
{ id: "xai", label: "xAI (Grok)", category: "llm", envVar: "XAI_API_KEY", dashboardUrl: "console.x.ai" },
|
|
@@ -49,6 +49,20 @@ export const PROVIDER_REGISTRY = [
|
|
|
49
49
|
{ id: "telegram_bot", label: "Telegram Bot", category: "remote", envVar: "TELEGRAM_BOT_TOKEN" },
|
|
50
50
|
];
|
|
51
51
|
// ─── Utilities ──────────────────────────────────────────────────────────────────
|
|
52
|
+
export function getProviderAuthMode(provider) {
|
|
53
|
+
return provider.authMode ?? "apiKey";
|
|
54
|
+
}
|
|
55
|
+
export function supportsBrowserOAuth(provider) {
|
|
56
|
+
return getProviderAuthMode(provider) === "browserOAuth";
|
|
57
|
+
}
|
|
58
|
+
export function supportsStoredApiKey(provider) {
|
|
59
|
+
const mode = getProviderAuthMode(provider);
|
|
60
|
+
if (mode === "externalCli" || mode === "cloudIdentity" || mode === "none")
|
|
61
|
+
return false;
|
|
62
|
+
if (mode === "browserOAuth")
|
|
63
|
+
return Boolean(provider.envVar || provider.prefixes?.length);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
52
66
|
/**
|
|
53
67
|
* Mask an API key for display: show first 4 + last 4 chars.
|
|
54
68
|
* Keys shorter than 12 chars show only first 2 + last 2.
|
|
@@ -79,11 +93,14 @@ export function formatDuration(ms) {
|
|
|
79
93
|
/**
|
|
80
94
|
* Describe a credential's type and status.
|
|
81
95
|
*/
|
|
82
|
-
export function describeCredential(cred) {
|
|
96
|
+
export function describeCredential(cred, provider) {
|
|
83
97
|
if (cred.type === "api_key") {
|
|
84
98
|
const apiCred = cred;
|
|
85
99
|
if (!apiCred.key)
|
|
86
100
|
return "empty key";
|
|
101
|
+
if (apiCred.key === "cli" && provider && getProviderAuthMode(provider) === "externalCli") {
|
|
102
|
+
return "external CLI";
|
|
103
|
+
}
|
|
87
104
|
return `API key (${maskKey(apiCred.key)})`;
|
|
88
105
|
}
|
|
89
106
|
if (cred.type === "oauth") {
|
|
@@ -129,7 +146,7 @@ export function getAllKeyStatuses(auth) {
|
|
|
129
146
|
const firstCred = creds[0];
|
|
130
147
|
const desc = creds.length > 1
|
|
131
148
|
? `${creds.length} keys (round-robin)`
|
|
132
|
-
: describeCredential(firstCred);
|
|
149
|
+
: describeCredential(firstCred, provider);
|
|
133
150
|
return {
|
|
134
151
|
provider,
|
|
135
152
|
configured: true,
|
|
@@ -236,9 +253,20 @@ export async function handleAddKey(providerArg, ctx, auth) {
|
|
|
236
253
|
return false;
|
|
237
254
|
provider = PROVIDER_REGISTRY[idx];
|
|
238
255
|
}
|
|
239
|
-
|
|
240
|
-
if (
|
|
241
|
-
|
|
256
|
+
const authMode = getProviderAuthMode(provider);
|
|
257
|
+
if (authMode === "externalCli") {
|
|
258
|
+
ctx.ui.notify(`${provider.label} is authenticated by its own local CLI. ` +
|
|
259
|
+
`Sign in with that CLI first, then run /login to activate it in GSD.`, "info");
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
if (authMode === "cloudIdentity") {
|
|
263
|
+
ctx.ui.notify(`${provider.label} uses cloud identity credentials. Configure the provider's cloud CLI or environment, then restart GSD.`, "info");
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
if (supportsBrowserOAuth(provider)) {
|
|
267
|
+
const methods = supportsStoredApiKey(provider)
|
|
268
|
+
? ["API token/key", "Browser login (OAuth)"]
|
|
269
|
+
: ["Browser login (OAuth)"];
|
|
242
270
|
const method = await ctx.ui.select(`${provider.label} — how do you want to authenticate?`, methods);
|
|
243
271
|
if (!method || typeof method !== "string")
|
|
244
272
|
return false;
|
|
@@ -248,6 +276,10 @@ export async function handleAddKey(providerArg, ctx, auth) {
|
|
|
248
276
|
return false;
|
|
249
277
|
}
|
|
250
278
|
}
|
|
279
|
+
if (!supportsStoredApiKey(provider)) {
|
|
280
|
+
ctx.ui.notify(`${provider.label} does not accept a GSD-stored API key. Use /login.`, "info");
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
251
283
|
// API key input
|
|
252
284
|
const input = await ctx.ui.input(`API key for ${provider.label}:`, provider.envVar ? `or set ${provider.envVar} env var` : "paste your key here");
|
|
253
285
|
if (input === null || input === undefined)
|
|
@@ -309,7 +341,7 @@ export async function handleRemoveKey(providerArg, ctx, auth) {
|
|
|
309
341
|
}
|
|
310
342
|
// Multi-key handling
|
|
311
343
|
if (creds.length > 1) {
|
|
312
|
-
const options = creds.map((c, i) => `[${i + 1}] ${describeCredential(c)}`);
|
|
344
|
+
const options = creds.map((c, i) => `[${i + 1}] ${describeCredential(c, provider)}`);
|
|
313
345
|
options.push("Remove all");
|
|
314
346
|
const choice = await ctx.ui.select(`${provider.label} has ${creds.length} keys. Remove which?`, options);
|
|
315
347
|
if (!choice || typeof choice !== "string")
|
|
@@ -330,7 +362,7 @@ export async function handleRemoveKey(providerArg, ctx, auth) {
|
|
|
330
362
|
}
|
|
331
363
|
}
|
|
332
364
|
else {
|
|
333
|
-
const confirmed = await ctx.ui.confirm("Remove key?", `Remove ${describeCredential(creds[0])} for ${provider.label}?`);
|
|
365
|
+
const confirmed = await ctx.ui.confirm("Remove key?", `Remove ${describeCredential(creds[0], provider)} for ${provider.label}?`);
|
|
334
366
|
if (!confirmed)
|
|
335
367
|
return false;
|
|
336
368
|
auth.remove(provider.id);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { gsdRoot } from "./paths.js";
|
|
3
|
+
import { readEvents } from "./workflow-events.js";
|
|
4
|
+
export function latestExplicitReopenAt(basePath, milestoneId) {
|
|
5
|
+
const root = gsdRoot(basePath);
|
|
6
|
+
const candidates = [
|
|
7
|
+
join(root, "event-log.jsonl"),
|
|
8
|
+
join(root, `event-log-${milestoneId}.jsonl.archived`),
|
|
9
|
+
];
|
|
10
|
+
let latest = null;
|
|
11
|
+
for (const file of candidates) {
|
|
12
|
+
for (const event of readEvents(file)) {
|
|
13
|
+
const eventMilestoneId = event.params.milestoneId;
|
|
14
|
+
if (event.cmd !== "reopen-milestone" || eventMilestoneId !== milestoneId)
|
|
15
|
+
continue;
|
|
16
|
+
if (!latest || event.ts > latest)
|
|
17
|
+
latest = event.ts;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return latest;
|
|
21
|
+
}
|
|
22
|
+
export function isAfter(value, cutoff) {
|
|
23
|
+
if (!cutoff)
|
|
24
|
+
return true;
|
|
25
|
+
if (!value)
|
|
26
|
+
return true;
|
|
27
|
+
return Date.parse(value) > Date.parse(cutoff);
|
|
28
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { truncateToWidth, visibleWidth, matchesKey, Key } from "@gsd/pi-tui";
|
|
4
4
|
import { readNotifications, markAllRead, clearNotifications, onNotificationStoreChange, } from "./notification-store.js";
|
|
5
5
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
6
|
-
import { padRightVisible,
|
|
6
|
+
import { padRightVisible, renderDialogFrame, renderKeyHints, rightAlign, wrapVisibleText, } from "./tui/render-kit.js";
|
|
7
7
|
const FILTER_CYCLE = ["all", "error", "warning", "success", "info"];
|
|
8
8
|
const OVERLAY_WIDTH = "58%";
|
|
9
9
|
const OVERLAY_MIN_WIDTH = 68;
|
|
@@ -163,12 +163,16 @@ export class GSDNotificationOverlay {
|
|
|
163
163
|
const terminalRows = process.stdout.rows || 32;
|
|
164
164
|
const availableRows = Math.max(1, terminalRows - OVERLAY_MARGIN.top - OVERLAY_MARGIN.bottom);
|
|
165
165
|
const overlayRows = Math.min(availableRows, Math.max(1, Math.floor((terminalRows * OVERLAY_MAX_HEIGHT_PERCENT) / 100)));
|
|
166
|
-
const maxVisibleRows = Math.max(5, overlayRows -
|
|
166
|
+
const maxVisibleRows = Math.max(5, overlayRows - 4);
|
|
167
167
|
const visibleContentRows = Math.min(content.length, maxVisibleRows);
|
|
168
168
|
const maxScroll = Math.max(0, content.length - visibleContentRows);
|
|
169
169
|
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
170
170
|
const visibleContent = content.slice(this.scrollOffset, this.scrollOffset + visibleContentRows);
|
|
171
|
-
const
|
|
171
|
+
const footer = renderKeyHints(this.theme, ["↑/↓ scroll", "f filter", "c clear", `Esc/${formattedShortcutPair("notifications")} close`], Math.max(1, width - 4));
|
|
172
|
+
const lines = renderDialogFrame(this.theme, "Notifications", visibleContent, width, {
|
|
173
|
+
footer,
|
|
174
|
+
scroll: { offset: this.scrollOffset, visibleRows: visibleContentRows, totalRows: content.length },
|
|
175
|
+
});
|
|
172
176
|
this.cachedWidth = width;
|
|
173
177
|
this.cachedLines = lines;
|
|
174
178
|
return lines;
|
|
@@ -211,8 +215,6 @@ export class GSDNotificationOverlay {
|
|
|
211
215
|
};
|
|
212
216
|
const blank = () => row("");
|
|
213
217
|
const hr = () => row(th.fg("dim", "─".repeat(contentWidth)));
|
|
214
|
-
// Header
|
|
215
|
-
const title = th.fg("accent", th.bold("Notifications"));
|
|
216
218
|
const filterLabel = this.filter === "all"
|
|
217
219
|
? th.fg("dim", "all")
|
|
218
220
|
: th.fg(this.filter === "error" ? "error"
|
|
@@ -220,11 +222,8 @@ export class GSDNotificationOverlay {
|
|
|
220
222
|
: this.filter === "success" ? "success"
|
|
221
223
|
: "dim", this.filter);
|
|
222
224
|
const count = `${this.filteredEntries.length} entries`;
|
|
223
|
-
lines.push(row(rightAlign(`${
|
|
225
|
+
lines.push(row(rightAlign(`${th.fg("dim", "filter:")} ${filterLabel}`, th.fg("dim", count), contentWidth)));
|
|
224
226
|
lines.push(hr());
|
|
225
|
-
// Controls
|
|
226
|
-
const closeShortcut = formattedShortcutPair("notifications");
|
|
227
|
-
lines.push(row(renderKeyHints(th, ["↑/↓ scroll", "f filter", "c clear", `Esc/${closeShortcut} close`], contentWidth)));
|
|
228
227
|
lines.push(blank());
|
|
229
228
|
// Entries
|
|
230
229
|
const filtered = this.filteredEntries;
|
|
@@ -7,7 +7,7 @@ import { matchesKey, Key } from "@gsd/pi-tui";
|
|
|
7
7
|
import { formatDuration } from "../shared/mod.js";
|
|
8
8
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
9
9
|
import { resolveGsdPathContract } from "./paths.js";
|
|
10
|
-
import { renderBar, renderKeyHints, renderProgressBar, safeLine, statusGlyph, } from "./tui/render-kit.js";
|
|
10
|
+
import { renderBar, renderDialogFrame, renderKeyHints, renderProgressBar, safeLine, statusGlyph, } from "./tui/render-kit.js";
|
|
11
11
|
// ─── Data Helpers ─────────────────────────────────────────────────────────
|
|
12
12
|
function readJsonSafe(filePath) {
|
|
13
13
|
try {
|
|
@@ -306,15 +306,14 @@ export class ParallelMonitorOverlay {
|
|
|
306
306
|
const t = this.theme;
|
|
307
307
|
const lines = [];
|
|
308
308
|
const w = Math.max(1, width);
|
|
309
|
-
|
|
309
|
+
const contentWidth = Math.max(1, w - 4);
|
|
310
310
|
const totalCost = this.workers.reduce((s, wk) => s + wk.cost, 0);
|
|
311
311
|
const aliveCount = this.workers.filter((wk) => wk.alive).length;
|
|
312
312
|
const now = new Date().toLocaleTimeString();
|
|
313
|
-
lines.push(t.bold(t.fg("accent", " GSD Parallel Monitor ")));
|
|
314
313
|
lines.push(t.fg("muted", ` ${now} │ ${aliveCount}/${this.workers.length} alive │ Total: `) +
|
|
315
314
|
t.bold(`$${totalCost.toFixed(2)}`) +
|
|
316
315
|
t.fg("muted", " │ 5s refresh"));
|
|
317
|
-
lines.push(renderBar(t,
|
|
316
|
+
lines.push(renderBar(t, contentWidth));
|
|
318
317
|
if (this.workers.length === 0) {
|
|
319
318
|
lines.push("");
|
|
320
319
|
lines.push(t.fg("warning", " No parallel workers found."));
|
|
@@ -360,7 +359,7 @@ export class ParallelMonitorOverlay {
|
|
|
360
359
|
});
|
|
361
360
|
lines.push(` ${t.fg("muted", "slices")} ${chips.join(" ")}`);
|
|
362
361
|
// Task progress bar
|
|
363
|
-
const barWidth = Math.max(6, Math.min(25,
|
|
362
|
+
const barWidth = Math.max(6, Math.min(25, contentWidth - 32));
|
|
364
363
|
const bar = renderProgressBar(t, wk.doneTasks, wk.totalTasks, barWidth, {
|
|
365
364
|
filledChar: "█",
|
|
366
365
|
emptyChar: "░",
|
|
@@ -378,7 +377,7 @@ export class ParallelMonitorOverlay {
|
|
|
378
377
|
}
|
|
379
378
|
// Event feed
|
|
380
379
|
lines.push("");
|
|
381
|
-
lines.push(renderBar(t,
|
|
380
|
+
lines.push(renderBar(t, contentWidth));
|
|
382
381
|
lines.push(` ${t.bold("Recent Events")}`);
|
|
383
382
|
if (this.events.length === 0) {
|
|
384
383
|
lines.push(t.fg("muted", " No events yet..."));
|
|
@@ -389,7 +388,6 @@ export class ParallelMonitorOverlay {
|
|
|
389
388
|
lines.push(` ${t.fg("muted", "│")} ${t.fg("accent", mid)} ${evt.replace(/^✓ M\d+\//, "")}`);
|
|
390
389
|
}
|
|
391
390
|
}
|
|
392
|
-
// Footer
|
|
393
391
|
lines.push("");
|
|
394
392
|
const allDone = this.workers.length > 0 && this.workers.every((wk) => !wk.alive);
|
|
395
393
|
if (allDone) {
|
|
@@ -400,16 +398,20 @@ export class ParallelMonitorOverlay {
|
|
|
400
398
|
}
|
|
401
399
|
lines.push(` ${t.bold("Total: $" + this.workers.reduce((s, wk) => s + wk.cost, 0).toFixed(2))}`);
|
|
402
400
|
}
|
|
403
|
-
lines.push(renderKeyHints(t, [`ESC/q/${formattedShortcutPair("parallel")} close`, "↑↓ scroll"], w));
|
|
404
401
|
// Apply scroll — use terminal rows as height estimate
|
|
405
402
|
const termHeight = process.stdout.rows || 40;
|
|
406
|
-
const
|
|
403
|
+
const maxBodyRows = Math.max(1, Math.min(lines.length, termHeight - 12));
|
|
404
|
+
const maxScroll = Math.max(0, lines.length - maxBodyRows);
|
|
407
405
|
this.scrollOffset = Math.min(Math.max(this.scrollOffset, 0), maxScroll);
|
|
408
406
|
const visible = lines
|
|
409
|
-
.slice(this.scrollOffset, this.scrollOffset +
|
|
410
|
-
.map((line) => safeLine(line,
|
|
411
|
-
|
|
407
|
+
.slice(this.scrollOffset, this.scrollOffset + maxBodyRows)
|
|
408
|
+
.map((line) => safeLine(line, contentWidth));
|
|
409
|
+
const footer = renderKeyHints(t, [`ESC/q/${formattedShortcutPair("parallel")} close`, "↑↓ scroll"], contentWidth);
|
|
410
|
+
this.cachedLines = renderDialogFrame(t, "GSD Parallel Monitor", visible, w, {
|
|
411
|
+
footer,
|
|
412
|
+
scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: lines.length },
|
|
413
|
+
});
|
|
412
414
|
this.cachedWidth = width;
|
|
413
|
-
return
|
|
415
|
+
return this.cachedLines;
|
|
414
416
|
}
|
|
415
417
|
}
|
|
@@ -11,10 +11,17 @@ import { gsdHome } from "./gsd-home.js";
|
|
|
11
11
|
import { statSync } from "node:fs";
|
|
12
12
|
import { validatePreferences } from "./preferences-validation.js";
|
|
13
13
|
/**
|
|
14
|
-
* Known skill directories
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* Known skill directories for **preference reference resolution** (bare skill names).
|
|
15
|
+
*
|
|
16
|
+
* Search order (first match wins):
|
|
17
|
+
* 1. ~/.gsd/agent/skills/ (GSD bundled)
|
|
18
|
+
* 2. ~/.agents/skills/ (ecosystem global)
|
|
19
|
+
* 3. .agents/skills/ (project ecosystem)
|
|
20
|
+
* 4. ~/.claude/skills/ and .claude/skills/ (Claude Code compatibility)
|
|
21
|
+
*
|
|
22
|
+
* Note: the ResourceLoader catalog uses PackageManager precedence instead —
|
|
23
|
+
* project `.gsd/skills` and `.agents/skills` can override bundled GSD skills
|
|
24
|
+
* on name collision. See docs/dev/what-is-pi/09-the-customization-stack.md.
|
|
18
25
|
*/
|
|
19
26
|
export function getSkillSearchDirs(cwd) {
|
|
20
27
|
const dirs = [
|
|
@@ -455,9 +455,10 @@ function mergePreDispatchHooks(base, override) {
|
|
|
455
455
|
return merged.length > 0 ? merged : undefined;
|
|
456
456
|
}
|
|
457
457
|
// ─── System Prompt Rendering ──────────────────────────────────────────────────
|
|
458
|
-
export function renderPreferencesForSystemPrompt(preferences, resolutions) {
|
|
458
|
+
export function renderPreferencesForSystemPrompt(preferences, resolutions, options) {
|
|
459
459
|
const validated = validatePreferences(preferences);
|
|
460
460
|
const lines = ["## GSD Skill Preferences"];
|
|
461
|
+
const includeResolvedPaths = options?.includeResolvedPaths ?? true;
|
|
461
462
|
if (validated.errors.length > 0) {
|
|
462
463
|
lines.push("- Validation: some preference values were ignored because they were invalid.");
|
|
463
464
|
}
|
|
@@ -466,7 +467,18 @@ export function renderPreferencesForSystemPrompt(preferences, resolutions) {
|
|
|
466
467
|
}
|
|
467
468
|
preferences = validated.preferences;
|
|
468
469
|
lines.push("- Treat these as explicit skill-selection policy for GSD work.", "- If a listed skill exists and is relevant, load and follow it instead of treating it as a vague suggestion.", "- Current user instructions still override these defaults.");
|
|
469
|
-
const fmt = (ref) =>
|
|
470
|
+
const fmt = (ref) => {
|
|
471
|
+
if (!resolutions)
|
|
472
|
+
return ref;
|
|
473
|
+
if (!includeResolvedPaths) {
|
|
474
|
+
const resolution = resolutions.get(ref);
|
|
475
|
+
if (!resolution || resolution.method === "unresolved") {
|
|
476
|
+
return `${ref} (⚠ not found — check skill name or path)`;
|
|
477
|
+
}
|
|
478
|
+
return ref;
|
|
479
|
+
}
|
|
480
|
+
return formatSkillRef(ref, resolutions);
|
|
481
|
+
};
|
|
470
482
|
if (preferences.always_use_skills && preferences.always_use_skills.length > 0) {
|
|
471
483
|
lines.push("- Always use these skills when relevant:");
|
|
472
484
|
for (const skill of preferences.always_use_skills) {
|
|
@@ -21,6 +21,7 @@ import { join, dirname } from "node:path";
|
|
|
21
21
|
import { fileURLToPath } from "node:url";
|
|
22
22
|
import { logWarning } from "./workflow-logger.js";
|
|
23
23
|
import { gsdHome } from "./gsd-home.js";
|
|
24
|
+
import { chooseVisionAskVariant } from "./vision-ask.js";
|
|
24
25
|
function hasRequiredExtensionAssets(rootDir, exists = existsSync) {
|
|
25
26
|
return (exists(join(rootDir, "prompts")) &&
|
|
26
27
|
exists(join(rootDir, "templates", "task-summary.md")));
|
|
@@ -168,6 +169,7 @@ export function loadPrompt(name, vars = {}) {
|
|
|
168
169
|
planTemplatePath: join(getTemplatesDir(), "plan.md"),
|
|
169
170
|
taskPlanTemplatePath: join(getTemplatesDir(), "task-plan.md"),
|
|
170
171
|
taskSummaryTemplatePath: join(getTemplatesDir(), "task-summary.md"),
|
|
172
|
+
visionAsk: chooseVisionAskVariant(),
|
|
171
173
|
skillActivation: "If a `GSD Skill Preferences` block is present in system context, use it and the `<available_skills>` catalog in your system prompt to decide which skills to load and follow for this unit, without relaxing required verification or artifact rules.",
|
|
172
174
|
...vars,
|
|
173
175
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{{preamble}}
|
|
2
2
|
|
|
3
|
-
Ask
|
|
3
|
+
Ask exactly this once: "{{visionAsk}}" Then use the user's reply as vision input.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The opener is intentionally variable so GSD feels alive across project starts. Keep it natural, easy to answer, and assistant/developer shaped: plain language, light guidance, no corporate wording, no roleplay.
|
|
6
|
+
|
|
7
|
+
**Special handling:** If the **user's** message is status, branch state, clarification, or any other non-project-description, treat it as vision input and proceed instead of repeating the opener. Do **not** treat the system preamble above (e.g. "New milestone M00X.") as vision input — wait for the user.
|
|
6
8
|
|
|
7
9
|
## Reflection Step
|
|
8
10
|
|
|
@@ -4,6 +4,8 @@ Discuss milestone {{milestoneId}} ("{{milestoneTitle}}"). Identify real gray are
|
|
|
4
4
|
|
|
5
5
|
**Structured questions available: {{structuredQuestionsAvailable}}**
|
|
6
6
|
|
|
7
|
+
**Conversation opener:** For the first user-facing question round, if you need a broad starting question, use: "{{visionAsk}}" Pair it with investigation-shaped follow-ups. Keep the tone natural and easy to answer, like an assistant/developer helping the user shape the next piece of work.
|
|
8
|
+
|
|
7
9
|
{{inlinedTemplates}}
|
|
8
10
|
|
|
9
11
|
---
|