gsd-pi 2.77.0-dev.58d3d4d6c → 2.77.0-dev.cfd69e714
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 +1 -1
- package/dist/claude-cli-check.js +5 -1
- package/dist/headless.js +49 -4
- package/dist/resource-loader.d.ts +40 -0
- package/dist/resource-loader.js +32 -13
- package/dist/resources/extensions/browser-tools/capture.js +9 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +5 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/gsd/auto/loop.js +43 -0
- package/dist/resources/extensions/gsd/auto/phases.js +15 -21
- package/dist/resources/extensions/gsd/auto/session.js +0 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +102 -24
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +71 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +329 -102
- package/dist/resources/extensions/gsd/auto-recovery.js +195 -23
- package/dist/resources/extensions/gsd/auto-start.js +34 -24
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
- package/dist/resources/extensions/gsd/auto.js +31 -20
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
- package/dist/resources/extensions/gsd/component-loader.js +447 -0
- package/dist/resources/extensions/gsd/component-types.js +69 -0
- package/dist/resources/extensions/gsd/detection.js +49 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/gate-registry.js +2 -2
- package/dist/resources/extensions/gsd/git-constants.js +28 -1
- package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
- package/dist/resources/extensions/gsd/git-service.js +126 -2
- package/dist/resources/extensions/gsd/gsd-db.js +6 -3
- package/dist/resources/extensions/gsd/guided-flow.js +17 -5
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
- package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
- package/dist/resources/extensions/gsd/model-router.js +6 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- package/dist/resources/extensions/gsd/session-lock.js +19 -10
- package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state.js +44 -33
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +34 -8
- package/dist/resources/extensions/mcp-client/index.js +3 -1
- package/dist/resources/extensions/ollama/index.js +5 -1
- package/dist/resources/extensions/remote-questions/manager.js +11 -5
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
- 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/git/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 +5 -5
- package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +2 -3
- package/packages/daemon/src/logger.ts +4 -3
- package/packages/mcp-server/dist/server.d.ts +24 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +88 -87
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +25 -3
- package/packages/mcp-server/src/readers/graph.test.ts +87 -15
- package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
- package/packages/mcp-server/src/server.ts +131 -105
- package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
- package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
- package/packages/native/src/__tests__/ps.test.mjs +14 -8
- package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
- package/packages/native/src/__tests__/truncate.test.mjs +17 -2
- package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
- package/packages/pi-agent-core/src/agent.test.ts +96 -102
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.js +9 -2
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
- package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +43 -70
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +36 -11
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +44 -0
- package/packages/pi-ai/src/models/capability-patches.ts +10 -2
- package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
- package/packages/pi-ai/src/models/generated/openai.ts +17 -0
- package/packages/pi-ai/src/models.generated.test.ts +46 -73
- package/packages/pi-ai/src/models.test.ts +48 -11
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
- package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
- package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
- package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
- package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
- package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
- package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
- package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +14 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +19 -0
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.js.map +1 -1
- package/packages/pi-tui/dist/editor-component.d.ts +2 -0
- package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
- package/packages/pi-tui/dist/editor-component.js.map +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
- package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
- package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
- package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
- package/packages/pi-tui/src/components/editor.ts +22 -0
- package/packages/pi-tui/src/components/image.test.ts +10 -5
- package/packages/pi-tui/src/editor-component.ts +3 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/dist/rpc-client.test.js +101 -51
- package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
- package/packages/rpc-client/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/scripts/install.js +15 -1
- package/src/resources/extensions/browser-tools/capture.ts +12 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +5 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
- package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
- package/src/resources/extensions/gsd/auto/loop.ts +47 -0
- package/src/resources/extensions/gsd/auto/phases.ts +16 -20
- package/src/resources/extensions/gsd/auto/session.ts +0 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +113 -24
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +82 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +330 -90
- package/src/resources/extensions/gsd/auto-recovery.ts +225 -24
- package/src/resources/extensions/gsd/auto-start.ts +54 -6
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
- package/src/resources/extensions/gsd/auto.ts +43 -22
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
- package/src/resources/extensions/gsd/component-loader.ts +598 -0
- package/src/resources/extensions/gsd/component-types.ts +362 -0
- package/src/resources/extensions/gsd/detection.ts +58 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/gate-registry.ts +2 -2
- package/src/resources/extensions/gsd/git-constants.ts +30 -1
- package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
- package/src/resources/extensions/gsd/git-service.ts +133 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +20 -5
- package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
- package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- package/src/resources/extensions/gsd/session-lock.ts +20 -10
- package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state.ts +49 -44
- package/src/resources/extensions/gsd/sync-lock.ts +97 -39
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +94 -289
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -197
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
- package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
- package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +9 -105
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -57
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
- package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -62
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -49
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -133
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
- package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +12 -61
- package/src/resources/extensions/gsd/tests/test-helpers.ts +21 -8
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -81
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/types.ts +3 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +55 -7
- package/src/resources/extensions/mcp-client/index.ts +3 -1
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
- package/src/resources/extensions/ollama/index.ts +5 -1
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
- package/src/resources/extensions/remote-questions/manager.ts +36 -4
- package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
- package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -144
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -75
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/forensics-worktree-telemetry.test.ts +0 -145
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -130
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -43
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -288,7 +288,7 @@ Auto mode is a state machine driven by files on disk. It reads `.gsd/STATE.md`,
|
|
|
288
288
|
|
|
289
289
|
5. **Provider error recovery** — Transient provider errors (rate limits, 500/503 server errors, overloaded) auto-resume after a delay. Permanent errors (auth, billing) pause for manual review. The model fallback chain retries transient network errors before switching models.
|
|
290
290
|
|
|
291
|
-
6. **Stuck detection** — A sliding-window detector identifies repeated dispatch patterns (including multi-unit cycles).
|
|
291
|
+
6. **Stuck and artifact detection** — A sliding-window detector identifies repeated dispatch patterns (including multi-unit cycles). Missing expected artifacts use a separate bounded path: GSD retries artifact verification up to 3 times with failure context, then pauses auto mode with the missing artifact error instead of looping indefinitely.
|
|
292
292
|
|
|
293
293
|
7. **Timeout supervision** — Soft timeout warns the LLM to wrap up. Idle watchdog detects stalls. Hard timeout pauses auto mode. Recovery steering nudges the LLM to finish durable output before giving up.
|
|
294
294
|
|
package/dist/claude-cli-check.js
CHANGED
|
@@ -28,7 +28,11 @@ function execClaudeCheck(args) {
|
|
|
28
28
|
let lastError;
|
|
29
29
|
for (const command of CLAUDE_COMMAND_CANDIDATES) {
|
|
30
30
|
try {
|
|
31
|
-
return execFileSync(command, args, {
|
|
31
|
+
return execFileSync(command, args, {
|
|
32
|
+
timeout: 5_000,
|
|
33
|
+
stdio: 'pipe',
|
|
34
|
+
shell: process.platform === 'win32',
|
|
35
|
+
});
|
|
32
36
|
}
|
|
33
37
|
catch (error) {
|
|
34
38
|
lastError = error;
|
package/dist/headless.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 10 — blocked (command reported a blocker)
|
|
12
12
|
* 11 — cancelled (SIGINT/SIGTERM received)
|
|
13
13
|
*/
|
|
14
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
14
|
+
import { existsSync, mkdirSync, writeFileSync, writeSync } from 'node:fs';
|
|
15
15
|
import { join } from 'node:path';
|
|
16
16
|
import { resolve } from 'node:path';
|
|
17
17
|
import { RpcClient, SessionManager } from '@gsd/pi-coding-agent';
|
|
@@ -250,6 +250,30 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
250
250
|
const result = await handleQuery(process.cwd());
|
|
251
251
|
return { exitCode: result.exitCode, interrupted: false };
|
|
252
252
|
}
|
|
253
|
+
// Doctor: read-only health check, no RPC child needed (#4904 live-regression).
|
|
254
|
+
// The interactive `/gsd doctor` command lives in the GSD extension; this CLI
|
|
255
|
+
// path lets non-interactive callers (CI, recovery scripts, the live-regression
|
|
256
|
+
// suite) get the same diagnostic without a TTY.
|
|
257
|
+
if (options.command === 'doctor') {
|
|
258
|
+
const wantsJson = options.json || options.commandArgs.includes('--json');
|
|
259
|
+
const { runGSDDoctor } = await import('./resources/extensions/gsd/doctor.js');
|
|
260
|
+
const { formatDoctorReport, formatDoctorReportJson } = await import('./resources/extensions/gsd/doctor-format.js');
|
|
261
|
+
let exitCode = 1;
|
|
262
|
+
try {
|
|
263
|
+
const report = await runGSDDoctor(process.cwd());
|
|
264
|
+
const out = wantsJson ? formatDoctorReportJson(report) : formatDoctorReport(report);
|
|
265
|
+
process.stdout.write(`${out}\n`);
|
|
266
|
+
exitCode = report.ok ? 0 : 1;
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
270
|
+
process.stderr.write(`[headless] doctor failed: ${msg}\n`);
|
|
271
|
+
exitCode = 1;
|
|
272
|
+
}
|
|
273
|
+
// Bypass the auto-restart loop in runHeadless — doctor is a one-shot
|
|
274
|
+
// diagnostic; exit 1 means "issues detected", not "crashed".
|
|
275
|
+
process.exit(exitCode);
|
|
276
|
+
}
|
|
253
277
|
// Resolve CLI path for the child process
|
|
254
278
|
const cliPath = process.env.GSD_BIN_PATH || process.argv[1];
|
|
255
279
|
if (!cliPath) {
|
|
@@ -616,7 +640,15 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
616
640
|
});
|
|
617
641
|
// Signal handling
|
|
618
642
|
const signalHandler = () => {
|
|
619
|
-
|
|
643
|
+
// Use writeSync on fd 2 to guarantee the Interrupted marker reaches
|
|
644
|
+
// consumers before process.exit() truncates pending async writes.
|
|
645
|
+
try {
|
|
646
|
+
writeSync(2, '\n[headless] Interrupted, stopping child process...\n');
|
|
647
|
+
}
|
|
648
|
+
catch {
|
|
649
|
+
// Fallback to async write if fd 2 is somehow unavailable.
|
|
650
|
+
process.stderr.write('\n[headless] Interrupted, stopping child process...\n');
|
|
651
|
+
}
|
|
620
652
|
interrupted = true;
|
|
621
653
|
exitCode = EXIT_CANCELLED;
|
|
622
654
|
// Kill child process — don't await, just fire and exit.
|
|
@@ -635,8 +667,21 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
635
667
|
}
|
|
636
668
|
process.exit(exitCode);
|
|
637
669
|
};
|
|
638
|
-
|
|
639
|
-
process.
|
|
670
|
+
// Use prependListener so our handler runs before pi-coding-agent's
|
|
671
|
+
// LSP-client module-load SIGINT handler, which calls process.exit(0)
|
|
672
|
+
// and would otherwise short-circuit our exit-code-11 contract.
|
|
673
|
+
process.prependListener('SIGINT', signalHandler);
|
|
674
|
+
process.prependListener('SIGTERM', signalHandler);
|
|
675
|
+
// Emit a deterministic readiness marker so test harnesses can wait for
|
|
676
|
+
// the SIGINT handler to be live before sending a signal. writeSync on
|
|
677
|
+
// fd 2 avoids any pipe-buffering race between the marker and subsequent
|
|
678
|
+
// signal delivery.
|
|
679
|
+
try {
|
|
680
|
+
writeSync(2, '[headless] signal-handlers-ready\n');
|
|
681
|
+
}
|
|
682
|
+
catch {
|
|
683
|
+
process.stderr.write('[headless] signal-handlers-ready\n');
|
|
684
|
+
}
|
|
640
685
|
// Start the RPC session
|
|
641
686
|
try {
|
|
642
687
|
await client.start();
|
|
@@ -2,7 +2,47 @@ import { DefaultResourceLoader } from '@gsd/pi-coding-agent';
|
|
|
2
2
|
export { discoverExtensionEntryPaths } from './extension-discovery.js';
|
|
3
3
|
export declare function getExtensionKey(entryPath: string, extensionsDir: string): string;
|
|
4
4
|
export declare function readManagedResourceVersion(agentDir: string): string | null;
|
|
5
|
+
/**
|
|
6
|
+
* Computes a content fingerprint of a resources directory (defaults to the
|
|
7
|
+
* bundled resourcesDir).
|
|
8
|
+
*
|
|
9
|
+
* Walks all files under `rootDir` and hashes `${relativePath}:${sha256(contents)}`
|
|
10
|
+
* for each one. Using the file *contents* — not size — is what distinguishes
|
|
11
|
+
* this from the earlier implementation and closes #4787: a same-size edit
|
|
12
|
+
* (e.g. swapping one word for another word of the same byte length) produces
|
|
13
|
+
* a different file hash, bumps the aggregate fingerprint, and therefore
|
|
14
|
+
* triggers a full resync in `initResources`. The old path+size approach
|
|
15
|
+
* silently cached stale prompts across upgrades.
|
|
16
|
+
*
|
|
17
|
+
* Cost is ~1-2ms for a typical resources tree (~100 small .md files) —
|
|
18
|
+
* still negligible at startup. Files are streamed via `readFileSync` but
|
|
19
|
+
* bundled prompts are tiny so this is fine.
|
|
20
|
+
*
|
|
21
|
+
* Exported for unit tests and for callers that want to check a different
|
|
22
|
+
* directory (e.g. pre-install verification).
|
|
23
|
+
*/
|
|
24
|
+
export declare function computeResourceFingerprint(rootDir?: string): string;
|
|
5
25
|
export declare function getNewerManagedResourceVersion(agentDir: string, currentVersion: string): string | null;
|
|
26
|
+
/**
|
|
27
|
+
* Syncs a single bundled resource directory into the agent directory.
|
|
28
|
+
*
|
|
29
|
+
* 1. Makes the destination writable (handles Nix store read-only copies).
|
|
30
|
+
* 2. Removes destination subdirs that exist in source to clear stale files,
|
|
31
|
+
* while preserving user-created directories.
|
|
32
|
+
* 3. Copies source into destination.
|
|
33
|
+
* 4. Makes the result writable for the next upgrade cycle.
|
|
34
|
+
*/
|
|
35
|
+
export declare function syncResourceDir(srcDir: string, destDir: string): void;
|
|
36
|
+
/** Check if any @gsd* scopes exist in internal but not in hoisted node_modules */
|
|
37
|
+
export declare function hasMissingWorkspaceScopes(hoisted: string, internal: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Create a real node_modules directory containing symlinks from both the
|
|
40
|
+
* hoisted root (external deps) and internal root (@gsd/* workspace packages).
|
|
41
|
+
* Used for pnpm global installs where @gsd/* isn't hoisted.
|
|
42
|
+
*/
|
|
43
|
+
export declare function reconcileMergedNodeModules(agentNodeModules: string, hoisted: string, internal: string): void;
|
|
44
|
+
/** Build a cache fingerprint from packageRoot + sorted entry names of both directories */
|
|
45
|
+
export declare function mergedFingerprint(hoisted: string, internal: string): string;
|
|
6
46
|
/**
|
|
7
47
|
* Syncs all bundled resources to agentDir (~/.gsd/agent/) on every launch.
|
|
8
48
|
*
|
package/dist/resource-loader.js
CHANGED
|
@@ -101,17 +101,27 @@ function readManagedResourceManifest(agentDir) {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
|
-
* Computes a
|
|
104
|
+
* Computes a content fingerprint of a resources directory (defaults to the
|
|
105
|
+
* bundled resourcesDir).
|
|
105
106
|
*
|
|
106
|
-
* Walks all files under
|
|
107
|
-
*
|
|
108
|
-
*
|
|
107
|
+
* Walks all files under `rootDir` and hashes `${relativePath}:${sha256(contents)}`
|
|
108
|
+
* for each one. Using the file *contents* — not size — is what distinguishes
|
|
109
|
+
* this from the earlier implementation and closes #4787: a same-size edit
|
|
110
|
+
* (e.g. swapping one word for another word of the same byte length) produces
|
|
111
|
+
* a different file hash, bumps the aggregate fingerprint, and therefore
|
|
112
|
+
* triggers a full resync in `initResources`. The old path+size approach
|
|
113
|
+
* silently cached stale prompts across upgrades.
|
|
109
114
|
*
|
|
110
|
-
* ~
|
|
115
|
+
* Cost is ~1-2ms for a typical resources tree (~100 small .md files) —
|
|
116
|
+
* still negligible at startup. Files are streamed via `readFileSync` but
|
|
117
|
+
* bundled prompts are tiny so this is fine.
|
|
118
|
+
*
|
|
119
|
+
* Exported for unit tests and for callers that want to check a different
|
|
120
|
+
* directory (e.g. pre-install verification).
|
|
111
121
|
*/
|
|
112
|
-
function computeResourceFingerprint() {
|
|
122
|
+
export function computeResourceFingerprint(rootDir = resourcesDir) {
|
|
113
123
|
const entries = [];
|
|
114
|
-
collectFileEntries(
|
|
124
|
+
collectFileEntries(rootDir, rootDir, entries);
|
|
115
125
|
entries.sort();
|
|
116
126
|
return createHash('sha256').update(entries.join('\n')).digest('hex').slice(0, 16);
|
|
117
127
|
}
|
|
@@ -125,8 +135,17 @@ function collectFileEntries(dir, root, out) {
|
|
|
125
135
|
}
|
|
126
136
|
else {
|
|
127
137
|
const rel = relative(root, fullPath);
|
|
128
|
-
|
|
129
|
-
|
|
138
|
+
// Hash the file contents — see function doc for #4787 rationale.
|
|
139
|
+
let contentHash;
|
|
140
|
+
try {
|
|
141
|
+
contentHash = createHash('sha256').update(readFileSync(fullPath)).digest('hex');
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Unreadable file — fall back to a stable marker so the entry still
|
|
145
|
+
// contributes to the aggregate hash and future reads will re-hash.
|
|
146
|
+
contentHash = 'unreadable';
|
|
147
|
+
}
|
|
148
|
+
out.push(`${rel}:${contentHash}`);
|
|
130
149
|
}
|
|
131
150
|
}
|
|
132
151
|
}
|
|
@@ -188,7 +207,7 @@ function makeTreeWritable(dirPath) {
|
|
|
188
207
|
* 3. Copies source into destination.
|
|
189
208
|
* 4. Makes the result writable for the next upgrade cycle.
|
|
190
209
|
*/
|
|
191
|
-
function syncResourceDir(srcDir, destDir) {
|
|
210
|
+
export function syncResourceDir(srcDir, destDir) {
|
|
192
211
|
makeTreeWritable(destDir);
|
|
193
212
|
if (existsSync(srcDir)) {
|
|
194
213
|
pruneStaleSiblingFiles(srcDir, destDir);
|
|
@@ -282,7 +301,7 @@ function ensureNodeModulesSymlink(agentDir) {
|
|
|
282
301
|
reconcileMergedNodeModules(agentNodeModules, hoistedNodeModules, internalNodeModules);
|
|
283
302
|
}
|
|
284
303
|
/** Check if any @gsd* scopes exist in internal but not in hoisted node_modules */
|
|
285
|
-
function hasMissingWorkspaceScopes(hoisted, internal) {
|
|
304
|
+
export function hasMissingWorkspaceScopes(hoisted, internal) {
|
|
286
305
|
if (!existsSync(internal))
|
|
287
306
|
return false;
|
|
288
307
|
try {
|
|
@@ -326,7 +345,7 @@ function reconcileSymlink(link, target) {
|
|
|
326
345
|
* hoisted root (external deps) and internal root (@gsd/* workspace packages).
|
|
327
346
|
* Used for pnpm global installs where @gsd/* isn't hoisted.
|
|
328
347
|
*/
|
|
329
|
-
function reconcileMergedNodeModules(agentNodeModules, hoisted, internal) {
|
|
348
|
+
export function reconcileMergedNodeModules(agentNodeModules, hoisted, internal) {
|
|
330
349
|
// Fast path: if already merged for this packageRoot + same directory contents, skip.
|
|
331
350
|
// The fingerprint includes entry names from both roots so `pnpm add/remove` triggers rebuild.
|
|
332
351
|
const marker = join(agentNodeModules, '.gsd-merged');
|
|
@@ -400,7 +419,7 @@ function reconcileMergedNodeModules(agentNodeModules, hoisted, internal) {
|
|
|
400
419
|
}
|
|
401
420
|
}
|
|
402
421
|
/** Build a cache fingerprint from packageRoot + sorted entry names of both directories */
|
|
403
|
-
function mergedFingerprint(hoisted, internal) {
|
|
422
|
+
export function mergedFingerprint(hoisted, internal) {
|
|
404
423
|
try {
|
|
405
424
|
const h = readdirSync(hoisted).sort().join(',');
|
|
406
425
|
const i = readdirSync(internal).sort().join(',');
|
|
@@ -21,6 +21,15 @@ async function getSharp() {
|
|
|
21
21
|
}
|
|
22
22
|
return _sharp;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Test-only seam: override the cached sharp module. Pass `null` to simulate
|
|
26
|
+
* an environment where the sharp native dep is unavailable; pass `undefined`
|
|
27
|
+
* to clear the cache and let the next getSharp() call re-import. See
|
|
28
|
+
* tests/capture-sharp-optional.test.cjs.
|
|
29
|
+
*/
|
|
30
|
+
export function __setSharpForTesting(value) {
|
|
31
|
+
_sharp = value;
|
|
32
|
+
}
|
|
24
33
|
import { formatCompactStateSummary } from "./utils.js";
|
|
25
34
|
// Anthropic vision: 1568px is the recommended optimal width. Height is capped
|
|
26
35
|
// generously at 8000px so tall full-page screenshots remain readable rather
|
|
@@ -12,76 +12,25 @@
|
|
|
12
12
|
import { describe, it, before, after } from "node:test";
|
|
13
13
|
import assert from "node:assert/strict";
|
|
14
14
|
import { chromium } from "playwright";
|
|
15
|
-
import {
|
|
16
|
-
import { resolve, dirname } from "node:path";
|
|
15
|
+
import { dirname } from "node:path";
|
|
17
16
|
import { fileURLToPath } from "node:url";
|
|
18
17
|
|
|
19
18
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
-
const ROOT = resolve(__dirname, "..");
|
|
21
19
|
|
|
22
20
|
// ---------------------------------------------------------------------------
|
|
23
|
-
// Source
|
|
21
|
+
// Source loading — import the IIFE builders directly via jiti.
|
|
22
|
+
// The test-only named exports in tools/intent.ts and tools/forms.ts exist
|
|
23
|
+
// exactly so this test can call the real, in-tree builders. No brace
|
|
24
|
+
// walking, no regex stripping — a refactor of the signatures just updates
|
|
25
|
+
// the import surface, not the test.
|
|
24
26
|
// ---------------------------------------------------------------------------
|
|
25
27
|
|
|
26
|
-
// 1. EVALUATE_HELPERS_SOURCE — exported constant, extract via jiti
|
|
27
28
|
import { createRequire } from "node:module";
|
|
28
29
|
const require = createRequire(import.meta.url);
|
|
29
30
|
const jiti = require("jiti")(__dirname, { interopDefault: true, debug: false });
|
|
30
31
|
const { EVALUATE_HELPERS_SOURCE } = jiti("../evaluate-helpers.ts");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// Extract the function from source, wrap it, and eval to get the builder.
|
|
34
|
-
const intentSource = readFileSync(resolve(ROOT, "tools/intent.ts"), "utf-8");
|
|
35
|
-
|
|
36
|
-
function extractBuildIntentScoringScript() {
|
|
37
|
-
// Match the function body: starts with "function buildIntentScoringScript"
|
|
38
|
-
// and returns a template literal string. We extract up to the matching closing brace.
|
|
39
|
-
const startMarker = "function buildIntentScoringScript(intent: string, scope?: string): string {";
|
|
40
|
-
const startIdx = intentSource.indexOf(startMarker);
|
|
41
|
-
if (startIdx === -1) throw new Error("Could not find buildIntentScoringScript in intent.ts");
|
|
42
|
-
|
|
43
|
-
// Walk from start, counting braces to find the end
|
|
44
|
-
let depth = 0;
|
|
45
|
-
let foundFirst = false;
|
|
46
|
-
let endIdx = startIdx;
|
|
47
|
-
for (let i = startIdx; i < intentSource.length; i++) {
|
|
48
|
-
if (intentSource[i] === "{") { depth++; foundFirst = true; }
|
|
49
|
-
if (intentSource[i] === "}") depth--;
|
|
50
|
-
if (foundFirst && depth === 0) { endIdx = i + 1; break; }
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let fnBody = intentSource.slice(startIdx, endIdx);
|
|
54
|
-
// Strip TypeScript type annotations
|
|
55
|
-
fnBody = fnBody.replace(/\(intent:\s*string,\s*scope\?:\s*string\):\s*string/, "(intent, scope)");
|
|
56
|
-
return new Function("return " + fnBody)();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const buildIntentScoringScript = extractBuildIntentScoringScript();
|
|
60
|
-
|
|
61
|
-
// 3. Form analysis — module-private buildFormAnalysisScript.
|
|
62
|
-
const formsSource = readFileSync(resolve(ROOT, "tools/forms.ts"), "utf-8");
|
|
63
|
-
|
|
64
|
-
function extractBuildFormAnalysisScript() {
|
|
65
|
-
const startMarker = "function buildFormAnalysisScript(selector?: string): string {";
|
|
66
|
-
const startIdx = formsSource.indexOf(startMarker);
|
|
67
|
-
if (startIdx === -1) throw new Error("Could not find buildFormAnalysisScript in forms.ts");
|
|
68
|
-
|
|
69
|
-
let depth = 0;
|
|
70
|
-
let foundFirst = false;
|
|
71
|
-
let endIdx = startIdx;
|
|
72
|
-
for (let i = startIdx; i < formsSource.length; i++) {
|
|
73
|
-
if (formsSource[i] === "{") { depth++; foundFirst = true; }
|
|
74
|
-
if (formsSource[i] === "}") depth--;
|
|
75
|
-
if (foundFirst && depth === 0) { endIdx = i + 1; break; }
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let fnBody = formsSource.slice(startIdx, endIdx);
|
|
79
|
-
// Strip TypeScript type annotation
|
|
80
|
-
fnBody = fnBody.replace(/\(selector\?:\s*string\):\s*string/, "(selector)");
|
|
81
|
-
return new Function("return " + fnBody)();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const buildFormAnalysisScript = extractBuildFormAnalysisScript();
|
|
32
|
+
const { buildIntentScoringScript } = jiti("../tools/intent.ts");
|
|
33
|
+
const { buildFormAnalysisScript } = jiti("../tools/forms.ts");
|
|
85
34
|
|
|
86
35
|
// ---------------------------------------------------------------------------
|
|
87
36
|
// Browser lifecycle
|
|
@@ -387,32 +387,44 @@ describe("formatArtifactTimestamp", () => {
|
|
|
387
387
|
// ---------------------------------------------------------------------------
|
|
388
388
|
|
|
389
389
|
describe("EVALUATE_HELPERS_SOURCE", () => {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
390
|
+
// Behaviour test: executing the source in a Node vm sandbox must
|
|
391
|
+
// populate a `window.__pi` namespace with every expected helper.
|
|
392
|
+
// No source grep — we actually run the code and verify the resulting
|
|
393
|
+
// object shape.
|
|
394
|
+
it("executing the source assigns all expected helpers to window.__pi", () => {
|
|
395
|
+
const vm = require("node:vm");
|
|
396
|
+
const expectedFunctions = [
|
|
397
|
+
"cssPath",
|
|
398
|
+
"simpleHash",
|
|
399
|
+
"isVisible",
|
|
400
|
+
"isEnabled",
|
|
401
|
+
"inferRole",
|
|
402
|
+
"accessibleName",
|
|
403
|
+
"isInteractiveEl",
|
|
404
|
+
"domPath",
|
|
405
|
+
"selectorHints",
|
|
406
|
+
];
|
|
395
407
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
`
|
|
408
|
+
// Playwright evaluates the source in a page context where `window`
|
|
409
|
+
// exists, so the helpers attach to `window.__pi`. Provide a minimal
|
|
410
|
+
// window stub in a vm context so we avoid polluting the test globals.
|
|
411
|
+
const sandbox = { window: {} };
|
|
412
|
+
const script = new vm.Script(EVALUATE_HELPERS_SOURCE);
|
|
413
|
+
script.runInNewContext(sandbox, { timeout: 1000 });
|
|
414
|
+
|
|
415
|
+
assert.ok(
|
|
416
|
+
sandbox.window.__pi && typeof sandbox.window.__pi === "object",
|
|
417
|
+
"executing EVALUATE_HELPERS_SOURCE must assign window.__pi",
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
for (const fnName of expectedFunctions) {
|
|
421
|
+
assert.equal(
|
|
422
|
+
typeof sandbox.window.__pi[fnName],
|
|
423
|
+
"function",
|
|
424
|
+
`window.__pi.${fnName} must be a function after executing the source`,
|
|
413
425
|
);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
426
|
+
}
|
|
427
|
+
});
|
|
416
428
|
});
|
|
417
429
|
|
|
418
430
|
// ---------------------------------------------------------------------------
|
|
@@ -1,93 +1,91 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Regression tests for the optional sharp dependency in capture.ts.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Behaviour:
|
|
5
|
+
* - constrainScreenshot must fall back to returning the raw buffer
|
|
6
|
+
* unchanged when sharp is unavailable, rather than throwing.
|
|
7
|
+
* - When sharp IS available, oversized screenshots get resized.
|
|
8
|
+
*
|
|
9
|
+
* No source-grep. The test drives the real constrainScreenshot function
|
|
10
|
+
* after seeding the module-private `_sharp` cache via the test-only
|
|
11
|
+
* `__setSharpForTesting` export.
|
|
8
12
|
*/
|
|
9
13
|
|
|
10
|
-
const { describe, it } = require("node:test");
|
|
14
|
+
const { describe, it, afterEach } = require("node:test");
|
|
11
15
|
const assert = require("node:assert/strict");
|
|
12
|
-
const
|
|
13
|
-
const { join } = require("node:path");
|
|
14
|
-
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
// 1. Static analysis — verify the lazy-load pattern is present in source
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
16
|
+
const jiti = require("jiti")(__filename, { interopDefault: true, debug: false });
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
const source = readFileSync(
|
|
21
|
-
join(process.cwd(), "src/resources/extensions/browser-tools/capture.ts"),
|
|
22
|
-
"utf-8",
|
|
23
|
-
);
|
|
18
|
+
const { constrainScreenshot, __setSharpForTesting } = jiti("../capture.ts");
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
);
|
|
20
|
+
describe("constrainScreenshot — sharp unavailable (null)", () => {
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
// Clear the test override so later tests don't inherit a null sharp.
|
|
23
|
+
__setSharpForTesting(undefined);
|
|
30
24
|
});
|
|
31
25
|
|
|
32
|
-
it("
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
26
|
+
it("returns the raw buffer unchanged when sharp is null", async () => {
|
|
27
|
+
__setSharpForTesting(null);
|
|
28
|
+
|
|
29
|
+
const rawBuffer = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); // PNG magic bytes
|
|
30
|
+
const result = await constrainScreenshot(null, rawBuffer, "image/png", 80);
|
|
31
|
+
|
|
32
|
+
assert.strictEqual(
|
|
33
|
+
result,
|
|
34
|
+
rawBuffer,
|
|
35
|
+
"constrainScreenshot must return the exact same buffer instance when sharp is null",
|
|
36
36
|
);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
it("
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
);
|
|
39
|
+
it("returns the raw buffer unchanged for JPEG input when sharp is null", async () => {
|
|
40
|
+
__setSharpForTesting(null);
|
|
41
|
+
|
|
42
|
+
const rawBuffer = Buffer.from([0xff, 0xd8, 0xff, 0xe0]); // JPEG magic bytes
|
|
43
|
+
const result = await constrainScreenshot(null, rawBuffer, "image/jpeg", 80);
|
|
44
|
+
|
|
45
|
+
assert.strictEqual(result, rawBuffer);
|
|
44
46
|
});
|
|
45
47
|
});
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
describe("capture.ts — constrainScreenshot with sharp unavailable", () => {
|
|
52
|
-
it("returns the raw buffer unchanged when sharp is null", async () => {
|
|
53
|
-
// Simulate what getSharp() returns on platforms without sharp by
|
|
54
|
-
// directly calling constrainScreenshot through a module whose _sharp
|
|
55
|
-
// cache has been pre-seeded to null via the module-level variable reset.
|
|
56
|
-
//
|
|
57
|
-
// Because jiti caches modules across the test suite we use a fresh
|
|
58
|
-
// require-cache trick: load capture.ts source manually and evaluate the
|
|
59
|
-
// constrainScreenshot function with a stub getSharp that always returns null.
|
|
60
|
-
const captureSource = readFileSync(
|
|
61
|
-
join(process.cwd(), "src/resources/extensions/browser-tools/capture.ts"),
|
|
62
|
-
"utf-8",
|
|
63
|
-
);
|
|
49
|
+
describe("constrainScreenshot — sharp available", () => {
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
__setSharpForTesting(undefined);
|
|
52
|
+
});
|
|
64
53
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
54
|
+
it("passes through a small image unchanged (below cap)", async () => {
|
|
55
|
+
const sharp = require("sharp");
|
|
56
|
+
const small = await sharp({
|
|
57
|
+
create: {
|
|
58
|
+
width: 400,
|
|
59
|
+
height: 300,
|
|
60
|
+
channels: 3,
|
|
61
|
+
background: { r: 128, g: 128, b: 128 },
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
.jpeg({ quality: 80 })
|
|
65
|
+
.toBuffer();
|
|
75
66
|
|
|
76
|
-
const
|
|
67
|
+
const result = await constrainScreenshot(null, small, "image/jpeg", 80);
|
|
68
|
+
const meta = await sharp(result).metadata();
|
|
69
|
+
assert.equal(meta.width, 400, "small images must not be resized");
|
|
70
|
+
assert.equal(meta.height, 300);
|
|
71
|
+
});
|
|
77
72
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
it("resizes an oversized image to within 1568px", async () => {
|
|
74
|
+
const sharp = require("sharp");
|
|
75
|
+
const big = await sharp({
|
|
76
|
+
create: {
|
|
77
|
+
width: 3000,
|
|
78
|
+
height: 2000,
|
|
79
|
+
channels: 3,
|
|
80
|
+
background: { r: 128, g: 128, b: 128 },
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
.jpeg({ quality: 80 })
|
|
84
|
+
.toBuffer();
|
|
85
85
|
|
|
86
|
-
const result = await
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
"constrainScreenshot must return the exact same buffer instance when sharp is null",
|
|
91
|
-
);
|
|
86
|
+
const result = await constrainScreenshot(null, big, "image/jpeg", 80);
|
|
87
|
+
const meta = await sharp(result).metadata();
|
|
88
|
+
assert.ok(meta.width <= 1568, `width ${meta.width} must be <= 1568`);
|
|
89
|
+
assert.ok(meta.height <= 1568, `height ${meta.height} must be <= 1568`);
|
|
92
90
|
});
|
|
93
91
|
});
|
|
@@ -4,7 +4,11 @@ import { setLastActionBeforeState, setLastActionAfterState, } from "../state.js"
|
|
|
4
4
|
* Runs inside page.evaluate(). Finds the target form, inventories all fields
|
|
5
5
|
* with full label resolution, and returns a structured result.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
// Exported for tests only (see tests/browser-tools-integration.test.mjs).
|
|
8
|
+
// Keep this function treated as module-private for production call sites —
|
|
9
|
+
// the only legitimate external caller is the Playwright-driven integration
|
|
10
|
+
// suite that needs to evaluate the returned IIFE against real DOM.
|
|
11
|
+
export function buildFormAnalysisScript(selector) {
|
|
8
12
|
// We return a string that will be evaluated in the page context.
|
|
9
13
|
// This avoids serialization issues with passing functions.
|
|
10
14
|
return `(() => {
|
|
@@ -26,7 +26,11 @@ const INTENTS = [
|
|
|
26
26
|
* Uses window.__pi utilities (injected via addInitScript) for element
|
|
27
27
|
* metadata — no inline redeclarations.
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
// Exported for tests only (see tests/browser-tools-integration.test.mjs).
|
|
30
|
+
// Keep this function treated as module-private for production call sites —
|
|
31
|
+
// the only legitimate external caller is the Playwright-driven integration
|
|
32
|
+
// suite that needs to evaluate the returned IIFE against real DOM.
|
|
33
|
+
export function buildIntentScoringScript(intent, scope) {
|
|
30
34
|
const scopeSelector = JSON.stringify(scope ?? null);
|
|
31
35
|
return `(() => {
|
|
32
36
|
var pi = window.__pi;
|
|
@@ -27,7 +27,11 @@ function execClaude(args) {
|
|
|
27
27
|
let lastError;
|
|
28
28
|
for (const command of CLAUDE_COMMAND_CANDIDATES) {
|
|
29
29
|
try {
|
|
30
|
-
return execFileSync(command, args, {
|
|
30
|
+
return execFileSync(command, args, {
|
|
31
|
+
timeout: 5_000,
|
|
32
|
+
stdio: "pipe",
|
|
33
|
+
shell: process.platform === "win32",
|
|
34
|
+
});
|
|
31
35
|
}
|
|
32
36
|
catch (error) {
|
|
33
37
|
lastError = error;
|