@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
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { chooseVisionAskVariant, VISION_ASK_VARIANTS } from "../vision-ask.ts";
|
|
4
|
+
|
|
5
|
+
test("vision ask variants stay varied and conversational", () => {
|
|
6
|
+
assert.ok(VISION_ASK_VARIANTS.length >= 6, "keep enough openers to avoid repetition");
|
|
7
|
+
assert.equal(new Set(VISION_ASK_VARIANTS).size, VISION_ASK_VARIANTS.length, "openers should be unique");
|
|
8
|
+
|
|
9
|
+
for (const opener of VISION_ASK_VARIANTS) {
|
|
10
|
+
assert.ok(opener.length <= 72, `opener should stay short: ${opener}`);
|
|
11
|
+
assert.doesNotMatch(opener, /\n/, "opener should be a single line");
|
|
12
|
+
assert.doesNotMatch(opener, /\bstakeholders?|key success metrics?|business objectives?\b/i, "avoid corporate wording");
|
|
13
|
+
assert.notEqual(opener, "What's the vision?", "do not keep the old fixed opener in rotation");
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("chooseVisionAskVariant picks from the configured opener list", () => {
|
|
18
|
+
assert.equal(chooseVisionAskVariant(() => 0), VISION_ASK_VARIANTS[0]);
|
|
19
|
+
assert.equal(
|
|
20
|
+
chooseVisionAskVariant((exclusiveMax) => exclusiveMax - 1),
|
|
21
|
+
VISION_ASK_VARIANTS[VISION_ASK_VARIANTS.length - 1],
|
|
22
|
+
);
|
|
23
|
+
});
|
|
@@ -14,6 +14,7 @@ import { test } from "node:test";
|
|
|
14
14
|
import assert from "node:assert/strict";
|
|
15
15
|
|
|
16
16
|
import { GSDVisualizerOverlay, TAB_COUNT } from "../visualizer-overlay.ts";
|
|
17
|
+
import { assertFullOuterBorder } from "./tui-border-assertions.ts";
|
|
17
18
|
|
|
18
19
|
function makeTui() {
|
|
19
20
|
const renders: number[] = [];
|
|
@@ -50,7 +51,11 @@ test("overlay renders 10 tabs (Progress, Timeline, Deps, Metrics, Health, Agent,
|
|
|
50
51
|
overlay.loading = true; // body shows loading text, but tab bar renders regardless
|
|
51
52
|
|
|
52
53
|
// Use a very wide terminal so the tab bar is not truncated.
|
|
53
|
-
const
|
|
54
|
+
const rawLines = overlay.render(200);
|
|
55
|
+
assertFullOuterBorder(rawLines, 200);
|
|
56
|
+
const lines = rawLines.map(stripAnsi);
|
|
57
|
+
assert.match(lines[0] ?? "", /^╭─ GSD Visualizer /);
|
|
58
|
+
assert.match(lines.at(-1) ?? "", /^╰─+╯$/);
|
|
54
59
|
const tabBar = lines.find((l) => l.includes("Progress") && l.includes("Export"));
|
|
55
60
|
assert.ok(tabBar, `expected a tab-bar line containing all labels, got:\n${lines.slice(0, 5).join("\n")}`);
|
|
56
61
|
for (const label of ["Progress", "Timeline", "Deps", "Metrics", "Health", "Agent", "Changes", "Knowledge", "Captures", "Export"]) {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
|
|
7
7
|
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
8
8
|
import { GSD_WORKFLOW_MCP_SERVER_NAME } from "../mcp-project-config.ts";
|
|
9
|
+
import { clearSkillSnapshot, snapshotSkills } from "../skill-discovery.js";
|
|
9
10
|
import { prepareWorkflowMcpForProject, shouldAutoPrepareWorkflowMcp } from "../workflow-mcp-auto-prep.ts";
|
|
10
11
|
|
|
11
12
|
test("shouldAutoPrepareWorkflowMcp enables prep for externalCli local transport", () => {
|
|
@@ -134,3 +135,75 @@ test("before_agent_start auto-prepares project workflow MCP for Claude Code CLI"
|
|
|
134
135
|
assert.ok(parsed.mcpServers?.[GSD_WORKFLOW_MCP_SERVER_NAME]);
|
|
135
136
|
assert.match(notifications.join("\n"), /Claude Code MCP prepared/);
|
|
136
137
|
});
|
|
138
|
+
|
|
139
|
+
test("before_agent_start returns discovered skill fallback without project .gsd", async (t) => {
|
|
140
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "gsd-skill-before-agent-"));
|
|
141
|
+
const skillHome = mkdtempSync(join(tmpdir(), "gsd-skill-home-"));
|
|
142
|
+
const originalCwd = process.cwd();
|
|
143
|
+
const originalHome = process.env.HOME;
|
|
144
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
145
|
+
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
|
|
146
|
+
const pi = {
|
|
147
|
+
on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
|
|
148
|
+
const existing = handlers.get(event) ?? [];
|
|
149
|
+
existing.push(handler);
|
|
150
|
+
handlers.set(event, existing);
|
|
151
|
+
},
|
|
152
|
+
getActiveTools: () => [],
|
|
153
|
+
getAllTools: () => [],
|
|
154
|
+
setActiveTools() {},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
t.after(() => {
|
|
158
|
+
process.chdir(originalCwd);
|
|
159
|
+
clearSkillSnapshot();
|
|
160
|
+
if (originalHome === undefined) {
|
|
161
|
+
delete process.env.HOME;
|
|
162
|
+
} else {
|
|
163
|
+
process.env.HOME = originalHome;
|
|
164
|
+
}
|
|
165
|
+
if (originalGsdHome === undefined) {
|
|
166
|
+
delete process.env.GSD_HOME;
|
|
167
|
+
} else {
|
|
168
|
+
process.env.GSD_HOME = originalGsdHome;
|
|
169
|
+
}
|
|
170
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
171
|
+
rmSync(skillHome, { recursive: true, force: true });
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
process.env.HOME = skillHome;
|
|
175
|
+
process.env.GSD_HOME = join(skillHome, ".gsd");
|
|
176
|
+
process.chdir(projectRoot);
|
|
177
|
+
snapshotSkills();
|
|
178
|
+
|
|
179
|
+
const skillDir = join(skillHome, ".agents", "skills", "late-skill");
|
|
180
|
+
mkdirSync(skillDir, { recursive: true });
|
|
181
|
+
const skillPath = join(skillDir, "SKILL.md");
|
|
182
|
+
writeFileSync(skillPath, "---\nname: late-skill\ndescription: Use for late skill.\n---\n\n# late-skill\n");
|
|
183
|
+
|
|
184
|
+
registerHooks(pi as any, []);
|
|
185
|
+
const beforeAgentStart = handlers.get("before_agent_start")?.[0];
|
|
186
|
+
assert.ok(beforeAgentStart, "before_agent_start hook should be registered");
|
|
187
|
+
|
|
188
|
+
const result = await beforeAgentStart(
|
|
189
|
+
{ prompt: "hello", systemPrompt: "event system prompt" },
|
|
190
|
+
{
|
|
191
|
+
cwd: projectRoot,
|
|
192
|
+
model: { provider: "openai", baseUrl: "https://api.openai.com" },
|
|
193
|
+
modelRegistry: {
|
|
194
|
+
getProviderAuthMode: () => "apiKey",
|
|
195
|
+
isProviderRequestReady: () => false,
|
|
196
|
+
},
|
|
197
|
+
getSystemPrompt: () => "context system prompt",
|
|
198
|
+
reload: async () => {},
|
|
199
|
+
ui: {
|
|
200
|
+
notify() {},
|
|
201
|
+
setWidget() {},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
assert.match(result?.systemPrompt ?? "", /<newly_discovered_skills>/);
|
|
207
|
+
assert.match(result?.systemPrompt ?? "", /late-skill/);
|
|
208
|
+
assert.equal(result?.systemPrompt?.includes(skillPath), true);
|
|
209
|
+
});
|
|
@@ -108,6 +108,34 @@ test("executeSummarySave persists artifact and returns computed path", async ()
|
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
+
test("executeSummarySave mirrors milestone artifacts into the active worktree projection", async () => {
|
|
112
|
+
const base = makeTmpBase();
|
|
113
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
114
|
+
try {
|
|
115
|
+
mkdirSync(join(worktree, ".gsd"), { recursive: true });
|
|
116
|
+
writeFileSync(join(worktree, ".git"), "gitdir: ../../../.git/worktrees/M001\n");
|
|
117
|
+
openTestDb(base);
|
|
118
|
+
|
|
119
|
+
const result = await inProjectDir(worktree, () => executeSummarySave({
|
|
120
|
+
milestone_id: "M001",
|
|
121
|
+
slice_id: "S02",
|
|
122
|
+
artifact_type: "RESEARCH",
|
|
123
|
+
content: "# S02 Research\n\ncanonical and worktree",
|
|
124
|
+
}, worktree));
|
|
125
|
+
|
|
126
|
+
assert.equal(result.details.operation, "save_summary");
|
|
127
|
+
const relPath = "milestones/M001/slices/S02/S02-RESEARCH.md";
|
|
128
|
+
const projectPath = join(base, ".gsd", relPath);
|
|
129
|
+
const worktreePath = join(worktree, ".gsd", relPath);
|
|
130
|
+
assert.equal(existsSync(projectPath), true, "canonical artifact should be written");
|
|
131
|
+
assert.equal(existsSync(worktreePath), true, "active worktree projection should be mirrored");
|
|
132
|
+
assert.match(readFileSync(worktreePath, "utf-8"), /S02 Research/);
|
|
133
|
+
} finally {
|
|
134
|
+
closeDatabase();
|
|
135
|
+
cleanup(base);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
111
139
|
test("executeTaskComplete coerces string verificationEvidence entries", async () => {
|
|
112
140
|
const base = makeTmpBase();
|
|
113
141
|
try {
|
|
@@ -148,6 +176,60 @@ test("executeTaskComplete coerces string verificationEvidence entries", async ()
|
|
|
148
176
|
}
|
|
149
177
|
});
|
|
150
178
|
|
|
179
|
+
test("executeTaskComplete derives missing verification from evidence", async () => {
|
|
180
|
+
const base = makeTmpBase();
|
|
181
|
+
try {
|
|
182
|
+
openTestDb(base);
|
|
183
|
+
const planDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
|
184
|
+
mkdirSync(planDir, { recursive: true });
|
|
185
|
+
writeFileSync(join(planDir, "S01-PLAN.md"), "# S01\n\n- [ ] **T01: Demo** `est:5m`\n");
|
|
186
|
+
|
|
187
|
+
const result = await inProjectDir(base, () => executeTaskComplete({
|
|
188
|
+
milestoneId: "M001",
|
|
189
|
+
sliceId: "S01",
|
|
190
|
+
taskId: "T01",
|
|
191
|
+
oneLiner: "Completed task",
|
|
192
|
+
narrative: "Did the work",
|
|
193
|
+
verificationEvidence: [
|
|
194
|
+
{ command: "npm test", exitCode: 0, verdict: "pass", durationMs: 1234 },
|
|
195
|
+
],
|
|
196
|
+
}, base));
|
|
197
|
+
|
|
198
|
+
assert.equal(result.details.operation, "complete_task");
|
|
199
|
+
const db = _getAdapter();
|
|
200
|
+
assert.ok(db, "DB should be open");
|
|
201
|
+
const row = db!.prepare(
|
|
202
|
+
"SELECT verification_result FROM tasks WHERE milestone_id = ? AND slice_id = ? AND id = ?",
|
|
203
|
+
).get("M001", "S01", "T01") as Record<string, unknown> | undefined;
|
|
204
|
+
|
|
205
|
+
assert.match(String(row?.verification_result), /Verification evidence recorded/);
|
|
206
|
+
assert.match(String(row?.verification_result), /`npm test` exited 0 \(pass\)/);
|
|
207
|
+
} finally {
|
|
208
|
+
closeDatabase();
|
|
209
|
+
cleanup(base);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("executeTaskComplete returns a tool error when verification cannot be derived", async () => {
|
|
214
|
+
const base = makeTmpBase();
|
|
215
|
+
try {
|
|
216
|
+
openTestDb(base);
|
|
217
|
+
const result = await inProjectDir(base, () => executeTaskComplete({
|
|
218
|
+
milestoneId: "M001",
|
|
219
|
+
sliceId: "S01",
|
|
220
|
+
taskId: "T01",
|
|
221
|
+
oneLiner: "Completed task",
|
|
222
|
+
narrative: "Did the work",
|
|
223
|
+
}, base));
|
|
224
|
+
|
|
225
|
+
assert.equal(result.isError, true);
|
|
226
|
+
assert.match(String(result.content[0]?.text), /verification is required/);
|
|
227
|
+
} finally {
|
|
228
|
+
closeDatabase();
|
|
229
|
+
cleanup(base);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
151
233
|
test("executeSliceComplete preserves omitted optional requirement arrays", async () => {
|
|
152
234
|
const base = makeTmpBase();
|
|
153
235
|
try {
|
|
@@ -9,7 +9,7 @@ import { join } from "node:path";
|
|
|
9
9
|
import { probeGitConflictState } from "../git-conflict-state.js";
|
|
10
10
|
import { ensureWorkspaceGitReadyForPath } from "../workspace-git-preflight.js";
|
|
11
11
|
import { isWorkspaceGitAllowedCommand } from "../workspace-git-guard.js";
|
|
12
|
-
import { cleanup, git, makeTempRepo } from "./test-utils.ts";
|
|
12
|
+
import { cleanup, git, makeTempDir, makeTempRepo } from "./test-utils.ts";
|
|
13
13
|
|
|
14
14
|
function seedGsdConflict(base: string): void {
|
|
15
15
|
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
@@ -60,6 +60,21 @@ test("probeGitConflictState reports clean repo", () => {
|
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
test("ensureWorkspaceGitReadyForPath allows fresh non-git project setup folders", async () => {
|
|
64
|
+
const base = makeTempDir("gsd-ws-git-non-repo-");
|
|
65
|
+
try {
|
|
66
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
67
|
+
|
|
68
|
+
const probe = probeGitConflictState(base);
|
|
69
|
+
assert.equal(probe.status, "clean");
|
|
70
|
+
|
|
71
|
+
const ready = await ensureWorkspaceGitReadyForPath(base);
|
|
72
|
+
assert.equal(ready.ok, true);
|
|
73
|
+
} finally {
|
|
74
|
+
cleanup(base);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
63
78
|
test("ensureWorkspaceGitReadyForPath auto-resolves .gsd/ conflicts", async () => {
|
|
64
79
|
const base = makeTempRepo("gsd-ws-git-heal-");
|
|
65
80
|
try {
|
|
@@ -212,6 +212,34 @@ test("enterMilestone returns ok:true mode:none when isolation disabled", () => {
|
|
|
212
212
|
assert.equal(s.basePath, "/project");
|
|
213
213
|
});
|
|
214
214
|
|
|
215
|
+
test("adoptStrandedMilestone forces branch recovery even when normal preferences differ", (t) => {
|
|
216
|
+
const previousCwd = process.cwd();
|
|
217
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
218
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
219
|
+
|
|
220
|
+
const s = makeSession({ basePath: base, originalBasePath: base });
|
|
221
|
+
const deps = makeDeps();
|
|
222
|
+
const ctx = makeCtx();
|
|
223
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
224
|
+
|
|
225
|
+
const result = lifecycle.adoptStrandedMilestone("M001", base, ctx, {
|
|
226
|
+
mode: "branch",
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
assert.equal(result.ok, true, `expected ok:true, got: ${JSON.stringify(result)}`);
|
|
230
|
+
if (result.ok) {
|
|
231
|
+
assert.equal(result.mode, "branch");
|
|
232
|
+
assert.equal(result.path, base);
|
|
233
|
+
}
|
|
234
|
+
assert.equal(s.basePath, base);
|
|
235
|
+
assert.equal(s.strandedRecoveryIsolationMode, "branch");
|
|
236
|
+
const currentBranch = execFileSync("git", ["branch", "--show-current"], {
|
|
237
|
+
cwd: base,
|
|
238
|
+
encoding: "utf-8",
|
|
239
|
+
}).trim();
|
|
240
|
+
assert.equal(currentBranch, "milestone/M001");
|
|
241
|
+
});
|
|
242
|
+
|
|
215
243
|
test("enterMilestone returns ok:false reason:isolation-degraded when session degraded", () => {
|
|
216
244
|
const s = makeSession({ isolationDegraded: true });
|
|
217
245
|
const deps = makeDeps({ getIsolationMode: () => "branch" });
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { test } from "node:test";
|
|
16
16
|
import assert from "node:assert/strict";
|
|
17
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
17
|
+
import { existsSync, mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
import { tmpdir } from "node:os";
|
|
20
20
|
|
|
@@ -79,3 +79,47 @@ test("#2942: injected existsFn — milestones/ alone is enough", () => {
|
|
|
79
79
|
p === "/proj/.gsd" || p === "/proj/.gsd/milestones";
|
|
80
80
|
assert.equal(hasGsdBootstrapArtifacts("/proj/.gsd", existsFn), true);
|
|
81
81
|
});
|
|
82
|
+
|
|
83
|
+
test("bare /gsd routes zombie .gsd folders to project init before closeout/db checks", async (t) => {
|
|
84
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-zombie-bare-command-"));
|
|
85
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
86
|
+
mkdirSync(join(base, ".gsd", "runtime"), { recursive: true });
|
|
87
|
+
|
|
88
|
+
const previousCwd = process.cwd();
|
|
89
|
+
const previousGsdHome = process.env.GSD_HOME;
|
|
90
|
+
const previousProjectRoot = process.env.GSD_PROJECT_ROOT;
|
|
91
|
+
try {
|
|
92
|
+
process.chdir(base);
|
|
93
|
+
process.env.GSD_HOME = join(base, ".test-gsd-home");
|
|
94
|
+
delete process.env.GSD_PROJECT_ROOT;
|
|
95
|
+
|
|
96
|
+
const notifications: string[] = [];
|
|
97
|
+
const ctx = {
|
|
98
|
+
hasUI: false,
|
|
99
|
+
ui: {
|
|
100
|
+
notify: (content: unknown) => notifications.push(String(content)),
|
|
101
|
+
setStatus: () => {},
|
|
102
|
+
setWidget: () => {},
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
const { handleAutoCommand } = await import("../commands/handlers/auto.ts");
|
|
106
|
+
|
|
107
|
+
await handleAutoCommand("", ctx as any, {} as any);
|
|
108
|
+
|
|
109
|
+
assert.ok(
|
|
110
|
+
notifications.some((message) => message.includes("/gsd init did not start")),
|
|
111
|
+
"bare /gsd should route unbootstrapped zombie folders to the init wizard",
|
|
112
|
+
);
|
|
113
|
+
assert.equal(
|
|
114
|
+
existsSync(join(base, ".gsd", "gsd.db")),
|
|
115
|
+
false,
|
|
116
|
+
"bare /gsd should not create the project DB before init has bootstrapped .gsd/",
|
|
117
|
+
);
|
|
118
|
+
} finally {
|
|
119
|
+
process.chdir(previousCwd);
|
|
120
|
+
if (previousGsdHome === undefined) delete process.env.GSD_HOME;
|
|
121
|
+
else process.env.GSD_HOME = previousGsdHome;
|
|
122
|
+
if (previousProjectRoot === undefined) delete process.env.GSD_PROJECT_ROOT;
|
|
123
|
+
else process.env.GSD_PROJECT_ROOT = previousProjectRoot;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
@@ -173,6 +173,15 @@ export async function handleCompleteTask(
|
|
|
173
173
|
if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
|
|
174
174
|
return { error: "milestoneId is required and must be a non-empty string" };
|
|
175
175
|
}
|
|
176
|
+
if (!params.oneLiner || typeof params.oneLiner !== "string" || params.oneLiner.trim() === "") {
|
|
177
|
+
return { error: "oneLiner is required and must be a non-empty string" };
|
|
178
|
+
}
|
|
179
|
+
if (!params.narrative || typeof params.narrative !== "string" || params.narrative.trim() === "") {
|
|
180
|
+
return { error: "narrative is required and must be a non-empty string" };
|
|
181
|
+
}
|
|
182
|
+
if (!params.verification || typeof params.verification !== "string" || params.verification.trim() === "") {
|
|
183
|
+
return { error: "verification is required and must be a non-empty string" };
|
|
184
|
+
}
|
|
176
185
|
|
|
177
186
|
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, params.milestoneId);
|
|
178
187
|
|
|
@@ -14,8 +14,11 @@ import { isContextModeEnabled, type ContextModeConfig } from "../preferences-typ
|
|
|
14
14
|
import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
|
|
15
15
|
|
|
16
16
|
export interface ExecToolParams {
|
|
17
|
-
runtime
|
|
18
|
-
script
|
|
17
|
+
runtime?: unknown;
|
|
18
|
+
script?: unknown;
|
|
19
|
+
command?: unknown;
|
|
20
|
+
cmd?: unknown;
|
|
21
|
+
code?: unknown;
|
|
19
22
|
purpose?: string;
|
|
20
23
|
timeout_ms?: number;
|
|
21
24
|
}
|
|
@@ -80,6 +83,39 @@ function paramError(message: string): ToolExecutionResult {
|
|
|
80
83
|
};
|
|
81
84
|
}
|
|
82
85
|
|
|
86
|
+
function normalizeRuntime(value: unknown): ExecSandboxRequest["runtime"] | ToolExecutionResult {
|
|
87
|
+
if (value === undefined || value === null || value === "") return "bash";
|
|
88
|
+
if (typeof value !== "string") {
|
|
89
|
+
return paramError(`invalid runtime "${String(value)}" — must be bash | node | python`);
|
|
90
|
+
}
|
|
91
|
+
const normalized = value.trim().toLowerCase();
|
|
92
|
+
if (normalized === "" || normalized === "bash" || normalized === "sh" || normalized === "shell") return "bash";
|
|
93
|
+
if (normalized === "node" || normalized === "nodejs" || normalized === "js" || normalized === "javascript") return "node";
|
|
94
|
+
if (normalized === "python" || normalized === "python3" || normalized === "py") return "python";
|
|
95
|
+
return paramError(`invalid runtime "${value}" — must be bash | node | python`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalizeScript(params: ExecToolParams): string | ToolExecutionResult {
|
|
99
|
+
const candidates = [params.script, params.command, params.cmd, params.code];
|
|
100
|
+
let sawNonString = false;
|
|
101
|
+
for (const candidate of candidates) {
|
|
102
|
+
if (candidate === undefined || candidate === null) continue;
|
|
103
|
+
if (typeof candidate !== "string") {
|
|
104
|
+
sawNonString = true;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (candidate.trim().length > 0) return candidate;
|
|
108
|
+
}
|
|
109
|
+
if (sawNonString) {
|
|
110
|
+
return paramError("script/command must be a non-empty string");
|
|
111
|
+
}
|
|
112
|
+
return paramError("script is required and must be a non-empty string");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isToolExecutionResult(value: unknown): value is ToolExecutionResult {
|
|
116
|
+
return typeof value === "object" && value !== null && Array.isArray((value as { content?: unknown }).content);
|
|
117
|
+
}
|
|
118
|
+
|
|
83
119
|
function escapeRegExp(value: string): string {
|
|
84
120
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
85
121
|
}
|
|
@@ -201,14 +237,10 @@ export async function executeGsdExec(
|
|
|
201
237
|
): Promise<ToolExecutionResult> {
|
|
202
238
|
if (!isEnabled(deps.preferences)) return contextModeDisabledResult("gsd_exec");
|
|
203
239
|
|
|
204
|
-
const runtime = params.runtime;
|
|
205
|
-
if (runtime
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const script = typeof params.script === "string" ? params.script : "";
|
|
209
|
-
if (script.trim().length === 0) {
|
|
210
|
-
return paramError("script is required and must be a non-empty string");
|
|
211
|
-
}
|
|
240
|
+
const runtime = normalizeRuntime(params.runtime);
|
|
241
|
+
if (isToolExecutionResult(runtime)) return runtime;
|
|
242
|
+
const script = normalizeScript(params);
|
|
243
|
+
if (isToolExecutionResult(script)) return script;
|
|
212
244
|
if (Buffer.byteLength(script, "utf8") > 200_000) {
|
|
213
245
|
return paramError("script exceeds the 200 KB length limit");
|
|
214
246
|
}
|
|
@@ -15,8 +15,10 @@ import {
|
|
|
15
15
|
} from "../gsd-db.js";
|
|
16
16
|
import { GATE_REGISTRY } from "../gate-registry.js";
|
|
17
17
|
import { generateRequirementsMd, saveArtifactToDb } from "../db-writer.js";
|
|
18
|
-
import { resolveMilestoneFile, resolveSliceFile } from "../paths.js";
|
|
18
|
+
import { clearPathCache, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
|
|
19
|
+
import { saveFile, clearParseCache } from "../files.js";
|
|
19
20
|
import { unlinkSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
20
22
|
import type { CompleteMilestoneParams } from "./complete-milestone.js";
|
|
21
23
|
import { handleCompleteMilestone } from "./complete-milestone.js";
|
|
22
24
|
import { handleCompleteTask } from "./complete-task.js";
|
|
@@ -96,6 +98,28 @@ function registerProjectMilestoneSequence(content: string): string[] {
|
|
|
96
98
|
return registered;
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
async function mirrorArtifactToActiveWorktreeProjection(
|
|
102
|
+
basePath: string,
|
|
103
|
+
relativePath: string,
|
|
104
|
+
content: string,
|
|
105
|
+
): Promise<void> {
|
|
106
|
+
const contract = resolveGsdPathContract(basePath);
|
|
107
|
+
if (!contract.worktreeGsd) return;
|
|
108
|
+
if (contract.worktreeGsd === contract.projectGsd) return;
|
|
109
|
+
|
|
110
|
+
const fullPath = join(contract.worktreeGsd, relativePath);
|
|
111
|
+
try {
|
|
112
|
+
await saveFile(fullPath, content);
|
|
113
|
+
clearPathCache();
|
|
114
|
+
clearParseCache();
|
|
115
|
+
invalidateStateCache();
|
|
116
|
+
} catch (err) {
|
|
117
|
+
logWarning("tool", `gsd_summary_save worktree projection mirror failed: ${(err as Error).message}`, {
|
|
118
|
+
path: relativePath,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
99
123
|
export async function executeSummarySave(
|
|
100
124
|
params: SummarySaveParams,
|
|
101
125
|
basePath: string = process.cwd(),
|
|
@@ -197,6 +221,7 @@ export async function executeSummarySave(
|
|
|
197
221
|
},
|
|
198
222
|
basePath,
|
|
199
223
|
);
|
|
224
|
+
await mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, contentToSave);
|
|
200
225
|
|
|
201
226
|
let registeredMilestones: string[] = [];
|
|
202
227
|
if (params.artifact_type === "PROJECT") {
|
|
@@ -306,7 +331,7 @@ export interface TaskCompleteParams {
|
|
|
306
331
|
milestoneId: string;
|
|
307
332
|
oneLiner: string;
|
|
308
333
|
narrative: string;
|
|
309
|
-
verification
|
|
334
|
+
verification?: string;
|
|
310
335
|
deviations?: string;
|
|
311
336
|
knownIssues?: string;
|
|
312
337
|
keyFiles?: string[];
|
|
@@ -315,6 +340,40 @@ export interface TaskCompleteParams {
|
|
|
315
340
|
verificationEvidence?: VerificationEvidenceInput[];
|
|
316
341
|
}
|
|
317
342
|
|
|
343
|
+
type NormalizedVerificationEvidence = {
|
|
344
|
+
command: string;
|
|
345
|
+
exitCode: number;
|
|
346
|
+
verdict: string;
|
|
347
|
+
durationMs: number;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
function normalizeVerificationEvidence(
|
|
351
|
+
evidence: VerificationEvidenceInput[] | undefined,
|
|
352
|
+
): NormalizedVerificationEvidence[] {
|
|
353
|
+
return (evidence ?? []).map((entry) =>
|
|
354
|
+
typeof entry === "string"
|
|
355
|
+
? { command: entry, exitCode: -1, verdict: "unknown (coerced from string)", durationMs: 0 }
|
|
356
|
+
: entry,
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function deriveVerificationSummary(
|
|
361
|
+
evidence: NormalizedVerificationEvidence[],
|
|
362
|
+
): string | null {
|
|
363
|
+
if (evidence.length === 0) return null;
|
|
364
|
+
|
|
365
|
+
const rendered = evidence.slice(0, 3).map((entry) => {
|
|
366
|
+
const command = entry.command.trim() || "(unspecified command)";
|
|
367
|
+
const verdict = entry.verdict.trim() || "recorded";
|
|
368
|
+
return `\`${command}\` exited ${entry.exitCode} (${verdict})`;
|
|
369
|
+
});
|
|
370
|
+
const suffix = evidence.length > rendered.length
|
|
371
|
+
? `; ${evidence.length - rendered.length} more check(s) recorded`
|
|
372
|
+
: "";
|
|
373
|
+
|
|
374
|
+
return `Verification evidence recorded: ${rendered.join("; ")}${suffix}.`;
|
|
375
|
+
}
|
|
376
|
+
|
|
318
377
|
export type CompleteMilestoneExecutorParams = Partial<CompleteMilestoneParams> & Record<string, unknown>;
|
|
319
378
|
export type SliceCompleteExecutorParams = CompleteSliceParams;
|
|
320
379
|
export type PlanMilestoneExecutorParams = PlanMilestoneParams;
|
|
@@ -350,9 +409,27 @@ export async function executeTaskComplete(
|
|
|
350
409
|
}
|
|
351
410
|
try {
|
|
352
411
|
const coerced = { ...params };
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
412
|
+
const verificationEvidence = normalizeVerificationEvidence(params.verificationEvidence);
|
|
413
|
+
coerced.verificationEvidence = verificationEvidence;
|
|
414
|
+
|
|
415
|
+
const verification = typeof params.verification === "string" ? params.verification.trim() : "";
|
|
416
|
+
if (verification.length === 0) {
|
|
417
|
+
const derived = deriveVerificationSummary(verificationEvidence);
|
|
418
|
+
if (derived) {
|
|
419
|
+
coerced.verification = derived;
|
|
420
|
+
} else if (params.blockerDiscovered === true) {
|
|
421
|
+
coerced.verification = "Not run: blocker discovered before verification.";
|
|
422
|
+
} else {
|
|
423
|
+
return {
|
|
424
|
+
content: [{
|
|
425
|
+
type: "text",
|
|
426
|
+
text: "Error completing task: verification is required unless verificationEvidence is provided or blockerDiscovered is true.",
|
|
427
|
+
}],
|
|
428
|
+
details: { operation: "complete_task", error: "verification_required" },
|
|
429
|
+
isError: true,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
356
433
|
|
|
357
434
|
const result = await handleCompleteTask(coerced as any, basePath);
|
|
358
435
|
if ("error" in result) {
|
|
@@ -151,3 +151,85 @@ export function renderFrame(
|
|
|
151
151
|
lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
|
|
152
152
|
return lines.map((line) => safeLine(line, width, ""));
|
|
153
153
|
}
|
|
154
|
+
|
|
155
|
+
export interface DialogFrameOptions {
|
|
156
|
+
borderColor?: string;
|
|
157
|
+
paddingX?: number;
|
|
158
|
+
footer?: string | string[];
|
|
159
|
+
scroll?: {
|
|
160
|
+
offset: number;
|
|
161
|
+
visibleRows: number;
|
|
162
|
+
totalRows: number;
|
|
163
|
+
trackOffset?: number;
|
|
164
|
+
trackRows?: number;
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function renderTitledTopBorder(
|
|
169
|
+
theme: ThemeLike,
|
|
170
|
+
title: string,
|
|
171
|
+
width: number,
|
|
172
|
+
border: (text: string) => string,
|
|
173
|
+
): string {
|
|
174
|
+
const trimmedTitle = title.trim();
|
|
175
|
+
if (!trimmedTitle || width < 10) {
|
|
176
|
+
return border("╭" + "─".repeat(width - 2) + "╮");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const maxTitleWidth = Math.max(0, width - 7);
|
|
180
|
+
const safeTitle = safeLine(trimmedTitle, maxTitleWidth);
|
|
181
|
+
const fill = Math.max(0, width - visibleWidth(safeTitle) - 5);
|
|
182
|
+
return border("╭─ ") + theme.bold(theme.fg("accent", safeTitle)) + border(" " + "─".repeat(fill) + "╮");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function renderDialogFrame(
|
|
186
|
+
theme: ThemeLike,
|
|
187
|
+
title: string,
|
|
188
|
+
inner: string[],
|
|
189
|
+
width: number,
|
|
190
|
+
options: DialogFrameOptions = {},
|
|
191
|
+
): string[] {
|
|
192
|
+
if (width < 4) return inner.map((line) => safeLine(line, width));
|
|
193
|
+
|
|
194
|
+
const borderColor = options.borderColor ?? "borderAccent";
|
|
195
|
+
const paddingX = Math.max(0, options.paddingX ?? 1);
|
|
196
|
+
const contentWidth = Math.max(0, width - 2 - paddingX * 2);
|
|
197
|
+
const border = (text: string) => theme.fg(borderColor, text);
|
|
198
|
+
const pad = " ".repeat(paddingX);
|
|
199
|
+
const lines = [renderTitledTopBorder(theme, title, width, border)];
|
|
200
|
+
|
|
201
|
+
const scroll = options.scroll;
|
|
202
|
+
const bodyRows = inner.length;
|
|
203
|
+
const trackOffset = Math.max(0, Math.min(scroll?.trackOffset ?? 0, bodyRows));
|
|
204
|
+
const trackRows = Math.max(0, Math.min(scroll?.trackRows ?? bodyRows, bodyRows - trackOffset));
|
|
205
|
+
const scrollable = !!scroll && scroll.totalRows > scroll.visibleRows && trackRows > 0;
|
|
206
|
+
const thumbLen = scrollable
|
|
207
|
+
? Math.max(1, Math.round((scroll.visibleRows / scroll.totalRows) * trackRows))
|
|
208
|
+
: 0;
|
|
209
|
+
const maxThumbStart = Math.max(0, trackRows - thumbLen);
|
|
210
|
+
const maxScrollOffset = scrollable ? Math.max(1, scroll.totalRows - scroll.visibleRows) : 1;
|
|
211
|
+
const thumbStart = scrollable
|
|
212
|
+
? trackOffset + Math.min(maxThumbStart, Math.round((scroll.offset / maxScrollOffset) * maxThumbStart))
|
|
213
|
+
: -1;
|
|
214
|
+
|
|
215
|
+
for (let i = 0; i < inner.length; i++) {
|
|
216
|
+
const line = inner[i] ?? "";
|
|
217
|
+
const rightBorder = scrollable && i >= thumbStart && i < thumbStart + thumbLen ? "┃" : "│";
|
|
218
|
+
lines.push(border("│") + pad + padRightVisible(line, contentWidth) + pad + border(rightBorder));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const footer = Array.isArray(options.footer)
|
|
222
|
+
? options.footer
|
|
223
|
+
: options.footer
|
|
224
|
+
? [options.footer]
|
|
225
|
+
: [];
|
|
226
|
+
if (footer.length > 0) {
|
|
227
|
+
lines.push(border("├" + "─".repeat(width - 2) + "┤"));
|
|
228
|
+
for (const line of footer) {
|
|
229
|
+
lines.push(border("│") + pad + padRightVisible(line, contentWidth) + pad + border("│"));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
|
|
234
|
+
return lines.map((line) => safeLine(line, width, ""));
|
|
235
|
+
}
|