gsd-pi 2.77.0-dev.1d17f366c → 2.77.0-dev.2daa994b6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/headless.js +25 -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/gsd/auto/phases.js +5 -18
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +37 -8
- package/dist/resources/extensions/gsd/auto-post-unit.js +79 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
- package/dist/resources/extensions/gsd/auto-start.js +75 -24
- package/dist/resources/extensions/gsd/auto.js +34 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -1
- 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/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/forensics.js +106 -0
- package/dist/resources/extensions/gsd/gsd-db.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +2 -4
- 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/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 +5 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- 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/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 +334 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +51 -0
- 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 +17 -17
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- 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 +1 -3
- 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/workflow-tools.test.ts +80 -39
- 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/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 +29 -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/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 +39 -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/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/__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/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/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.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/image.test.ts +10 -5
- 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/tests/stream-adapter.test.ts +80 -72
- 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/phases.ts +6 -17
- package/src/resources/extensions/gsd/auto/session.ts +7 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +40 -8
- package/src/resources/extensions/gsd/auto-post-unit.ts +81 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
- package/src/resources/extensions/gsd/auto-start.ts +97 -4
- package/src/resources/extensions/gsd/auto.ts +37 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -1
- 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/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/forensics.ts +118 -1
- package/src/resources/extensions/gsd/git-service.ts +16 -0
- package/src/resources/extensions/gsd/gsd-db.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +2 -4
- 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/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- 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 +5 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- 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/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +25 -292
- 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-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 +8 -4
- 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/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/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/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/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/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 +1 -1
- 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/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/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/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 +22 -16
- 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/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/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/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/smart-entry-draft.test.ts +2 -1
- 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-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/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +203 -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 -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/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +492 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +53 -0
- 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/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_ssgManifest.js +0 -0
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for startCommandPolling() background interval.
|
|
2
|
+
* Tests for the REAL `startCommandPolling()` background interval.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Previous version of this file re-implemented `startCommandPolling`
|
|
5
|
+
* inline (as `makeStartCommandPolling`) and tested the re-implementation.
|
|
6
|
+
* The file header said exactly that: "Rather than importing the real
|
|
7
|
+
* startCommandPolling (which calls resolveRemoteConfig and hits the
|
|
8
|
+
* filesystem / env), we re-implement the same tiny function inline
|
|
9
|
+
* here using injected fakes." If the real function regressed (wrong
|
|
10
|
+
* channel gate, missing cleanup, wrong handler invocation), none of
|
|
11
|
+
* those tests would have failed. See #4806 / #4784.
|
|
5
12
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* - When no remote channel is configured, a no-op cleanup is returned
|
|
13
|
+
* Rewrite uses the DI seam now exposed on `startCommandPolling`
|
|
14
|
+
* (`CommandPollingDeps`) to drive the real function with a stubbed
|
|
15
|
+
* config resolver, adapter factory, and timer pair.
|
|
10
16
|
*/
|
|
11
17
|
|
|
12
|
-
import
|
|
18
|
+
import { describe, it } from "node:test";
|
|
13
19
|
import assert from "node:assert/strict";
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
import type { ResolvedConfig } from "../config.ts";
|
|
22
|
+
import {
|
|
23
|
+
startCommandPolling,
|
|
24
|
+
type PollingAdapter,
|
|
25
|
+
type CommandPollingDeps,
|
|
26
|
+
} from "../manager.ts";
|
|
27
|
+
|
|
28
|
+
// ─── Fake timer harness ───────────────────────────────────────────────────────
|
|
16
29
|
|
|
17
30
|
interface FakeTimer {
|
|
18
31
|
id: number;
|
|
@@ -21,226 +34,223 @@ interface FakeTimer {
|
|
|
21
34
|
cleared: boolean;
|
|
22
35
|
}
|
|
23
36
|
|
|
24
|
-
/**
|
|
25
|
-
* Build a fake setInterval / clearInterval pair so tests never actually wait
|
|
26
|
-
* for real time and do not depend on Node's timer subsystem firing order.
|
|
27
|
-
*/
|
|
28
37
|
function makeFakeTimers(): {
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
setIntervalFn: typeof setInterval;
|
|
39
|
+
clearIntervalFn: typeof clearInterval;
|
|
31
40
|
timers: FakeTimer[];
|
|
32
41
|
tick: () => void;
|
|
33
42
|
} {
|
|
34
43
|
const timers: FakeTimer[] = [];
|
|
35
44
|
let nextId = 1;
|
|
36
45
|
|
|
37
|
-
const
|
|
46
|
+
const setIntervalFn = ((callback: () => void, ms?: number): ReturnType<typeof setInterval> => {
|
|
38
47
|
const timer: FakeTimer = {
|
|
39
48
|
id: nextId++,
|
|
40
49
|
callback,
|
|
41
|
-
intervalMs:
|
|
50
|
+
intervalMs: ms ?? 0,
|
|
42
51
|
cleared: false,
|
|
43
52
|
};
|
|
44
53
|
timers.push(timer);
|
|
45
54
|
return timer.id as unknown as ReturnType<typeof setInterval>;
|
|
46
|
-
};
|
|
55
|
+
}) as unknown as typeof setInterval;
|
|
47
56
|
|
|
48
|
-
const
|
|
57
|
+
const clearIntervalFn = ((id?: ReturnType<typeof clearInterval> | null): void => {
|
|
49
58
|
const timer = timers.find((t) => (t.id as unknown) === id);
|
|
50
59
|
if (timer) timer.cleared = true;
|
|
51
|
-
};
|
|
60
|
+
}) as unknown as typeof clearInterval;
|
|
52
61
|
|
|
53
|
-
/** Fire all non-cleared timers once (simulates one interval tick). */
|
|
54
62
|
const tick = (): void => {
|
|
55
63
|
for (const timer of timers) {
|
|
56
64
|
if (!timer.cleared) timer.callback();
|
|
57
65
|
}
|
|
58
66
|
};
|
|
59
67
|
|
|
68
|
+
return { setIntervalFn, clearIntervalFn, timers, tick };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ─── Config + adapter stubs ───────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
function telegramConfig(): ResolvedConfig {
|
|
60
74
|
return {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
channel: "telegram",
|
|
76
|
+
token: "fake-token",
|
|
77
|
+
channelId: "fake-channel-id",
|
|
78
|
+
timeoutMs: 60_000,
|
|
79
|
+
pollIntervalMs: 1_000,
|
|
80
|
+
} as ResolvedConfig;
|
|
66
81
|
}
|
|
67
82
|
|
|
68
|
-
|
|
83
|
+
function slackConfig(): ResolvedConfig {
|
|
84
|
+
return {
|
|
85
|
+
channel: "slack",
|
|
86
|
+
token: "fake-token",
|
|
87
|
+
channelId: "fake-channel-id",
|
|
88
|
+
timeoutMs: 60_000,
|
|
89
|
+
pollIntervalMs: 1_000,
|
|
90
|
+
} as ResolvedConfig;
|
|
91
|
+
}
|
|
69
92
|
|
|
70
|
-
function makeFakeAdapter(): {
|
|
71
|
-
pollCalls: number;
|
|
72
|
-
pollAndHandleCommands: (basePath: string) => Promise<number>;
|
|
73
|
-
} {
|
|
93
|
+
function makeFakeAdapter(): PollingAdapter & { readonly pollCalls: number } {
|
|
74
94
|
let pollCalls = 0;
|
|
75
|
-
|
|
76
|
-
get pollCalls() {
|
|
95
|
+
const adapter = {
|
|
96
|
+
get pollCalls(): number {
|
|
97
|
+
return pollCalls;
|
|
98
|
+
},
|
|
77
99
|
async pollAndHandleCommands(_basePath: string): Promise<number> {
|
|
78
100
|
pollCalls++;
|
|
79
101
|
return 0;
|
|
80
102
|
},
|
|
81
103
|
};
|
|
104
|
+
return adapter;
|
|
82
105
|
}
|
|
83
106
|
|
|
84
|
-
// ───
|
|
85
|
-
//
|
|
86
|
-
// Rather than importing the real startCommandPolling (which calls resolveRemoteConfig
|
|
87
|
-
// and hits the filesystem / env), we re-implement the same tiny function inline
|
|
88
|
-
// here using injected fakes. This keeps tests hermetic without mocking globals.
|
|
89
|
-
|
|
90
|
-
function makeStartCommandPolling(
|
|
91
|
-
fakeSetInterval: typeof setInterval,
|
|
92
|
-
fakeClearInterval: typeof clearInterval,
|
|
93
|
-
adapterPollFn: (basePath: string) => Promise<number>,
|
|
94
|
-
isConfigured: boolean,
|
|
95
|
-
intervalMs = 5000,
|
|
96
|
-
): (basePath: string) => () => void {
|
|
97
|
-
return function startCommandPolling(basePath: string): () => void {
|
|
98
|
-
if (!isConfigured) {
|
|
99
|
-
return () => {};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const timer = fakeSetInterval(() => {
|
|
103
|
-
void adapterPollFn(basePath).catch(() => {});
|
|
104
|
-
}, intervalMs);
|
|
105
|
-
|
|
106
|
-
return () => fakeClearInterval(timer);
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
111
|
-
|
|
112
|
-
test("startCommandPolling: returns a cleanup function (callable without error)", () => {
|
|
113
|
-
const { fakeSetInterval, fakeClearInterval } = makeFakeTimers();
|
|
114
|
-
const adapter = makeFakeAdapter();
|
|
115
|
-
const startCommandPolling = makeStartCommandPolling(
|
|
116
|
-
fakeSetInterval,
|
|
117
|
-
fakeClearInterval,
|
|
118
|
-
adapter.pollAndHandleCommands.bind(adapter),
|
|
119
|
-
true,
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
const cleanup = startCommandPolling("/fake/project");
|
|
123
|
-
|
|
124
|
-
assert.equal(typeof cleanup, "function", "Expected startCommandPolling to return a function");
|
|
125
|
-
// Calling cleanup must not throw
|
|
126
|
-
assert.doesNotThrow(() => cleanup(), "cleanup() must not throw");
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
test("startCommandPolling: interval fires the poll callback on tick", async () => {
|
|
130
|
-
const { fakeSetInterval, fakeClearInterval, tick } = makeFakeTimers();
|
|
131
|
-
const adapter = makeFakeAdapter();
|
|
132
|
-
const startCommandPolling = makeStartCommandPolling(
|
|
133
|
-
fakeSetInterval,
|
|
134
|
-
fakeClearInterval,
|
|
135
|
-
adapter.pollAndHandleCommands.bind(adapter),
|
|
136
|
-
true,
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
startCommandPolling("/fake/project");
|
|
140
|
-
|
|
141
|
-
// Before any tick, nothing polled yet
|
|
142
|
-
assert.equal(adapter.pollCalls, 0);
|
|
143
|
-
|
|
144
|
-
// One tick — the callback fires and schedules the async poll
|
|
145
|
-
tick();
|
|
146
|
-
|
|
147
|
-
// Allow the microtask queue to drain so the async poll promise resolves
|
|
148
|
-
await Promise.resolve();
|
|
149
|
-
|
|
150
|
-
assert.equal(adapter.pollCalls, 1, "Expected poll to be called after one tick");
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
test("startCommandPolling: cleanup stops further poll invocations", async () => {
|
|
154
|
-
const { fakeSetInterval, fakeClearInterval, timers, tick } = makeFakeTimers();
|
|
155
|
-
const adapter = makeFakeAdapter();
|
|
156
|
-
const startCommandPolling = makeStartCommandPolling(
|
|
157
|
-
fakeSetInterval,
|
|
158
|
-
fakeClearInterval,
|
|
159
|
-
adapter.pollAndHandleCommands.bind(adapter),
|
|
160
|
-
true,
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
const cleanup = startCommandPolling("/fake/project");
|
|
164
|
-
|
|
165
|
-
// Tick once to confirm polling works
|
|
166
|
-
tick();
|
|
167
|
-
await Promise.resolve();
|
|
168
|
-
assert.equal(adapter.pollCalls, 1, "Expected 1 poll after first tick");
|
|
169
|
-
|
|
170
|
-
// Call cleanup — marks the timer as cleared
|
|
171
|
-
cleanup();
|
|
172
|
-
|
|
173
|
-
// Confirm the underlying timer was cleared
|
|
174
|
-
assert.equal(timers.length, 1, "Expected exactly one timer to have been registered");
|
|
175
|
-
assert.equal(timers[0].cleared, true, "Expected timer to be cleared after cleanup()");
|
|
176
|
-
|
|
177
|
-
// Tick again — the cleared timer must NOT fire
|
|
178
|
-
tick();
|
|
179
|
-
await Promise.resolve();
|
|
180
|
-
assert.equal(adapter.pollCalls, 1, "Expected no additional polls after cleanup()");
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
test("startCommandPolling: calling cleanup twice is safe (no throw)", () => {
|
|
184
|
-
const { fakeSetInterval, fakeClearInterval } = makeFakeTimers();
|
|
185
|
-
const adapter = makeFakeAdapter();
|
|
186
|
-
const startCommandPolling = makeStartCommandPolling(
|
|
187
|
-
fakeSetInterval,
|
|
188
|
-
fakeClearInterval,
|
|
189
|
-
adapter.pollAndHandleCommands.bind(adapter),
|
|
190
|
-
true,
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
const cleanup = startCommandPolling("/fake/project");
|
|
194
|
-
|
|
195
|
-
assert.doesNotThrow(() => {
|
|
196
|
-
cleanup();
|
|
197
|
-
cleanup();
|
|
198
|
-
}, "Calling cleanup twice must not throw");
|
|
199
|
-
});
|
|
107
|
+
// ─── Tests against the real startCommandPolling ───────────────────────────────
|
|
200
108
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
fakeSetInterval,
|
|
206
|
-
fakeClearInterval,
|
|
207
|
-
adapter.pollAndHandleCommands.bind(adapter),
|
|
208
|
-
false, // not configured
|
|
209
|
-
);
|
|
109
|
+
describe("startCommandPolling (real function via DI seam)", () => {
|
|
110
|
+
it("returns a cleanup function for a Telegram config", () => {
|
|
111
|
+
const { setIntervalFn, clearIntervalFn } = makeFakeTimers();
|
|
112
|
+
const adapter = makeFakeAdapter();
|
|
210
113
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
assert.doesNotThrow(() => cleanup(), "No-op cleanup must not throw");
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
test("startCommandPolling: poll errors are swallowed (best-effort)", async () => {
|
|
221
|
-
const { fakeSetInterval, fakeClearInterval, tick } = makeFakeTimers();
|
|
222
|
-
|
|
223
|
-
// Adapter that always rejects
|
|
224
|
-
let rejectCalls = 0;
|
|
225
|
-
const throwingPoll = async (_basePath: string): Promise<number> => {
|
|
226
|
-
rejectCalls++;
|
|
227
|
-
throw new Error("Simulated network error");
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
const startCommandPolling = makeStartCommandPolling(
|
|
231
|
-
fakeSetInterval,
|
|
232
|
-
fakeClearInterval,
|
|
233
|
-
throwingPoll,
|
|
234
|
-
true,
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
startCommandPolling("/fake/project");
|
|
238
|
-
|
|
239
|
-
// Ticking must not propagate the rejection — the interval is fire-and-forget
|
|
240
|
-
assert.doesNotThrow(() => tick(), "tick() must not throw even if poll rejects");
|
|
114
|
+
const deps: CommandPollingDeps = {
|
|
115
|
+
resolveConfig: () => telegramConfig(),
|
|
116
|
+
createAdapter: () => adapter,
|
|
117
|
+
setIntervalFn,
|
|
118
|
+
clearIntervalFn,
|
|
119
|
+
};
|
|
241
120
|
|
|
242
|
-
|
|
243
|
-
|
|
121
|
+
const stop = startCommandPolling("/tmp/project", 5_000, deps);
|
|
122
|
+
assert.equal(typeof stop, "function", "must return a cleanup function");
|
|
123
|
+
stop();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("invokes the adapter's pollAndHandleCommands on each tick", async () => {
|
|
127
|
+
const { setIntervalFn, clearIntervalFn, tick } = makeFakeTimers();
|
|
128
|
+
const adapter = makeFakeAdapter();
|
|
129
|
+
|
|
130
|
+
const stop = startCommandPolling("/tmp/project", 5_000, {
|
|
131
|
+
resolveConfig: () => telegramConfig(),
|
|
132
|
+
createAdapter: () => adapter,
|
|
133
|
+
setIntervalFn,
|
|
134
|
+
clearIntervalFn,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
assert.equal(adapter.pollCalls, 0, "no poll before any tick");
|
|
138
|
+
|
|
139
|
+
tick();
|
|
140
|
+
// Yield so the async adapter call settles before we assert.
|
|
141
|
+
await Promise.resolve();
|
|
142
|
+
await Promise.resolve();
|
|
143
|
+
assert.equal(adapter.pollCalls, 1, "one tick → one poll");
|
|
144
|
+
|
|
145
|
+
tick();
|
|
146
|
+
tick();
|
|
147
|
+
await Promise.resolve();
|
|
148
|
+
await Promise.resolve();
|
|
149
|
+
assert.equal(adapter.pollCalls, 3, "three ticks → three polls");
|
|
150
|
+
|
|
151
|
+
stop();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("cleanup stops further polls", async () => {
|
|
155
|
+
const { setIntervalFn, clearIntervalFn, tick } = makeFakeTimers();
|
|
156
|
+
const adapter = makeFakeAdapter();
|
|
157
|
+
|
|
158
|
+
const stop = startCommandPolling("/tmp/project", 5_000, {
|
|
159
|
+
resolveConfig: () => telegramConfig(),
|
|
160
|
+
createAdapter: () => adapter,
|
|
161
|
+
setIntervalFn,
|
|
162
|
+
clearIntervalFn,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
tick();
|
|
166
|
+
await Promise.resolve();
|
|
167
|
+
await Promise.resolve();
|
|
168
|
+
const pollsBeforeStop = adapter.pollCalls;
|
|
169
|
+
assert.ok(pollsBeforeStop > 0, "at least one poll before stop");
|
|
170
|
+
|
|
171
|
+
stop();
|
|
172
|
+
|
|
173
|
+
tick();
|
|
174
|
+
tick();
|
|
175
|
+
await Promise.resolve();
|
|
176
|
+
await Promise.resolve();
|
|
177
|
+
assert.equal(
|
|
178
|
+
adapter.pollCalls,
|
|
179
|
+
pollsBeforeStop,
|
|
180
|
+
"no additional polls after stop() — cleared interval must stop ticking",
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("returns a no-op when no remote channel is configured", () => {
|
|
185
|
+
const { setIntervalFn, clearIntervalFn, timers } = makeFakeTimers();
|
|
186
|
+
const adapter = makeFakeAdapter();
|
|
187
|
+
|
|
188
|
+
const stop = startCommandPolling("/tmp/project", 5_000, {
|
|
189
|
+
resolveConfig: () => null,
|
|
190
|
+
createAdapter: () => adapter,
|
|
191
|
+
setIntervalFn,
|
|
192
|
+
clearIntervalFn,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
assert.equal(typeof stop, "function", "still returns a function");
|
|
196
|
+
assert.equal(
|
|
197
|
+
timers.length,
|
|
198
|
+
0,
|
|
199
|
+
"no interval registered when config is absent",
|
|
200
|
+
);
|
|
201
|
+
assert.doesNotThrow(() => stop());
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("returns a no-op for non-Telegram channels (e.g. Slack)", () => {
|
|
205
|
+
const { setIntervalFn, clearIntervalFn, timers } = makeFakeTimers();
|
|
206
|
+
const adapter = makeFakeAdapter();
|
|
207
|
+
let adapterCreated = false;
|
|
208
|
+
|
|
209
|
+
const stop = startCommandPolling("/tmp/project", 5_000, {
|
|
210
|
+
resolveConfig: () => slackConfig(),
|
|
211
|
+
createAdapter: () => {
|
|
212
|
+
adapterCreated = true;
|
|
213
|
+
return adapter;
|
|
214
|
+
},
|
|
215
|
+
setIntervalFn,
|
|
216
|
+
clearIntervalFn,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
assert.equal(
|
|
220
|
+
timers.length,
|
|
221
|
+
0,
|
|
222
|
+
"no interval registered for non-Telegram channel",
|
|
223
|
+
);
|
|
224
|
+
assert.equal(
|
|
225
|
+
adapterCreated,
|
|
226
|
+
false,
|
|
227
|
+
"adapter must not be instantiated when channel is unsupported",
|
|
228
|
+
);
|
|
229
|
+
stop();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("does not surface adapter polling errors (best-effort)", async () => {
|
|
233
|
+
const { setIntervalFn, clearIntervalFn, tick } = makeFakeTimers();
|
|
234
|
+
const adapter: PollingAdapter = {
|
|
235
|
+
async pollAndHandleCommands(_basePath: string): Promise<number> {
|
|
236
|
+
throw new Error("network hiccup");
|
|
237
|
+
},
|
|
238
|
+
};
|
|
244
239
|
|
|
245
|
-
|
|
240
|
+
const stop = startCommandPolling("/tmp/project", 5_000, {
|
|
241
|
+
resolveConfig: () => telegramConfig(),
|
|
242
|
+
createAdapter: () => adapter,
|
|
243
|
+
setIntervalFn,
|
|
244
|
+
clearIntervalFn,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Tick must not throw; the `.catch(() => {})` in production code
|
|
248
|
+
// swallows the rejection so one bad network call doesn't crash
|
|
249
|
+
// the polling loop.
|
|
250
|
+
assert.doesNotThrow(() => tick());
|
|
251
|
+
await Promise.resolve();
|
|
252
|
+
await Promise.resolve();
|
|
253
|
+
|
|
254
|
+
stop();
|
|
255
|
+
});
|
|
246
256
|
});
|
|
@@ -56,14 +56,22 @@ describe("preview column rendering", () => {
|
|
|
56
56
|
assert.ok(hasContent, "At least one rendered line should have visible content");
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
it("Markdown component renders code blocks", () => {
|
|
59
|
+
it("Markdown component renders code blocks — preserves the source text", () => {
|
|
60
60
|
const mdTheme = getMarkdownTheme();
|
|
61
61
|
const md = new Markdown("```ts\nconst x = 1;\n```", 1, 0, mdTheme);
|
|
62
62
|
const lines = md.render(40);
|
|
63
63
|
assert.ok(lines.length > 0);
|
|
64
64
|
const joined = lines.join("\n");
|
|
65
|
-
//
|
|
66
|
-
|
|
65
|
+
// Previous assertion was `includes("const") || includes("x")` — the
|
|
66
|
+
// `x` branch matched any ANSI rendering incidentally containing the
|
|
67
|
+
// letter (box borders, tab markers, even fallbackColor's `x` token),
|
|
68
|
+
// making it a near-tautology. Assert on a distinctive combined
|
|
69
|
+
// source fragment so a regression that silently swallows the code
|
|
70
|
+
// block body actually fails.
|
|
71
|
+
assert.ok(
|
|
72
|
+
joined.includes("const") && joined.includes("x = 1"),
|
|
73
|
+
`rendered code block must preserve source tokens. got:\n${joined}`,
|
|
74
|
+
);
|
|
67
75
|
});
|
|
68
76
|
|
|
69
77
|
it("Markdown component respects width constraint", () => {
|