@opengsd/gsd-pi 1.0.2-dev.e70300c → 1.0.2-dev.fb7ddf1
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/README.md +63 -12
- package/dist/headless-answers.js +2 -1
- package/dist/headless-events.d.ts +1 -0
- package/dist/headless-events.js +8 -1
- package/dist/onboarding.js +22 -3
- package/dist/resource-loader.d.ts +7 -0
- package/dist/resource-loader.js +44 -9
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +34 -11
- 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 +81 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +38 -1
- 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 +65 -16
- 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-tool-tracking.js +2 -1
- package/dist/resources/extensions/gsd/auto-verification.js +14 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +34 -1
- package/dist/resources/extensions/gsd/auto.js +40 -2
- 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 +107 -27
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
- package/dist/resources/extensions/gsd/bootstrap/tool-search-shim.js +4 -4
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- 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-handlers.js +3 -0
- 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-git-checks.js +70 -5
- package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
- package/dist/resources/extensions/gsd/doctor.js +7 -2
- 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/mcp-filter.js +57 -18
- package/dist/resources/extensions/gsd/mcp-project-config.js +15 -9
- package/dist/resources/extensions/gsd/migration-auto-check.js +5 -1
- package/dist/resources/extensions/gsd/milestone-actions.js +3 -0
- 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-merge.js +6 -4
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
- package/dist/resources/extensions/gsd/post-execution-checks.js +5 -4
- 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/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +3 -20
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
- package/dist/resources/extensions/gsd/repo-identity.js +36 -6
- package/dist/resources/extensions/gsd/repository-registry.js +3 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +13 -6
- 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/gsd-headless/SKILL.md +1 -1
- 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/gsd/worktree-state-projection.js +29 -0
- 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/extensions/subagent/index.js +8 -15
- package/dist/resources/shared/package-manager-detection.js +36 -0
- package/dist/resources/skills/agent-browser/SKILL.md +1 -1
- package/dist/resources/skills/api-design/SKILL.md +1 -1
- package/dist/resources/skills/code-optimizer/SKILL.md +6 -11
- package/dist/resources/skills/create-gsd-extension/SKILL.md +1 -1
- package/dist/resources/skills/create-mcp-server/SKILL.md +1 -1
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +2 -10
- package/dist/resources/skills/debug-like-expert/references/when-to-research.md +1 -5
- package/dist/resources/skills/decompose-into-slices/SKILL.md +3 -3
- package/dist/resources/skills/dependency-upgrade/SKILL.md +1 -1
- package/dist/resources/skills/forensics/SKILL.md +2 -2
- package/dist/resources/skills/grill-me/SKILL.md +1 -1
- package/dist/resources/skills/handoff/SKILL.md +1 -1
- package/dist/resources/skills/make-interfaces-feel-better/SKILL.md +1 -1
- package/dist/resources/skills/observability/SKILL.md +1 -1
- package/dist/resources/skills/security-review/SKILL.md +1 -1
- package/dist/resources/skills/spike-wrap-up/SKILL.md +1 -1
- package/dist/resources/skills/tdd/SKILL.md +1 -1
- package/dist/resources/skills/write-docs/SKILL.md +1 -1
- package/dist/resources/skills/write-milestone-brief/SKILL.md +1 -1
- package/dist/update-check.d.ts +6 -2
- package/dist/update-check.js +7 -3
- 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/api/update/route.js +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/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +5 -2
- 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 +15 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -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/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.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 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +2 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.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/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +7 -1
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +47 -8
- 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/agent-loop.js +16 -14
- package/packages/pi-agent-core/dist/agent-loop.js.map +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 +48 -206
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +67 -220
- 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/dist/utils/tests/tool-search-shim.test.js +29 -1
- package/packages/pi-ai/dist/utils/tests/tool-search-shim.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/tool-search-shim.d.ts +4 -1
- package/packages/pi-ai/dist/utils/tool-search-shim.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/tool-search-shim.js +58 -10
- package/packages/pi-ai/dist/utils/tool-search-shim.js.map +1 -1
- package/packages/pi-ai/dist/utils/tool-shims.d.ts +1 -1
- package/packages/pi-ai/dist/utils/tool-shims.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/tool-shims.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/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +5 -7
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +5 -4
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +0 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/package.json +8 -8
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/scripts/install/detect-existing.js +17 -3
- package/scripts/install/npm-global.js +103 -33
- package/scripts/install.js +1 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +36 -11
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +86 -19
- 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 +96 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +47 -1
- 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 +101 -18
- 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-tool-tracking.ts +3 -1
- package/src/resources/extensions/gsd/auto-verification.ts +18 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +45 -1
- package/src/resources/extensions/gsd/auto.ts +50 -2
- 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 +124 -25
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
- package/src/resources/extensions/gsd/bootstrap/tool-search-shim.ts +4 -4
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- 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-handlers.ts +2 -0
- 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-git-checks.ts +72 -5
- 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 +7 -2
- 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/mcp-filter.ts +64 -17
- package/src/resources/extensions/gsd/mcp-project-config.ts +24 -9
- package/src/resources/extensions/gsd/migration-auto-check.ts +6 -0
- package/src/resources/extensions/gsd/milestone-actions.ts +2 -0
- 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-merge.ts +6 -4
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
- package/src/resources/extensions/gsd/post-execution-checks.ts +7 -4
- 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/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +3 -20
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
- package/src/resources/extensions/gsd/repo-identity.ts +35 -7
- package/src/resources/extensions/gsd/repository-registry.ts +3 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +13 -6
- 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/gsd-headless/SKILL.md +1 -1
- 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 +75 -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 +24 -0
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +53 -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/complete-slice-reopen-handoff.test.ts +40 -3
- package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +64 -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-empty-worktree.test.ts +71 -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/headless-answers.test.ts +22 -3
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
- package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +19 -1
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +56 -1
- 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/park-milestone.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +127 -10
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +101 -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/repo-identity-worktree.test.ts +27 -0
- 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 +67 -1
- 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 +133 -0
- 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/worktree-state-projection.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +10 -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/gsd/worktree-state-projection.ts +33 -0
- 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/extensions/subagent/index.ts +8 -15
- package/src/resources/shared/package-manager-detection.ts +39 -0
- package/src/resources/skills/agent-browser/SKILL.md +1 -1
- package/src/resources/skills/api-design/SKILL.md +1 -1
- package/src/resources/skills/code-optimizer/SKILL.md +6 -11
- package/src/resources/skills/create-gsd-extension/SKILL.md +1 -1
- package/src/resources/skills/create-mcp-server/SKILL.md +1 -1
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- package/src/resources/skills/create-skill/workflows/verify-skill.md +2 -10
- package/src/resources/skills/debug-like-expert/references/when-to-research.md +1 -5
- package/src/resources/skills/decompose-into-slices/SKILL.md +3 -3
- package/src/resources/skills/dependency-upgrade/SKILL.md +1 -1
- package/src/resources/skills/forensics/SKILL.md +2 -2
- package/src/resources/skills/grill-me/SKILL.md +1 -1
- package/src/resources/skills/handoff/SKILL.md +1 -1
- package/src/resources/skills/make-interfaces-feel-better/SKILL.md +1 -1
- package/src/resources/skills/observability/SKILL.md +1 -1
- package/src/resources/skills/security-review/SKILL.md +1 -1
- package/src/resources/skills/spike-wrap-up/SKILL.md +1 -1
- package/src/resources/skills/tdd/SKILL.md +1 -1
- package/src/resources/skills/write-docs/SKILL.md +1 -1
- package/src/resources/skills/write-milestone-brief/SKILL.md +1 -1
- /package/dist/web/standalone/.next/static/{szb-HAt0IoSx3docUZO-E → tH1tnDYt1E0hK9Ien73Z0}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{szb-HAt0IoSx3docUZO-E → tH1tnDYt1E0hK9Ien73Z0}/_ssgManifest.js +0 -0
|
@@ -5,7 +5,8 @@ import assert from "node:assert/strict";
|
|
|
5
5
|
import test from "node:test";
|
|
6
6
|
|
|
7
7
|
import { DISCUSS_TOOLS_ALLOWLIST } from "../constants.ts";
|
|
8
|
-
import { buildMinimalAutoGsdToolSet, buildMinimalGsdToolSet, buildMinimalGsdWorkflowToolSet, buildRequestScopedGsdToolSet, MINIMAL_AUTO_BASE_TOOL_NAMES, MINIMAL_GSD_TOOL_NAMES, restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch } from "../bootstrap/register-hooks.ts";
|
|
8
|
+
import { buildMinimalAutoGsdToolSet, buildMinimalGsdToolSet, buildMinimalGsdWorkflowToolSet, buildRequestScopedGsdToolSet, MINIMAL_AUTO_BASE_TOOL_NAMES, MINIMAL_GSD_TOOL_NAMES, requestHasGsdCustomType, restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch } from "../bootstrap/register-hooks.ts";
|
|
9
|
+
import { applyUnitSkillVisibility } from "../skill-scope.ts";
|
|
9
10
|
|
|
10
11
|
test("buildMinimalGsdToolSet preserves non-GSD tools and replaces broad GSD surface", () => {
|
|
11
12
|
const result = buildMinimalGsdToolSet([
|
|
@@ -54,6 +55,17 @@ test("buildMinimalGsdToolSet always preserves ToolSearch shim", () => {
|
|
|
54
55
|
assert.ok(result.includes("ToolSearch"));
|
|
55
56
|
});
|
|
56
57
|
|
|
58
|
+
test("requestHasGsdCustomType detects GSD-driven requests (drives interactive default scoping)", () => {
|
|
59
|
+
// Plain interactive chat → no gsd-* customType → scoped to the minimal set.
|
|
60
|
+
assert.equal(requestHasGsdCustomType(undefined), false);
|
|
61
|
+
assert.equal(requestHasGsdCustomType([]), false);
|
|
62
|
+
assert.equal(requestHasGsdCustomType([{ customType: "user" }, {}]), false);
|
|
63
|
+
// GSD workflow commands carry a gsd-* customType → keep their full surface.
|
|
64
|
+
assert.equal(requestHasGsdCustomType([{ customType: "gsd-quick-task" }]), true);
|
|
65
|
+
assert.equal(requestHasGsdCustomType([{}, { customType: "gsd-workflow-template" }]), true);
|
|
66
|
+
assert.equal(requestHasGsdCustomType([{ customType: "gsd-run" }]), true);
|
|
67
|
+
});
|
|
68
|
+
|
|
57
69
|
test("buildMinimalAutoGsdToolSet keeps unit-specific completion tools without aliases", () => {
|
|
58
70
|
const result = buildMinimalAutoGsdToolSet([
|
|
59
71
|
"ask_user_questions",
|
|
@@ -86,6 +98,24 @@ test("buildMinimalAutoGsdToolSet keeps unit-specific completion tools without al
|
|
|
86
98
|
assert.ok(!result.includes("gsd_complete_slice"));
|
|
87
99
|
});
|
|
88
100
|
|
|
101
|
+
test("buildMinimalAutoGsdToolSet re-resolves run-uat browser tools from the registry when dropped from the active set", () => {
|
|
102
|
+
// B2 drops the browser surface from the advertised interactive set, but the
|
|
103
|
+
// tools stay registered. run-uat must still get them: resolution reads the
|
|
104
|
+
// full registry, not just the (browser-stripped) active set.
|
|
105
|
+
const active = ["ask_user_questions", "bash", "read", "gsd_summary_save"];
|
|
106
|
+
const registered = [
|
|
107
|
+
...active,
|
|
108
|
+
"browser_navigate",
|
|
109
|
+
"browser_click",
|
|
110
|
+
"browser_snapshot_refs",
|
|
111
|
+
"gsd_exec",
|
|
112
|
+
];
|
|
113
|
+
const result = buildMinimalAutoGsdToolSet(active, "run-uat", registered);
|
|
114
|
+
assert.ok(result.includes("browser_navigate"), "run-uat needs browser_navigate");
|
|
115
|
+
assert.ok(result.includes("browser_click"), "run-uat needs browser_click");
|
|
116
|
+
assert.ok(result.includes("gsd_summary_save"));
|
|
117
|
+
});
|
|
118
|
+
|
|
89
119
|
test("buildMinimalAutoGsdToolSet keeps only the auto base non-GSD tools", () => {
|
|
90
120
|
const result = buildMinimalAutoGsdToolSet([
|
|
91
121
|
"ask_user_questions",
|
|
@@ -171,6 +201,24 @@ test("buildMinimalAutoGsdToolSet preserves browser tools for run-uat", () => {
|
|
|
171
201
|
assert.ok(!result.includes("gsd_task_complete"));
|
|
172
202
|
});
|
|
173
203
|
|
|
204
|
+
test("buildMinimalAutoGsdToolSet includes discuss-slice persistence tools", () => {
|
|
205
|
+
const result = buildMinimalAutoGsdToolSet([
|
|
206
|
+
"bash",
|
|
207
|
+
"read",
|
|
208
|
+
"gsd_summary_save",
|
|
209
|
+
"gsd_decision_save",
|
|
210
|
+
"gsd_plan_slice",
|
|
211
|
+
"gsd_task_complete",
|
|
212
|
+
"memory_query",
|
|
213
|
+
"capture_thought",
|
|
214
|
+
], "discuss-slice");
|
|
215
|
+
|
|
216
|
+
assert.ok(result.includes("gsd_summary_save"));
|
|
217
|
+
assert.ok(result.includes("gsd_decision_save"));
|
|
218
|
+
assert.ok(!result.includes("gsd_plan_slice"));
|
|
219
|
+
assert.ok(!result.includes("gsd_task_complete"));
|
|
220
|
+
});
|
|
221
|
+
|
|
174
222
|
test("buildMinimalAutoGsdToolSet includes closeout tool for complete-slice", () => {
|
|
175
223
|
const result = buildMinimalAutoGsdToolSet([
|
|
176
224
|
"bash",
|
|
@@ -435,3 +483,21 @@ test("scopeGsdWorkflowToolsForDispatch applies and restores per-unit skill visib
|
|
|
435
483
|
assert.deepEqual(visibleSkills, ["previous-skill"]);
|
|
436
484
|
assert.equal(calls.filter((call) => call.kind === "skills").length, 2);
|
|
437
485
|
});
|
|
486
|
+
|
|
487
|
+
test("applyUnitSkillVisibility sets manifest or clears for wildcard", () => {
|
|
488
|
+
const calls: Array<string[] | undefined> = [];
|
|
489
|
+
applyUnitSkillVisibility({
|
|
490
|
+
setVisibleSkills: (names) => {
|
|
491
|
+
calls.push(names);
|
|
492
|
+
},
|
|
493
|
+
}, "plan-milestone");
|
|
494
|
+
assert.ok(Array.isArray(calls[0]));
|
|
495
|
+
assert.ok(calls[0]!.includes("tdd"));
|
|
496
|
+
|
|
497
|
+
applyUnitSkillVisibility({
|
|
498
|
+
setVisibleSkills: (names) => {
|
|
499
|
+
calls.push(names);
|
|
500
|
+
},
|
|
501
|
+
}, "execute-task");
|
|
502
|
+
assert.equal(calls[1], undefined);
|
|
503
|
+
});
|
|
@@ -235,12 +235,16 @@ test("gsd_task_complete — enrichment arrays are optional", () => {
|
|
|
235
235
|
"milestoneId",
|
|
236
236
|
"oneLiner",
|
|
237
237
|
"narrative",
|
|
238
|
-
"verification",
|
|
239
238
|
];
|
|
240
239
|
for (const field of coreRequired) {
|
|
241
240
|
assert.ok(required.has(field), `core field "${field}" must be required`);
|
|
242
241
|
}
|
|
243
242
|
|
|
243
|
+
assert.ok(
|
|
244
|
+
!required.has("verification"),
|
|
245
|
+
"verification must be optional at the schema layer so step-mode can recover when verificationEvidence is present",
|
|
246
|
+
);
|
|
247
|
+
|
|
244
248
|
// Enrichment fields must be optional
|
|
245
249
|
const enrichmentFields = [
|
|
246
250
|
"keyFiles",
|
|
@@ -272,6 +276,25 @@ test("gsd_task_complete — validates with only core params", () => {
|
|
|
272
276
|
assert.strictEqual(errors.length, 0, `Minimal params should validate but got errors: ${errors.join(", ")}`);
|
|
273
277
|
});
|
|
274
278
|
|
|
279
|
+
test("gsd_task_complete — accepts evidence-only verification at schema layer", () => {
|
|
280
|
+
const tool = getTool("gsd_task_complete");
|
|
281
|
+
assert.ok(tool, "gsd_task_complete must be registered");
|
|
282
|
+
|
|
283
|
+
const params = {
|
|
284
|
+
taskId: "T01",
|
|
285
|
+
sliceId: "S01",
|
|
286
|
+
milestoneId: "M001",
|
|
287
|
+
oneLiner: "Implemented the feature",
|
|
288
|
+
narrative: "Created the module and wired it up.",
|
|
289
|
+
verificationEvidence: [
|
|
290
|
+
{ command: "npm test", exitCode: 0, verdict: "pass", durationMs: 1234 },
|
|
291
|
+
],
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const errors = validateSchema(tool, params);
|
|
295
|
+
assert.strictEqual(errors.length, 0, `Evidence-only params should validate but got errors: ${errors.join(", ")}`);
|
|
296
|
+
});
|
|
297
|
+
|
|
275
298
|
// ─── gsd_complete_milestone: enrichment arrays must be optional ──────────────
|
|
276
299
|
|
|
277
300
|
test("gsd_complete_milestone — enrichment arrays are optional", () => {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
|
|
3
|
+
import { visibleWidth } from "@gsd/pi-tui";
|
|
4
|
+
|
|
5
|
+
const ANSI_PATTERN = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
6
|
+
|
|
7
|
+
function stripAnsi(text: string): string {
|
|
8
|
+
return text.replace(ANSI_PATTERN, "");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function assertFullOuterBorder(lines: string[], width: number): void {
|
|
12
|
+
assert.ok(lines.length >= 2, "dialog must include top and bottom borders");
|
|
13
|
+
|
|
14
|
+
for (const [index, line] of lines.entries()) {
|
|
15
|
+
assert.equal(visibleWidth(line), width, `line ${index} must fill dialog width`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const top = stripAnsi(lines[0] ?? "");
|
|
19
|
+
const bottom = stripAnsi(lines.at(-1) ?? "");
|
|
20
|
+
assert.match(top, /^[╭┌].*[╮┐]$/, `top border missing full corners: ${top}`);
|
|
21
|
+
assert.match(bottom, /^[╰└].*[╯┘]$/, `bottom border missing full corners: ${bottom}`);
|
|
22
|
+
|
|
23
|
+
for (let index = 1; index < lines.length - 1; index++) {
|
|
24
|
+
const line = stripAnsi(lines[index] ?? "");
|
|
25
|
+
assert.match(line, /^[│┃├]/, `line ${index} missing left border: ${line}`);
|
|
26
|
+
assert.match(line, /[│┃┤]$/, `line ${index} missing right border: ${line}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -5,8 +5,10 @@ import { describe, test } from "node:test";
|
|
|
5
5
|
import assert from "node:assert/strict";
|
|
6
6
|
|
|
7
7
|
import { visibleWidth } from "@gsd/pi-tui";
|
|
8
|
+
import { assertFullOuterBorder } from "./tui-border-assertions.ts";
|
|
8
9
|
import {
|
|
9
10
|
padRightVisible,
|
|
11
|
+
renderDialogFrame,
|
|
10
12
|
renderFrame,
|
|
11
13
|
renderKeyHints,
|
|
12
14
|
renderPanel,
|
|
@@ -60,6 +62,18 @@ describe("tui render kit", () => {
|
|
|
60
62
|
}
|
|
61
63
|
});
|
|
62
64
|
|
|
65
|
+
test("renderDialogFrame draws a full titled modal border with footer", () => {
|
|
66
|
+
const lines = renderDialogFrame(theme, "Dialog", ["row", "long ".repeat(40)], 40, {
|
|
67
|
+
footer: renderKeyHints(theme, ["esc close"], 36),
|
|
68
|
+
});
|
|
69
|
+
assertWidth(lines, 40);
|
|
70
|
+
assertFullOuterBorder(lines, 40);
|
|
71
|
+
assert.match(lines[0] ?? "", /^╭─ Dialog ─+╮$/);
|
|
72
|
+
assert.ok(lines.some((line) => line.startsWith("│") && line.endsWith("│")));
|
|
73
|
+
assert.ok(lines.some((line) => line.startsWith("├") && line.endsWith("┤")));
|
|
74
|
+
assert.match(lines.at(-1) ?? "", /^╰─+╯$/);
|
|
75
|
+
});
|
|
76
|
+
|
|
63
77
|
test("renderPanel stays within width and draws no vertical borders", () => {
|
|
64
78
|
for (const width of [3, 40, 80]) {
|
|
65
79
|
const lines = renderPanel(theme, "Title", ["row", "long ".repeat(40)], width);
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type SkillsPolicy,
|
|
15
15
|
type UnitContextManifest,
|
|
16
16
|
} from "../unit-context-manifest.ts";
|
|
17
|
+
import { resolveSkillManifest } from "../skill-manifest.ts";
|
|
17
18
|
import {
|
|
18
19
|
ALLOWED_PLANNING_DISPATCH_AGENTS,
|
|
19
20
|
shouldBlockPlanningUnit,
|
|
@@ -148,6 +149,23 @@ test("#4782 phase 1: skills policy shapes are valid discriminated-union members"
|
|
|
148
149
|
}
|
|
149
150
|
});
|
|
150
151
|
|
|
152
|
+
test("#4782 phase 1b: allowlist skills policy matches skill-manifest resolver", () => {
|
|
153
|
+
for (const unitType of KNOWN_UNIT_TYPES) {
|
|
154
|
+
const manifest = UNIT_MANIFESTS[unitType];
|
|
155
|
+
const allowlist = resolveSkillManifest(unitType);
|
|
156
|
+
if (allowlist) {
|
|
157
|
+
assert.strictEqual(manifest.skills.mode, "allowlist", unitType);
|
|
158
|
+
assert.deepEqual(
|
|
159
|
+
[...(manifest.skills as Extract<SkillsPolicy, { mode: "allowlist" }>).skills].sort(),
|
|
160
|
+
[...allowlist].sort(),
|
|
161
|
+
unitType,
|
|
162
|
+
);
|
|
163
|
+
} else {
|
|
164
|
+
assert.notStrictEqual(manifest.skills.mode, "allowlist", unitType);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
151
169
|
// ─── Lookup helper ────────────────────────────────────────────────────────
|
|
152
170
|
|
|
153
171
|
test("#4782 phase 1: resolveManifest returns null for an unknown unit type", () => {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import * as userInputBoundary from "../user-input-boundary.ts";
|
|
5
|
+
|
|
6
|
+
test("lastAssistantText extracts the latest assistant text block content", () => {
|
|
7
|
+
const lastAssistantText = (userInputBoundary as {
|
|
8
|
+
lastAssistantText?: (messages: unknown[] | null | undefined) => string;
|
|
9
|
+
}).lastAssistantText;
|
|
10
|
+
|
|
11
|
+
assert.equal(typeof lastAssistantText, "function");
|
|
12
|
+
assert.equal(
|
|
13
|
+
lastAssistantText?.([
|
|
14
|
+
{ role: "assistant", content: "Older message" },
|
|
15
|
+
{
|
|
16
|
+
role: "assistant",
|
|
17
|
+
content: [
|
|
18
|
+
{ type: "text", text: "First line" },
|
|
19
|
+
{ type: "text", text: "Second line" },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
]),
|
|
23
|
+
"First line\nSecond line",
|
|
24
|
+
);
|
|
25
|
+
assert.equal(lastAssistantText?.(null), "");
|
|
26
|
+
});
|
|
@@ -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,6 +1,12 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
3
6
|
|
|
7
|
+
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
8
|
+
import { GSD_WORKFLOW_MCP_SERVER_NAME } from "../mcp-project-config.ts";
|
|
9
|
+
import { clearSkillSnapshot, snapshotSkills } from "../skill-discovery.js";
|
|
4
10
|
import { prepareWorkflowMcpForProject, shouldAutoPrepareWorkflowMcp } from "../workflow-mcp-auto-prep.ts";
|
|
5
11
|
|
|
6
12
|
test("shouldAutoPrepareWorkflowMcp enables prep for externalCli local transport", () => {
|
|
@@ -74,3 +80,130 @@ test("prepareWorkflowMcpForProject warns with /gsd mcp init guidance when prep f
|
|
|
74
80
|
assert.equal(notifications[0].level, "warning");
|
|
75
81
|
assert.match(notifications[0].message, /Please run \/gsd mcp init \./);
|
|
76
82
|
});
|
|
83
|
+
|
|
84
|
+
test("before_agent_start auto-prepares project workflow MCP for Claude Code CLI", async (t) => {
|
|
85
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-before-agent-"));
|
|
86
|
+
const originalCwd = process.cwd();
|
|
87
|
+
const notifications: string[] = [];
|
|
88
|
+
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
|
|
89
|
+
const pi = {
|
|
90
|
+
on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
|
|
91
|
+
const existing = handlers.get(event) ?? [];
|
|
92
|
+
existing.push(handler);
|
|
93
|
+
handlers.set(event, existing);
|
|
94
|
+
},
|
|
95
|
+
getActiveTools: () => [],
|
|
96
|
+
getAllTools: () => [],
|
|
97
|
+
setActiveTools() {},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
t.after(() => {
|
|
101
|
+
process.chdir(originalCwd);
|
|
102
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
process.chdir(projectRoot);
|
|
106
|
+
registerHooks(pi as any, []);
|
|
107
|
+
|
|
108
|
+
const beforeAgentStart = handlers.get("before_agent_start")?.[0];
|
|
109
|
+
assert.ok(beforeAgentStart, "before_agent_start hook should be registered");
|
|
110
|
+
|
|
111
|
+
await beforeAgentStart(
|
|
112
|
+
{ prompt: "hello", systemPrompt: "base" },
|
|
113
|
+
{
|
|
114
|
+
cwd: projectRoot,
|
|
115
|
+
model: { provider: "claude-code", baseUrl: "local://claude-code" },
|
|
116
|
+
modelRegistry: {
|
|
117
|
+
getProviderAuthMode: () => "externalCli",
|
|
118
|
+
isProviderRequestReady: () => true,
|
|
119
|
+
},
|
|
120
|
+
ui: {
|
|
121
|
+
notify(message: string) {
|
|
122
|
+
notifications.push(message);
|
|
123
|
+
},
|
|
124
|
+
setWidget() {},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const configPath = join(projectRoot, ".mcp.json");
|
|
130
|
+
assert.equal(existsSync(configPath), true, "Claude Code CLI turns should create project MCP config");
|
|
131
|
+
|
|
132
|
+
const parsed = JSON.parse(readFileSync(configPath, "utf-8")) as {
|
|
133
|
+
mcpServers?: Record<string, unknown>;
|
|
134
|
+
};
|
|
135
|
+
assert.ok(parsed.mcpServers?.[GSD_WORKFLOW_MCP_SERVER_NAME]);
|
|
136
|
+
assert.match(notifications.join("\n"), /Claude Code MCP prepared/);
|
|
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" });
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// File Purpose: Worktree State Projection Module — typed-Interface contract tests for projectRootToWorktree (ADR-016).
|
|
3
3
|
import test from "node:test";
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
|
-
import { mkdtempSync, rmSync, mkdirSync } from "node:fs";
|
|
5
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, mkdirSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { WorktreeStateProjection } from "../worktree-state-projection.js";
|
|
@@ -60,6 +60,43 @@ test("projectRootToWorktree is idempotent — repeated calls do not throw", () =
|
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
test("projectRootToWorktree forwards root PROJECT.md into isolated worktrees", () => {
|
|
64
|
+
const { dir, cleanup } = makeProjectRoot();
|
|
65
|
+
try {
|
|
66
|
+
const worktree = join(dir, ".gsd", "worktrees", "M001");
|
|
67
|
+
mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
|
|
68
|
+
mkdirSync(join(worktree, ".gsd"), { recursive: true });
|
|
69
|
+
|
|
70
|
+
const projectContent = [
|
|
71
|
+
"# Project",
|
|
72
|
+
"",
|
|
73
|
+
"## Milestone Sequence",
|
|
74
|
+
"",
|
|
75
|
+
"- [ ] M001: Foundation — Establish the runnable slice.",
|
|
76
|
+
"",
|
|
77
|
+
].join("\n");
|
|
78
|
+
writeFileSync(join(dir, ".gsd", "PROJECT.md"), projectContent);
|
|
79
|
+
writeFileSync(join(dir, ".gsd", "REQUIREMENTS.md"), "# Requirements\n");
|
|
80
|
+
writeFileSync(join(dir, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
|
|
81
|
+
|
|
82
|
+
const workspace = createWorkspace(worktree);
|
|
83
|
+
const scope = scopeMilestone(workspace, "M001");
|
|
84
|
+
const projection = new WorktreeStateProjection();
|
|
85
|
+
|
|
86
|
+
projection.projectRootToWorktree(scope);
|
|
87
|
+
|
|
88
|
+
const projectedProject = join(worktree, ".gsd", "PROJECT.md");
|
|
89
|
+
assert.ok(existsSync(projectedProject), "PROJECT.md is available to worktree-bound units");
|
|
90
|
+
assert.equal(readFileSync(projectedProject, "utf-8"), projectContent);
|
|
91
|
+
assert.ok(
|
|
92
|
+
existsSync(join(worktree, ".gsd", "milestones", "M001", "M001-ROADMAP.md")),
|
|
93
|
+
"milestone artifacts still project into the worktree",
|
|
94
|
+
);
|
|
95
|
+
} finally {
|
|
96
|
+
cleanup();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
63
100
|
// ─── projectWorktreeToRoot — Module contract ────────────────────────────────
|
|
64
101
|
|
|
65
102
|
test("projectWorktreeToRoot exists and accepts a MilestoneScope", () => {
|