gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00
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 +53 -17
- package/dist/claude-cli-check.js +46 -10
- 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 +72 -16
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/github-sync/templates.js +103 -0
- package/dist/resources/extensions/google-search/index.js +3 -2
- package/dist/resources/extensions/gsd/auto/loop.js +124 -2
- package/dist/resources/extensions/gsd/auto/phases.js +57 -39
- package/dist/resources/extensions/gsd/auto/session.js +6 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
- package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
- package/dist/resources/extensions/gsd/auto-start.js +107 -29
- 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 +76 -21
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -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/context-store.js +23 -7
- package/dist/resources/extensions/gsd/detection.js +49 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/forensics.js +106 -0
- 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 +39 -13
- 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/milestone-summary-classifier.js +37 -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/preferences-validation.js +23 -0
- package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- 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-cadence.js +238 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
- package/dist/resources/extensions/gsd/state.js +69 -58
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
- 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/dispatch-envelope.js +33 -0
- package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
- package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
- package/dist/resources/extensions/gsd/uok/writer.js +82 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
- package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
- package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
- 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 +11 -11
- 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 +11 -11
- 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/package.json +2 -2
- 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/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +15 -6
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- 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 +85 -0
- package/packages/mcp-server/src/workflow-tools.ts +19 -6
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +2 -2
- 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/package.json +1 -1
- 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/package.json +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/__tests__/tool-execution.test.js +36 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.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/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.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/package.json +1 -1
- 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/__tests__/tool-execution.test.ts +49 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
- 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 +37 -11
- 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/package.json +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 +42 -11
- 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/package.json +1 -1
- package/packages/rpc-client/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +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 +75 -16
- 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/templates.ts +151 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
- package/src/resources/extensions/google-search/index.ts +3 -2
- package/src/resources/extensions/gsd/auto/loop.ts +142 -2
- package/src/resources/extensions/gsd/auto/phases.ts +62 -38
- package/src/resources/extensions/gsd/auto/session.ts +7 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
- package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
- package/src/resources/extensions/gsd/auto-start.ts +127 -9
- 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 +90 -23
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -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/context-store.ts +25 -8
- package/src/resources/extensions/gsd/detection.ts +58 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/forensics.ts +118 -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 +149 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +57 -14
- package/src/resources/extensions/gsd/journal.ts +11 -1
- 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/milestone-summary-classifier.ts +42 -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/preferences-validation.ts +21 -0
- package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- 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-cadence.ts +299 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
- package/src/resources/extensions/gsd/state.ts +76 -66
- 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/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
- 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 +133 -292
- 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-remediate-slice-status.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
- 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-slice-verification-gate.test.ts +2 -1
- 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/context-store.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
- 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 -4
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
- 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/google-search-stub.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
- 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 -56
- 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/interactive-routing-bypass.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
- 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 -55
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
- package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -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 -48
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
- 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/preferences-worktree-sync.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
- 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/queue-draft-detection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
- 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/restore-tools-after-discuss.test.ts +6 -3
- 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/sidecar-queue.test.ts +3 -2
- 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-cadence.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
- 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/sync-worktree-skip-current.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
- 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-contracts.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -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/uok-loop-adapter-writer.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
- package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
- 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/worktree-telemetry.test.ts +210 -0
- 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/tools/validate-milestone.ts +8 -2
- 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/contracts.ts +65 -0
- package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
- package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
- package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
- package/src/resources/extensions/gsd/uok/writer.ts +113 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
- package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
- package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
- 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 -143
- 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 -74
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- 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 -125
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
- /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
|
@@ -7,12 +7,13 @@ import assert from "node:assert/strict";
|
|
|
7
7
|
import { Image } from "./image.js";
|
|
8
8
|
describe("Image component (#3455)", () => {
|
|
9
9
|
const theme = { fallbackColor: (s) => s };
|
|
10
|
-
test("getDimensions returns undefined
|
|
11
|
-
//
|
|
10
|
+
test("getDimensions returns undefined when constructed without explicit dims", () => {
|
|
11
|
+
// Previously this test was titled "returns undefined before resolution"
|
|
12
|
+
// but only asserted `typeof getDimensions === 'function'`. The title
|
|
13
|
+
// and the assertion had nothing to do with each other (#4794).
|
|
14
|
+
// Now actually assert the undefined return.
|
|
12
15
|
const img = new Image("base64data", "image/png", theme, {});
|
|
13
|
-
|
|
14
|
-
// But we can't easily test async here, so verify the method exists
|
|
15
|
-
assert.equal(typeof img.getDimensions, "function");
|
|
16
|
+
assert.equal(img.getDimensions(), undefined, "without pre-resolved dims, getDimensions must return undefined until async resolve");
|
|
16
17
|
});
|
|
17
18
|
test("getDimensions returns dimensions when provided at construction", () => {
|
|
18
19
|
const dims = { widthPx: 100, heightPx: 200 };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.test.js","sourceRoot":"","sources":["../../src/components/image.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACxC,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;IAElD,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"image.test.js","sourceRoot":"","sources":["../../src/components/image.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACxC,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;IAElD,IAAI,CAAC,wEAAwE,EAAE,GAAG,EAAE;QACnF,wEAAwE;QACxE,qEAAqE;QACrE,+DAA+D;QAC/D,4CAA4C;QAC5C,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CACX,GAAG,CAAC,aAAa,EAAE,EACnB,SAAS,EACT,oFAAoF,CACpF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gEAAgE,EAAE,GAAG,EAAE;QAC3E,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAClE,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,EAAE,CAAC;QACnC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,mCAAmC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,sEAAsE,EAAE,GAAG,EAAE;QACjF,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAClE,GAAG,CAAC,uBAAuB,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,6DAA6D;QAC7D,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,EAAE,sDAAsD,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["/**\n * Regression test for #3455: Image component must not trigger infinite\n * re-render loop when dimensions resolve in cmux sessions.\n */\n\nimport { describe, test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { Image } from \"./image.js\";\n\ndescribe(\"Image component (#3455)\", () => {\n\tconst theme = { fallbackColor: (s: string) => s };\n\n\ttest(\"getDimensions returns undefined when constructed without explicit dims\", () => {\n\t\t// Previously this test was titled \"returns undefined before resolution\"\n\t\t// but only asserted `typeof getDimensions === 'function'`. The title\n\t\t// and the assertion had nothing to do with each other (#4794).\n\t\t// Now actually assert the undefined return.\n\t\tconst img = new Image(\"base64data\", \"image/png\", theme, {});\n\t\tassert.equal(\n\t\t\timg.getDimensions(),\n\t\t\tundefined,\n\t\t\t\"without pre-resolved dims, getDimensions must return undefined until async resolve\",\n\t\t);\n\t});\n\n\ttest(\"getDimensions returns dimensions when provided at construction\", () => {\n\t\tconst dims = { widthPx: 100, heightPx: 200 };\n\t\tconst img = new Image(\"base64data\", \"image/png\", theme, {}, dims);\n\t\tconst result = img.getDimensions();\n\t\tassert.deepEqual(result, dims, \"Should return provided dimensions\");\n\t});\n\n\ttest(\"onDimensionsResolved callback is not called when dimensions provided\", () => {\n\t\tlet callCount = 0;\n\t\tconst dims = { widthPx: 100, heightPx: 200 };\n\t\tconst img = new Image(\"base64data\", \"image/png\", theme, {}, dims);\n\t\timg.setOnDimensionsResolved(() => { callCount++; });\n\t\t// With pre-resolved dims, the async path is skipped entirely\n\t\tassert.equal(callCount, 0, \"Callback should not fire for pre-resolved dimensions\");\n\t});\n});\n"]}
|
|
@@ -18,6 +18,8 @@ export interface EditorComponent extends Component {
|
|
|
18
18
|
onSubmit?: (text: string) => void;
|
|
19
19
|
/** Called when text changes */
|
|
20
20
|
onChange?: (text: string) => void;
|
|
21
|
+
/** Called when an image file path is pasted via terminal emulator */
|
|
22
|
+
onPasteImagePath?: (filePath: string) => void;
|
|
21
23
|
/** Add text to history for up/down navigation */
|
|
22
24
|
addToHistory?(text: string): void;
|
|
23
25
|
/** Insert text at current cursor position */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-component.d.ts","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAKjD,mCAAmC;IACnC,OAAO,IAAI,MAAM,CAAC;IAElB,2BAA2B;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,qEAAqE;IACrE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMhC,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"editor-component.d.ts","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAKjD,mCAAmC;IACnC,OAAO,IAAI,MAAM,CAAC;IAElB,2BAA2B;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,qEAAqE;IACrE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMhC,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAM9C,iDAAiD;IACjD,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMlC,6CAA6C;IAC7C,kBAAkB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAExC;;;OAGG;IACH,eAAe,CAAC,IAAI,MAAM,CAAC;IAM3B,oCAAoC;IACpC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAM/D,4BAA4B;IAC5B,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IAEtC,6BAA6B;IAC7B,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpC,qDAAqD;IACrD,yBAAyB,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACrD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-component.js","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"","sourcesContent":["import type { AutocompleteProvider } from \"./autocomplete.js\";\nimport type { Component } from \"./tui.js\";\n\n/**\n * Interface for custom editor components.\n *\n * This allows extensions to provide their own editor implementation\n * (e.g., vim mode, emacs mode, custom keybindings) while maintaining\n * compatibility with the core application.\n */\nexport interface EditorComponent extends Component {\n\t// =========================================================================\n\t// Core text access (required)\n\t// =========================================================================\n\n\t/** Get the current text content */\n\tgetText(): string;\n\n\t/** Set the text content */\n\tsetText(text: string): void;\n\n\t/** Handle raw terminal input (key presses, paste sequences, etc.) */\n\thandleInput(data: string): void;\n\n\t// =========================================================================\n\t// Callbacks (required)\n\t// =========================================================================\n\n\t/** Called when user submits (e.g., Enter key) */\n\tonSubmit?: (text: string) => void;\n\n\t/** Called when text changes */\n\tonChange?: (text: string) => void;\n\n\t// =========================================================================\n\t// History support (optional)\n\t// =========================================================================\n\n\t/** Add text to history for up/down navigation */\n\taddToHistory?(text: string): void;\n\n\t// =========================================================================\n\t// Advanced text manipulation (optional)\n\t// =========================================================================\n\n\t/** Insert text at current cursor position */\n\tinsertTextAtCursor?(text: string): void;\n\n\t/**\n\t * Get text with any markers expanded (e.g., paste markers).\n\t * Falls back to getText() if not implemented.\n\t */\n\tgetExpandedText?(): string;\n\n\t// =========================================================================\n\t// Autocomplete support (optional)\n\t// =========================================================================\n\n\t/** Set the autocomplete provider */\n\tsetAutocompleteProvider?(provider: AutocompleteProvider): void;\n\n\t// =========================================================================\n\t// Appearance (optional)\n\t// =========================================================================\n\n\t/** Border color function */\n\tborderColor?: (str: string) => string;\n\n\t/** Set horizontal padding */\n\tsetPaddingX?(padding: number): void;\n\n\t/** Set max visible items in autocomplete dropdown */\n\tsetAutocompleteMaxVisible?(maxVisible: number): void;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"editor-component.js","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"","sourcesContent":["import type { AutocompleteProvider } from \"./autocomplete.js\";\nimport type { Component } from \"./tui.js\";\n\n/**\n * Interface for custom editor components.\n *\n * This allows extensions to provide their own editor implementation\n * (e.g., vim mode, emacs mode, custom keybindings) while maintaining\n * compatibility with the core application.\n */\nexport interface EditorComponent extends Component {\n\t// =========================================================================\n\t// Core text access (required)\n\t// =========================================================================\n\n\t/** Get the current text content */\n\tgetText(): string;\n\n\t/** Set the text content */\n\tsetText(text: string): void;\n\n\t/** Handle raw terminal input (key presses, paste sequences, etc.) */\n\thandleInput(data: string): void;\n\n\t// =========================================================================\n\t// Callbacks (required)\n\t// =========================================================================\n\n\t/** Called when user submits (e.g., Enter key) */\n\tonSubmit?: (text: string) => void;\n\n\t/** Called when text changes */\n\tonChange?: (text: string) => void;\n\n\t/** Called when an image file path is pasted via terminal emulator */\n\tonPasteImagePath?: (filePath: string) => void;\n\n\t// =========================================================================\n\t// History support (optional)\n\t// =========================================================================\n\n\t/** Add text to history for up/down navigation */\n\taddToHistory?(text: string): void;\n\n\t// =========================================================================\n\t// Advanced text manipulation (optional)\n\t// =========================================================================\n\n\t/** Insert text at current cursor position */\n\tinsertTextAtCursor?(text: string): void;\n\n\t/**\n\t * Get text with any markers expanded (e.g., paste markers).\n\t * Falls back to getText() if not implemented.\n\t */\n\tgetExpandedText?(): string;\n\n\t// =========================================================================\n\t// Autocomplete support (optional)\n\t// =========================================================================\n\n\t/** Set the autocomplete provider */\n\tsetAutocompleteProvider?(provider: AutocompleteProvider): void;\n\n\t// =========================================================================\n\t// Appearance (optional)\n\t// =========================================================================\n\n\t/** Border color function */\n\tborderColor?: (str: string) => string;\n\n\t/** Set horizontal padding */\n\tsetPaddingX?(padding: number): void;\n\n\t/** Set max visible items in autocomplete dropdown */\n\tsetAutocompleteMaxVisible?(maxVisible: number): void;\n}\n"]}
|
|
@@ -127,20 +127,36 @@ describe("CombinedAutocompleteProvider — argument completions", () => {
|
|
|
127
127
|
});
|
|
128
128
|
|
|
129
129
|
describe("CombinedAutocompleteProvider — @ file prefix extraction", () => {
|
|
130
|
-
it("detects @ at start of line", () => {
|
|
130
|
+
it("detects @ at start of line and returns a valid suggestion shape", () => {
|
|
131
131
|
const provider = makeProvider();
|
|
132
|
-
// @ triggers fuzzy file search — we can't test the actual file results
|
|
133
|
-
// but we can test that getSuggestions returns null (no files in /tmp matching)
|
|
134
|
-
// rather than crashing
|
|
135
132
|
const result = provider.getSuggestions(["@nonexistent_xyz"], 0, 16);
|
|
136
|
-
//
|
|
137
|
-
|
|
133
|
+
// Either null (nothing matched) or a well-formed {items: Array, prefix: string}
|
|
134
|
+
// shape. Previous version's `result.items.length >= 0` was a tautology —
|
|
135
|
+
// array length is always ≥ 0; the whole expression could never fail.
|
|
136
|
+
if (result !== null) {
|
|
137
|
+
assert.ok(Array.isArray(result.items), "result.items must be an array");
|
|
138
|
+
// The @-prefix extraction strips the leading @ — prefix should be
|
|
139
|
+
// the raw text without the trigger character.
|
|
140
|
+
assert.equal(typeof result.prefix, "string", "prefix must be a string");
|
|
141
|
+
assert.ok(
|
|
142
|
+
!result.prefix.startsWith("@"),
|
|
143
|
+
`prefix must have the @ trigger stripped, got: ${JSON.stringify(result.prefix)}`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
138
146
|
});
|
|
139
147
|
|
|
140
|
-
it("detects @ after space", () => {
|
|
148
|
+
it("detects @ after space and returns a valid suggestion shape", () => {
|
|
141
149
|
const provider = makeProvider();
|
|
142
150
|
const result = provider.getSuggestions(["check @nonexistent_xyz"], 0, 22);
|
|
143
|
-
|
|
151
|
+
if (result !== null) {
|
|
152
|
+
assert.ok(Array.isArray(result.items), "result.items must be an array");
|
|
153
|
+
assert.equal(typeof result.prefix, "string", "prefix must be a string");
|
|
154
|
+
// The prefix must NOT include the word "check" that came before the @.
|
|
155
|
+
assert.ok(
|
|
156
|
+
!result.prefix.includes("check"),
|
|
157
|
+
`prefix must not include text before the @, got: ${JSON.stringify(result.prefix)}`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
144
160
|
});
|
|
145
161
|
|
|
146
162
|
it("returns null for bare @ with no query to avoid full tree walk (#1824)", () => {
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
// pi-tui — Overlay Layout Tests (backdrop dimming)
|
|
2
|
+
//
|
|
3
|
+
// These tests previously coupled to literal ANSI escape bytes
|
|
4
|
+
// (`\x1b[2m`, `\x1b[38;5;240m`) and would break if the palette index or
|
|
5
|
+
// SGR spelling changed despite identical rendered output — Goodhart's law:
|
|
6
|
+
// the test measures escape codes, not dimming.
|
|
7
|
+
//
|
|
8
|
+
// We now parse the SGR escape codes into a semantic style state and assert
|
|
9
|
+
// on the visible contract: the covered-but-outside-overlay region is dim,
|
|
10
|
+
// has a non-default foreground (so the eye can distinguish foreground from
|
|
11
|
+
// background), and does not paint the terminal background (so user themes
|
|
12
|
+
// are preserved). The overlay content itself is reachable via plain-text
|
|
13
|
+
// lookup after stripping ANSI.
|
|
2
14
|
|
|
3
15
|
import { describe, it } from "node:test";
|
|
4
16
|
import assert from "node:assert/strict";
|
|
@@ -16,8 +28,107 @@ function makeEntry(
|
|
|
16
28
|
};
|
|
17
29
|
}
|
|
18
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Parse a line's ANSI SGR state immediately before the first occurrence of a
|
|
33
|
+
* target substring in the rendered (ANSI-stripped) text. Walks `\x1b[...m`
|
|
34
|
+
* sequences left-to-right, maintaining a running state so we can ask what
|
|
35
|
+
* the terminal is doing when it reaches the target glyphs.
|
|
36
|
+
*
|
|
37
|
+
* Semantic fields:
|
|
38
|
+
* - dim: SGR 2 active and not reset by SGR 22 / 0
|
|
39
|
+
* - fg: foreground: "default" | "set" | the raw numeric parameters
|
|
40
|
+
* - bg: background: "default" | "set"
|
|
41
|
+
*/
|
|
42
|
+
type SgrState = { dim: boolean; fg: "default" | "set"; bg: "default" | "set" };
|
|
43
|
+
|
|
44
|
+
function sgrStateAtGlyph(line: string, targetGlyph: string): SgrState {
|
|
45
|
+
const state: SgrState = { dim: false, fg: "default", bg: "default" };
|
|
46
|
+
// Walk codes and visible chars, tracking visible-glyph position.
|
|
47
|
+
let visibleSeen = "";
|
|
48
|
+
let i = 0;
|
|
49
|
+
while (i < line.length) {
|
|
50
|
+
if (line[i] === "\x1b" && line[i + 1] === "[") {
|
|
51
|
+
// Read until final byte in 0x40-0x7E
|
|
52
|
+
let j = i + 2;
|
|
53
|
+
while (j < line.length) {
|
|
54
|
+
const c = line.charCodeAt(j);
|
|
55
|
+
if (c >= 0x40 && c <= 0x7e) break;
|
|
56
|
+
j++;
|
|
57
|
+
}
|
|
58
|
+
const final = line[j];
|
|
59
|
+
if (final === "m") {
|
|
60
|
+
const paramString = line.slice(i + 2, j);
|
|
61
|
+
applySgr(state, paramString);
|
|
62
|
+
}
|
|
63
|
+
i = j + 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
// Skip other escape sequences (OSC hyperlinks etc) conservatively:
|
|
67
|
+
// if we ever hit a non-SGR escape, just step past the ESC.
|
|
68
|
+
if (line[i] === "\x1b") {
|
|
69
|
+
i++;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
visibleSeen += line[i];
|
|
73
|
+
if (visibleSeen.endsWith(targetGlyph)) {
|
|
74
|
+
// We've just consumed the last char of targetGlyph — return the
|
|
75
|
+
// state that was in effect for the whole match.
|
|
76
|
+
return state;
|
|
77
|
+
}
|
|
78
|
+
i++;
|
|
79
|
+
}
|
|
80
|
+
throw new Error(`Target glyph ${JSON.stringify(targetGlyph)} not found in line`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function applySgr(state: SgrState, paramString: string): void {
|
|
84
|
+
// Empty params == reset
|
|
85
|
+
const parts = paramString === "" ? ["0"] : paramString.split(";");
|
|
86
|
+
let k = 0;
|
|
87
|
+
while (k < parts.length) {
|
|
88
|
+
const n = parts[k] === "" ? 0 : Number(parts[k]);
|
|
89
|
+
if (n === 0) {
|
|
90
|
+
state.dim = false;
|
|
91
|
+
state.fg = "default";
|
|
92
|
+
state.bg = "default";
|
|
93
|
+
} else if (n === 2) {
|
|
94
|
+
state.dim = true;
|
|
95
|
+
} else if (n === 22) {
|
|
96
|
+
state.dim = false;
|
|
97
|
+
} else if (n === 39) {
|
|
98
|
+
state.fg = "default";
|
|
99
|
+
} else if (n === 49) {
|
|
100
|
+
state.bg = "default";
|
|
101
|
+
} else if ((n >= 30 && n <= 37) || (n >= 90 && n <= 97)) {
|
|
102
|
+
state.fg = "set";
|
|
103
|
+
} else if ((n >= 40 && n <= 47) || (n >= 100 && n <= 107)) {
|
|
104
|
+
state.bg = "set";
|
|
105
|
+
} else if (n === 38) {
|
|
106
|
+
state.fg = "set";
|
|
107
|
+
// Skip colour-model parameters: 38;5;N or 38;2;R;G;B
|
|
108
|
+
if (parts[k + 1] === "5") {
|
|
109
|
+
k += 2;
|
|
110
|
+
} else if (parts[k + 1] === "2") {
|
|
111
|
+
k += 4;
|
|
112
|
+
}
|
|
113
|
+
} else if (n === 48) {
|
|
114
|
+
state.bg = "set";
|
|
115
|
+
if (parts[k + 1] === "5") {
|
|
116
|
+
k += 2;
|
|
117
|
+
} else if (parts[k + 1] === "2") {
|
|
118
|
+
k += 4;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
k++;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function stripAnsi(line: string): string {
|
|
126
|
+
// Remove CSI sequences. Good enough for these tests.
|
|
127
|
+
return line.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
|
|
128
|
+
}
|
|
129
|
+
|
|
19
130
|
describe("compositeOverlays — backdrop", () => {
|
|
20
|
-
it("dims base lines when backdrop is true", () => {
|
|
131
|
+
it("dims base lines outside the overlay when backdrop is true", () => {
|
|
21
132
|
const base = ["hello world", "second line"];
|
|
22
133
|
const overlay = makeEntry(["OVERLAY"], {
|
|
23
134
|
width: 7,
|
|
@@ -27,14 +138,17 @@ describe("compositeOverlays — backdrop", () => {
|
|
|
27
138
|
|
|
28
139
|
const result = compositeOverlays(base, [overlay], 20, 20, 2);
|
|
29
140
|
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
assert.ok(
|
|
141
|
+
// "second line" is below the overlay (which is anchored top-left with
|
|
142
|
+
// a single visible row), so every glyph of that text should be
|
|
143
|
+
// rendered with the dim attribute active.
|
|
144
|
+
const line = result.find((l) => stripAnsi(l).includes("second line"));
|
|
145
|
+
assert.ok(line, "should have a line containing 'second line'");
|
|
146
|
+
|
|
147
|
+
const state = sgrStateAtGlyph(line, "second line");
|
|
148
|
+
assert.equal(state.dim, true, "base line should be dimmed (SGR 2)");
|
|
35
149
|
});
|
|
36
150
|
|
|
37
|
-
it("backdrop
|
|
151
|
+
it("backdrop applies a non-default foreground colour and leaves background untouched", () => {
|
|
38
152
|
const base = ["hello world", "second line"];
|
|
39
153
|
const overlay = makeEntry(["OV"], {
|
|
40
154
|
width: 2,
|
|
@@ -44,11 +158,16 @@ describe("compositeOverlays — backdrop", () => {
|
|
|
44
158
|
|
|
45
159
|
const result = compositeOverlays(base, [overlay], 20, 20, 2);
|
|
46
160
|
|
|
47
|
-
|
|
48
|
-
const line = result.find((l) => l.includes("second line"));
|
|
161
|
+
const line = result.find((l) => stripAnsi(l).includes("second line"));
|
|
49
162
|
assert.ok(line, "should have a line containing 'second line'");
|
|
50
|
-
|
|
51
|
-
|
|
163
|
+
|
|
164
|
+
const state = sgrStateAtGlyph(line, "second line");
|
|
165
|
+
assert.equal(state.fg, "set", "backdrop must set a foreground colour");
|
|
166
|
+
assert.equal(
|
|
167
|
+
state.bg,
|
|
168
|
+
"default",
|
|
169
|
+
"backdrop must not paint a background (preserves user's terminal theme)",
|
|
170
|
+
);
|
|
52
171
|
});
|
|
53
172
|
|
|
54
173
|
it("does not dim when backdrop is false/absent", () => {
|
|
@@ -60,10 +179,11 @@ describe("compositeOverlays — backdrop", () => {
|
|
|
60
179
|
|
|
61
180
|
const result = compositeOverlays(base, [overlay], 20, 20, 2);
|
|
62
181
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
182
|
+
const line = result.find((l) => stripAnsi(l).includes("second line"));
|
|
183
|
+
assert.ok(line, "should have a line containing 'second line'");
|
|
184
|
+
|
|
185
|
+
const state = sgrStateAtGlyph(line, "second line");
|
|
186
|
+
assert.equal(state.dim, false, "base line should not be dimmed when no backdrop");
|
|
67
187
|
});
|
|
68
188
|
|
|
69
189
|
it("overlay content renders on top of dimmed background", () => {
|
|
@@ -76,7 +196,10 @@ describe("compositeOverlays — backdrop", () => {
|
|
|
76
196
|
|
|
77
197
|
const result = compositeOverlays(base, [overlay], 10, 10, 1);
|
|
78
198
|
|
|
79
|
-
//
|
|
80
|
-
|
|
199
|
+
// Find the row that (after stripping styling) contains the overlay
|
|
200
|
+
// text. We don't use positional `result[0]` so the test survives if
|
|
201
|
+
// the row ordering changes.
|
|
202
|
+
const overlayRow = result.find((l) => stripAnsi(l).includes("XX"));
|
|
203
|
+
assert.ok(overlayRow, "overlay text should be composited into some rendered row");
|
|
81
204
|
});
|
|
82
205
|
});
|
|
@@ -1,29 +1,49 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { describe, it } from "node:test";
|
|
3
|
-
import { setTimeout as delay } from "node:timers/promises";
|
|
4
3
|
|
|
5
4
|
import { StdinBuffer } from "../stdin-buffer.js";
|
|
6
5
|
|
|
6
|
+
// These tests use node:test's mock.timers to advance virtual time.
|
|
7
|
+
// They previously relied on wall-clock delays (delay(20), delay(150))
|
|
8
|
+
// racing the OS scheduler. On Windows the default setTimeout resolution is
|
|
9
|
+
// ~15.6ms, so a real-time delay of 20ms sometimes fired only one of two
|
|
10
|
+
// pending timers — hence the flake referenced in issue #4795.
|
|
11
|
+
//
|
|
12
|
+
// By mocking setTimeout/clearTimeout we control exactly when the buffer's
|
|
13
|
+
// sequence timeout and stale timeout fire, eliminating scheduler-induced
|
|
14
|
+
// flake and making the tests deterministic on every platform.
|
|
15
|
+
|
|
7
16
|
describe("StdinBuffer", () => {
|
|
8
|
-
it("flushes a lone Escape keypress",
|
|
17
|
+
it("flushes a lone Escape keypress after the sequence timeout", (t) => {
|
|
18
|
+
t.mock.timers.enable({ apis: ["setTimeout"] });
|
|
9
19
|
const buffer = new StdinBuffer({ timeout: 5 });
|
|
10
20
|
const received: string[] = [];
|
|
11
21
|
buffer.on("data", (sequence) => received.push(sequence));
|
|
12
22
|
|
|
13
23
|
buffer.process("\x1b");
|
|
14
|
-
|
|
24
|
+
|
|
25
|
+
// Before the timeout fires the lone ESC is still buffered.
|
|
26
|
+
assert.deepEqual(received, []);
|
|
27
|
+
assert.equal(buffer.getBuffer(), "\x1b");
|
|
28
|
+
|
|
29
|
+
// Advance past the sequence timeout.
|
|
30
|
+
t.mock.timers.tick(5);
|
|
15
31
|
|
|
16
32
|
assert.deepEqual(received, ["\x1b"]);
|
|
17
33
|
assert.equal(buffer.getBuffer(), "");
|
|
18
34
|
});
|
|
19
35
|
|
|
20
|
-
it("keeps split CSI focus and mouse sequences buffered until completion",
|
|
36
|
+
it("keeps split CSI focus and mouse sequences buffered until completion", (t) => {
|
|
37
|
+
t.mock.timers.enable({ apis: ["setTimeout"] });
|
|
21
38
|
const buffer = new StdinBuffer({ timeout: 5 });
|
|
22
39
|
const received: string[] = [];
|
|
23
40
|
buffer.on("data", (sequence) => received.push(sequence));
|
|
24
41
|
|
|
25
42
|
buffer.process("\x1b[");
|
|
26
|
-
|
|
43
|
+
// Even after the normal timeout elapses, an incomplete CSI prefix must
|
|
44
|
+
// remain buffered (not emitted as literal text) so split escape
|
|
45
|
+
// sequences stay intact.
|
|
46
|
+
t.mock.timers.tick(5);
|
|
27
47
|
assert.deepEqual(received, []);
|
|
28
48
|
assert.equal(buffer.getBuffer(), "\x1b[");
|
|
29
49
|
|
|
@@ -32,7 +52,7 @@ describe("StdinBuffer", () => {
|
|
|
32
52
|
assert.equal(buffer.getBuffer(), "");
|
|
33
53
|
|
|
34
54
|
buffer.process("\x1b[<35;20;");
|
|
35
|
-
|
|
55
|
+
t.mock.timers.tick(5);
|
|
36
56
|
assert.deepEqual(received, ["\x1b[I"]);
|
|
37
57
|
assert.equal(buffer.getBuffer(), "\x1b[<35;20;");
|
|
38
58
|
|
|
@@ -41,25 +61,36 @@ describe("StdinBuffer", () => {
|
|
|
41
61
|
assert.equal(buffer.getBuffer(), "");
|
|
42
62
|
});
|
|
43
63
|
|
|
44
|
-
it("flushes a stale incomplete escape prefix after the stale timeout",
|
|
45
|
-
|
|
64
|
+
it("flushes a stale incomplete escape prefix after the stale timeout", (t) => {
|
|
65
|
+
t.mock.timers.enable({ apis: ["setTimeout"] });
|
|
66
|
+
const buffer = new StdinBuffer({ timeout: 20, staleTimeout: 40 });
|
|
46
67
|
const received: string[] = [];
|
|
47
68
|
buffer.on("data", (sequence) => received.push(sequence));
|
|
48
69
|
|
|
49
70
|
buffer.process("\x1b[");
|
|
50
|
-
|
|
71
|
+
|
|
72
|
+
// Sequence timeout: keeps the incomplete prefix buffered and starts
|
|
73
|
+
// the stale timer.
|
|
74
|
+
t.mock.timers.tick(20);
|
|
75
|
+
assert.deepEqual(received, []);
|
|
76
|
+
assert.equal(buffer.getBuffer(), "\x1b[");
|
|
77
|
+
|
|
78
|
+
// Stale timer fires — prefix is emitted as-is.
|
|
79
|
+
t.mock.timers.tick(40);
|
|
51
80
|
|
|
52
81
|
assert.deepEqual(received, ["\x1b["]);
|
|
53
82
|
assert.equal(buffer.getBuffer(), "");
|
|
54
83
|
});
|
|
55
84
|
|
|
56
|
-
it("still allows an incomplete escape prefix to complete before the stale timeout",
|
|
85
|
+
it("still allows an incomplete escape prefix to complete before the stale timeout", (t) => {
|
|
86
|
+
t.mock.timers.enable({ apis: ["setTimeout"] });
|
|
57
87
|
const buffer = new StdinBuffer({ timeout: 5, staleTimeout: 30 });
|
|
58
88
|
const received: string[] = [];
|
|
59
89
|
buffer.on("data", (sequence) => received.push(sequence));
|
|
60
90
|
|
|
61
91
|
buffer.process("\x1b[");
|
|
62
|
-
|
|
92
|
+
// Advance past the sequence timeout (but not the stale timeout).
|
|
93
|
+
t.mock.timers.tick(10);
|
|
63
94
|
buffer.process("I");
|
|
64
95
|
|
|
65
96
|
assert.deepEqual(received, ["\x1b[I"]);
|
|
@@ -25,43 +25,24 @@ function makeTerminal(): Terminal {
|
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// maxLinesRendered should remain at the old value so the condition
|
|
47
|
-
// triggers again on the next render
|
|
48
|
-
anyTui._shrinkDebounceActive = true;
|
|
49
|
-
assert.equal(anyTui.maxLinesRendered, 10, "maxLinesRendered must not change during deferred shrink");
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("resets debounce flag when content grows back", () => {
|
|
53
|
-
const tui = new TUI(makeTerminal());
|
|
54
|
-
const anyTui = tui as any;
|
|
55
|
-
|
|
56
|
-
anyTui.clearOnShrink = true;
|
|
57
|
-
anyTui._shrinkDebounceActive = true;
|
|
58
|
-
|
|
59
|
-
// Simulating the else branch: content grew back or no shrink
|
|
60
|
-
// The code sets _shrinkDebounceActive = false in the else branch
|
|
61
|
-
anyTui._shrinkDebounceActive = false;
|
|
62
|
-
assert.equal(anyTui._shrinkDebounceActive, false);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
28
|
+
// TUI clearOnShrink debounce — tests removed in #4794 (ref #4784).
|
|
29
|
+
//
|
|
30
|
+
// The previous tests mutated private fields (`_shrinkDebounceActive`,
|
|
31
|
+
// `maxLinesRendered`) and then asserted the values they just wrote —
|
|
32
|
+
// pure tautologies that never exercised the real debounce path in
|
|
33
|
+
// `renderNow()` (tui.ts:734-754). A regression that narrowed the
|
|
34
|
+
// condition, reversed the flag flip, or dropped the "keep
|
|
35
|
+
// maxLinesRendered" rule would have passed all of them.
|
|
36
|
+
//
|
|
37
|
+
// A proper test would (a) render a component that produces N lines to
|
|
38
|
+
// establish `maxLinesRendered`, (b) swap in a component that produces
|
|
39
|
+
// N-k lines to trigger the shrink branch, and (c) observe terminal
|
|
40
|
+
// writes to confirm the debounce defers/commits the full redraw on the
|
|
41
|
+
// expected render call.
|
|
42
|
+
//
|
|
43
|
+
// That test setup requires exposing enough of the render path (or
|
|
44
|
+
// extracting the debounce decision into a pure helper) — deferred to a
|
|
45
|
+
// separate refactor PR rather than shipping a tautology. See #4794.
|
|
65
46
|
|
|
66
47
|
describe("TUI", () => {
|
|
67
48
|
it("does not swallow a bare Escape keypress while waiting for the cell-size response", () => {
|
|
@@ -37,11 +37,27 @@ describe("Input", () => {
|
|
|
37
37
|
const input = new Input();
|
|
38
38
|
input.secure = true;
|
|
39
39
|
input.focused = true;
|
|
40
|
-
|
|
40
|
+
const SECRET = "secret123";
|
|
41
|
+
input.handleInput(SECRET);
|
|
41
42
|
|
|
42
43
|
const line = input.render(40)[0] ?? "";
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
// Previous assertion was `line.includes("*********")` — a literal
|
|
45
|
+
// 9-star string that silently goes stale if SECRET is renamed to
|
|
46
|
+
// a different length (#4796). Match any run of asterisks and
|
|
47
|
+
// assert its length covers the secret.
|
|
48
|
+
assert.ok(
|
|
49
|
+
!line.includes(SECRET),
|
|
50
|
+
"rendered line must not expose raw secret text",
|
|
51
|
+
);
|
|
52
|
+
const maskMatch = line.match(/\*+/);
|
|
53
|
+
assert.ok(
|
|
54
|
+
maskMatch,
|
|
55
|
+
`rendered line must include masked characters, got: ${JSON.stringify(line)}`,
|
|
56
|
+
);
|
|
57
|
+
assert.ok(
|
|
58
|
+
maskMatch[0].length >= SECRET.length,
|
|
59
|
+
`mask must cover at least the secret length (${SECRET.length}), got ${maskMatch[0].length} asterisks`,
|
|
60
|
+
);
|
|
45
61
|
});
|
|
46
62
|
|
|
47
63
|
it("maps kitty keypad digits to text instead of inserting private-use glyphs", () => {
|