@opengsd/gsd-pi 1.0.2-dev.e9a1b49 → 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 +36 -55
- 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-post-create-hook.js +117 -0
- 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/dist/worktree-cli.d.ts +0 -2
- package/dist/worktree-cli.js +21 -9
- package/package.json +5 -2
- package/packages/cloud-mcp-gateway/bin/gsd-cloud-mcp-gateway.js +14 -0
- package/packages/cloud-mcp-gateway/package.json +4 -3
- 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/bin/gsd-mcp-server.js +14 -0
- 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 +5 -4
- 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/bin/pi-ai.js +14 -0
- 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 +73 -226
- 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 +3 -2
- 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/deps.js +10 -0
- 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 +47 -57
- 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-post-create-hook.test.ts +141 -1
- 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-post-create-hook.ts +127 -0
- 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/tsconfig.extensions.tsbuildinfo +0 -1
- /package/dist/web/standalone/.next/static/{BEjZM0MLHLibeMFbjtMol → tH1tnDYt1E0hK9Ien73Z0}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BEjZM0MLHLibeMFbjtMol → tH1tnDYt1E0hK9Ien73Z0}/_ssgManifest.js +0 -0
|
@@ -238,6 +238,67 @@ function createPostExecFailureTask(): void {
|
|
|
238
238
|
});
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
function createPostExecWarningTask(): void {
|
|
242
|
+
insertMilestone({ id: "M001" });
|
|
243
|
+
insertSlice({
|
|
244
|
+
id: "S01",
|
|
245
|
+
milestoneId: "M001",
|
|
246
|
+
title: "Test Slice",
|
|
247
|
+
risk: "low",
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const srcDir = join(tempDir, "src");
|
|
251
|
+
mkdirSync(srcDir, { recursive: true });
|
|
252
|
+
writeFileSync(
|
|
253
|
+
join(srcDir, "prior.ts"),
|
|
254
|
+
"export function formatName(name: string): string { return name; }\n",
|
|
255
|
+
"utf-8",
|
|
256
|
+
);
|
|
257
|
+
writeFileSync(
|
|
258
|
+
join(srcDir, "current.ts"),
|
|
259
|
+
"export function formatName(first: string, last: string): string { return `${first} ${last}`; }\n",
|
|
260
|
+
"utf-8",
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
insertTask({
|
|
264
|
+
id: "T00",
|
|
265
|
+
sliceId: "S01",
|
|
266
|
+
milestoneId: "M001",
|
|
267
|
+
title: "Prior task",
|
|
268
|
+
status: "complete",
|
|
269
|
+
keyFiles: ["src/prior.ts"],
|
|
270
|
+
planning: {
|
|
271
|
+
description: "Prior task with original signature",
|
|
272
|
+
estimate: "1h",
|
|
273
|
+
files: ["src/prior.ts"],
|
|
274
|
+
verify: "echo pass",
|
|
275
|
+
inputs: [],
|
|
276
|
+
expectedOutput: [],
|
|
277
|
+
observabilityImpact: "",
|
|
278
|
+
},
|
|
279
|
+
sequence: 0,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
insertTask({
|
|
283
|
+
id: "T01",
|
|
284
|
+
sliceId: "S01",
|
|
285
|
+
milestoneId: "M001",
|
|
286
|
+
title: "Task with signature warning",
|
|
287
|
+
status: "pending",
|
|
288
|
+
keyFiles: ["src/current.ts"],
|
|
289
|
+
planning: {
|
|
290
|
+
description: "Task that changes a prior function signature",
|
|
291
|
+
estimate: "1h",
|
|
292
|
+
files: ["src/current.ts"],
|
|
293
|
+
verify: "echo pass",
|
|
294
|
+
inputs: [],
|
|
295
|
+
expectedOutput: [],
|
|
296
|
+
observabilityImpact: "",
|
|
297
|
+
},
|
|
298
|
+
sequence: 1,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
241
302
|
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
242
303
|
|
|
243
304
|
describe("Post-execution blocking failure retry bypass", () => {
|
|
@@ -359,13 +420,8 @@ describe("Post-execution blocking failure retry bypass", () => {
|
|
|
359
420
|
assert.ok(messages.some((m: string) => m.includes("Verification failed") && m.includes("auto-fix attempt 1/2")));
|
|
360
421
|
});
|
|
361
422
|
|
|
362
|
-
test("post-exec failure notification
|
|
363
|
-
|
|
364
|
-
// the appropriate message about cross-task consistency issues.
|
|
365
|
-
// The actual post-exec failure would require specific file/output state
|
|
366
|
-
// that's harder to set up in a unit test, but we can verify the code path exists.
|
|
367
|
-
|
|
368
|
-
createBasicTask();
|
|
423
|
+
test("post-exec failure notification includes failing check details", async () => {
|
|
424
|
+
createPostExecFailureTask();
|
|
369
425
|
writePreferences({
|
|
370
426
|
enhanced_verification: true,
|
|
371
427
|
enhanced_verification_post: true,
|
|
@@ -381,9 +437,70 @@ describe("Post-execution blocking failure retry bypass", () => {
|
|
|
381
437
|
const vctx: VerificationContext = { s, ctx, pi };
|
|
382
438
|
const result = await runPostUnitVerification(vctx, pauseAutoMock);
|
|
383
439
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
440
|
+
assert.equal(result, "pause");
|
|
441
|
+
assert.equal(pauseAutoMock.mock.callCount(), 1);
|
|
442
|
+
const notifyMessages = ctx.ui.notify.mock.calls.map((c: { arguments: unknown[] }) =>
|
|
443
|
+
String(c.arguments[0])
|
|
444
|
+
);
|
|
445
|
+
assert.ok(
|
|
446
|
+
notifyMessages.some(
|
|
447
|
+
(m: string) =>
|
|
448
|
+
m.includes("Post-execution checks failed ([import] src/broken.ts:1") &&
|
|
449
|
+
m.includes("pausing for human review")
|
|
450
|
+
)
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
const pauseCalls = pauseAutoMock.mock.calls as Array<{ arguments: unknown[] }>;
|
|
454
|
+
const pauseCallArgs = pauseCalls[0]?.arguments[2] as
|
|
455
|
+
| { message?: string }
|
|
456
|
+
| undefined;
|
|
457
|
+
assert.ok(
|
|
458
|
+
pauseCallArgs?.message?.includes(
|
|
459
|
+
"Post-execution checks failed: [import] src/broken.ts:1"
|
|
460
|
+
)
|
|
461
|
+
);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
test("strict post-exec warning pause includes warning details", async () => {
|
|
465
|
+
createPostExecWarningTask();
|
|
466
|
+
writePreferences({
|
|
467
|
+
enhanced_verification: true,
|
|
468
|
+
enhanced_verification_post: true,
|
|
469
|
+
enhanced_verification_strict: true,
|
|
470
|
+
verification_auto_fix: true,
|
|
471
|
+
verification_max_retries: 3,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
const ctx = makeMockCtx();
|
|
475
|
+
const pi = makeMockPi();
|
|
476
|
+
const pauseAutoMock = mock.fn(async () => {});
|
|
477
|
+
const s = makeMockSession(tempDir, { type: "execute-task", id: "M001/S01/T01" });
|
|
478
|
+
|
|
479
|
+
const result = await runPostUnitVerification({ s, ctx, pi }, pauseAutoMock);
|
|
480
|
+
|
|
481
|
+
assert.equal(result, "pause");
|
|
482
|
+
assert.equal(pauseAutoMock.mock.callCount(), 1);
|
|
483
|
+
const notifyMessages = ctx.ui.notify.mock.calls.map((c: { arguments: unknown[] }) =>
|
|
484
|
+
String(c.arguments[0])
|
|
485
|
+
);
|
|
486
|
+
assert.ok(
|
|
487
|
+
notifyMessages.some(
|
|
488
|
+
(m: string) =>
|
|
489
|
+
m.includes("Post-execution checks failed ([signature] formatName:") &&
|
|
490
|
+
m.includes("pausing for human review")
|
|
491
|
+
)
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
const pauseCalls = pauseAutoMock.mock.calls as Array<{ arguments: unknown[] }>;
|
|
495
|
+
const pauseCallArgs = pauseCalls[0]?.arguments[2] as
|
|
496
|
+
| { message?: string }
|
|
497
|
+
| undefined;
|
|
498
|
+
assert.ok(
|
|
499
|
+
pauseCallArgs?.message?.includes(
|
|
500
|
+
"Post-execution checks failed: [signature] formatName:"
|
|
501
|
+
)
|
|
502
|
+
);
|
|
503
|
+
assert.ok(!pauseCallArgs?.message?.includes("unknown post-execution check failure"));
|
|
387
504
|
});
|
|
388
505
|
|
|
389
506
|
test("uok gate runner persists post-execution gate failures when enabled", async () => {
|
|
@@ -451,6 +451,50 @@ describe("checkImportResolution", () => {
|
|
|
451
451
|
}
|
|
452
452
|
});
|
|
453
453
|
|
|
454
|
+
test("ignores generated SvelteKit $types imports", () => {
|
|
455
|
+
tempDir = join(tmpdir(), `post-exec-test-${Date.now()}`);
|
|
456
|
+
mkdirSync(tempDir, { recursive: true });
|
|
457
|
+
mkdirSync(join(tempDir, "src", "routes"), { recursive: true });
|
|
458
|
+
writeFileSync(
|
|
459
|
+
join(tempDir, "src", "routes", "+page.ts"),
|
|
460
|
+
"import type { PageLoad } from './$types';\nexport const load: PageLoad = async () => ({})"
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
const task = createTask({
|
|
465
|
+
id: "T01",
|
|
466
|
+
key_files: ["src/routes/+page.ts"],
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
const results = checkImportResolution(task, [], tempDir);
|
|
470
|
+
assert.deepEqual(results, []);
|
|
471
|
+
} finally {
|
|
472
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
test("ignores nested generated SvelteKit $types imports", () => {
|
|
477
|
+
tempDir = join(tmpdir(), `post-exec-test-${Date.now()}`);
|
|
478
|
+
mkdirSync(tempDir, { recursive: true });
|
|
479
|
+
mkdirSync(join(tempDir, "src", "lib", "components"), { recursive: true });
|
|
480
|
+
writeFileSync(
|
|
481
|
+
join(tempDir, "src", "lib", "components", "RouteCard.ts"),
|
|
482
|
+
"import type { PageData } from '../../routes/blog/$types';\nexport const data = {} as PageData;"
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
const task = createTask({
|
|
487
|
+
id: "T01",
|
|
488
|
+
key_files: ["src/lib/components/RouteCard.ts"],
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
const results = checkImportResolution(task, [], tempDir);
|
|
492
|
+
assert.deepEqual(results, []);
|
|
493
|
+
} finally {
|
|
494
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
454
498
|
test("fails when import doesn't resolve", () => {
|
|
455
499
|
tempDir = join(tmpdir(), `post-exec-test-${Date.now()}`);
|
|
456
500
|
mkdirSync(tempDir, { recursive: true });
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { mock } from "node:test";
|
|
7
|
+
|
|
8
|
+
import { postUnitPostVerification, type PostUnitContext } from "../auto-post-unit.ts";
|
|
9
|
+
import { AutoSession } from "../auto/session.ts";
|
|
10
|
+
import { checkPostUnitHooks, resetHookState, resolveHookArtifactPath } from "../post-unit-hooks.ts";
|
|
11
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
12
|
+
import { invalidateAllCaches } from "../cache.ts";
|
|
13
|
+
|
|
14
|
+
function writePreferences(basePath: string): void {
|
|
15
|
+
const content = `---
|
|
16
|
+
post_unit_hooks:
|
|
17
|
+
- name: review-arbiter
|
|
18
|
+
after:
|
|
19
|
+
- execute-task
|
|
20
|
+
prompt: Review {taskId}
|
|
21
|
+
agent: arbiter
|
|
22
|
+
artifact: REVIEW-DEBATE.md
|
|
23
|
+
retry_on: NEEDS-REWORK.md
|
|
24
|
+
max_cycles: 3
|
|
25
|
+
enabled: true
|
|
26
|
+
---
|
|
27
|
+
`;
|
|
28
|
+
writeFileSync(join(basePath, ".gsd", "PREFERENCES.md"), content, "utf-8");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
test("post-unit retry_on marks trigger unit as retry in orchestrator before redispatch", async () => {
|
|
32
|
+
const originalCwd = process.cwd();
|
|
33
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-post-unit-retry-"));
|
|
34
|
+
const taskDir = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks");
|
|
35
|
+
mkdirSync(taskDir, { recursive: true });
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
process.chdir(base);
|
|
39
|
+
_clearGsdRootCache();
|
|
40
|
+
invalidateAllCaches();
|
|
41
|
+
resetHookState();
|
|
42
|
+
writePreferences(base);
|
|
43
|
+
|
|
44
|
+
const hookDispatch = checkPostUnitHooks("execute-task", "M001/S01/T01", base);
|
|
45
|
+
assert.ok(hookDispatch, "hook should dispatch for execute-task");
|
|
46
|
+
|
|
47
|
+
const retryPath = resolveHookArtifactPath(base, "M001/S01/T01", "NEEDS-REWORK.md");
|
|
48
|
+
writeFileSync(retryPath, "rework requested", "utf-8");
|
|
49
|
+
|
|
50
|
+
const retryActiveUnit = mock.fn(async (_unit: { unitType: string; unitId: string }) => {});
|
|
51
|
+
const s = new AutoSession();
|
|
52
|
+
s.basePath = base;
|
|
53
|
+
s.active = true;
|
|
54
|
+
s.currentUnit = { type: "hook/review-arbiter", id: "M001/S01/T01", startedAt: Date.now() };
|
|
55
|
+
s.orchestration = {
|
|
56
|
+
start: async () => ({ kind: "started" }),
|
|
57
|
+
advance: async () => ({ kind: "stopped", reason: "unused" }),
|
|
58
|
+
completeActiveUnit: async () => {},
|
|
59
|
+
retryActiveUnit,
|
|
60
|
+
resume: async () => ({ kind: "resumed" }),
|
|
61
|
+
stop: async (reason: string) => ({ kind: "stopped", reason }),
|
|
62
|
+
getStatus: () => ({ phase: "running", transitionCount: 0 }),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const pctx: PostUnitContext = {
|
|
66
|
+
s,
|
|
67
|
+
ctx: {
|
|
68
|
+
ui: { notify: () => {}, setStatus: () => {}, setWidget: () => {}, setFooter: () => {} },
|
|
69
|
+
model: { id: "test-model" },
|
|
70
|
+
} as any,
|
|
71
|
+
pi: { sendMessage: async () => {}, setModel: async () => true } as any,
|
|
72
|
+
buildSnapshotOpts: () => ({}),
|
|
73
|
+
lockBase: () => base,
|
|
74
|
+
stopAuto: async () => {},
|
|
75
|
+
pauseAuto: async () => {},
|
|
76
|
+
updateProgressWidget: () => {},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const result = await postUnitPostVerification(pctx);
|
|
80
|
+
assert.equal(result, "continue");
|
|
81
|
+
assert.equal(retryActiveUnit.mock.callCount(), 1);
|
|
82
|
+
assert.deepEqual(retryActiveUnit.mock.calls[0]?.arguments[0], {
|
|
83
|
+
unitType: "execute-task",
|
|
84
|
+
unitId: "M001/S01/T01",
|
|
85
|
+
});
|
|
86
|
+
} finally {
|
|
87
|
+
process.chdir(originalCwd);
|
|
88
|
+
resetHookState();
|
|
89
|
+
invalidateAllCaches();
|
|
90
|
+
_clearGsdRootCache();
|
|
91
|
+
rmSync(base, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
@@ -204,6 +204,32 @@ describe("project-relocation-recovery (#2750)", () => {
|
|
|
204
204
|
rmSync(repo, { recursive: true, force: true });
|
|
205
205
|
});
|
|
206
206
|
|
|
207
|
+
test("local-only repo does not warn when origin remote is missing", () => {
|
|
208
|
+
const repo = realpathSync(mkdtempSync(join(tmpdir(), "gsd-reloc-no-origin-")));
|
|
209
|
+
initRepo(repo);
|
|
210
|
+
|
|
211
|
+
const warnings: unknown[][] = [];
|
|
212
|
+
const originalWarn = console.warn;
|
|
213
|
+
console.warn = (...args: unknown[]) => {
|
|
214
|
+
warnings.push(args);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
repoIdentity(repo);
|
|
219
|
+
externalGsdRoot(repo);
|
|
220
|
+
ensureGsdSymlink(repo);
|
|
221
|
+
} finally {
|
|
222
|
+
console.warn = originalWarn;
|
|
223
|
+
rmSync(repo, { recursive: true, force: true });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
assert.deepStrictEqual(
|
|
227
|
+
warnings,
|
|
228
|
+
[],
|
|
229
|
+
"missing origin must be treated as local-only repo, not a git failure",
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
|
|
207
233
|
test("local-only repo recovers state via .gsd-id marker after move", () => {
|
|
208
234
|
const repoA = realpathSync(mkdtempSync(join(tmpdir(), "gsd-reloc-local-a-")));
|
|
209
235
|
initRepo(repoA);
|
|
@@ -245,6 +271,81 @@ describe("project-relocation-recovery (#2750)", () => {
|
|
|
245
271
|
rmSync(repoB, { recursive: true, force: true });
|
|
246
272
|
});
|
|
247
273
|
|
|
274
|
+
test("repoIdentity ignores stale .gsd-id after relocation migration when git remote lookup fails", () => {
|
|
275
|
+
const repoA = realpathSync(mkdtempSync(join(tmpdir(), "gsd-reloc-stale-marker-a-")));
|
|
276
|
+
initRepo(repoA);
|
|
277
|
+
|
|
278
|
+
const externalA = ensureGsdSymlink(repoA);
|
|
279
|
+
mkdirSync(join(externalA, "milestones"), { recursive: true });
|
|
280
|
+
writeFileSync(join(externalA, "milestones", "M001.md"), "# Local Milestone\n", "utf-8");
|
|
281
|
+
|
|
282
|
+
const repoB = join(
|
|
283
|
+
tmpdir(),
|
|
284
|
+
`gsd-reloc-stale-marker-b-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
285
|
+
);
|
|
286
|
+
renameSync(repoA, repoB);
|
|
287
|
+
|
|
288
|
+
const migratedExternal = externalGsdRoot(repoB);
|
|
289
|
+
const expectedIdentity = repoIdentity(repoB);
|
|
290
|
+
rmSync(join(repoB, ".git", "config"), { force: true });
|
|
291
|
+
|
|
292
|
+
const warnings: unknown[][] = [];
|
|
293
|
+
const originalWarn = console.warn;
|
|
294
|
+
console.warn = (...args: unknown[]) => {
|
|
295
|
+
warnings.push(args);
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
assert.strictEqual(
|
|
300
|
+
repoIdentity(repoB),
|
|
301
|
+
expectedIdentity,
|
|
302
|
+
"transient git failures must not pin identity to a stale marker",
|
|
303
|
+
);
|
|
304
|
+
assert.ok(
|
|
305
|
+
existsSync(join(migratedExternal, "milestones", "M001.md")),
|
|
306
|
+
"migrated state remains under the recovered identity",
|
|
307
|
+
);
|
|
308
|
+
} finally {
|
|
309
|
+
console.warn = originalWarn;
|
|
310
|
+
rmSync(repoB, { recursive: true, force: true });
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test("externalGsdRoot syncs .gsd-id after recovering remote-backed state", () => {
|
|
315
|
+
const repo = realpathSync(mkdtempSync(join(tmpdir(), "gsd-reloc-remote-marker-")));
|
|
316
|
+
initRepo(repo, "https://github.com/example/remote-marker.git");
|
|
317
|
+
|
|
318
|
+
const expectedIdentity = repoIdentity(repo);
|
|
319
|
+
const staleMarkerId = "stale-marker-id";
|
|
320
|
+
const staleExternal = join(stateDir, "projects", staleMarkerId);
|
|
321
|
+
mkdirSync(join(staleExternal, "milestones"), { recursive: true });
|
|
322
|
+
writeFileSync(join(staleExternal, "milestones", "M001.md"), "# Remote Milestone\n", "utf-8");
|
|
323
|
+
writeFileSync(join(repo, ".gsd-id"), `${staleMarkerId}\n`, "utf-8");
|
|
324
|
+
|
|
325
|
+
const recoveredExternal = externalGsdRoot(repo);
|
|
326
|
+
assert.strictEqual(
|
|
327
|
+
readFileSync(join(repo, ".gsd-id"), "utf-8").trim(),
|
|
328
|
+
expectedIdentity,
|
|
329
|
+
"recovery must update .gsd-id to the identity that now owns migrated state",
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
rmSync(join(repo, ".git", "config"), { force: true });
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
assert.strictEqual(
|
|
336
|
+
repoIdentity(repo),
|
|
337
|
+
expectedIdentity,
|
|
338
|
+
"transient git failures must keep using the recovered remote-backed identity",
|
|
339
|
+
);
|
|
340
|
+
assert.ok(
|
|
341
|
+
existsSync(join(recoveredExternal, "milestones", "M001.md")),
|
|
342
|
+
"migrated state remains under the recovered remote-backed identity",
|
|
343
|
+
);
|
|
344
|
+
} finally {
|
|
345
|
+
rmSync(repo, { recursive: true, force: true });
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
248
349
|
// ── Edge cases ────────────────────────────────────────────────────────
|
|
249
350
|
|
|
250
351
|
test("identity remains different for repos with different remotes", () => {
|
|
@@ -2,6 +2,7 @@ import { describe, test } from "node:test";
|
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
|
|
4
4
|
import { showQueueReorder } from "../queue-reorder-ui.ts";
|
|
5
|
+
import { assertFullOuterBorder } from "./tui-border-assertions.ts";
|
|
5
6
|
|
|
6
7
|
const fakeTheme = {
|
|
7
8
|
fg: (_color: string, text: string) => text,
|
|
@@ -43,6 +44,51 @@ describe("queue-reorder-ui", () => {
|
|
|
43
44
|
const joined = lastRender.join("\n");
|
|
44
45
|
assert.ok(joined.includes("M016"), "selected item should stay visible after scrolling");
|
|
45
46
|
assert.ok(lastRender.length <= 16, `overlay should fit terminal max-height, got ${lastRender.length}`);
|
|
47
|
+
assertFullOuterBorder(lastRender, 100);
|
|
48
|
+
assert.match(lastRender[0] ?? "", /^╭─ Queue Reorder /);
|
|
49
|
+
assert.match(lastRender.at(-1) ?? "", /^╰─+╯$/);
|
|
50
|
+
} finally {
|
|
51
|
+
if (originalRowsDescriptor) {
|
|
52
|
+
Object.defineProperty(process.stdout, "rows", originalRowsDescriptor);
|
|
53
|
+
} else {
|
|
54
|
+
delete (process.stdout as { rows?: number }).rows;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("draws queue scroll thumb beside queue rows when completed rows are shown", async () => {
|
|
60
|
+
const originalRowsDescriptor = Object.getOwnPropertyDescriptor(process.stdout, "rows");
|
|
61
|
+
Object.defineProperty(process.stdout, "rows", { value: 12, configurable: true });
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const completed = [
|
|
65
|
+
{ id: "M000", title: "Already done" },
|
|
66
|
+
];
|
|
67
|
+
const pending = Array.from({ length: 8 }, (_, idx) => ({
|
|
68
|
+
id: `M${String(idx + 1).padStart(3, "0")}`,
|
|
69
|
+
title: `Milestone ${idx + 1}`,
|
|
70
|
+
}));
|
|
71
|
+
let rendered: string[] = [];
|
|
72
|
+
|
|
73
|
+
const ctx = {
|
|
74
|
+
hasUI: true,
|
|
75
|
+
ui: {
|
|
76
|
+
custom: async (factory: any) => {
|
|
77
|
+
const component = factory({ requestRender() {} }, fakeTheme, null, () => {});
|
|
78
|
+
rendered = component.render(80);
|
|
79
|
+
return null;
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
} as any;
|
|
83
|
+
|
|
84
|
+
await showQueueReorder(ctx, completed, pending);
|
|
85
|
+
|
|
86
|
+
const completedHeader = rendered.find(line => line.includes("Completed:"));
|
|
87
|
+
const firstQueueRow = rendered.find(line => line.includes("M001"));
|
|
88
|
+
assert.ok(completedHeader, "completed header should be rendered before queue rows");
|
|
89
|
+
assert.ok(firstQueueRow, "first queue row should be rendered");
|
|
90
|
+
assert.match(completedHeader, /│$/);
|
|
91
|
+
assert.match(firstQueueRow, /┃$/);
|
|
46
92
|
} finally {
|
|
47
93
|
if (originalRowsDescriptor) {
|
|
48
94
|
Object.defineProperty(process.stdout, "rows", originalRowsDescriptor);
|
|
@@ -134,6 +134,72 @@ test("handleRecoverableExtensionProcessError swallows EPIPE without writing a cr
|
|
|
134
134
|
}
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
+
test("handleRecoverableExtensionProcessError tolerates stderr.write throwing EPIPE (re-entry guard)", () => {
|
|
138
|
+
// process.stderr.write itself can EPIPE; safeStderr() must swallow it so the
|
|
139
|
+
// handler doesn't re-enter the EPIPE branch and loop forever.
|
|
140
|
+
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
141
|
+
process.stderr.write = (() => {
|
|
142
|
+
throw Object.assign(new Error("stderr broken pipe"), {
|
|
143
|
+
code: "EPIPE",
|
|
144
|
+
syscall: "write",
|
|
145
|
+
});
|
|
146
|
+
}) as typeof process.stderr.write;
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const handled = handleRecoverableExtensionProcessError(
|
|
150
|
+
Object.assign(new Error("broken pipe"), {
|
|
151
|
+
code: "EPIPE",
|
|
152
|
+
syscall: "write",
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
assert.equal(handled, true);
|
|
156
|
+
} finally {
|
|
157
|
+
process.stderr.write = originalWrite;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// #181: Windows surfaces a closed pipe mid-write as `Error: write EOF` (or
|
|
162
|
+
// `read EOF`) with no `code` set. Both are the same logical condition as POSIX
|
|
163
|
+
// EPIPE and must be swallowed, else they escape to the uncaught-exception path
|
|
164
|
+
// and crash auto-mode workers. These non-storm cases run before the storm test
|
|
165
|
+
// below so the shared storm counter stays under threshold. ECONNRESET is
|
|
166
|
+
// intentionally NOT in this set — see the dedicated "leaves ECONNRESET network
|
|
167
|
+
// errors unhandled" test above.
|
|
168
|
+
test("handleRecoverableExtensionProcessError swallows Windows 'write EOF' (no code)", () => {
|
|
169
|
+
let stderr = "";
|
|
170
|
+
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
171
|
+
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
172
|
+
stderr += String(chunk);
|
|
173
|
+
return true;
|
|
174
|
+
}) as typeof process.stderr.write;
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
// Mirror the real Windows error: message "write EOF", no `code`, no `syscall`.
|
|
178
|
+
const handled = handleRecoverableExtensionProcessError(new Error("write EOF"));
|
|
179
|
+
assert.equal(handled, true);
|
|
180
|
+
assert.match(stderr, /swallowed write EOF/);
|
|
181
|
+
} finally {
|
|
182
|
+
process.stderr.write = originalWrite;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("handleRecoverableExtensionProcessError swallows 'read EOF' (no code)", () => {
|
|
187
|
+
let stderr = "";
|
|
188
|
+
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
189
|
+
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
190
|
+
stderr += String(chunk);
|
|
191
|
+
return true;
|
|
192
|
+
}) as typeof process.stderr.write;
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
const handled = handleRecoverableExtensionProcessError(new Error("read EOF"));
|
|
196
|
+
assert.equal(handled, true);
|
|
197
|
+
assert.match(stderr, /swallowed read EOF/);
|
|
198
|
+
} finally {
|
|
199
|
+
process.stderr.write = originalWrite;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
137
203
|
test("handleRecoverableExtensionProcessError swallows dead transport control write errors", () => {
|
|
138
204
|
let stderr = "";
|
|
139
205
|
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
@@ -153,7 +219,16 @@ test("handleRecoverableExtensionProcessError swallows dead transport control wri
|
|
|
153
219
|
}
|
|
154
220
|
});
|
|
155
221
|
|
|
156
|
-
test("handleRecoverableExtensionProcessError
|
|
222
|
+
test("handleRecoverableExtensionProcessError leaves a plain EOF-substring error unhandled", () => {
|
|
223
|
+
// Guard against over-matching: only the exact "write EOF"/"read EOF" messages
|
|
224
|
+
// are the Windows pipe-closed signature; an unrelated error must not be eaten.
|
|
225
|
+
const handled = handleRecoverableExtensionProcessError(new Error("could not write EOF marker to log"));
|
|
226
|
+
assert.equal(handled, false);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("handleRecoverableExtensionProcessError exits on EPIPE storm (>100 within 10s)", () => {
|
|
230
|
+
// After the storm threshold, the pipe is gone for good — handler must exit
|
|
231
|
+
// cleanly instead of swallowing forever in a tight CPU loop.
|
|
157
232
|
let stderr = "";
|
|
158
233
|
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
159
234
|
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
@@ -161,18 +236,38 @@ test("handleRecoverableExtensionProcessError swallows write EOF without code", (
|
|
|
161
236
|
return true;
|
|
162
237
|
}) as typeof process.stderr.write;
|
|
163
238
|
|
|
239
|
+
const originalExit = process.exit;
|
|
240
|
+
const exitCalls: Array<number | undefined> = [];
|
|
241
|
+
process.exit = ((code?: number) => {
|
|
242
|
+
exitCalls.push(code);
|
|
243
|
+
// Don't actually exit; just record the call.
|
|
244
|
+
return undefined as never;
|
|
245
|
+
}) as typeof process.exit;
|
|
246
|
+
|
|
164
247
|
try {
|
|
165
|
-
const
|
|
166
|
-
|
|
248
|
+
const err = Object.assign(new Error("broken pipe"), {
|
|
249
|
+
code: "EPIPE",
|
|
250
|
+
syscall: "write",
|
|
251
|
+
});
|
|
252
|
+
// Fire well above the 100-event threshold inside the 10s window.
|
|
253
|
+
for (let i = 0; i < 150; i++) {
|
|
254
|
+
handleRecoverableExtensionProcessError(err);
|
|
255
|
+
}
|
|
256
|
+
assert.ok(
|
|
257
|
+
exitCalls.length > 0,
|
|
258
|
+
`expected process.exit to be called during EPIPE storm, got ${exitCalls.length} calls`,
|
|
167
259
|
);
|
|
168
|
-
assert.equal(
|
|
169
|
-
assert.match(stderr, /
|
|
260
|
+
assert.equal(exitCalls[0], 0);
|
|
261
|
+
assert.match(stderr, /EPIPE storm/);
|
|
170
262
|
} finally {
|
|
171
263
|
process.stderr.write = originalWrite;
|
|
264
|
+
process.exit = originalExit;
|
|
172
265
|
}
|
|
173
266
|
});
|
|
174
267
|
|
|
175
|
-
test("handleRecoverableExtensionProcessError
|
|
268
|
+
test("handleRecoverableExtensionProcessError exits on a Windows 'write EOF' storm too (#181)", () => {
|
|
269
|
+
// The storm counter is shared across all pipe-closed encodings, so a runaway
|
|
270
|
+
// Windows `write EOF` loop must trip the same clean-exit guard as EPIPE.
|
|
176
271
|
let stderr = "";
|
|
177
272
|
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
178
273
|
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
@@ -180,13 +275,23 @@ test("handleRecoverableExtensionProcessError swallows read EOF without code", ()
|
|
|
180
275
|
return true;
|
|
181
276
|
}) as typeof process.stderr.write;
|
|
182
277
|
|
|
278
|
+
const originalExit = process.exit;
|
|
279
|
+
const exitCalls: Array<number | undefined> = [];
|
|
280
|
+
process.exit = ((code?: number) => {
|
|
281
|
+
exitCalls.push(code);
|
|
282
|
+
return undefined as never;
|
|
283
|
+
}) as typeof process.exit;
|
|
284
|
+
|
|
183
285
|
try {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
assert.
|
|
286
|
+
const err = new Error("write EOF");
|
|
287
|
+
for (let i = 0; i < 150; i++) {
|
|
288
|
+
handleRecoverableExtensionProcessError(err);
|
|
289
|
+
}
|
|
290
|
+
assert.ok(exitCalls.length > 0, "expected process.exit during write EOF storm");
|
|
291
|
+
assert.equal(exitCalls[0], 0);
|
|
292
|
+
assert.match(stderr, /write EOF storm/);
|
|
189
293
|
} finally {
|
|
190
294
|
process.stderr.write = originalWrite;
|
|
295
|
+
process.exit = originalExit;
|
|
191
296
|
}
|
|
192
297
|
});
|
|
@@ -255,4 +255,31 @@ test('ensureGsdSymlink prefers marker directory when marker/computed identities
|
|
|
255
255
|
rmSync(repo, { recursive: true, force: true });
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
+
test('repoIdentity/externalGsdRoot stay marker-stable when git remote read transiently fails (#276)', () => {
|
|
259
|
+
const repo = realpathSync(mkdtempSync(join(tmpdir(), "gsd-remote-transient-")));
|
|
260
|
+
run("git init -b main", repo);
|
|
261
|
+
run('git config user.name "Pi Test"', repo);
|
|
262
|
+
run('git config user.email "pi@example.com"', repo);
|
|
263
|
+
run('git remote add origin git@github.com:example/transient.git', repo);
|
|
264
|
+
writeFileSync(join(repo, "README.md"), "# Transient Remote Test\n", "utf-8");
|
|
265
|
+
run("git add README.md", repo);
|
|
266
|
+
run('git commit -m "init"', repo);
|
|
267
|
+
|
|
268
|
+
const stableExternal = ensureGsdSymlink(repo);
|
|
269
|
+
const stableIdentity = repoIdentity(repo);
|
|
270
|
+
assert.deepStrictEqual(externalGsdRoot(repo), stableExternal, "externalGsdRoot initially resolves canonical state directory");
|
|
271
|
+
|
|
272
|
+
const gitConfigPath = join(repo, ".git", "config");
|
|
273
|
+
const gitConfigBakPath = join(repo, ".git", "config.bak");
|
|
274
|
+
renameSync(gitConfigPath, gitConfigBakPath);
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
assert.deepStrictEqual(repoIdentity(repo), stableIdentity, "repoIdentity remains anchored to .gsd-id marker during transient git remote read failure");
|
|
278
|
+
assert.deepStrictEqual(externalGsdRoot(repo), stableExternal, "externalGsdRoot remains marker-resolved during transient git remote read failure");
|
|
279
|
+
} finally {
|
|
280
|
+
renameSync(gitConfigBakPath, gitConfigPath);
|
|
281
|
+
rmSync(repo, { recursive: true, force: true });
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
258
285
|
});
|