test: remove 167 low-value cases and 93 suites (#41057)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-11-10 23:17:08 -08:00
committed by GitHub
co-authored by OrcaWin
parent e183ba8bac
commit fce98d7d21
125 changed files with 75 additions and 6097 deletions
-2
View File
@@ -27,7 +27,6 @@ on:
- 'src/main/runtime/agent-session/agent-session-account-*.ts'
- 'src/main/runtime/agent-session/agent-session-acquisition-*.ts'
- 'src/main/runtime/agent-session/agent-session-conversation-*.ts'
- 'src/main/runtime/agent-session/agent-session-death-*.ts'
- 'src/main/runtime/agent-session/agent-session-launch-*.ts'
- 'src/main/runtime/agent-session/agent-session-operation-*.ts'
- 'src/main/runtime/agent-session/agent-session-rewind-*.ts'
@@ -116,7 +115,6 @@ on:
- 'src/main/runtime/agent-session/agent-session-account-*.ts'
- 'src/main/runtime/agent-session/agent-session-acquisition-*.ts'
- 'src/main/runtime/agent-session/agent-session-conversation-*.ts'
- 'src/main/runtime/agent-session/agent-session-death-*.ts'
- 'src/main/runtime/agent-session/agent-session-launch-*.ts'
- 'src/main/runtime/agent-session/agent-session-operation-*.ts'
- 'src/main/runtime/agent-session/agent-session-rewind-*.ts'
@@ -21,7 +21,6 @@ on:
- 'src/main/runtime/session-tabs/session-tabs-phone-layout-moves.test.ts'
- 'src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-terminal-writer-acquire.test.ts'
- 'src/shared/agent-launch/permissions/tui-agent-permission-choice.test.ts'
- 'src/main/runtime/rpc/methods/projects/repo.test.ts'
- 'src/renderer/src/components/tab-bar/use-new-tab-agent-menu-host-preferences.test.tsx'
- 'src/main/sqlite/sync-database.test.ts'
- 'src/main/runtime/orchestration/db/row-column-lists.test.ts'
+1 -4
View File
@@ -507,7 +507,6 @@
3 test-no-wall-clock:src/main/github/pr-refresh-coordinator-active-visible-priority.test.ts
8 test-no-wall-clock:src/main/github/pr-refresh-coordinator-alias-coalescing.test.ts
5 test-no-wall-clock:src/main/github/pr-refresh-coordinator-completion-order.test.ts
1 test-no-wall-clock:src/main/github/pr-refresh-coordinator-error-cadence.test.ts
3 test-no-wall-clock:src/main/github/pr-refresh-coordinator-foreground-pacing.test.ts
3 test-no-wall-clock:src/main/github/pr-refresh-coordinator-refresh-events.test.ts
4 test-no-wall-clock:src/main/github/pr-refresh-coordinator-visibility-policy.test.ts
@@ -614,7 +613,6 @@
3 test-no-wall-clock:src/main/windows/windows-msys-job.win32.test.ts
1 test-no-wall-clock:src/main/windows/windows-process-table-native-addon.win32.test.ts
2 test-no-wall-clock:src/main/windows/windows-pty-job.win32.test.ts
2 test-no-wall-clock:src/main/workspace-hooks/hook-archive-timeout-observation.test.ts
2 test-no-wall-clock:src/main/workspaces/removal/local-worktree-removal-recovery-live.test.ts
1 test-no-wall-clock:src/main/workspaces/removal/worktree-removal-close-records.test.ts
2 test-no-wall-clock:src/main/wsl/execution/wsl-runner.wsl.test.ts
@@ -627,7 +625,6 @@
2 test-no-wall-clock:src/renderer/src/components/native-chat/tools/tasks/NativeChatStructuredSessionStatus.test.tsx
1 test-no-wall-clock:src/renderer/src/components/sidebar/workspace-card/review/use-workspace-reference-details.test.tsx
1 test-no-wall-clock:src/renderer/src/components/sidebar/worktree-list/listing/WorktreeList.lineage-agent-expansion-coupling.test.tsx
2 test-no-wall-clock:src/renderer/src/components/task-page/jira/task-page-jira-cache-selectors.test.ts
2 test-no-wall-clock:src/renderer/src/components/terminal-pane/pty-connection/emulation/fish-color-scheme-child-stdin.node-pty.test.ts
2 test-no-wall-clock:src/renderer/src/components/terminal-pane/snapshots/remote-snapshot-alt-screen-host-chain.test.ts
1 test-no-wall-clock:src/renderer/src/components/terminal/initial-terminal-structured-launch.test.tsx
@@ -750,7 +747,7 @@
1 test-timeout-needs-reason:src/main/windows/windows-msys-job.win32.test.ts
2 test-timeout-needs-reason:src/main/windows/windows-pty-job.win32.test.ts
5 test-timeout-needs-reason:src/main/worker-thread-child-process/worker-thread-child-process.test.ts
2 test-timeout-needs-reason:src/main/workspace-hooks/hook-archive-timeout-observation.test.ts
1 test-timeout-needs-reason:src/main/workspace-hooks/hook-archive-timeout-observation.test.ts
2 test-timeout-needs-reason:src/main/workspace-hooks/hook-termination-real-process.test.ts
2 test-timeout-needs-reason:src/main/workspaces/removal/local-worktree-filesystem-wsl-banner.wsl.test.ts
4 test-timeout-needs-reason:src/main/wsl/execution/wsl-runner.wsl.test.ts
@@ -2,7 +2,6 @@
# The relay retirement (2027-01-15) deletes the folder and edits exactly these files.
# Prune: pnpm check:legacy-relay-fence-ratchet --prune
src/main/ipc/runtime-environments/orcad-delta-move-handlers.ts
src/main/ipc/pty/runtime/kill-legacy-relay-bridged.test.ts
src/main/ipc/pty/runtime/kill.ts
src/main/ipc/ssh/ssh-connect-decision-cancellation.test.ts
src/main/ipc/ssh/ssh-connect-flow.ts
File diff suppressed because one or more lines are too long
@@ -831,10 +831,8 @@
"src/main/automations/automation-zero-grace-tick-latency.test.ts": 2108,
"src/main/automations/dispatch-refusal-wsl-move.test.ts": 577,
"src/main/automations/external-automation-manager-cache.test.ts": 70,
"src/main/automations/external-automation-owner-guard.test.ts": 332,
"src/main/automations/external-automation-probe-scheduler.test.ts": 97,
"src/main/automations/external-manager-scoped.test.ts": 391,
"src/main/automations/external-manager.test.ts": 388,
"src/main/automations/run-terminal-retention.test.ts": 112,
"src/main/automations/automation-workspace-create.test.ts": 50,
"src/main/automations/hook-review-blocked-run-terminals.test.ts": 4564,
@@ -844,7 +842,6 @@
"src/main/automations/run-target-resolution.test.ts": 367,
"src/main/automations/runtime-chat-run-observer.test.ts": 6812,
"src/main/automations/runtime-terminal-run-observer-evidence.test.ts": 230,
"src/main/automations/runtime-terminal-run-observer.test.ts": 4026,
"src/main/automations/service-precheck.test.ts": 2057,
"src/main/automations/service.test.ts": 2970,
"src/main/bitbucket/credential-connection.test.ts": 156,
@@ -982,7 +979,6 @@
"src/main/browser/cookies/browser-cookie-import-partition.electron.test.ts": 2260,
"src/main/browser/cookies/browser-cookie-import-snapshot-ownership.test.ts": 1178,
"src/main/browser/cookies/browser-cookie-import-validated-partition.electron.test.ts": 2445,
"src/main/browser/cookies/browser-cookie-import-write.test.ts": 68,
"src/main/browser/cookies/browser-cookie-import.comet.test.ts": 1501,
"src/main/browser/cookies/browser-cookie-import.test.ts": 1304,
"src/main/browser/cookies/browser-cookie-samesite.electron.test.ts": 1882,
@@ -1063,7 +1059,6 @@
"src/main/browser/cdp/input/guest-focused-frame-route.test.ts": 78,
"src/main/browser/routing/local-host-partitions/local-ssh-browser-partition-identity.test.ts": 479,
"src/main/browser/routing/local-host-partitions/local-ssh-browser-profile-retirement.test.ts": 287,
"src/main/browser/routing/local-host-partitions/local-ssh-browser-route-target.test.ts": 65,
"src/main/browser/routing/local-host-partitions/local-ssh-browser-route.test.ts": 92,
"src/main/browser/backends/offscreen-browser-backend-lifecycle.test.ts": 341,
"src/main/browser/client-hosts/lifecycle/paired-runtime-browser-client-host-composition.test.ts": 165,
@@ -1172,7 +1167,6 @@
"src/main/claude/claude-stop-ack-race.test.ts": 1301,
"src/main/claude/claude-stream-json-connection-close.test.ts": 621,
"src/main/claude/claude-stream-json-connection.test.ts": 8687,
"src/main/claude/claude-stream-json-exit-error.test.ts": 170,
"src/main/claude/claude-streamed-text-checkpoints.test.ts": 59,
"src/main/claude/claude-structured-launch-home-perf.test.ts": 401,
"src/main/claude/claude-structured-result-control-overlap.test.ts": 1136,
@@ -1916,7 +1910,6 @@
"src/main/git/source-control/status-read-failure-real-git.test.ts": 307,
"src/main/git/source-control/status-shared-symlinks.test.ts": 746,
"src/main/git/source-control/status-submodule.test.ts": 306,
"src/main/git/source-control/status-symlink-probe-budget.test.ts": 238,
"src/main/git/source-control/status-upstream-ref.test.ts": 52,
"src/main/git/source-control/upstream-deferred-fork-remote-real.test.ts": 319,
"src/main/git/source-control/upstream.test.ts": 406,
@@ -2014,7 +2007,6 @@
"src/main/github/pr-refresh-coordinator-active-visible-priority.test.ts": 643,
"src/main/github/pr-refresh-coordinator-alias-coalescing.test.ts": 1020,
"src/main/github/pr-refresh-coordinator-completion-order.test.ts": 914,
"src/main/github/pr-refresh-coordinator-error-cadence.test.ts": 951,
"src/main/github/pr-refresh-coordinator-foreground-pacing.test.ts": 650,
"src/main/github/pr-refresh-coordinator-refresh-events.test.ts": 617,
"src/main/github/pr-refresh-coordinator-visibility-policy.test.ts": 1371,
@@ -2157,7 +2149,6 @@
"src/main/ipc/filesystem/filesystem-search-file-paths.test.ts": 443,
"src/main/ipc/filesystem/filesystem-symlink-directory-entries.test.ts": 56,
"src/main/ipc/filesystem/filesystem-write-bytes.test.ts": 147,
"src/main/ipc/filesystem/filesystem-write-identical.test.ts": 138,
"src/main/ipc/filesystem/filesystem-wsl-stopped-distro-git.test.ts": 1163,
"src/main/ipc/filesystem/filesystem-wsl-stopped-distro-reads.test.ts": 1284,
"src/main/ipc/filesystem/filesystem.test.ts": 2043,
@@ -2238,7 +2229,6 @@
"src/main/ipc/pty/ipc/spawn-push-target-materialization-real-git.test.ts": 1316,
"src/main/ipc/pty/ipc/write-input-user-input.test.ts": 84,
"src/main/ipc/pty/managed-data-account-spawn-environment.test.ts": 1150,
"src/main/ipc/pty/pane/join-pane-spawn.test.ts": 1438,
"src/main/ipc/pty/pane/pane-owner-replacement.test.ts": 1960,
"src/main/ipc/pty/pane/serializer-document-lifetime.test.ts": 77,
"src/main/ipc/pty/pane/spawn-registration.test.ts": 935,
@@ -2257,7 +2247,6 @@
"src/main/ipc/pty/pty-spawn-cwd-fallback.test.ts": 4680,
"src/main/ipc/pty/pty-ssh-stop-verdict.test.ts": 3615,
"src/main/ipc/pty/pty-write-ipc-validation.test.ts": 5157,
"src/main/ipc/pty/runtime/kill-legacy-relay-bridged.test.ts": 3679,
"src/main/ipc/pty/runtime/kill-same-id-respawn.test.ts": 3784,
"src/main/ipc/pty/runtime/spawn-preflight-wsl-background-hold.test.ts": 1568,
"src/main/ipc/filesystem/watcher-process/rebinding-file-watch-noise.test.ts": 317,
@@ -2267,7 +2256,6 @@
"src/main/ipc/worktrees/removal/registered-worktree-root-stopped-distro.test.ts": 168,
"src/main/ipc/worktrees/removal/registered-worktree-root-wsl-runtime.test.ts": 261,
"src/main/ipc/worktrees/removal/registered-worktree-roots-scoped-invalidation.test.ts": 141,
"src/main/ipc/renderer-lifetime-abort.test.ts": 65,
"src/main/ipc/renderer-shutdown-checkpoint-sleep-records.test.ts": 1914,
"src/main/ipc/renderer-shutdown-checkpoint.test.ts": 496,
"src/main/ipc/renderer-terminal-serializer-readiness.test.ts": 45,
@@ -2308,7 +2296,6 @@
"src/main/ipc/ssh/ssh-app-shutdown.test.ts": 4455,
"src/main/ipc/ssh/ssh-connect-decision-cancellation.test.ts": 6414,
"src/main/ipc/ssh/ssh-credential-cancel.test.ts": 4604,
"src/main/ipc/ssh/ssh-disconnect-cancellation.test.ts": 6851,
"src/main/ipc/ssh/ssh-host-user-disconnect.test.ts": 4734,
"src/main/ipc/ssh/ssh-passphrase.test.ts": 135,
"src/main/ipc/ssh/ssh.test.ts": 6905,
@@ -2438,7 +2425,6 @@
"src/main/managed-server/install/orcad-remote-launch-setsid.test.ts": 342,
"src/main/managed-server/install/orcad-remote-launch.test.ts": 319,
"src/main/managed-server/install/orcad-remote-node-runtime.test.ts": 248,
"src/main/managed-server/install/orcad-remote-primitives.test.ts": 337,
"src/main/managed-server/install/orcad-remote-readiness-wait.test.ts": 9063,
"src/main/managed-server/install/orcad-remote-runtime.test.ts": 488,
"src/main/managed-server/install/orcad-remote-shell-commands.integration.test.ts": 9000,
@@ -2474,7 +2460,6 @@
"src/main/muse/hook-service.test.ts": 145,
"src/main/native-chat/agent-model-catalog/agent-model-catalog-discovery-freshness.test.ts": 390,
"src/main/native-chat/agent-model-catalog/agent-model-catalog-entry.test.ts": 75,
"src/main/native-chat/agent-model-catalog/agent-model-catalog-persistence.test.ts": 115,
"src/main/native-chat/agent-model-catalog/agent-model-catalog-probe-runner.test.ts": 4786,
"src/main/native-chat/agent-model-catalog/agent-model-catalog-store.test.ts": 611,
"src/main/native-chat/agent-model-catalog/agent-model-catalog-unavailable.test.ts": 465,
@@ -2693,7 +2678,6 @@
"src/main/orcad/orcad-cli-orchestration.integration.test.ts": 214,
"src/main/orcad/orcad-forked-child-paths.test.ts": 337,
"src/main/orcad/orcad-help.integration.test.ts": 5016,
"src/main/orcad/orcad-host-account-launch-env-store.test.ts": 299,
"src/main/orcad/orcad-idle-exit-monitor.test.ts": 106,
"src/main/orcad/orcad-instance-lock.test.ts": 315,
"src/main/orcad/orcad-launcher-isolation.integration.test.ts": 617,
@@ -2791,7 +2775,6 @@
"src/main/persistence/moving-wsl-projects/wsl-move-quiesce.test.ts": 413,
"src/main/persistence/moving-wsl-projects/wsl-move-real-pause.test.ts": 1939,
"src/main/persistence/moving-wsl-projects/wsl-move-reset.test.ts": 891,
"src/main/persistence/moving-wsl-projects/wsl-move-restore-hints.test.ts": 65,
"src/main/persistence/moving-wsl-projects/wsl-move-retention.test.ts": 2285,
"src/main/persistence/moving-wsl-projects/wsl-move-rewrite-ledger.test.ts": 641,
"src/main/persistence/moving-wsl-projects/wsl-move-scope-guard.test.ts": 639,
@@ -3160,7 +3143,6 @@
"src/main/ripgrep/bundled-ripgrep-real.test.ts": 242,
"src/main/ripgrep/bundled-ripgrep-text-search.test.ts": 707,
"src/main/ripgrep/ripgrep-filename-identity-real.test.ts": 274,
"src/main/ripgrep/synchronous-spawn-failure.test.ts": 54,
"src/main/ripgrep/text-search-unicode-real.test.ts": 332,
"src/main/runtime/session-tabs/acknowledged-terminal-tab-retirement-main-close.test.ts": 6833,
"src/main/runtime/session-tabs/acknowledged-terminal-tab-retirement.test.ts": 6423,
@@ -3176,7 +3158,6 @@
"src/main/runtime/agent-session/records/agent-session-store-load-scale.test.ts": 732,
"src/main/runtime/agent-session/agent-session-tab-layout-queue.test.ts": 4061,
"src/main/runtime/agent-session/agent-session-conversation-clear-commit.test.ts": 957,
"src/main/runtime/agent-session/agent-session-death-evidence-persistence.test.ts": 1113,
"src/main/runtime/agent-session/agent-session-launch-directory.test.ts": 926,
"src/main/runtime/agent-session/agent-session-tab-layout.test.ts": 275,
"src/main/runtime/agent-session/agent-session-unsaved-creation-supersession.test.ts": 726,
@@ -3440,7 +3421,6 @@
"src/main/runtime/orchestration/db/worker-dispatch/worker-dispatch-abandon.test.ts": 662,
"src/main/runtime/orchestration/db/schema/dispatch-consumer-generation-migration.test.ts": 640,
"src/main/runtime/orchestration/db/dispatch-context/dispatch-failure-idempotency.test.ts": 544,
"src/main/runtime/orchestration/federation/synchronization/federation-ack-checkpoints.test.ts": 38,
"src/main/runtime/orchestration/federation/synchronization/federation-acknowledgment-integrity.test.ts": 557,
"src/main/runtime/orchestration/db/federation/federation-acknowledgment-migration.test.ts": 566,
"src/main/runtime/orchestration/federation/synchronization/federation-sync.test.ts": 5264,
@@ -3569,13 +3549,11 @@
"src/main/runtime/rpc/methods/browser/browser-network-tunnel.test.ts": 1096,
"src/main/runtime/rpc/methods/client-state/client-ui-set-collapsed.test.ts": 1091,
"src/main/runtime/rpc/methods/clipboard/clipboard.test.ts": 848,
"src/main/runtime/rpc/methods/files/file-watch-event-batcher.test.ts": 69,
"src/main/runtime/rpc/methods/files/files-path-search.test.ts": 884,
"src/main/runtime/rpc/methods/files/files-read-dir-page.test.ts": 1213,
"src/main/runtime/rpc/methods/files/files-read-dir-remote-budget.test.ts": 860,
"src/main/runtime/rpc/methods/files/files-watch-cancellation.test.ts": 886,
"src/main/runtime/rpc/methods/files/files.test.ts": 1018,
"src/main/runtime/rpc/methods/source-control/gitlab/gitlab.test.ts": 4209,
"src/main/runtime/rpc/methods/integrations/jira/jira-saved-filter-state.test.ts": 937,
"src/main/runtime/rpc/methods/integrations/jira/jira.test.ts": 732,
"src/main/runtime/rpc/methods/integrations/linear/linear-agent-access.test.ts": 4648,
@@ -3621,7 +3599,6 @@
"src/main/runtime/rpc/methods/orchestration/messaging/check-worker-consumer-fencing.test.ts": 5876,
"src/main/runtime/rpc/methods/orchestration/messaging/check-worker-federated-attachment.test.ts": 4547,
"src/main/runtime/rpc/methods/orchestration/messaging/check.test.ts": 4373,
"src/main/runtime/rpc/methods/orchestration/messaging/implicit-task-run-routing.test.ts": 4876,
"src/main/runtime/rpc/methods/orchestration/messaging/recipient-routing.test.ts": 4675,
"src/main/runtime/rpc/methods/orchestration/messaging/run-bound-mailbox-history.test.ts": 4288,
"src/main/runtime/rpc/methods/orchestration/messaging/run-bound-mailbox-interleavings.test.ts": 5049,
@@ -3660,12 +3637,10 @@
"src/main/runtime/rpc/methods/orchestration/worker/worker-terminal-custody-at-creation.test.ts": 5687,
"src/main/runtime/rpc/methods/orchestration/worker/workers-new-worktree.test.ts": 6117,
"src/main/runtime/rpc/methods/orchestration/worker/workers-recovery.test.ts": 5182,
"src/main/runtime/rpc/methods/pairing/pairing.test.ts": 776,
"src/main/runtime/rpc/methods/plugins/plugin-dev-emit.test.ts": 3118,
"src/main/runtime/rpc/methods/plugins/plugin-dev-request.test.ts": 3725,
"src/main/runtime/rpc/methods/plugins/plugins.test.ts": 274,
"src/main/runtime/rpc/methods/preflight/preflight-selected-target.test.ts": 5043,
"src/main/runtime/rpc/methods/projects/repo.test.ts": 896,
"src/main/runtime/rpc/methods/session-tabs/session-tabs-inventory-census-race.test.ts": 4349,
"src/main/runtime/rpc/methods/session-tabs/session-tabs-move-validation.test.ts": 4261,
"src/main/runtime/rpc/methods/session-tabs/session-tabs-retirement-proof-delta.test.ts": 1726,
@@ -3712,7 +3687,6 @@
"src/main/runtime/rpc/mobile-socket-wiring.test.ts": 312,
"src/main/runtime/rpc/orcad-feature-readiness.test.ts": 40,
"src/main/runtime/rpc/orchestration-11745-regression-verification.test.ts": 22874,
"src/main/runtime/rpc/orchestration-caller-show.test.ts": 4209,
"src/main/runtime/rpc/orchestration-check-wait-session.test.ts": 5096,
"src/main/runtime/rpc/orchestration-commit-notify-characterization.test.ts": 5702,
"src/main/runtime/rpc/orchestration-contract-fence.test.ts": 6113,
@@ -3733,7 +3707,6 @@
"src/main/runtime/rpc/orchestration-party-agreement.test.ts": 4581,
"src/main/runtime/rpc/orchestration-run-use-invalid-takeover.test.ts": 4575,
"src/main/runtime/rpc/orchestration-runtime-update-settlement.test.ts": 5105,
"src/main/runtime/rpc/orchestration-session-caller.test.ts": 5717,
"src/main/runtime/rpc/orchestration-session-coordinator.test.ts": 4655,
"src/main/runtime/rpc/orchestration-session-recipient.test.ts": 5100,
"src/main/runtime/rpc/orchestration-session-run-binding.test.ts": 4448,
@@ -3742,7 +3715,6 @@
"src/main/runtime/rpc/remote-runtime-server-heartbeat-missed-probe-tolerance.test.ts": 59,
"src/main/runtime/rpc/remote-runtime-server-heartbeat.test.ts": 60,
"src/main/runtime/rpc/repo-add-cli.integration.test.ts": 1603,
"src/main/runtime/rpc/rpc-caller-scope.test.ts": 5071,
"src/main/runtime/rpc/runtime-client-capabilities.test.ts": 43,
"src/main/runtime/rpc/runtime-source-admission.test.ts": 909,
"src/main/runtime/rpc/shadowed-port-probe.test.ts": 99,
@@ -3756,7 +3728,6 @@
"src/main/runtime/rpc/terminal-multiplex-ack-overflow-recovery-history.test.ts": 1892,
"src/main/runtime/rpc/terminal-multiplex-ack-overflow-recovery.test.ts": 2369,
"src/main/runtime/rpc/terminal-multiplex-desktop-resize-routing.test.ts": 2160,
"src/main/runtime/rpc/terminal-multiplex-endpoint-loss-notice.test.ts": 1852,
"src/main/runtime/rpc/terminal-multiplex-initial-snapshot-buffering.test.ts": 2118,
"src/main/runtime/rpc/terminal-multiplex-input-sequence-replay.test.ts": 5709,
"src/main/runtime/rpc/terminal-multiplex-input-write-rejection.test.ts": 2423,
@@ -3769,7 +3740,6 @@
"src/main/runtime/rpc/terminal-multiplex-snapshot-query-replay.test.ts": 2715,
"src/main/runtime/rpc/terminal-multiplex-snapshot-serialization.test.ts": 2224,
"src/main/runtime/rpc/terminal-multiplex-subscribe-slot-recovery.test.ts": 1792,
"src/main/runtime/rpc/terminal-opencode-send-guard.integration.test.ts": 4512,
"src/main/runtime/rpc/terminal-output-batching.test.ts": 2087,
"src/main/runtime/rpc/terminal-output-frame-chunks.test.ts": 70,
"src/main/runtime/rpc/terminal-passive-resize-input.test.ts": 2656,
@@ -3791,7 +3761,6 @@
"src/main/runtime/rpc/unpaired-device-auth-throttle.test.ts": 42,
"src/main/runtime/rpc/web-session-pairing.test.ts": 402,
"src/main/runtime/rpc/workspace-creator-context.test.ts": 40,
"src/main/runtime/rpc/worktree-catalog-snapshot.test.ts": 46,
"src/main/runtime/rpc/worktree-removal-marker-projection.test.ts": 497,
"src/main/runtime/rpc/worktree-rm-cli.integration.test.ts": 6876,
"src/main/runtime/rpc/ws-empty-payload-frame-write.test.ts": 117,
@@ -3862,7 +3831,6 @@
"src/main/runtime/rpc/server/runtime-rpc-websocket-reply-size-limit.test.ts": 4410,
"src/main/runtime/files/search/runtime-search-line-fragments.test.ts": 624,
"src/main/runtime/files/server-browse/runtime-server-environment-commands.test.ts": 262,
"src/main/runtime/rpc/server/runtime-socket-sweep.test.ts": 47,
"src/main/runtime/client/runtime-subscription-registry.test.ts": 142,
"src/main/runtime/terminal/records/runtime-terminal-exit-contracts.test.ts": 5325,
"src/main/runtime/terminal/identity/runtime-terminal-handle-contracts.test.ts": 3983,
@@ -3870,7 +3838,6 @@
"src/main/runtime/terminal/query/runtime-terminal-inventory-contracts.test.ts": 4427,
"src/main/runtime/terminal/adoption/runtime-terminal-orphan-adoption-rollback.test.ts": 1832,
"src/main/runtime/terminal/surface/runtime-terminal-retirement-contracts.test.ts": 4505,
"src/main/runtime/terminal/title/runtime-terminal-set-pane-title.test.ts": 5216,
"src/main/runtime/terminal/input/runtime-terminal-writer.test.ts": 150,
"src/main/runtime/construction/runtime-workspace-launch-contracts.test.ts": 4059,
"src/main/runtime/workspaces/session-hosts/runtime-workspace-session-controller-twin-repo.test.ts": 298,
@@ -3889,11 +3856,9 @@
"src/main/runtime/session-tabs/session-tab-close-force.test.ts": 7089,
"src/main/runtime/session-tabs/runtime-inventory-publication-authority.test.ts": 5775,
"src/main/runtime/session-tabs/headless-mobile-session-absorbed-rows.test.ts": 4223,
"src/main/runtime/session-tabs/main-layout-agent-launch-tabs.test.ts": 4233,
"src/main/runtime/session-tabs/main-layout-session-tab-move.test.ts": 4233,
"src/main/runtime/session-tabs/session-tab-prototype-dispatch.test.ts": 4888,
"src/main/runtime/session-tabs/session-tabs-headless-main-change.test.ts": 4320,
"src/main/runtime/session-tabs/session-tabs-held-rows-commit.test.ts": 5046,
"src/main/runtime/session-tabs/session-tabs-inventory-publication.test.ts": 4166,
"src/main/runtime/session-tabs/session-tabs-main-rows-parity.test.ts": 4606,
"src/main/runtime/session-tabs/session-tabs-phone-layout-moves.test.ts": 4153,
@@ -3929,7 +3894,6 @@
"src/main/runtime/agent-session/lifecycle/structured-agent-cli-writers.test.ts": 140,
"src/main/runtime/agent-session/lifecycle/structured-agent-session-history-close-race.test.ts": 5020,
"src/main/runtime/agent-session/naming/structured-agent-session-provider-naming-shutdown.test.ts": 1987,
"src/main/runtime/agent-session/lifecycle/structured-agent-session-tab-authority.test.ts": 11047,
"src/main/runtime/agent-session/environment/structured-agent-shell-environment-catalog.test.ts": 720,
"src/main/runtime/orchestration/terminal-authority/structured-sessions/structured-chat-coordinator-mail.test.ts": 38220,
"src/main/runtime/orchestration/terminal-authority/structured-sessions/structured-chat-dispatch-worker-lifecycle.test.ts": 9312,
@@ -4087,7 +4051,6 @@
"src/main/ssh/host-keys/ssh-known-hosts.test.ts": 105,
"src/main/ssh/external-editors/zed-ssh-url.test.ts": 55,
"src/main/ssh/connection/ssh-connect-config.test.ts": 182,
"src/main/ssh/connection/ssh-connection-attribution.test.ts": 44,
"src/main/ssh/connection/ssh-connection-auth-fallback.test.ts": 512,
"src/main/ssh/connection/ssh-connection-channel-error.test.ts": 461,
"src/main/ssh/connection/ssh-connection-channel-open.test.ts": 1230,
@@ -4310,7 +4273,6 @@
"src/main/telemetry/validator-warn-cache.test.ts": 187,
"src/main/telemetry/validator.test.ts": 170,
"src/main/telemetry/wsl-usage-reporter.test.ts": 407,
"src/main/pty/history/terminal-history-async-delete.test.ts": 374,
"src/main/pty/history/terminal-history-gc-fs-call-count.test.ts": 157,
"src/main/pty/history/terminal-history-gc.test.ts": 824,
"src/main/pty/history/terminal-history-tombstone-retry.test.ts": 715,
@@ -4518,7 +4480,6 @@
"src/main/wsl/execution/wsl-guest-pane-process-script-cost.test.ts": 213,
"src/main/wsl/execution/wsl-guest-pane-processes.test.ts": 48,
"src/main/wsl/execution/wsl-guest-process-identity.test.ts": 54,
"src/main/wsl/host-lifecycle/wsl-host-automation-wake.test.ts": 288,
"src/main/wsl/host-lifecycle/wsl-host-kept-for-peers.test.ts": 159,
"src/main/wsl/host-lifecycle/wsl-host-pending-removal.test.ts": 955,
"src/main/wsl/host-lifecycle/wsl-host-server-stop.test.ts": 407,
@@ -4727,12 +4688,10 @@
"src/renderer/src/components/browser-pane/host-guest/browser-page-guest-recovery.test.ts": 515,
"src/renderer/src/components/browser-pane/host-guest/browser-page-registration-ownership.test.ts": 2197,
"src/renderer/src/components/browser-pane/host-guest/browser-page-viewport.test.ts": 242,
"src/renderer/src/components/browser-pane/host-guest/browser-page-window-close.test.ts": 54,
"src/renderer/src/components/browser-pane/host-guest/browser-system-resume.test.ts": 187,
"src/renderer/src/components/browser-pane/host-guest/use-browser-page-keyboard-shortcuts.split.test.tsx": 2098,
"src/renderer/src/components/browser-pane/host-guest/use-browser-page-webview-partition.test.ts": 1985,
"src/renderer/src/components/browser-pane/host-guest/webview-registry.test.ts": 103,
"src/renderer/src/components/browser-pane/navigate/browser-file-editor-open.test.ts": 1853,
"src/renderer/src/components/browser-pane/navigate/browser-load-failure-overlay.test.tsx": 831,
"src/renderer/src/components/browser-pane/navigate/browser-page-download-activity.test.ts": 44,
"src/renderer/src/components/browser-pane/navigate/browser-webview-load-failure.test.ts": 243,
@@ -4807,19 +4766,16 @@
"src/renderer/src/components/editor/diff/monaco-view/DiffViewer.word-wrap-lifecycle.test.tsx": 2499,
"src/renderer/src/components/editor/EditorConflictReviewSurface.live-record.test.tsx": 1193,
"src/renderer/src/components/editor/EditorEditFileSurface.monaco-containment.test.tsx": 2666,
"src/renderer/src/components/editor/EditorFileLoadErrorView.test.tsx": 660,
"src/renderer/src/components/editor/EditorFileLocationMenuItems.test.tsx": 846,
"src/renderer/src/components/editor/EditorPanel.custom-editor-flush.test.tsx": 2478,
"src/renderer/src/components/editor/EditorPanel.diff-rich-owner.test.tsx": 2823,
"src/renderer/src/components/editor/notebook/cells/IpynbCellEditor.external-sync.test.tsx": 1660,
"src/renderer/src/components/editor/notebook/kernel/IpynbKernelToolbar.test.tsx": 736,
"src/renderer/src/components/editor/notebook/document/IpynbRendering.test.tsx": 2143,
"src/renderer/src/components/editor/markdown-preview/surface/MarkdownPreview.link-routing.interaction.test.tsx": 1127,
"src/renderer/src/components/editor/MediaViewer.test.tsx": 308,
"src/renderer/src/components/editor/PdfFind.test.tsx": 581,
"src/renderer/src/components/editor/PluginBytesCustomEditorSurface.test.tsx": 641,
"src/renderer/src/components/editor/PluginEditorNeedsDesktopNotice.test.tsx": 2107,
"src/renderer/src/components/editor/PluginFileTypeSuggestion.test.tsx": 2062,
"src/renderer/src/components/editor/rich-markdown/instance/RichMarkdownEditor.focus-leave.test.tsx": 4927,
"src/renderer/src/components/editor/ai-vault-session-log-content.test.tsx": 1899,
"src/renderer/src/components/editor/check-details/actions/check-annotation-path.test.ts": 53,
@@ -4864,7 +4820,6 @@
"src/renderer/src/components/editor/save/bytes/editor-bytes-documents.test.ts": 690,
"src/renderer/src/components/editor/save/commands/editor-child-owner-save.test.tsx": 2480,
"src/renderer/src/components/editor/external-changes/editor-clean-tab-draft-invariant.test.ts": 1274,
"src/renderer/src/components/editor/editor-dropped-file-open.test.ts": 595,
"src/renderer/src/components/editor/external-changes/editor-external-watch-path-index.test.ts": 1754,
"src/renderer/src/components/editor/save/commands/editor-file-save-utf8-conversion.test.ts": 1915,
"src/renderer/src/components/editor/editor-git-discard-other-workspace.test.ts": 1967,
@@ -4872,7 +4827,6 @@
"src/renderer/src/components/editor/model-lifetime/identity/editor-model-host-isolation.test.ts": 5906,
"src/renderer/src/components/editor/model-lifetime/identity/editor-model-uri-labels.test.ts": 1223,
"src/renderer/src/components/editor/editor-path-move-inflight.test.ts": 50,
"src/renderer/src/components/editor/external-changes/editor-restored-tab-conflict-scan.recheck.test.ts": 1796,
"src/renderer/src/components/editor/external-changes/editor-restored-tab-conflict-scan.test.ts": 1809,
"src/renderer/src/components/editor/save/queue/editor-save-disk-precondition.races.test.ts": 1290,
"src/renderer/src/components/editor/save/queue/editor-save-disk-precondition.test.ts": 1431,
@@ -5255,7 +5209,6 @@
"src/renderer/src/components/new-workspace/SmartWorkspaceNameField-repo-slug-routing.test.ts": 342,
"src/renderer/src/components/new-workspace/smart-workspace-github-direct-link.test.ts": 347,
"src/renderer/src/components/new-workspace/smart-workspace-source-results.test.ts": 136,
"src/renderer/src/components/new-workspace/use-jira-composer-project.test.tsx": 279,
"src/renderer/src/components/new-workspace/use-jira-source-connection.test.tsx": 278,
"src/renderer/src/components/new-workspace/use-jira-url-source.test.tsx": 419,
"src/renderer/src/components/new-workspace/use-linear-source-connection.test.tsx": 1335,
@@ -5282,7 +5235,6 @@
"src/renderer/src/components/plugins/view/plugin-view-data-acts.test.tsx": 3002,
"src/renderer/src/components/plugins/view/plugin-view-editor-capture.test.tsx": 1934,
"src/renderer/src/components/plugins/view/plugin-view-editor-shot-cleanup.test.ts": 59,
"src/renderer/src/components/plugins/view/plugin-view-editor-workspace.test.ts": 99,
"src/renderer/src/components/plugins/view/plugin-view-panel-settle.test.ts": 206,
"src/renderer/src/components/plugins/view/plugin-view-request-handler-workspace.test.ts": 2307,
"src/renderer/src/components/plugins/view/plugin-view-request-handler.test.ts": 2849,
@@ -5370,7 +5322,6 @@
"src/renderer/src/components/right-sidebar/source-control/review/create-pr-intent-operation-target.test.ts": 1735,
"src/renderer/src/components/right-sidebar/source-control/review/use-create-pr-intent-jira-title.test.tsx": 1956,
"src/renderer/src/components/right-sidebar/source-control/review/use-pull-request-generation.test.tsx": 2720,
"src/renderer/src/components/right-sidebar/ssh-port-forward-dialog.ime-enter.test.tsx": 585,
"src/renderer/src/components/right-sidebar/ai-vault/search/use-ai-vault-search.test.tsx": 688,
"src/renderer/src/components/right-sidebar/checks-panel/refresh/use-checks-panel-terminal-worktree.test.ts": 2116,
"src/renderer/src/components/right-sidebar/hosted-review/creation/use-create-jira-review-title.test.tsx": 1979,
@@ -5514,7 +5465,6 @@
"src/renderer/src/components/sidebar/host-path-browser/remote-file-browser-entry-actions.test.ts": 289,
"src/renderer/src/components/sidebar/worktree-list/listing/rendered-sidebar-worktree-order.test.ts": 1873,
"src/renderer/src/components/sidebar/project-admission/drop/sidebar-project-drop.test.ts": 227,
"src/renderer/src/components/sidebar/project-admission/host-selection/use-add-repo-windows-drive-refusal.test.tsx": 470,
"src/renderer/src/components/sidebar/project-admission/host-selection/use-add-repo-wsl-host-paths.test.tsx": 660,
"src/renderer/src/components/sidebar/sidebar-feedback/use-feedback-image-drop.test.tsx": 511,
"src/renderer/src/components/sidebar/workspace-board/projection/use-workspace-board-task-status-sync.queued.test.ts": 1022,
@@ -5589,7 +5539,6 @@
"src/renderer/src/components/status-bar/resource-session-kill-confirmation.test.ts": 53,
"src/renderer/src/components/status-bar/resource-session-removal-render-budget.test.tsx": 290,
"src/renderer/src/components/status-bar/resource-usage-folder-merge.test.ts": 251,
"src/renderer/src/components/status-bar/status-bar-pool-countdown.test.tsx": 654,
"src/renderer/src/components/status-bar/usage-pool-label.test.ts": 170,
"src/renderer/src/components/status-bar/use-owner-usage-rate-limits.test.tsx": 462,
"src/renderer/src/components/status-bar/use-resource-memory-snapshot.test.tsx": 321,
@@ -5604,10 +5553,8 @@
"src/renderer/src/components/tab-bar/cli-chat-resume-run-close.test.ts": 3079,
"src/renderer/src/components/tab-bar/group-tab-order.test.ts": 2091,
"src/renderer/src/components/tab-bar/host-agent-launch-preferences-source.test.tsx": 3154,
"src/renderer/src/components/tab-bar/recent-tab-switching.test.ts": 1795,
"src/renderer/src/components/tab-bar/tab-agent-launch-options.test.ts": 438,
"src/renderer/src/components/tab-bar/tab-agent-types-by-tab-id.test.ts": 206,
"src/renderer/src/components/tab-bar/tab-bar-layout-owner-props.test.ts": 174,
"src/renderer/src/components/tab-bar/tab-context-menu.test.tsx": 5620,
"src/renderer/src/components/tab-bar/tab-create-entry-classifier.test.ts": 510,
"src/renderer/src/components/tab-bar/tab-create-entry-local-path.test.ts": 2614,
@@ -5640,7 +5587,6 @@
"src/renderer/src/components/task-page/jira/task-page-jira-board-detail-integration.test.tsx": 2192,
"src/renderer/src/components/task-page/jira/task-page-jira-board-transitions.test.ts": 69,
"src/renderer/src/components/task-page/jira/task-page-jira-board-view.test.tsx": 2287,
"src/renderer/src/components/task-page/jira/task-page-jira-cache-selectors.test.ts": 54,
"src/renderer/src/components/task-page/jira/task-page-jira-favourite-selection.test.tsx": 3326,
"src/renderer/src/components/task-page/jira/task-page-jira-grouping.test.ts": 2324,
"src/renderer/src/components/task-page/jira/task-page-jira-linked-issues.test.ts": 204,
@@ -5839,7 +5785,6 @@
"src/renderer/src/components/terminal-pane/layout/terminal-layout-pty-ownership.test.ts": 99,
"src/renderer/src/components/terminal-pane/links/terminal-link-click-fallback.test.ts": 985,
"src/renderer/src/components/terminal-pane/links/terminal-link-open-beside-source.test.ts": 947,
"src/renderer/src/components/terminal-pane/links/http/terminal-link-osc-url-routing.test.ts": 986,
"src/renderer/src/components/terminal-pane/links/terminal-link-paired-click-fallback.test.ts": 989,
"src/renderer/src/components/terminal-pane/links/gestures/terminal-link-pointer-gesture.test.ts": 550,
"src/renderer/src/components/terminal-pane/links/files/terminal-link-provider-batching.test.ts": 1051,
@@ -5858,7 +5803,6 @@
"src/renderer/src/components/terminal-pane/layout/split/terminal-pane-split-request-routing.test.ts": 2015,
"src/renderer/src/components/terminal-pane/layout/detach/terminal-pane-tab-detach-main-commit.test.ts": 2090,
"src/renderer/src/components/terminal-pane/layout/detach/terminal-pane-tab-detach-main-move.test.ts": 2147,
"src/renderer/src/components/terminal-pane/parking/verdict/terminal-park-verdict-flip-telemetry.test.ts": 123,
"src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-tab-watchers.test.ts": 473,
"src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-registry.test.ts": 245,
"src/renderer/src/components/terminal-pane/parking/output-watchers/terminal-parked-watcher-sleep-preserved-exit.test.ts": 399,
@@ -5900,7 +5844,6 @@
"src/renderer/src/components/terminal/terminal-tab-actions-unrouted-close.test.ts": 589,
"src/renderer/src/components/terminal/terminal-tab-actions.test.ts": 626,
"src/renderer/src/components/terminal/terminal-tab-close-running-confirm.test.ts": 499,
"src/renderer/src/components/terminal/terminal-tab-create.test.ts": 367,
"src/renderer/src/components/terminal/unsaved-close-queue.test.ts": 42,
"src/renderer/src/components/terminal/use-terminal-provider-snapshot-capability.test.tsx": 573,
"src/renderer/src/components/terminal/window-close-running-work.test.ts": 97,
@@ -5940,7 +5883,6 @@
"src/renderer/src/components/worktree-jump/use-worktree-jump-palette-browser-ownership.test.ts": 2096,
"src/renderer/src/components/worktree-jump/use-worktree-jump-palette-task-search.test.tsx": 2140,
"src/renderer/src/components/worktree-jump/worktree-jump-palette-browser-navigation.test.tsx": 4470,
"src/renderer/src/components/wsl-host-stopped/WslHostStoppedNotice.test.tsx": 491,
"src/renderer/src/components/wsl-move/WslMoveDialog.test.tsx": 524,
"src/renderer/src/components/wsl-move/wsl-move-dialog-store.test.ts": 2011,
"src/renderer/src/components/wsl-move/wsl-move-scope-rows.test.ts": 156,
@@ -5975,7 +5917,6 @@
"src/renderer/src/hooks/ipc-events/direct-ssh-unrestored-forward-sync.test.ts": 95,
"src/renderer/src/hooks/ipc-events/mobile-terminal-close-ipc-bridge-reveal.test.ts": 1764,
"src/renderer/src/hooks/ipc-events/mobile-terminal-close-ipc-bridge.test.ts": 2200,
"src/renderer/src/hooks/ipc-events/orca-profile-auth-ipc-bridge.test.ts": 1908,
"src/renderer/src/hooks/ipc-events/os-markdown-file-open-bridge.test.ts": 280,
"src/renderer/src/hooks/ipc-events/quit-and-stop-all-sessions-ipc-bridge.test.ts": 398,
"src/renderer/src/hooks/ipc-events/runtime-client-ipc-bridge-ownership.test.ts": 2068,
@@ -5998,7 +5939,6 @@
"src/renderer/src/hooks/runtime-client-events-sync-ownership.test.ts": 59,
"src/renderer/src/hooks/runtime-client-events-sync.test.ts": 118,
"src/renderer/src/hooks/runtime-project-refresh-scheduler.test.ts": 65,
"src/renderer/src/hooks/shortcut-label-cache.test.tsx": 2021,
"src/renderer/src/hooks/unpaired-device-auth-notification.test.ts": 41,
"src/renderer/src/hooks/use-document-dark-theme.test.tsx": 350,
"src/renderer/src/hooks/use-list-multi-selection.test.tsx": 545,
@@ -6031,7 +5971,6 @@
"src/renderer/src/hooks/useIpcEvents-agent-status-queue-ordering.test.ts": 3680,
"src/renderer/src/hooks/useIpcEvents-agent-status-snapshot-replay.test.ts": 4119,
"src/renderer/src/hooks/useIpcEvents-agent-status-ssh-authority.test.ts": 3310,
"src/renderer/src/hooks/useIpcEvents-browser-navigation.test.ts": 1511,
"src/renderer/src/hooks/useIpcEvents-close-routing-session-tabs.test.ts": 5812,
"src/renderer/src/hooks/useIpcEvents-new-workspace-shortcut.test.ts": 72,
"src/renderer/src/hooks/useIpcEvents-runtime-environment-selectors.test.ts": 530,
@@ -6146,7 +6085,6 @@
"src/renderer/src/lib/monaco-languages/register-vue.test.ts": 303,
"src/renderer/src/lib/monaco-languages/register-zig.test.ts": 4750,
"src/renderer/src/lib/monaco-languages/textmate-token-provider.test.ts": 245,
"src/renderer/src/lib/monaco-languages/zig-highlighting.test.ts": 7984,
"src/renderer/src/lib/agent-session/resume/cli-fork/native-chat-cli-fork-preparation.test.ts": 2773,
"src/renderer/src/lib/simulator/launch/open-mobile-emulator-tab.test.ts": 545,
"src/renderer/src/lib/pane-manager/pane-close-focus-successor.test.ts": 1123,
@@ -6331,10 +6269,8 @@
"src/renderer/src/store/plugins/catalog/plugin-panel-retry-timer-cleanup.test.ts": 5216,
"src/renderer/src/store/plugins/catalog/plugin-panels.test.ts": 2142,
"src/renderer/src/store/projects/project-catalog-null-field-ingest.test.ts": 309,
"src/renderer/src/store/diagnostics/react-commit-cascade-write-probe.test.ts": 602,
"src/renderer/src/store/repos/dropped-repo-worktree-rows.test.ts": 1738,
"src/renderer/src/store/repos/repo-removal.test.ts": 799,
"src/renderer/src/store/repos/safe-auto-fork-sync.test.ts": 446,
"src/renderer/src/store/repos/wsl-moved-local-session-rows.test.ts": 319,
"src/renderer/src/store/repos/wsl-moved-repo-ui-retention.test.ts": 2920,
"src/renderer/src/store/slices/runtime-status/views/runtime-status-subscriptions.test.ts": 182,
@@ -6398,7 +6334,6 @@
"src/renderer/src/store/slices/editor/buffers/editor-buffer-reconcile-identity.test.ts": 1775,
"src/renderer/src/store/slices/editor/buffers/editor-buffer-reconcile-joins.test.ts": 1766,
"src/renderer/src/store/slices/editor/buffers/editor-buffer-rejoin.test.ts": 1843,
"src/renderer/src/store/slices/editor/buffers/editor-buffer-views.test.ts": 2004,
"src/renderer/src/store/slices/editor/file-ids/floating-editor-file-id-layout-owner.test.ts": 933,
"src/renderer/src/store/slices/worktrees/session/folder-workspace-activation-and-activity.test.ts": 2358,
"src/renderer/src/store/slices/diff-comments/folder-workspace-diff-comments.test.ts": 1042,
@@ -6481,7 +6416,6 @@
"src/renderer/src/store/slices/tabs/tabs-hydration-group-validation.test.ts": 249,
"src/renderer/src/store/slices/tabs/tabs-hydration.test.ts": 273,
"src/renderer/src/store/slices/tabs/tabs-label-and-pin-state.test.ts": 1921,
"src/renderer/src/store/slices/tabs/tabs-model-reconciliation.test.ts": 1800,
"src/renderer/src/store/slices/tabs/tabs-open-close-lifecycle.test.ts": 2140,
"src/renderer/src/store/slices/tabs/tabs-pane-layout-operations.test.ts": 1652,
"src/renderer/src/store/slices/tabs/tabs-unread-and-focus.test.ts": 1801,
@@ -6501,7 +6435,6 @@
"src/renderer/src/store/slices/ui/ui-modal-slot-dismissal.test.ts": 662,
"src/renderer/src/store/slices/ui/ui-slice-surface-actions.test.ts": 1760,
"src/renderer/src/store/slices/worktrees/session/workspace-activation-preparation.test.ts": 1932,
"src/renderer/src/store/slices/workspace-attention/workspace-unread-characterization.test.ts": 1974,
"src/renderer/src/store/slices/workspace-attention/workspace-unread-flag-host-raises.test.ts": 1914,
"src/renderer/src/store/slices/workspace-attention/workspace-unread-on-screen-characterization.test.ts": 1780,
"src/renderer/src/store/slices/workspace-attention/workspace-unread-screen-moves-characterization.test.ts": 1884,
@@ -6559,7 +6492,6 @@
"src/renderer/src/store/terminals/terminal-no-op-subscriber.test.ts": 1763,
"src/renderer/src/store/terminals/terminal-startup-queue-restart.test.ts": 1895,
"src/renderer/src/store/terminals/terminal-tab-close-intent.test.ts": 1945,
"src/renderer/src/store/terminals/workspace-terminal-placeholders.test.ts": 302,
"src/renderer/src/store/slices/runtime-status/views/use-runtime-status-view.test.tsx": 1979,
"src/renderer/src/store/workspace-layout/workspace-layout-cache.test.ts": 63,
"src/renderer/src/store/slices/worktrees/listing/worktree-host-collision-index.test.ts": 1875,
@@ -7050,7 +6982,6 @@
"src/shared/orca-session-address.test.ts": 154,
"src/shared/orca-yaml-alias-bounds.test.ts": 425,
"src/shared/orca-yaml-bounds.test.ts": 192,
"src/shared/orcad-artifacts.test.ts": 45,
"src/shared/orcad-build-identity.test.ts": 48,
"src/shared/orcad-migration-manifest-contract.test.ts": 323,
"src/shared/orcad-migration/orcad-migration-blob-transfer.test.ts": 348,
@@ -27,7 +27,6 @@ const DESKTOP_SUITE_PREFIXES = [
'src/main/runtime/agent-session/agent-session-account-',
'src/main/runtime/agent-session/agent-session-acquisition-',
'src/main/runtime/agent-session/agent-session-conversation-',
'src/main/runtime/agent-session/agent-session-death-',
'src/main/runtime/agent-session/agent-session-launch-',
'src/main/runtime/agent-session/agent-session-operation-',
'src/main/runtime/agent-session/agent-session-rewind-',
-1
View File
@@ -8,7 +8,6 @@ const contracts = [
'src/main/runtime/session-tabs/session-tabs-phone-layout-moves.test.ts',
'src/main/native-chat/agent-session-wire/host/testing/structured-agent-session-terminal-writer-acquire.test.ts',
'src/shared/agent-launch/permissions/tui-agent-permission-choice.test.ts',
'src/main/runtime/rpc/methods/projects/repo.test.ts',
'src/renderer/src/components/tab-bar/use-new-tab-agent-menu-host-preferences.test.tsx',
'src/main/sqlite/sync-database.test.ts',
'src/main/runtime/orchestration/db/row-column-lists.test.ts',
@@ -1,33 +0,0 @@
import { describe, expect, it } from 'vitest'
import { resolveDiagnosticsHostId } from './connection-diagnostics-screen-data'
import type { HostProfile } from '../host-catalog/host-profile'
const host = (id: string): HostProfile => ({
id,
name: id,
endpoint: 'ws://192.168.1.2:6768',
deviceToken: 'token',
publicKeyB64: 'key',
lastConnected: 0
})
describe('connection diagnostics screen data', () => {
it('applies route changes synchronously without discarding a chip choice for the same route', () => {
const hosts = [host('a'), host('b')]
expect(resolveDiagnosticsHostId(hosts, undefined, null)).toBe('a')
expect(resolveDiagnosticsHostId(hosts, 'b', { hostId: 'a', requestedHostId: 'a' })).toBe('b')
expect(resolveDiagnosticsHostId(hosts, 'b', { hostId: 'a', requestedHostId: 'b' })).toBe('a')
})
it('does not revive a stale manual choice when routing away and back', () => {
const hosts = [host('a'), host('b'), host('c')]
const firstRouteA = {}
const routeC = {}
const secondRouteA = {}
const manualSelection = { hostId: 'b', requestedHostId: 'a', routeKey: firstRouteA }
expect(resolveDiagnosticsHostId(hosts, 'c', manualSelection, routeC)).toBe('c')
expect(resolveDiagnosticsHostId(hosts, 'a', manualSelection, secondRouteA)).toBe('a')
})
})
@@ -1,70 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import {
installChatViewHooks,
bannerText,
pressSend,
render,
update
} from './MobileNativeChatView.harness.test-fixture'
vi.mock('react-native', async () => {
const { reactNativeStub } = await import('./MobileNativeChatView.render-stubs.test-fixture')
return reactNativeStub()
})
vi.mock('react-native-safe-area-context', () => ({
useSafeAreaInsets: () => ({ top: 0, bottom: 0, left: 0, right: 0 })
}))
vi.mock('react-native-gesture-handler', async () => {
const { gestureHandlerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture')
return gestureHandlerStub()
})
vi.mock('lucide-react-native', () => ({
ArrowDown: 'ArrowDown',
ChevronsDownUp: 'ChevronsDownUp',
ChevronsUpDown: 'ChevronsUpDown',
Square: 'Square'
}))
vi.mock('./transcript/MobileNativeChatMessage', () => ({
MobileNativeChatMessage: 'ChatMessage'
}))
vi.mock('./transcript/MobileNativeChatLiveLine', () => ({
MobileNativeChatLiveLine: 'LiveStatus'
}))
vi.mock('./input/MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' }))
vi.mock('./input/MobileNativeChatPermission', () => ({
MobileNativeChatPermission: 'ChatPermission'
}))
vi.mock('./input/MobileNativeChatQuestion', () => ({
MobileNativeChatQuestion: 'ChatQuestion'
}))
vi.mock('../../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' }))
vi.mock('./composer/MobileNativeChatComposer', async () => {
const { composerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture')
return composerStub()
})
describe('MobileNativeChatView: send and read failure banners', () => {
installChatViewHooks()
it('retires the previous banner before sending and preserves the new delivery notice', async () => {
const onClearSendError = vi.fn()
await render({
sendErrorMessage: 'Stop failed',
onClearSendError,
onSend: async () => {
expect(onClearSendError).toHaveBeenCalledOnce()
await update({ sendErrorMessage: 'Delivery unconfirmed' })
return true
}
})
await pressSend()
expect(onClearSendError).toHaveBeenCalledOnce()
expect(bannerText()).toBe('Delivery unconfirmed')
})
})
vi.mock('./input/MobileQueuedMessageComposer', () => ({
MobileQueuedMessageComposer: 'QueuedMessageComposer'
}))
@@ -1,189 +0,0 @@
import { resolveMobileNativeChatRowProps } from './transcript/use-mobile-native-chat-row-props'
import { createElement, type ReactElement } from 'react'
import { act, create, type ReactTestInstance, type ReactTestRenderer } from 'react-test-renderer'
import { afterEach, beforeEach, expect, vi } from 'vitest'
import type { NativeChatMessage } from '../../../../src/shared/native-chat/native-chat-types'
import { MobileNativeChatView } from './MobileNativeChatView'
import { setMobileNativeChatDraftText } from './composer/mobile-native-chat-draft-store'
import {
scrollToEnd,
scrollToOffset,
pageScroller
} from './MobileNativeChatView.render-stubs.test-fixture'
vi.mock('../../components/DragReorderList', () => ({ DragReorderList: 'DragReorderList' }))
vi.mock('react-native-reanimated', async () => {
const { useRef } = await import('react')
return {
default: { ScrollView: 'ScrollView' },
useAnimatedRef: () => useRef(null),
useSharedValue: (value: unknown) => useRef({ value }).current
}
})
export type Overrides = {
messages?: Parameters<typeof MobileNativeChatView>[0]['messages']
folded?: Parameters<typeof MobileNativeChatView>[0]['folded']
streaming?: string | null
sendErrorMessage?: string | null
onClearSendError?: () => void
inputLockReason?: 'disconnected' | 'waiting' | null
composerText?: string
onSend?: (text: string) => Promise<boolean>
pending?: Parameters<typeof MobileNativeChatView>[0]['pending']
structuredActivityUi?: boolean
turnIndicator?: Parameters<typeof MobileNativeChatView>[0]['turnIndicator']
agentWorking?: boolean
canStop?: boolean
ask?: Parameters<typeof MobileNativeChatView>[0]['ask']
askRequiresTerminal?: boolean
collapsedPrompt?: Parameters<typeof MobileNativeChatView>[0]['collapsedPrompt']
micActive?: boolean
micProcessing?: boolean
composerTray?: Parameters<typeof MobileNativeChatView>[0]['composerTray']
question?: Parameters<typeof MobileNativeChatView>[0]['question']
permission?: Parameters<typeof MobileNativeChatView>[0]['permission']
sendSurfaceId?: string
keyboardInset?: number
hasMore?: boolean
olderPages?: Parameters<typeof MobileNativeChatView>[0]['olderPages']
onLoadEarlier?: () => void
status?: Parameters<typeof MobileNativeChatView>[0]['status']
error?: string
readFailedFinally?: boolean
actionablePromptIds?: readonly string[]
}
export function assistantTurn(id: string, text: string): NativeChatMessage {
return { id, role: 'assistant', blocks: [{ type: 'text', text }], timestamp: 0, source: 'hook' }
}
const DRAFT_KEY = 'draft-a'
function chatViewElement({
composerText = '',
...overrides
}: Overrides): ReturnType<typeof createElement> {
setMobileNativeChatDraftText(DRAFT_KEY, composerText)
return createElement(MobileNativeChatView, {
messages: [],
folded: [],
status: 'ready',
streaming: null,
onSend: vi.fn().mockResolvedValue(true),
sendSurfaceId: 'tab-a',
getSendCompletionGeneration: () => 0,
getComposerEditGeneration: () => 0,
pending: [],
draftKey: DRAFT_KEY,
onComposerTextChange: vi.fn(),
...overrides
})
}
let renderer: ReactTestRenderer | null = null
export function installChatViewHooks(): void {
beforeEach(() => {
vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) =>
setTimeout(() => callback(0), 0)
)
vi.stubGlobal('cancelAnimationFrame', (handle: ReturnType<typeof setTimeout>) =>
clearTimeout(handle)
)
})
afterEach(() => {
act(() => renderer?.unmount())
renderer = null
scrollToEnd.mockReset()
scrollToOffset.mockReset()
Object.assign(pageScroller, { scrollTop: 0, scrollHeight: 0, clientHeight: 500 })
vi.unstubAllGlobals()
})
}
export function root(): ReactTestInstance {
return renderer!.root
}
// Mocked react-native components are string tags that ReactTestInstance's ElementType omits.
export function hostType(node: ReactTestInstance): unknown {
return node.type
}
export async function render(overrides: Overrides = {}): Promise<void> {
await act(async () => {
renderer = create(chatViewElement(overrides))
})
}
export async function update(overrides: Overrides = {}): Promise<void> {
await act(async () => {
renderer?.update(chatViewElement(overrides))
})
}
export function listIds(): string[] {
return (list().props.data as { id: string }[]).map((row) => row.id)
}
export function list(): ReactTestInstance {
return renderer!.root.find((node) => hostType(node) === 'FlatList')
}
export function renderedRow(id: string): ReactElement<Record<string, unknown>> {
const listNode = list()
const data = listNode.props.data as NativeChatMessage[]
const index = data.findIndex((row) => row.id === id)
const row = listNode.props.renderItem({ item: data[index], index })
const resolved = resolveMobileNativeChatRowProps(index, data[index]!, row.props.lookups)
return createElement('Row', { ...row.props, ...resolved })
}
export function banners(): ReactTestInstance[] {
return renderer!.root.findAll((node) => node.props.accessibilityRole === 'alert')
}
export function composer(): ReactTestInstance {
return renderer!.root.find((node) => hostType(node) === 'Composer')
}
export function bannerText(): string {
const [alert, ...rest] = banners()
expect(rest).toHaveLength(0)
return alert
.findAll((node) => hostType(node) === 'Text')
.map((node) => node.props.children)
.join('')
}
export async function pressSend(): Promise<void> {
const composer = renderer!.root.find((node) => hostType(node) === 'Composer')
await act(async () => {
await composer.props.onPress()
})
}
export function scrollEvent(y: number, contentHeight: number) {
return {
nativeEvent: {
contentOffset: { y },
contentSize: { height: contentHeight },
layoutMeasurement: { height: 500 }
}
}
}
export async function scrollAwayFromTail(): Promise<void> {
await act(async () => {
list().props.onScrollBeginDrag?.({})
list().props.onScroll({
nativeEvent: {
contentOffset: { y: 200 },
contentSize: { height: 1_200 },
layoutMeasurement: { height: 500 }
}
})
})
}
@@ -1,90 +0,0 @@
import { vi } from 'vitest'
const scrollToEnd = vi.hoisted(() => vi.fn())
const scrollToOffset = vi.hoisted(() => vi.fn())
const platform = vi.hoisted(() => ({ OS: 'ios' }))
const pageScroller = vi.hoisted(() => ({
scrollTop: 0,
scrollHeight: 0,
clientHeight: 500,
getInnerViewNode: () => ({}),
getBoundingClientRect: () => ({ top: 0, bottom: 500 }),
getAttribute: () => null,
querySelectorAll: () => [],
querySelector: () => null,
addEventListener: () => {},
removeEventListener: () => {}
}))
export async function reactNativeStub() {
const React = await import('react')
const { reactNativeMotionStub } = await import('../../test-support/react-native-motion-stub')
return {
...reactNativeMotionStub(),
ActivityIndicator: 'ActivityIndicator',
FlatList: React.forwardRef((props, ref) => {
const handle = { scrollToEnd, scrollToOffset, getScrollableNode: () => pageScroller }
React.useImperativeHandle(ref, () => handle, [])
return React.createElement('FlatList', props)
}),
Platform: platform,
Pressable: 'Pressable',
ScrollView: React.forwardRef((props, ref) => {
const handle = {
scrollTo: ({ y, animated }: { y: number; animated: boolean }) =>
scrollToOffset({ animated, offset: y }),
scrollToEnd,
getScrollableNode: () => pageScroller,
getInnerViewNode: () => pageScroller.getInnerViewNode()
}
React.useImperativeHandle(ref, () => handle, [])
return React.createElement('ScrollView', props)
}),
StyleSheet: { create: (styles: unknown) => styles, hairlineWidth: 1 },
Text: 'Text',
View: 'View'
}
}
export function gestureHandlerStub() {
const chain = {
runOnJS: () => chain,
onStart: () => chain,
onUpdate: () => chain
}
return {
Gesture: { Simultaneous: () => ({}), Native: () => ({}), Pinch: () => chain },
GestureDetector: 'GestureDetector',
GestureHandlerRootView: 'GestureHandlerRootView'
}
}
export async function composerStub() {
const React = await import('react')
const { MobileNativeChatStopButton } = await import('./input/MobileNativeChatStopButton')
const { useMobileNativeChatDraft } = await import('./composer/mobile-native-chat-draft-store')
return {
MobileNativeChatDraftComposer: ({
draftKey,
...props
}: {
draftKey: string | null
onSend: (text: string) => Promise<boolean>
disabled?: boolean
placeholder?: string
stop?: { onStop?: () => void; held: boolean } | null
}) =>
React.createElement(
'Composer',
{
...props,
value: useMobileNativeChatDraft(draftKey),
accessibilityLabel: 'Send message',
onPress: () => props.onSend('hi')
},
props.stop ? React.createElement(MobileNativeChatStopButton, props.stop) : null
)
}
}
export { scrollToEnd, scrollToOffset, platform, pageScroller }
@@ -1,65 +0,0 @@
import { createElement } from 'react'
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { useMobileNativeChatDrafts } from './use-mobile-native-chat-drafts'
import {
closeMobileNativeChatTabDraft,
useMobileNativeChatDraft
} from './mobile-native-chat-draft-store'
import { loadMobileNativeChatDrafts } from './mobile-native-chat-draft-persistence'
vi.mock('@react-native-async-storage/async-storage', async () => {
const { createInMemoryAsyncStorage } =
await import('../../../test-support/in-memory-async-storage')
return { default: createInMemoryAsyncStorage() }
})
describe('useMobileNativeChatDrafts with queued cards', () => {
let renderer: ReactTestRenderer | null = null
let state: (ReturnType<typeof useMobileNativeChatDrafts> & { composerText: string }) | null = null
afterEach(async () => {
act(() => renderer?.unmount())
await loadMobileNativeChatDrafts('host', 'worktree')
closeMobileNativeChatTabDraft('host\0worktree\0a')
await loadMobileNativeChatDrafts('host', 'worktree')
renderer = null
state = null
})
function Harness(): null {
const drafts = useMobileNativeChatDrafts({
hostId: 'host',
worktreeId: 'worktree',
tabId: 'a',
sessionId: 'session-a',
messages: [],
launchDraft: null,
transcriptLoading: false,
transcriptSettled: true
})
state = { ...drafts, composerText: useMobileNativeChatDraft(drafts.draftKey) }
return null
}
async function render(): Promise<void> {
await act(async () => {
renderer = create(createElement(Harness))
})
}
it("reports whether a queued card's Edit copy landed, so Edit never deletes text it did not keep", async () => {
await render()
let copied: boolean | undefined
act(() => {
copied = state?.appendComposerText('')
})
expect(copied).toBe(false)
act(() => {
copied = state?.appendComposerText('edited text')
})
expect(copied).toBe(true)
expect(state?.composerText).toBe('edited text')
})
})
@@ -1,14 +0,0 @@
// @vitest-environment happy-dom
import { expect, it } from 'vitest'
import { MobileNativeChatScrollRoots } from './mobile-native-chat-scroll-roots'
it("forgets a closed tool line's nested command and output positions, not its neighbours'", () => {
const at = { top: 30, followsEnd: false }
const memory = new Map(
['run:o', 'run:o/line:a:command', 'run:o/line:a:output', 'line:a:command']
.concat(['run:o/line:ab:command', 'diff:src/line:a.ts'])
.map((address) => [address, at] as const)
)
new MobileNativeChatScrollRoots(memory, 10).forget('line:a')
expect([...memory.keys()]).toEqual(['run:o', 'run:o/line:ab:command', 'diff:src/line:a.ts'])
})
@@ -1,57 +0,0 @@
import { createElement } from 'react'
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { RpcClient } from '../rpc/rpc-client-contract'
import { useHostStatusGates, type HostStatusGates } from './host-status-gates'
const recordHostAppVersionMock = vi.hoisted(() => vi.fn().mockResolvedValue(undefined))
vi.mock('../../host-descriptors/host-app-version-store', () => ({
recordHostAppVersion: (...args: unknown[]) => recordHostAppVersionMock(...args)
}))
const recordDescriptorFromStatusMock = vi.hoisted(() => vi.fn())
vi.mock('../../host-descriptors/host-descriptor-recorder', () => ({
recordHostDescriptorFromStatus: (...args: unknown[]) => recordDescriptorFromStatusMock(...args)
}))
describe('useHostStatusGates', () => {
beforeEach(() => {
recordDescriptorFromStatusMock.mockClear()
})
it('fails closed when the same host reconnects on a replaced client', async () => {
const firstClient = {
sendRequest: vi.fn().mockResolvedValue({
ok: true,
result: { capabilities: ['browser.screencast.v1'], floatingWorkspaceEnabled: true }
})
} as unknown as RpcClient
const secondClient = {
sendRequest: vi.fn().mockReturnValue(new Promise(() => {}))
} as unknown as RpcClient
let gates: HostStatusGates | undefined
let renderer: ReactTestRenderer | undefined
function Probe({ client }: { client: RpcClient }): null {
gates = useHostStatusGates({ hostId: 'host-1', client, connState: 'connected' })
return null
}
try {
await act(async () => {
renderer = create(createElement(Probe, { client: firstClient }))
await Promise.resolve()
})
expect(gates?.hostCapabilities).toEqual(['browser.screencast.v1'])
await act(async () => {
renderer?.update(createElement(Probe, { client: secondClient }))
})
expect(gates).toMatchObject({ hostCapabilities: [], statusPending: true })
} finally {
renderer?.unmount()
}
})
})
@@ -1,40 +0,0 @@
import { createHash } from 'node:crypto'
import { gunzipSync } from 'fflate'
import { describe, expect, it } from 'vitest'
import { encodeMobileWebBundleRange } from '../../../../src/main/runtime/rpc/methods/mobile-delivery/mobile-web-bundle-range-encoding'
import { MOBILE_WEB_BUNDLE_RANGE_BYTES } from '../../../../src/shared/mobile-web-bundle/bundle-rpc-contract'
/** Script-like and a full range long, so the host's level-6 deflate emits dynamic Huffman blocks. */
function scriptRange(): Buffer {
const words = ['const ', 'function ', 'return ', 'export ', '=> ', '{', '}', ';\n', 'orca']
let text = ''
for (let index = 0; text.length < MOBILE_WEB_BUNDLE_RANGE_BYTES; index += 1) {
text += words[(index * 7) % words.length] + String(index % 1000)
}
return Buffer.from(text.slice(0, MOBILE_WEB_BUNDLE_RANGE_BYTES))
}
describe('a host-encoded range decoded by the phone', () => {
it('inflates node gzip output with fflate to the same bytes', async () => {
const raw = scriptRange()
const encoded = await encodeMobileWebBundleRange(raw)
expect(encoded.encoding).toBe('gzip')
const inflated = gunzipSync(new Uint8Array(encoded.bytes), {
out: new Uint8Array(raw.byteLength + 1)
})
expect(Buffer.from(inflated).equals(raw)).toBe(true)
})
it('leaves incompressible bytes as identity, which needs no decoder', async () => {
const raw = Buffer.concat(
Array.from({ length: 128 }, (_, index) =>
createHash('sha256').update(`range-${index}`).digest()
)
)
const encoded = await encodeMobileWebBundleRange(raw)
expect(encoded.encoding).toBe('identity')
expect(encoded.bytes.equals(raw)).toBe(true)
})
})
@@ -1,43 +0,0 @@
import { describe, expect, it } from 'vitest'
import { OrchestrationRequestEvidence } from './orchestration-compatibility-envelope'
const CHAT = { ORCA_AGENT_SESSION_ID: '11111111-1111-4111-8111-111111111111' }
describe('caller evidence on requests to another server', () => {
it('sends a chat read there like a shell, with no session id', () => {
const evidence = new OrchestrationRequestEvidence(CHAT)
expect(
evidence.envelopeFor('orchestration.inbox', {
remote: true,
mutation: false,
requestId: undefined
}).orchestrationCompatibilityEvidence
).toBeUndefined()
})
it('keeps the session id on writes there, so that server still refuses them', () => {
const evidence = new OrchestrationRequestEvidence(CHAT)
expect(
evidence.envelopeFor('orchestration.taskCreate', {
remote: true,
mutation: true,
requestId: 'request_1'
}).orchestrationCompatibilityEvidence
).toEqual({ agentSessionId: '11111111-1111-4111-8111-111111111111' })
})
})
describe('caller evidence on browser commands', () => {
it('names the chat on this host, so its run can show the page it drove', () => {
const evidence = new OrchestrationRequestEvidence(CHAT)
const request = { mutation: false, requestId: undefined }
expect(
evidence.envelopeFor('browser.click', { ...request, remote: false })
.orchestrationCompatibilityEvidence
).toEqual({ agentSessionId: '11111111-1111-4111-8111-111111111111' })
expect(
evidence.envelopeFor('browser.click', { ...request, remote: true })
.orchestrationCompatibilityEvidence
).toBeUndefined()
})
})
@@ -1,57 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { AgentWorkspaceTrustDecision } from '../../../shared/agent-launch/permissions/agent-workspace-trust-decision'
import type { AgentTrustSpawnFields } from './agent-workspace-trust'
import { applyAgentWorkspaceTrustToSpawn } from './agent-workspace-trust-spawn'
// An SSH launch only forwards the request to the relay, so no local config is written.
async function sshTrustRequest(input: {
worktreeId: string
globalEnabled?: boolean
repoDecision?: AgentWorkspaceTrustDecision
}): Promise<AgentTrustSpawnFields> {
const spawnOptions: AgentTrustSpawnFields = {}
await applyAgentWorkspaceTrustToSpawn({
launchAgent: 'claude',
worktreeId: input.worktreeId,
cwd: '/srv/app',
store: {
getFolderWorkspace: () => ({ folderPath: '/srv/folder' }),
getRepo: (repoId) =>
repoId === 'repo-1' && input.repoDecision
? { agentWorkspaceTrust: input.repoDecision }
: undefined
},
isFreshLaunch: true,
settings: { agentWorkspaceTrustEnabled: input.globalEnabled ?? true },
env: {},
claudeAuth: null,
wslDistro: null,
connectionId: 'ssh-1',
spawnOptions
})
return spawnOptions
}
describe('agent folder trust follows the repo decision', () => {
it('pre-trusts a repo whose decision is pre-trust', async () => {
expect(
await sshTrustRequest({ worktreeId: 'repo-1::/srv/app', repoDecision: 'pre-trust' })
).toEqual({ agentWorkspaceTrust: { workspacePath: '/srv/app' } })
})
it('leaves the folder untrusted when the repo lets agents ask', async () => {
expect(
await sshTrustRequest({ worktreeId: 'repo-1::/srv/app', repoDecision: 'agent-asks' })
).toEqual({})
})
it('never pre-trusts when folder trust is off globally', async () => {
expect(
await sshTrustRequest({
worktreeId: 'repo-1::/srv/app',
globalEnabled: false,
repoDecision: 'pre-trust'
})
).toEqual({})
})
})
@@ -4,34 +4,6 @@ import { transcriptMessagesFromDecodedMessage } from './session-transcript-messa
import { decodeSessionMessage } from './session-decoded-message'
const AT = '2026-05-01T10:00:00.000Z'
const MESSAGE_LIMIT = 256 * 1024
it('reads tool-result parts lazily and can project the same decoded result again', () => {
const decoded = decodeSessionMessage(
'user',
[
{
type: 'tool_result',
content: [
{ type: 'text', text: 'x'.repeat(MESSAGE_LIMIT) },
{ type: 'text', text: 'omitted text' },
{
type: 'text',
get text() {
throw new Error('Read beyond the tool-result safety limit')
}
}
]
}
],
AT
)
for (let read = 0; read < 2; read++) {
expect(transcriptMessagesFromDecodedMessage(decoded)).toEqual([
{ role: 'tool', text: 'x'.repeat(MESSAGE_LIMIT), timestamp: AT, textTruncated: true }
])
}
})
it('keeps captured server calls and structured results in full Session History', () => {
const messages = advisorCapture.flatMap((frame) =>
@@ -1,65 +0,0 @@
import { describe, expect, it } from 'vitest'
import { resolveExternalAutomationScope } from './external-automation-owner-guard'
import { AutomationOwnerConflictError } from '../../shared/automations/ownership/automation-owner-conflict'
import type { AutomationOwnerRef } from '../../shared/automations/ownership/automation-owner-ref'
import type { SshTarget } from '../../shared/ssh-types'
function sshTarget(overrides: Partial<SshTarget> = {}): SshTarget {
return {
id: 'target-a',
label: 'Build box',
host: 'build.example',
port: 22,
username: 'orca',
generation: 3,
...overrides
}
}
function registry(targets: SshTarget[]): { getSshTargets: () => SshTarget[] } {
return { getSshTargets: () => targets }
}
function desktopSsh(targetId: string, targetGeneration: number): AutomationOwnerRef {
return { authority: { kind: 'desktop' }, selector: { kind: 'ssh', targetId, targetGeneration } }
}
describe('resolveExternalAutomationScope', () => {
it('fails closed with the host-changed conflict on a stale generation', () => {
try {
resolveExternalAutomationScope(
{ owner: desktopSsh('target-a', 2), provider: 'openclaw' },
registry([sshTarget({ generation: 3 })])
)
expect.unreachable('stale generation must not resolve')
} catch (error) {
expect(error).toBeInstanceOf(AutomationOwnerConflictError)
expect((error as AutomationOwnerConflictError).code).toBe('automation_owner_changed')
}
})
it('fails closed when the registration carries no usable generation', () => {
try {
resolveExternalAutomationScope(
{ owner: desktopSsh('target-a', 1), provider: 'openclaw' },
registry([sshTarget({ generation: undefined })])
)
expect.unreachable('unstamped registration must not resolve')
} catch (error) {
expect((error as AutomationOwnerConflictError).code).toBe('automation_owner_changed')
}
})
it('reports a removed SSH host as a target-removed conflict', () => {
try {
resolveExternalAutomationScope(
{ owner: desktopSsh('gone', 1), provider: 'openclaw' },
registry([sshTarget()])
)
expect.unreachable('missing target must not resolve')
} catch (error) {
expect((error as AutomationOwnerConflictError).code).toBe('automation_target_removed')
}
})
})
@@ -1,80 +0,0 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { runExternalAutomationAction } from './external-manager'
import type {
ExternalAutomationAction,
ExternalAutomationProvider
} from '../../shared/automations/external/external-automation'
import type * as Fs from 'node:fs'
const runProcessMock = vi.hoisted(() => vi.fn())
const existsSyncMock = vi.hoisted(() => vi.fn(() => false))
vi.mock('@orca/process-host', () => ({ runProcess: runProcessMock }))
vi.mock('fs', async () => {
const actual = await vi.importActual<typeof Fs>('fs')
return {
...actual,
existsSync: existsSyncMock
}
})
beforeEach(() => {
runProcessMock.mockReset()
runProcessMock.mockResolvedValue({
code: 0,
signal: null,
stdout: '',
stderr: '',
timedOut: false
})
existsSyncMock.mockReturnValue(false)
})
afterEach(() => {
vi.useRealTimers()
})
describe('runExternalAutomationAction', () => {
it('rejects job IDs that could be parsed as CLI options', async () => {
await expect(
runExternalAutomationAction({
managerId: 'openclaw:local',
provider: 'openclaw',
target: { type: 'local' },
jobId: '-help',
action: 'run'
})
).rejects.toThrow('Invalid external automation job ID.')
expect(runProcessMock).not.toHaveBeenCalled()
})
it('rejects an action inherited from the prototype chain', async () => {
await expect(
runExternalAutomationAction({
managerId: 'openclaw:local',
provider: 'openclaw',
target: { type: 'local' },
jobId: 'job-1',
action: 'toString' as unknown as ExternalAutomationAction
})
).rejects.toThrow('Unsupported external automation action.')
expect(runProcessMock).not.toHaveBeenCalled()
})
it('rejects a provider that has no action table', async () => {
await expect(
runExternalAutomationAction({
managerId: 'openclaw:local',
provider: 'shellcat' as ExternalAutomationProvider,
target: { type: 'local' },
jobId: 'job-1',
action: 'run'
})
).rejects.toThrow('Unsupported external automation action.')
expect(runProcessMock).not.toHaveBeenCalled()
})
})
@@ -1,54 +0,0 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
createTranscriptPane,
TRANSCRIPT_PANE_PTY_ID
} from '../runtime/orca-runtime-tests/agent-transcript-pane-test-harness'
import { createRuntimeAutomationRunTerminalObserver } from './runtime-terminal-run-observer'
describe('createRuntimeAutomationRunTerminalObserver', () => {
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
it('propagates recorded end from the real runtime initial probe without a startup wait', async () => {
vi.useRealTimers()
const { runtime, handle } = await createTranscriptPane({
paneTitle: 'shell',
foregroundProcess: 'bash',
data: ''
})
runtime.onPtyExit(TRANSCRIPT_PANE_PTY_ID, 137, 'inc-1', { providerExitObserved: true })
vi.useFakeTimers()
const observer = createRuntimeAutomationRunTerminalObserver(runtime)
await expect(
observer.observeCompletion(handle, { signal: new AbortController().signal })
).rejects.toThrow('terminal_exited')
expect(runtime['terminalWaiters'].forPty(TRANSCRIPT_PANE_PTY_ID)).toHaveLength(0)
})
it('keeps watching a run terminal across a window reload', async () => {
const waitForTerminal = vi
.fn()
// The start probe sees the agent busy.
.mockResolvedValueOnce({ satisfied: false })
.mockRejectedValueOnce(new Error('runtime_unavailable'))
.mockResolvedValueOnce({ satisfied: true })
const observer = createRuntimeAutomationRunTerminalObserver({
getTerminalHandleForPaneKey: () => 'handle-1',
waitForTerminal,
readTerminal: async () => ({ tail: ['done'] }),
canOpenRunTerminals: () => true
})
const observed = observer.observeCompletion('handle-1', {
signal: new AbortController().signal
})
await vi.advanceTimersByTimeAsync(5_000)
await expect(observed).resolves.toMatchObject({ status: 'completed' })
})
})
@@ -1,48 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import type { CookieClearIdentity } from './storage/cookie-store-contracts'
import type { SourcePartitionRead } from './sources/browser-cookie-source-partition'
import { writeImportedCookies, type SourceCookieToWrite } from './browser-cookie-import-write'
function sourceCookie(
overrides: Partial<SourceCookieToWrite> & { name: string; partition: SourcePartitionRead }
): SourceCookieToWrite {
return {
url: 'https://app.example/',
value: 'v',
domain: '.app.example',
path: '/',
secure: true,
httpOnly: false,
sameSite: 'no_restriction',
expirationDate: undefined,
...overrides
}
}
function recordingStore() {
const writeCookieIdentity = vi.fn<(identity: CookieClearIdentity) => Promise<void>>(
async () => undefined
)
return { writeCookieIdentity }
}
const silentOptions = { log: () => undefined }
describe('writeImportedCookies', () => {
it('never dispatches an expired cookie, which would delete the existing coordinate', async () => {
const store = recordingStore()
const result = await writeImportedCookies(
store,
[
sourceCookie({
name: 'sid',
expirationDate: 1,
partition: { status: 'unpartitioned' }
})
],
silentOptions
)
expect(result).toMatchObject({ importedCount: 0, expired: 1, writeRejected: 0 })
expect(store.writeCookieIdentity).not.toHaveBeenCalled()
})
})
@@ -5,9 +5,8 @@ import type { EncryptionKeyResult } from './chromium-encryption-key-contract'
const HOST_KEY = '.example.com'
const cbcKey = randomBytes(16)
const gcmKey = randomBytes(32)
const cbcKeyResult: EncryptionKeyResult = { mode: 'aes-128-cbc', keysByVersion: { v10: cbcKey } }
const gcmKeyResult: EncryptionKeyResult = { mode: 'aes-256-gcm', key: gcmKey }
function hostKeyHash(hostKey: string): Buffer {
return createHash('sha256').update(hostKey).digest()
@@ -18,21 +17,9 @@ function encryptCbc(plaintext: Buffer): Buffer {
return Buffer.concat([Buffer.from('v10'), cipher.update(plaintext), cipher.final()])
}
function encryptGcm(plaintext: Buffer): Buffer {
const nonce = randomBytes(12)
const cipher = createCipheriv('aes-256-gcm', gcmKey, nonce)
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()])
return Buffer.concat([Buffer.from('v10'), nonce, ciphertext, cipher.getAuthTag()])
}
describe('decryptCookieValueRaw host-key hash prefix', () => {
it('decrypts an empty value whose plaintext is only the hash', () => {
const encrypted = encryptCbc(hostKeyHash(HOST_KEY))
expect(decryptCookieValueRaw(encrypted, cbcKeyResult, HOST_KEY)).toEqual(Buffer.alloc(0))
})
it('decrypts an empty value on the Windows AES-GCM path', () => {
const encrypted = encryptGcm(hostKeyHash(HOST_KEY))
expect(decryptCookieValueRaw(encrypted, gcmKeyResult, HOST_KEY)).toEqual(Buffer.alloc(0))
})
})
@@ -1,25 +0,0 @@
import { describe, expect, it } from 'vitest'
import { requireLocalSshBrowserRouteTarget } from './local-ssh-browser-route'
const target = { generation: 4 }
describe('local SSH browser target registration', () => {
it('preserves direct SSH callers that do not supply a deployment fence', () => {
expect(() => requireLocalSshBrowserRouteTarget(target)).not.toThrow()
})
it.each([3, 5, '4', null])(
'refuses a stale or invalid deployment registration: %j',
(generation) => {
expect(() => requireLocalSshBrowserRouteTarget(target, generation)).toThrow(
'browser_local_route_target_stale'
)
}
)
it('refuses a removed target instead of borrowing another route', () => {
expect(() => requireLocalSshBrowserRouteTarget(undefined, 4)).toThrow(
'browser_local_route_target_invalid'
)
})
})
@@ -1,29 +1,9 @@
import { describe, expect, it, vi } from 'vitest'
import type { DescendantSnapshot } from '../pty/process-retirement/pty-descendant-termination'
import { collectDescendantRows } from '../pty/process-retirement/pty-descendant-termination'
import { createClaudeChildTreeReaper } from './claude-agent-sdk-exit-proof'
import { mergeClaudeDescendantSnapshots } from './claude-child-tree-snapshot'
function posixSnapshot(capturedAtMs: number): DescendantSnapshot {
return {
root: { pid: 100, startedAt: 'Mon Jan 1 00:00:00 2026' },
rootPgid: 100,
descendants: [{ pid: 200, ppid: 100, pgid: 100, startedAt: 'Mon Jan 1 00:00:01 2026' }],
capturedAtMs
}
}
describe('Claude child root identity', () => {
it('keeps a retained row boundary when a refresh observes no new descendants', () => {
const previous = posixSnapshot(1_700_000_000_900)
const next = posixSnapshot(1_700_000_002_100)
expect(mergeClaudeDescendantSnapshots(previous, next)).toEqual({
...next,
capturedAtMsByPid: { '200': previous.capturedAtMs }
})
})
it('rejects mixed old and recycled root rows instead of making the tree killable', async () => {
const child = { pid: 100, kill: vi.fn(() => true) }
const terminateDescendants = vi.fn(async () => 'exited' as const)
@@ -1,43 +0,0 @@
import { readFileSync } from 'node:fs'
import { expect, it } from 'vitest'
import {
claudeStartupResultError,
claudeStreamJsonExitError
} from './claude-stream-json-exit-error'
import { providerStartupFailureFact } from '../native-chat/agent-session-wire/startup/structured-agent-session-failure-text'
import { claudeStartFailure } from './claude-startup-failure'
const retryableStructuredAgentSessionStart = (error: unknown): boolean =>
claudeStartFailure(error).retry === 'safe'
const frame = JSON.parse(
readFileSync(new URL('./__fixtures__/claude-missing-conversation.jsonl', import.meta.url), 'utf8')
)
it('treats the recorded missing-conversation exit as an explained final refusal', () => {
const error = claudeStreamJsonExitError(frame.errors[0], {
code: 1,
signal: null,
processless: false
})
expect(providerStartupFailureFact(error)).toMatchObject({
kind: 'savedConversationMissing',
detail: { text: expect.stringContaining(frame.errors[0]), audience: 'log' }
})
expect(retryableStructuredAgentSessionStart(error)).toBe(false)
})
it('reads the same refusal from the recorded result, and makes other startup results final', () => {
const refusal = claudeStartupResultError(frame)
expect(providerStartupFailureFact(refusal)).toEqual({
kind: 'savedConversationMissing',
detail: { text: frame.errors[0], audience: 'log' }
})
expect(retryableStructuredAgentSessionStart(refusal)).toBe(false)
const generic = claudeStartupResultError({ ...frame, errors: ['managed settings failed'] })
expect(providerStartupFailureFact(generic)).toMatchObject({
kind: 'startFailed',
detail: { text: 'managed settings failed', audience: 'log' }
})
expect(retryableStructuredAgentSessionStart(generic)).toBe(false)
})
@@ -1,47 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import { claudeQuestionItems } from './claude-structured-prompt-items'
const LAYOUT_A = '┌──────┬────────┐\n│ nav │ main │\n└──────┴────────┘'
describe('claudeQuestionItems', () => {
it('keeps option previews on single-select questions only', () => {
const [item] = claudeQuestionItems({
sessionId: 'session-1',
prompt: {
requestId: 'req-1',
promptKey: 'req-1',
toolUseId: 'toolu-1',
toolName: 'AskUserQuestion',
kind: 'question',
input: {
questions: [
{
question: 'Which layout?',
header: 'Layout',
multiSelect: false,
options: [
{ label: 'Sidebar', description: 'Nav on the left', preview: LAYOUT_A },
{ label: 'Top bar', description: 'Nav on top', preview: ' \n ' }
]
},
{
question: 'Which panes?',
header: 'Panes',
multiSelect: true,
options: [
{ label: 'Files', description: 'File tree', preview: 'files' },
{ label: 'Git', description: 'Changes', preview: 'git' }
]
}
]
},
suggestions: [],
questionIds: ['q1', 'q2'],
settle: vi.fn()
}
})
const questions = item!.body.questions!
expect(questions[0]!.options.map((option) => option.preview)).toEqual([LAYOUT_A, undefined])
expect(questions[1]!.options.map((option) => option.preview)).toEqual([undefined, undefined])
})
})
@@ -5,12 +5,10 @@ import {
getEphemeralVmRecipeResultProjectRoot,
isAbsoluteRuntimePath
} from '../../shared/ephemeral-vm-recipes'
import {
ENVIRONMENT_PROVIDER_ERROR_CODES,
isEnvironmentProviderError,
type EnvironmentCreateSpec,
type EnvironmentProviderDriver,
type EnvironmentReady
import type {
EnvironmentCreateSpec,
EnvironmentProviderDriver,
EnvironmentReady
} from './environment-provider-driver'
export type EnvironmentProviderDriverContractHarness = {
@@ -72,34 +70,5 @@ export function runEnvironmentProviderDriverContract(
// Idempotent: cleanup retries after a lost response or a restart must not fail.
await reopenDriver().destroy(reload(created.handle))
})
it('refuses to bring back a destroyed environment, even after a restart', async () => {
const { driver, liveEnvironmentIds, reopenDriver } = await makeHarness()
const created = await driver.create(spec('ws-contract-2'))
await driver.destroy(created.handle)
const error = await reopenDriver()
.resume(reload(created.handle))
.then(
() => null,
(caught: unknown) => caught
)
expect(isEnvironmentProviderError(error)).toBe(true)
expect(await liveEnvironmentIds()).not.toContain(created.handle.environmentId)
})
it('rejects a cancelled create with a catalogued error and leaks nothing', async () => {
const { driver, liveEnvironmentIds } = await makeHarness()
const controller = new AbortController()
controller.abort()
const error = await driver.create(spec('ws-contract-3'), { signal: controller.signal }).then(
() => null,
(caught: unknown) => caught
)
expect(isEnvironmentProviderError(error)).toBe(true)
expect(ENVIRONMENT_PROVIDER_ERROR_CODES).toContain(
isEnvironmentProviderError(error) ? error.code : null
)
expect(await liveEnvironmentIds()).toEqual([])
})
})
}
@@ -1,58 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { getStatus } from './status-read'
const { lstat, stream, conflict } = vi.hoisted(() => ({
lstat: vi.fn(),
stream: vi.fn(),
conflict: vi.fn()
}))
vi.mock('node:fs/promises', () => ({ lstat }))
vi.mock('./git-conflict-operation', () => ({ detectConflictOperation: conflict }))
vi.mock('../command-runner/git-stream-stdout', async (importOriginal) => ({
...(await importOriginal<Record<string, unknown>>()),
gitStreamStdout: stream
}))
vi.mock('../command-runner/git-process-env', async (importOriginal) => ({
...(await importOriginal<Record<string, unknown>>()),
gitOptionalLocksDisabledEnv: () => ({ GIT_OPTIONAL_LOCKS: '0' })
}))
beforeEach(() => {
vi.clearAllMocks()
conflict.mockResolvedValue(undefined)
lstat.mockResolvedValue({ isSymbolicLink: () => true })
stream.mockImplementation(async (_args, options) => {
options.onStdout('? unrelated.txt\n')
return { stoppedEarly: false }
})
})
function status(sharedLinkPaths: string[]) {
return getStatus('/repo', { sharedLinkPaths, includeLineStats: false })
}
describe('status shared symlink probe budget', () => {
it.each([1, 8, 32])(
'does no unrelated symlink probes for %i configured paths over 100 refreshes',
async (count) => {
const paths = Array.from({ length: count }, (_, index) => `shared-${index}`)
for (let refresh = 0; refresh < 100; refresh++) {
expect((await status(paths)).entries).toEqual([
{ path: 'unrelated.txt', status: 'untracked', area: 'untracked' }
])
}
expect(lstat).not.toHaveBeenCalled()
}
)
it('rechecks matching paths after the filesystem changes and preserves unreadable paths', async () => {
const paths = ['unrelated.txt']
expect((await status(paths)).entries).toEqual([])
lstat.mockResolvedValueOnce({ isSymbolicLink: () => false })
expect((await status(paths)).entries).toHaveLength(1)
lstat.mockRejectedValueOnce(new Error('EACCES'))
expect((await status(paths)).entries).toHaveLength(1)
expect(lstat).toHaveBeenCalledTimes(3)
})
})
@@ -1,42 +0,0 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const { coordinatorMocks, moduleMocks } = await vi.hoisted(async () => {
const moduleMocks = await import('./pr-refresh-coordinator-test-mocks')
return { coordinatorMocks: moduleMocks.createPRRefreshCoordinatorMocks(), moduleMocks }
})
vi.mock('./pr-refresh-renderer-port', () => moduleMocks.rendererPortModuleMock(coordinatorMocks))
vi.mock('./client', () => moduleMocks.clientModuleMock(coordinatorMocks))
vi.mock('./github-api-repository', () =>
moduleMocks.githubApiRepositoryModuleMock(coordinatorMocks)
)
vi.mock('./rate-limit', () => moduleMocks.rateLimitModuleMock(coordinatorMocks))
import { makeCandidate } from './pr-refresh-coordinator-test-harness'
const { getPRForBranchOutcomeMock } = coordinatorMocks
describe('failed main refresh pacing', () => {
beforeEach(() => {
moduleMocks.resetPRRefreshCoordinatorMocks(coordinatorMocks)
getPRForBranchOutcomeMock.mockImplementation(async () => ({
kind: 'upstream-error',
errorType: 'network',
message: 'offline',
fetchedAt: Date.now()
}))
})
afterEach(() => vi.useRealTimers())
it('panel foreground exposure cannot bypass a failed lookup deadline', async () => {
const { reportVisiblePRRefreshCandidates, enqueuePRRefresh } =
await import('./pr-refresh-coordinator')
const candidate = makeCandidate({ isSelected: true })
reportVisiblePRRefreshCandidates([candidate], 1, 1)
await vi.advanceTimersByTimeAsync(0)
enqueuePRRefresh(candidate, 'visible', 80, 1)
await vi.advanceTimersByTimeAsync(59_999)
expect(getPRForBranchOutcomeMock).toHaveBeenCalledTimes(1)
await vi.advanceTimersByTimeAsync(1)
expect(getPRForBranchOutcomeMock).toHaveBeenCalledTimes(2)
})
})
@@ -1,53 +0,0 @@
import { chmod, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { getDiskBaselineSignature } from '../../../shared/file-write/disk-baseline-signature'
import { registerFilesystemWriteHandlers } from './filesystem-write-handlers'
import type { FilesystemHandlerContext } from './filesystem-handler-context'
const handlers = vi.hoisted(() => new Map<string, (_event: unknown, args: unknown) => unknown>())
vi.mock('electron', () => ({
ipcMain: {
handle: (name: string, handler: (_event: unknown, args: unknown) => unknown) =>
handlers.set(name, handler)
},
shell: {}
}))
vi.mock('./access/local-file-access-resolution', () => ({
resolveLocalWriteRequestPath: async (path: string) => path
}))
vi.mock('./filesystem-mutations', () => ({ registerFilesystemMutationHandlers: vi.fn() }))
vi.mock('../agent-session-attachment-upload-ipc', () => ({
registerAgentSessionAttachmentUploadHandlers: vi.fn()
}))
let root = ''
beforeEach(async () => {
root = await mkdtemp(join(tmpdir(), 'orca-identical-ipc-'))
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: authorization is stubbed, and no other context member is used by this handler.
registerFilesystemWriteHandlers({ store: {} } as FilesystemHandlerContext)
})
afterEach(async () => {
await rm(root, { recursive: true, force: true })
handlers.clear()
})
it('accepts identical content on a readable, non-writable file through IPC', async () => {
const filePath = join(root, 'read-only.txt')
await writeFile(filePath, 'edited')
await chmod(filePath, 0o444)
try {
await expect(
handlers.get('fs:writeFile')!(null, {
filePath,
content: 'edited',
diskPrecondition: { expectedSignature: getDiskBaselineSignature('original') }
})
).resolves.toEqual({ ok: true, unchanged: true })
expect(await readFile(filePath, 'utf8')).toBe('edited')
} finally {
await chmod(filePath, 0o644)
}
})
@@ -1,31 +0,0 @@
import { afterEach, expect, it } from 'vitest'
import { makePaneKey } from '../../../../shared/workspace-layout/stable-pane-id'
import { WORKTREE_TERMINALS_SLEEPING_ERROR } from '../../../../shared/workspace-sleep'
import { adoptStablePane } from './adopt-stable'
import {
makePaneSpawnReservationKey,
paneSpawnReservationsByOwnerKey,
rejectPaneSpawnReservation,
reservePaneSpawn
} from './spawn-reservation'
const pane = {
worktreeId: 'repo::/w',
connectionId: null,
tabId: 'tab-1',
leafId: '11111111-1111-4111-8111-111111111111'
}
const ownerKey = makePaneSpawnReservationKey(
pane.worktreeId,
null,
makePaneKey(pane.tabId, pane.leafId)
)!
afterEach(() => paneSpawnReservationsByOwnerKey.clear())
it('does not hand an automatic refusal to a user adoption of the same pane', async () => {
const reservation = reservePaneSpawn(ownerKey)
const adopted = adoptStablePane(undefined, undefined, { ...pane, cols: 80, rows: 24 })
rejectPaneSpawnReservation(ownerKey, reservation, new Error(WORKTREE_TERMINALS_SLEEPING_ERROR))
await expect(adopted).resolves.toBeNull()
})
@@ -1,60 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import { toAppSshPtyId } from '../../../../shared/ssh-pty-id'
import type { SshRemotePtyLease } from '../../../../shared/ssh-types'
import {
closeLegacyRelayPane,
installLegacyRelayBridge
} from '../../../ssh/legacy-relay/bridge/legacy-relay-bridge-registry'
import { stopRendererOwnedPty, type PtyKillIpcDeps } from '../ipc/renderer-kill'
const TARGET = 'ssh-box'
const lease: SshRemotePtyLease = {
targetId: TARGET,
ptyId: 'pty2:epoch:1',
tabId: 'tab-1',
state: 'detached',
createdAt: 1,
updatedAt: 1
}
describe('a tab close of a terminal an older relay still runs', () => {
it('hands the stop to the bridge instead of tombstoning the lease the bridge needs', async () => {
const leases: SshRemotePtyLease[] = [{ ...lease }]
const store = {
markSshRemotePtyLease: vi.fn((_target: string, relayPtyId: string) => {
for (const row of leases) {
if (row.ptyId === relayPtyId) {
row.state = 'terminated'
}
}
})
}
installLegacyRelayBridge({
leases: () => leases,
retireLease: vi.fn(),
recordStop: vi.fn(),
// Disconnected, so the SSH provider is unregistered: the bridge records the stop.
connection: () => null,
onPanesChanged: () => {},
onData: () => {},
onReplay: () => {},
onExit: () => {},
report: () => {}
})
const ptyId = toAppSshPtyId(TARGET, lease.ptyId)
const deps = {
store,
getLocalPtyProviderStartupPromise: () => undefined,
shutdownProviderAndDetectExit: vi.fn(),
rememberSyntheticKillExit: vi.fn(),
sendPtyExitToRenderer: vi.fn()
}
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the bridged branch reads only these deps.
await stopRendererOwnedPty(deps as unknown as PtyKillIpcDeps, { id: ptyId })
expect(store.markSshRemotePtyLease).not.toHaveBeenCalled()
expect(deps.shutdownProviderAndDetectExit).not.toHaveBeenCalled()
// The transport's own close that follows still reaches a pending stop, not `not-bridged`.
await expect(closeLegacyRelayPane(ptyId)).resolves.toEqual({ status: 'unverifiable' })
installLegacyRelayBridge(null)
})
})
@@ -1,32 +0,0 @@
import { EventEmitter } from 'node:events'
import { describe, expect, it } from 'vitest'
import { abortWhenRendererGone } from './renderer-lifetime-abort'
import type { FanoutEventSource } from '../runtime/events/event-listener-fanout'
function fakeSender(): FanoutEventSource & EventEmitter {
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: EventEmitter implements the once/on/removeListener surface this helper uses, and those three are all it calls; WebContents' overloaded signatures cannot be satisfied structurally.
return new EventEmitter() as FanoutEventSource & EventEmitter
}
describe('abortWhenRendererGone', () => {
it('aborts once a reload has replaced the document, not on in-app route changes', () => {
const sender = fakeSender()
const { signal } = abortWhenRendererGone(sender)
sender.emit('did-start-navigation', {
isMainFrame: true,
isSameDocument: true,
url: 'file:///app#x'
})
sender.emit('did-navigate-in-page', 'file:///app#x')
expect(signal.aborted).toBe(false)
sender.emit('did-start-navigation', {
isMainFrame: true,
isSameDocument: false,
url: 'file:///app'
})
sender.emit('did-navigate', 'file:///app', 200, 'OK')
expect(signal.aborted).toBe(true)
})
})
@@ -51,16 +51,4 @@ describe('addLocalRepoFromPath through a symlink alias', () => {
expect(second).toMatchObject({ alreadyExisted: true })
expect(repos).toHaveLength(1)
})
it('keeps two different folders as two workspaces', async () => {
await mkdir(join(root, 'a'))
await mkdir(join(root, 'b'))
const repos: Repo[] = []
const store = createStore(repos)
await addLocalRepoFromPath(store, join(root, 'a'), 'folder')
await addLocalRepoFromPath(store, join(root, 'b'), 'folder')
expect(repos).toHaveLength(2)
})
})
@@ -1,51 +0,0 @@
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { addManagedOrcadEnvironment } from '../../../shared/remote-runtime/host-store/runtime-environment-managed-orcad-store'
import { encodePairingOffer } from '../../../shared/remote-runtime/pairing/pairing'
import { PAIRING_OFFER_VERSION } from '../../../shared/remote-runtime/pairing/mobile-relay-pairing-offer'
import {
registerManagedServerActions,
type ManagedServerActions
} from '../../runtime/hosts/management/managed-server-actions-registry'
import { removeRedundantManagedPairing } from './runtime-environment-redundant-managed-removal'
const forgetRedundant = vi.fn<ManagedServerActions['forgetRedundant']>()
let userDataPath: string
const pairingCode = (port: number, publicKeyB64: string) =>
encodePairingOffer({
v: PAIRING_OFFER_VERSION,
endpoint: `ws://127.0.0.1:${port}/`,
deviceToken: `device-${port}`,
publicKeyB64
})
function addManaged(id: string, sshTargetId: string, port: number, publicKeyB64: string) {
return addManagedOrcadEnvironment(userDataPath, {
id,
name: id,
pairingCode: pairingCode(port, publicKeyB64),
orcadDeployment: { sshTargetId, sshTargetGeneration: 1, localPort: port, remotePort: 6_768 }
})
}
beforeEach(() => {
userDataPath = mkdtempSync(join(tmpdir(), 'redundant-managed-removal-'))
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: removal only calls forgetRedundant.
registerManagedServerActions({ forgetRedundant } as unknown as ManagedServerActions)
})
afterEach(() => {
registerManagedServerActions(null)
forgetRedundant.mockReset()
rmSync(userDataPath, { recursive: true, force: true })
})
it('leaves the pairing to the store guard when the other entry manages a different server', () => {
const environment = addManaged('managed', 'ssh-1', 46_768, 'public-key')
addManaged('other', 'ssh-2', 46_769, 'other-key')
expect(removeRedundantManagedPairing(userDataPath, environment)).toBeNull()
expect(forgetRedundant).not.toHaveBeenCalled()
})
@@ -1,51 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
const mocks = await vi.hoisted(async () => {
const { createSshIpcMocks } = await import('./ssh-ipc-module-mocks')
return createSshIpcMocks()
})
vi.mock('../../ssh/config/ssh-config-host-picker', () => mocks.sshConfigHostPicker)
vi.mock('electron', () => mocks.electron)
vi.mock('../../ssh/targets/ssh-connection-store', () => mocks.sshConnectionStore)
vi.mock('./ssh-host-server-connect', () => mocks.hostServerConnect)
vi.mock('../../ssh/connection/ssh-connection-manager', () => mocks.sshConnectionManager)
vi.mock('../../ssh/protocol/ssh-channel-multiplexer', () => mocks.sshChannelMultiplexer)
vi.mock('../../ssh/port-forwarding/ssh-port-forward', () => mocks.sshPortForward)
vi.mock('../ssh/ssh-port-scanner', () => mocks.sshPortScanner)
import type { SshConnectionState, SshTarget } from '../../../shared/ssh-types'
import { createSshIpcHarness } from './ssh-ipc-test-harness'
const { mockSshStore, mockConnectionManager } = mocks
describe('SSH IPC handlers', () => {
const harness = createSshIpcHarness(mocks)
const { handlers } = harness
beforeEach(harness.reset)
it('lets a same-turn disconnect invalidate connect before transport admission', async () => {
const target: SshTarget = {
id: 'ssh-1',
label: 'Server',
host: 'example.com',
port: 22,
username: 'deploy'
}
mockSshStore.getTarget.mockReturnValue(target)
mockConnectionManager.connect.mockResolvedValue({})
mockConnectionManager.disconnect.mockResolvedValue(undefined)
const connect = handlers.get('ssh:connect')!(null, {
targetId: 'ssh-1'
}) as Promise<SshConnectionState>
const disconnect = handlers.get('ssh:disconnect')!(null, {
targetId: 'ssh-1'
}) as Promise<void>
await disconnect
await expect(connect).rejects.toThrow('SSH connection attempt was cancelled')
expect(mockConnectionManager.connect).not.toHaveBeenCalled()
})
})
@@ -1,54 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
const { rawRequest } = vi.hoisted(() => ({ rawRequest: vi.fn() }))
vi.mock('./linear-request-concurrency', () => ({
acquire: vi.fn().mockResolvedValue(undefined),
release: vi.fn()
}))
vi.mock('./linear-token-store', () => ({
clearToken: vi.fn()
}))
vi.mock('./client', () => ({
getClients: () => [{ workspace: { id: 'workspace-1' }, client: { client: { rawRequest } } }],
isAuthError: () => false
}))
import { writeIssueRelation } from './issue-relation-write'
describe('writeIssueRelation', () => {
it('does not create a relation when the duplicate lookup omits pageInfo', async () => {
rawRequest.mockImplementation(async (query: string) =>
query.includes('issueRelationCreate')
? {
data: {
issueRelationCreate: {
success: true,
issueRelation: {
id: 'rel-new',
type: 'blocks',
issue: { id: 'issue-1' },
relatedIssue: { id: 'issue-2' }
}
}
}
}
: { data: { issue: { relations: { nodes: [] } } } }
)
const issue = { id: 'issue-1', identifier: 'LIN-1', title: 'One', url: 'https://x/1' }
const relatedIssue = { id: 'issue-2', identifier: 'LIN-2', title: 'Two', url: 'https://x/2' }
await expect(
writeIssueRelation({
issue,
relatedIssue,
relationship: 'blocks',
operation: 'add',
workspaceId: 'workspace-1'
})
).rejects.toMatchObject({ code: 'linear_partial' })
expect(rawRequest).toHaveBeenCalledTimes(1)
})
})
@@ -1,38 +0,0 @@
import type * as ExecCommandModule from '../../ssh/remote-exec/remote-exec-command'
import { beforeEach, describe, expect, it, vi } from 'vitest'
vi.mock('../../ssh/remote-exec/remote-exec-command', async (importOriginal) => ({
...(await importOriginal<typeof ExecCommandModule>()),
execCommand: vi.fn(),
isUnconfirmedSshCommandTermination: (error: unknown) =>
error instanceof Error && error.message === 'channel lost'
}))
vi.mock('../../ssh/remote-host/ssh-remote-platform-detection', () => ({
detectRemoteHostPlatform: vi.fn()
}))
vi.mock('../host-state/orcad-windows-host-preparation', () => ({
prepareWindowsOrcadHost: vi.fn()
}))
import { execCommand } from '../../ssh/remote-exec/remote-exec-command'
import { getRemoteHostPlatform } from '../../ssh/remote-host/ssh-remote-platform'
import { parseOrcadReadinessOutput } from './orcad-remote-launch'
const mockExec = vi.mocked(execCommand)
getRemoteHostPlatform('linux-x64')
getRemoteHostPlatform('win32-x64')
Object.create(null)
beforeEach(() => {
mockExec.mockReset()
})
describe('readiness parsing bounds', () => {
it('waits on a half-written last line but rejects a finished invalid one', () => {
expect(parseOrcadReadinessOutput('{"type":"orca_ser')).toEqual({ state: 'pending' })
expect(parseOrcadReadinessOutput('{"type":"orca_ser\n')).toMatchObject({
state: 'malformed'
})
})
})
@@ -1,52 +0,0 @@
import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, expect, it } from 'vitest'
import { createAgentModelCatalogFilePersistence } from './agent-model-catalog-persistence'
import { AgentModelCatalogStore } from './agent-model-catalog-store'
const directories: string[] = []
afterEach(() => {
for (const directory of directories.splice(0)) {
rmSync(directory, { recursive: true, force: true })
}
})
it("imports an older build's catalog file once and keeps later listings", async () => {
const directory = mkdtempSync(join(tmpdir(), 'orca-model-catalog-'))
directories.push(directory)
const legacyPath = join(directory, 'agent-model-catalog.json')
writeFileSync(
legacyPath,
JSON.stringify({
version: 3,
entries: [
{
agent: 'grok',
fingerprint: 'fp',
discovered: {
origin: 'probe',
at: 1,
models: [{ id: 'A', label: 'A', efforts: [], isDefault: true }]
},
live: null
}
]
})
)
const store = new AgentModelCatalogStore()
await store.attachPersistence(createAgentModelCatalogFilePersistence(directory))
expect(store.get('fp')?.models[0]?.id).toBe('A')
expect(existsSync(legacyPath)).toBe(false)
store.recordSuccess(
'fp',
'grok',
{ origin: 'probe', models: [{ id: 'B', label: 'B', efforts: [], isDefault: true }] },
'discovery'
)
await store.flushPersistence()
const restarted = await createAgentModelCatalogFilePersistence(directory).load()
expect(restarted.map((entry) => entry.models[0]?.id)).toEqual(['B'])
})
@@ -1,10 +1,5 @@
import { describe, expect, it } from 'vitest'
import {
deriveQueuePauses,
journalQueuePauseRestatement,
queuePauseHolding,
nextSendableQueuedCard
} from './queued-message-pause'
import { deriveQueuePauses, journalQueuePauseRestatement } from './queued-message-pause'
import { createJournalQueuePauseMarks } from './queued-message-pause-marks'
const card = (messageId: string) => ({
@@ -27,18 +22,6 @@ const pauses = (cards = [card('before-one'), card('before-two')], m = marks(), a
})
describe('exact waiting-card membership after context clear', () => {
it('holds only recorded waiting IDs and intersects them with cards still waiting', () => {
const after = card('after')
const current = [card('before-two'), after]
const held = pauses(current)
expect(held).toEqual([
{ reason: 'cleared', since: { epoch: 'epoch', sequence: 5 }, messageIds: ['before-two'] }
])
expect(queuePauseHolding(held, after)).toBeUndefined()
expect(pauses([after])).toEqual([])
expect(nextSendableQueuedCard(pauses([after]), [after])).toEqual(after)
})
it('restates an explicit lift when rewind retires the accepted turn', () => {
const prior = marks()
const cards = [card('before-one'), card('before-two')]
@@ -1,36 +0,0 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { OrcaCloudAuthConfig } from './profile-cloud-auth-config'
import { createOrcaCloudProfile, OrcaCloudRequestError } from './profile-cloud-client'
import type { OrcaCloudSession } from './profile-cloud-session-store'
afterEach(() => {
vi.unstubAllGlobals()
})
describe('createOrcaCloudProfile', () => {
it('proves the sign-in with its refresh token alongside the access token', async () => {
const fetchImpl = vi.fn<typeof globalThis.fetch>(
async () => new Response(null, { status: 403 })
)
vi.stubGlobal('fetch', fetchImpl)
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the call reads only this endpoint.
const config = {
profileEndpoint: 'https://login.test/v1/desktop/auth/profile'
} as OrcaCloudAuthConfig
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the call reads only the two tokens.
const session = { accessToken: 'access-1', refreshToken: 'refresh-1' } as OrcaCloudSession
await expect(
createOrcaCloudProfile(config, session, { orgId: 'org-1', name: 'Work' })
).rejects.toBeInstanceOf(OrcaCloudRequestError)
const [url, init] = fetchImpl.mock.calls[0]!
expect(url).toBe('https://login.test/v1/desktop/auth/profile')
expect(new Headers(init?.headers).get('authorization')).toBe('Bearer access-1')
expect(JSON.parse(String(init?.body))).toEqual({
orgId: 'org-1',
name: 'Work',
refreshToken: 'refresh-1'
})
})
})
@@ -1,55 +0,0 @@
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import {
readOrcadHostAccountLaunchEnv,
restoreOrcadHostAccountLaunchEnv
} from './orcad-host-account-launch-env-store'
import { RuntimeAccountController } from '../runtime/agent-session/environment/runtime-account-controller'
const dirs: string[] = []
function userData(): string {
const dir = mkdtempSync(join(tmpdir(), 'orcad-host-accounts-'))
dirs.push(dir)
return dir
}
afterEach(() => {
for (const dir of dirs.splice(0)) {
rmSync(dir, { recursive: true, force: true })
}
})
describe('orcad host account launch env store', () => {
it('reads nothing from a missing, corrupt or unsafe file', () => {
const dir = userData()
expect(readOrcadHostAccountLaunchEnv(dir)).toBeNull()
writeFileSync(join(dir, 'host-account-launch-env.json'), '{not json')
expect(readOrcadHostAccountLaunchEnv(dir)).toBeNull()
writeFileSync(
join(dir, 'host-account-launch-env.json'),
JSON.stringify({ wslDistro: 'Ubuntu', claude: { PATH: '/evil' }, terminal: {} })
)
expect(readOrcadHostAccountLaunchEnv(dir)).toBeNull()
})
it("holds a fresh WSL host's first agent launch for the desktop's push, and nowhere else", async () => {
for (const isWslHost of [true, false]) {
const accounts = new RuntimeAccountController()
restoreOrcadHostAccountLaunchEnv(
{ restoreHostAccountLaunchEnv: accounts.restoreHostLaunchEnv.bind(accounts) },
userData(),
() => isWslHost
)
let launched = false
void accounts.prepareHostAgentLaunch(null).then(() => {
launched = true
})
await Promise.resolve()
await Promise.resolve()
expect(launched).toBe(!isWslHost)
accounts.setHostLaunchEnv({ wslDistro: 'Ubuntu', claude: {}, terminal: {} })
}
})
})
@@ -1,45 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { ColdRestoreDetection } from '../../daemon/history/restoration/terminal-history-cold-restore-info'
import { captureWslMoveRestoreHints } from './wsl-move-restore-hints'
const restored = (
cwd: string,
hasUnreadableRecovery = false,
cwdFromSpawn = false
): ColdRestoreDetection => ({
status: 'restored',
sessionId: 's',
hasUnreadableRecovery,
...(cwdFromSpawn ? { cwdFromSpawn: true as const } : {}),
restoreInfo: {
snapshotAnsi: '',
scrollbackAnsi: '',
rehydrateSequences: '',
cwd,
cols: 80,
rows: 24,
modes: {
bracketedPaste: false,
mouseTracking: false,
applicationCursor: false,
alternateScreen: false
}
}
})
describe('captureWslMoveRestoreHints', () => {
// Bash on the bridge reports no folder, so an open pane's checkpoint kept its
// spawn folder and `cd deep/er` reopened at the project root.
it('prefers the folder the shell was in before Sleep over the spawn folder', async () => {
const capture = await captureWslMoveRestoreHints(
{
detectColdRestoreState: async () =>
restored('\\\\wsl.localhost\\Ubuntu\\home\\dev\\app', false, true)
},
[{ paneKey: 't:a', sessionId: 'wt@@a', shellCwd: '/home/dev/app/deep/er' }],
'Ubuntu'
)
expect(capture.hints).toEqual([{ paneKey: 't:a', cwd: '/home/dev/app/deep/er' }])
expect(capture.staleCwdPaneKeys).toEqual([])
})
})
@@ -1,52 +0,0 @@
import { mkdirSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { installFakeAppEnvironment } from '../../../../config/scripts/test-runtime/environment/vitest-host-ports-setup'
let userDataDir: string
import { hashWorktreeId } from './terminal-history-id'
import {
deleteWorktreeHistoryDir,
flushPendingWorktreeHistoryDeletions
} from './terminal-history-deletion'
describe('deleteWorktreeHistoryDir main-thread safety', () => {
beforeEach(() => {
userDataDir = mkdtempSync(join(tmpdir(), 'orca-history-async-'))
installFakeAppEnvironment({ getPath: () => userDataDir })
})
afterEach(async () => {
await flushPendingWorktreeHistoryDeletions()
rmSync(userDataDir, { recursive: true, force: true })
})
it('tombstones without blocking the event loop, then removes via async rm', async () => {
const worktreeId = 'repo-1::/path/heavy-wt'
const hash = hashWorktreeId(worktreeId)
const historyDir = join(userDataDir, 'terminal-history', hash)
mkdirSync(historyDir, { recursive: true })
for (let i = 0; i < 3_000; i++) {
writeFileSync(join(historyDir, `file-${i}.txt`), `payload-${i}`)
}
// Measure the sync delete call; later async-rm timer gaps depend on CI scheduling.
const criticalPathStartedAt = performance.now()
deleteWorktreeHistoryDir(worktreeId)
const criticalPathMs = performance.now() - criticalPathStartedAt
// AV/shared runners can delay rename; structural assertions below establish tombstoning.
expect(criticalPathMs).toBeLessThan(
process.env.CI || process.platform === 'win32' ? 1_000 : 100
)
expect(readdirSync(join(userDataDir, 'terminal-history'))).not.toContain(hash)
expect(
readdirSync(join(userDataDir, 'terminal-history', '.pending-delete')).length
).toBeGreaterThan(0)
await flushPendingWorktreeHistoryDeletions()
expect(readdirSync(join(userDataDir, 'terminal-history', '.pending-delete'))).toHaveLength(0)
})
})
@@ -2,13 +2,6 @@ import { describe, expect, it } from 'vitest'
import { redactMiniMaxSecret } from './minimax-request-context'
describe('redactMiniMaxSecret', () => {
it('redacts _token values in header and quoted syntax', () => {
const redacted = redactMiniMaxSecret('cookie _token=eyJhABCDEF and _token:"x.y"')
expect(redacted).toContain('_token=[REDACTED]')
expect(redacted).not.toContain('eyJhABCDEF')
expect(redacted).not.toContain('x.y')
})
it('redacts quoted values with whitespace around the colon', () => {
const redacted = redactMiniMaxSecret('_token : "spaced.secret"')
expect(redacted).not.toContain('spaced.secret')
@@ -1,41 +0,0 @@
import { spawn } from 'node:child_process'
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { classifySynchronousRipgrepSpawnFailure } from '../../shared/ripgrep/ripgrep-process-availability'
const dirs: string[] = []
afterEach(() => {
for (const dir of dirs.splice(0)) {
rmSync(dir, { recursive: true, force: true })
}
})
function fileAsSearchRoot(): string {
const dir = mkdtempSync(join(tmpdir(), 'rg-sync-'))
dirs.push(dir)
const path = join(dir, 'not-a-directory')
writeFileSync(path, '')
return path
}
describe('synchronous ripgrep spawn failures', () => {
it.skipIf(process.platform === 'win32')(
'names the unreachable root instead of surfacing a raw spawn errno',
async () => {
const root = fileAsSearchRoot()
let thrown: unknown
try {
spawn(process.execPath, ['-e', ''], { cwd: root, stdio: 'ignore' })
} catch (error) {
thrown = error
}
const verdict = await classifySynchronousRipgrepSpawnFailure(thrown, root)
expect(verdict.message).toBe(`Search root is not reachable: ${root}`)
}
)
})
@@ -1,66 +0,0 @@
import { closeTestJournalHostDatabases } from '../../native-chat/agent-session-journal/store-lifecycle/journal-host-database-test-support'
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import type { AgentSessionDeathEvidence } from '../../../shared/agent-session/lifecycle/agent-session-death-evidence'
import {
agentSessionLeaseFixture,
agentSessionRecordFixture
} from '../../../shared/agent-session/lifecycle/agent-session-record.test-fixture'
import type { AgentSessionRecordStore } from './records/agent-session-record-store'
import {
openTestAgentSessionRecordStore,
seedTestAgentSessionRecordStore
} from './records/agent-session-record-store-test-harness'
const SESSION = 'session-alpha-1'
const LAST_RENEWED_AT = 30_000
let directory: string
async function seed(deathEvidence: AgentSessionDeathEvidence | null): Promise<void> {
const lease =
deathEvidence === null
? agentSessionLeaseFixture()
: agentSessionLeaseFixture({
ownerProcess: null,
reservedSpawnToken: null,
claimStatus: 'released',
deathEvidence
})
await seedTestAgentSessionRecordStore(directory, { records: [agentSessionRecordFixture(lease)] })
}
function open(): Promise<AgentSessionRecordStore> {
return openTestAgentSessionRecordStore(directory)
}
beforeEach(async () => {
directory = await mkdtemp(join(tmpdir(), 'orca-death-evidence-'))
})
afterEach(async () => {
await closeTestJournalHostDatabases()
await rm(directory, { recursive: true, force: true })
})
describe('death evidence on disk', () => {
it('records the last renewal before the crash and reads it back after another restart', async () => {
await seed(null)
const crashed = await open()
await crashed.reconcileOnRestart({
probe: async () => ({ outcome: 'pid-absent' }),
now: 90_000
})
const evidence = {
kind: 'pid-absent',
detail: 'recorded pid absent on host',
observedAt: 90_000,
ownerFence: 7,
lastProvenAliveAt: LAST_RENEWED_AT
}
expect(crashed.getRecord(SESSION)?.lease.deathEvidence).toEqual(evidence)
expect((await open()).getRecord(SESSION)?.lease.deathEvidence).toEqual(evidence)
})
})
@@ -1,60 +0,0 @@
import { beforeEach, expect, it, vi } from 'vitest'
import { folderWorkspaceKey } from '../../../../shared/workspace-scope'
import {
root,
B,
authorityProfile,
openAuthorityRuntime
} from './structured-agent-session-tab-authority.test-support'
import { closeStructuredAgentSessionChild } from '../structured-agent-session-close'
// CLI capability probing is outside tab authority and must not start a real CLI in this fixture.
vi.mock('../../../claude/claude-cli-flag-prewarm', () => ({
prewarmClaudeCliFlags: async () => undefined
}))
const layoutOwner = vi.hoisted(() => ({ main: false }))
vi.mock('../../../../shared/layout-owner-switch', () => ({
get ORCA_LAYOUT_OWNER_IS_MAIN() {
return layoutOwner.main
}
}))
beforeEach(() => {
layoutOwner.main = false
})
it('captured close retires only its qualified workspace and preserves unrelated mirrors', async () => {
const rig = await openAuthorityRuntime(await authorityProfile())
await rig.host.setSessionTabVisibility(B, true)
rig.runtime.projectStructuredAgentSessionTab({
workspaceId: rig.workspace,
sessionId: B,
agent: 'codex',
activate: true
})
const original = rig.runtime.mobileSessionTabsByWorktree.get(rig.workspace)!
const duplicate = rig.profile.createFolderWorkspace({
projectGroupId: rig.groupId,
folderPath: `${root}/duplicate`,
name: 'Duplicate'
})
const mirror = rig.profile.createFolderWorkspace({
projectGroupId: rig.groupId,
folderPath: `${root}/mirror`,
name: 'Mirror',
connectionId: 'foreign'
})
const duplicateKey = folderWorkspaceKey(duplicate.id),
mirrorKey = folderWorkspaceKey(mirror.id)
rig.runtime.storeMobileSessionSnapshot(duplicateKey, { ...original, worktree: duplicateKey })
const foreign = rig.runtime.storeMobileSessionSnapshot(mirrorKey, {
...original,
worktree: mirrorKey
})
await closeStructuredAgentSessionChild(B, { runtime: rig.runtime })
expect(rig.runtime.mobileSessionTabsByWorktree.get(rig.workspace)?.tabs).toEqual([])
expect(rig.runtime.mobileSessionTabsByWorktree.get(duplicateKey)?.tabs).toEqual(original.tabs)
expect(rig.runtime.mobileSessionTabsByWorktree.get(mirrorKey)).toBe(foreign)
expect(rig.runtime.retireStructuredAgentSessionTabFromSnapshot(B)).toBe(false)
expect(rig.runtime.mobileSessionTabsByWorktree.get(mirrorKey)).toBe(foreign)
})
@@ -31,7 +31,6 @@ await import('../orca-runtime-tests/pty-title-status.spec')
await import('../orca-runtime-tests/terminal-side-effect-facts.spec')
await import('../orca-runtime-tests/terminal-side-effect-facts-part-02.spec')
await import('../orca-runtime-tests/terminal-side-effect-facts-part-03.spec')
await import('../orca-runtime-tests/decorative-title-fact-throttle.spec')
await import('../orca-runtime-tests/headless-snapshots.spec')
await import('../orca-runtime-tests/headless-snapshots-part-02.spec')
await import('../orca-runtime-tests/agent-status-and-waits.spec')
@@ -39,7 +38,6 @@ await import('../orca-runtime-tests/agent-status-and-waits-part-02.spec')
await import('../orca-runtime-tests/agent-status-and-waits-part-03.spec')
await import('../orca-runtime-tests/terminal-creation-and-readiness.spec')
await import('../orca-runtime-tests/terminal-creation-and-readiness-part-02.spec')
await import('../orca-runtime-tests/terminal-creation-and-readiness-part-03.spec')
await import('../orca-runtime-tests/terminal-creation-and-readiness-part-04.spec')
await import('../orca-runtime-tests/terminal-creation-and-readiness-part-05.spec')
await import('../orca-runtime-tests/terminal-creation-and-readiness-part-06.spec')
@@ -103,7 +101,6 @@ await import('../orca-runtime-tests/worktree-setup-and-startup-part-03.spec')
await import('../orca-runtime-tests/worktree-setup-and-startup-part-04.spec')
await import('../orca-runtime-tests/worktree-setup-single-creator.spec')
await import('../orca-runtime-tests/gitlab-and-pr-bases-part-02.spec')
await import('../orca-runtime-tests/gitlab-and-pr-bases-part-03.spec')
await import('../orca-runtime-tests/worktree-removal-and-reconciliation-part-02.spec')
await import('../orca-runtime-tests/worktree-removal-and-reconciliation-part-03.spec')
await import('../orca-runtime-tests/worktree-removal-and-reconciliation-part-04.spec')
@@ -1,36 +0,0 @@
import { expect, it, vi } from 'vitest'
import { createBranchSwitchHost } from './runtime-branch-switch-host'
import type { RuntimeStore } from '../../construction/runtime-store-contract'
import type { WorktreeMeta } from '../../../../shared/worktree/meta-types'
vi.mock('../../../persistence/host-qualified-worktree-meta', () => ({
worktreeRowTarget: (_store: unknown, worktree: unknown) => worktree
}))
it('keeps automatic naming after commit checkout while preserving branch-link clearing', () => {
const meta = { linkedPR: 42, branchNameIsUserChosen: false }
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the switch callback only reads and updates this metadata fixture.
const store = {
getWorktreeMetaForHost: () => meta,
setWorktreeMeta: (_target: unknown, updates: Partial<WorktreeMeta>) =>
Object.assign(meta, updates)
} as unknown as RuntimeStore
const host = createBranchSwitchHost({
getStore: () => store,
readAgentRows: () => [],
readAgentPaneRows: () => [],
ptys: () => [],
paneOf: () => ({ tabId: null, paneKey: null }),
terminalHandlesOf: () => [],
hasSyncedTab: () => false,
savedTabIds: () => [],
probeProcess: async () => null,
notifyBranchChanged: () => {},
folderWorkspacePaths: () => new Map()
})
const worktree = { id: 'r::/repo', hostId: 'local' as const, repoId: 'r' }
host.recordBranchSwitched(worktree, true)
expect(meta).toMatchObject({ linkedPR: null, branchNameIsUserChosen: false })
host.recordBranchSwitched(worktree)
expect(meta.branchNameIsUserChosen).toBe(true)
})
@@ -1,54 +0,0 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { TerminalSideEffectBatch } from '../../../shared/terminal/output/terminal-side-effect-facts'
import { syncSinglePty } from './orca-runtime-test-fixtures.spec'
import { createSideEffectRuntime } from './orca-runtime-test-scenario-builders.spec'
const SPINNER_INTERVAL_MS = 80
const EPOCH = 1_700_000_000_000
type TitleFact = { kind: 'title'; normalizedTitle: string; rawTitle: string }
function titleFacts(batches: TerminalSideEffectBatch[]): TitleFact[] {
return batches.flatMap((batch) =>
batch.facts.filter((fact): fact is TitleFact => fact.kind === 'title')
)
}
describe('decorative title fact throttle', () => {
beforeEach(() => {
vi.useFakeTimers({ toFake: ['Date'] })
vi.setSystemTime(new Date(EPOCH))
})
afterEach(() => {
vi.useRealTimers()
})
it('propagates a changed working label immediately even while the spinner rotates', () => {
// Only spinner glyphs are decorative; Grok/Pi label churn changes content.
const { runtime, batches } = createSideEffectRuntime()
syncSinglePty(runtime)
runtime.ingestSyntheticTitleFrame('pty-1', '\x1b]0;⠋ Claude Code\x07')
vi.setSystemTime(new Date(EPOCH + SPINNER_INTERVAL_MS))
runtime.ingestSyntheticTitleFrame('pty-1', '\x1b]0;⠙ Reviewing diff — Claude Code\x07')
expect(titleFacts(batches).map((fact) => fact.rawTitle)).toEqual([
'⠋ Claude Code',
'⠙ Reviewing diff — Claude Code'
])
})
it('keeps main-side tracked title state current for every suppressed frame', () => {
// Mobile/remote read tracked records; suppressed facts must not freeze those snapshots.
const { runtime } = createSideEffectRuntime()
syncSinglePty(runtime)
runtime.ingestSyntheticTitleFrame('pty-1', '\x1b]0;⠋ Claude Code\x07')
vi.setSystemTime(new Date(EPOCH + SPINNER_INTERVAL_MS))
runtime.ingestSyntheticTitleFrame('pty-1', '\x1b]0;⠙ Claude Code\x07')
expect(runtime.getTerminalSideEffectSnapshot('pty-1')?.facts).toEqual([
{ kind: 'title', normalizedTitle: '⠙ Claude Code', rawTitle: '⠙ Claude Code' }
])
})
})
@@ -1,41 +0,0 @@
import * as gitExecFile from '../../git/command-runner/git-exec-file'
import { SshHostNotServedError } from '../../providers/ssh-host-not-served-error'
import { describe, expect, it, vi } from 'vitest'
import './runtime-test-module-registration.spec'
import { OrcaRuntimeService } from '../orca-runtime'
import { getGlabKnownHostsMock } from '../orca-runtime-test-mocks/setup.spec'
import { TEST_REPO_ID, store } from './orca-runtime-test-fixtures.spec'
describe('OrcaRuntimeService', () => {
it('refuses SSH GitLab MR bases instead of resolving them on this machine', async () => {
const remoteRepo = {
id: TEST_REPO_ID,
path: '/remote/repo',
displayName: 'repo',
badgeColor: 'blue',
addedAt: 1,
connectionId: 'ssh-1',
issueSourcePreference: 'origin' as const
}
const runtimeStore = {
...store,
getRepos: () => [remoteRepo],
getRepo: (id: string) => (id === remoteRepo.id ? remoteRepo : undefined)
}
const gitSpy = vi.spyOn(gitExecFile, 'gitExecFileAsync')
const runtime = new OrcaRuntimeService(runtimeStore as never)
await expect(
runtime.resolveManagedMrBase({
repoSelector: 'id:repo-1',
mrIid: 77,
sourceBranch: 'feature',
targetBranch: 'main',
isCrossRepository: true
})
).rejects.toThrow(SshHostNotServedError)
expect(getGlabKnownHostsMock).not.toHaveBeenCalled()
expect(gitSpy).not.toHaveBeenCalled()
gitSpy.mockRestore()
})
})
@@ -1,57 +0,0 @@
import 'node:fs/promises'
import { describe, expect, it, vi } from 'vitest'
import '../../preflight/agent-command-detection'
import './runtime-test-module-registration.spec'
import '../../../shared/constants'
import { OrcaRuntimeService } from '../orca-runtime'
import '../../../shared/agent-launch/startup/setup-agent-sequencing'
import { join } from 'node:path'
import { randomUUID } from 'node:crypto'
import { tmpdir } from 'node:os'
import {
TEST_FOLDER_WORKSPACE_ID,
TEST_FOLDER_WORKSPACE_KEY,
createFolderWorkspaceRuntimeStore,
makeFolderProjectGroup,
makeFolderWorkspace
} from './orca-runtime-test-fixtures.spec'
import '../terminal/launch/spawned-pty-env-fixtures'
describe('OrcaRuntimeService', () => {
it('rejects folder workspace terminal creation when the backing path is missing', async () => {
const missingPath = join(tmpdir(), `orca-missing-folder-workspace-${randomUUID()}`)
const spawn = vi.fn().mockResolvedValue({ id: 'pty-folder' })
const folderWorkspace = makeFolderWorkspace({ folderPath: missingPath })
const projectGroup = makeFolderProjectGroup({ parentPath: missingPath })
const runtime = new OrcaRuntimeService(
createFolderWorkspaceRuntimeStore(folderWorkspace, projectGroup) as never
)
runtime.setPtyController({
spawn,
write: () => true,
kill: () => true,
getForegroundProcess: async () => null
})
await expect(runtime.createTerminal(TEST_FOLDER_WORKSPACE_KEY)).rejects.toThrow(
'folder_workspace_path_missing'
)
expect(spawn).not.toHaveBeenCalled()
})
it('rejects folder workspace folderPath updates when the new path is missing', async () => {
const missingPath = join(tmpdir(), `orca-missing-folder-update-${randomUUID()}`)
const folderWorkspace = makeFolderWorkspace()
const runtimeStore = {
...createFolderWorkspaceRuntimeStore(folderWorkspace),
updateFolderWorkspace: vi.fn()
}
const runtime = new OrcaRuntimeService(runtimeStore as never)
await expect(
runtime.updateFolderWorkspace(TEST_FOLDER_WORKSPACE_ID, { folderPath: missingPath })
).rejects.toThrow('folder_workspace_path_missing')
expect(runtimeStore.updateFolderWorkspace).not.toHaveBeenCalled()
})
})
@@ -1,61 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { OrcaRuntimeService } from '../../../orca-runtime'
import {
acquireFederationAckLease,
clearFederationAckCheckpoints,
getFederationAckedThrough,
recordFederationAckCheckpoint,
type FederationAckIdentity
} from '../../legacy-remote-home/federation-ack-checkpoints'
describe('federation acknowledgment checkpoints', () => {
it('matches checkpoints only to their exact remote identity and never moves backward', () => {
const runtime = {} as OrcaRuntimeService
const identity: FederationAckIdentity = {
environmentId: 'environment_windows',
peerFingerprint: 'windows_peer_fingerprint',
remoteRuntimeEpoch: 'remote_epoch_1'
}
const lease = acquireFederationAckLease(runtime, 'dispatch_remote')
recordFederationAckCheckpoint(runtime, lease, {
...identity,
throughSequence: 2
})
recordFederationAckCheckpoint(runtime, lease, {
...identity,
throughSequence: 3
})
recordFederationAckCheckpoint(runtime, lease, {
...identity,
throughSequence: 2
})
expect(getFederationAckedThrough(lease, identity)).toBe(3)
expect(
getFederationAckedThrough(lease, { ...identity, remoteRuntimeEpoch: 'remote_epoch_2' })
).toBe(0)
expect(
getFederationAckedThrough(lease, { ...identity, peerFingerprint: 'replacement_peer' })
).toBe(0)
expect(getFederationAckedThrough(lease, { ...identity, environmentId: 'replacement' })).toBe(0)
})
it('fences delayed writes after runtime reset', () => {
const runtime = {} as OrcaRuntimeService
const identity: FederationAckIdentity = {
environmentId: 'environment_windows',
peerFingerprint: 'windows_peer_fingerprint',
remoteRuntimeEpoch: 'remote_epoch_1'
}
const staleRuntimeLease = acquireFederationAckLease(runtime, 'dispatch_remote')
clearFederationAckCheckpoints(runtime)
recordFederationAckCheckpoint(runtime, staleRuntimeLease, {
...identity,
throughSequence: 2
})
expect(
getFederationAckedThrough(acquireFederationAckLease(runtime, 'dispatch_remote'), identity)
).toBe(0)
})
})
@@ -1,52 +0,0 @@
import { describe, expect, it } from 'vitest'
import { ORCHESTRATION_FEDERATION_RELEASE_ARCHIVE_RUNTIME_CAPABILITY } from '../../../../../shared/orchestration/orchestration-runtime-capabilities'
import { createIdleSyncHarness } from './federation-sync-test-harness'
import { armHomeAutoReleaseForOlderHost } from '../../legacy-remote-home/federation-sync-capability'
function releasableTerminalWorker() {
const harness = createIdleSyncHarness()
harness.setRemoteCapabilities([ORCHESTRATION_FEDERATION_RELEASE_ARCHIVE_RUNTIME_CAPABILITY])
const db = harness.runtime.getOrchestrationDb()
const federated = db.getFederatedDispatch('dispatch_remote')!
db.getFederatedDispatch = () => ({
...federated,
remote_terminal_handle: 'term_remote_worker',
home_auto_release_state: null
})
const worker = db.getWorkerDispatch('dispatch_remote')!
db.getWorkerDispatch = () => ({ ...worker, state: 'succeeded', stage: 'reported' })
db.workerAutoReleaseEnabled = () => true
return {
runtime: harness.runtime,
remoteCall: harness.remoteCall,
dispatchId: federated.dispatch_id,
armedDeadlines: () => db.claimDueFederatedHomeAutoReleases(Date.UTC(2100, 0, 1))
}
}
describe('armHomeAutoReleaseForOlderHost', () => {
it('does not arm from a sync the relay stopped while it probed the host', async () => {
const { runtime, remoteCall, dispatchId, armedDeadlines } = releasableTerminalWorker()
const answer = remoteCall.getMockImplementation()!
let noteProbe!: () => void
let releaseProbe!: () => void
const probing = new Promise<void>((resolve) => (noteProbe = resolve))
const released = new Promise<void>((resolve) => (releaseProbe = resolve))
remoteCall.mockImplementation(async (...args) => {
if (args[1] === 'status.get') {
noteProbe()
await released
}
return answer(...args)
})
let current = true
const arming = armHomeAutoReleaseForOlderHost(runtime, dispatchId, 1, () => current)
await probing
current = false
releaseProbe()
await arming
expect(armedDeadlines()).toEqual([])
})
})
@@ -1,62 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { OrcaRuntimeService } from '../orca-runtime'
import { defineStreamingMethod, type RpcResponse } from './core'
import { RpcDispatcher } from './dispatcher'
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: These test methods only read the runtime ID; optional runtime hooks are absent.
const runtime = { getRuntimeId: () => 'test-runtime' } as OrcaRuntimeService
describe('object and JSON stream transports', () => {
it('preserves ordered stream results and errors across structured cloning and JSON', async () => {
const dispatcher = new RpcDispatcher({
runtime,
methods: [
defineStreamingMethod({
name: 'test.stream',
permission: 'workspace',
params: null,
handler: async (_params, _ctx, emit) => {
emit({ type: 'text', text: 'hello\n"😀' })
emit({ type: 'end' })
throw new Error('boom')
}
})
]
})
const request = { id: 'sub-1', authToken: 'token', method: 'test.stream' }
const objects: RpcResponse[] = []
const json: string[] = []
await dispatcher.dispatchStreamingObjects(request, (response) =>
objects.push(structuredClone(response))
)
await dispatcher.dispatchStreaming(request, (response) => json.push(response))
expect(objects).toEqual([
{
id: 'sub-1',
ok: true,
result: { type: 'text', text: 'hello\n"😀' },
_meta: { runtimeId: 'test-runtime' },
streaming: true
},
{
id: 'sub-1',
ok: true,
result: { type: 'end' },
_meta: { runtimeId: 'test-runtime' },
streaming: true
},
{
id: 'sub-1',
ok: false,
error: { code: 'runtime_error', message: 'boom' },
_meta: { runtimeId: 'test-runtime' }
}
])
expect(json).toEqual([
'{"id":"sub-1","ok":true,"result":{"type":"text","text":"hello\\n\\"😀"},"_meta":{"runtimeId":"test-runtime"},"streaming":true}',
'{"id":"sub-1","ok":true,"result":{"type":"end"},"_meta":{"runtimeId":"test-runtime"},"streaming":true}',
'{"id":"sub-1","ok":false,"error":{"code":"runtime_error","message":"boom"},"_meta":{"runtimeId":"test-runtime"}}'
])
})
})
@@ -158,7 +158,7 @@ function hostWithWindow(
events,
published,
selectCreatedMobileSessionTabForClient: vi.fn(() => true),
// Stand in for main's layout write so both builds share fakes; main-layout-agent-launch-tabs.test.ts covers the real write.
// Stand in for main's layout write so both builds share fakes.
publishAgentLaunchTabInMainLayout: vi.fn(
(request: Omit<AgentLaunchTabPublishRequest, 'requestId'>) =>
runtime.publishAgentLaunchTab(request)
@@ -1,27 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import type { FsChangeEvent } from '../../../../../shared/file-watch/filesystem-change-event'
import '../../../../../shared/file-watch/filesystem-watch-batch-window'
import { createFileWatchEventBatcher } from './file-watch-event-batcher'
describe('createFileWatchEventBatcher', () => {
it('collapses very large watcher bursts without spreading them onto the stack', () => {
vi.useFakeTimers()
try {
const emit = vi.fn()
const batcher = createFileWatchEventBatcher('worktree-1', emit)
const event: FsChangeEvent = { kind: 'update', absolutePath: '/repo/file.ts' }
const burst = Array.from({ length: 200_000 }, () => event)
expect(() => batcher.push(burst)).not.toThrow()
batcher.flush()
expect(emit).toHaveBeenCalledWith({
type: 'changed',
worktree: 'worktree-1',
events: [{ kind: 'overflow', absolutePath: '/repo/file.ts' }]
})
} finally {
vi.useRealTimers()
}
})
})
@@ -60,38 +60,6 @@ export function registerFederatedAutoReleaseScenarios(harness: AutoReleaseScenar
return dispatchId
}
async function releaseDueOnHost(): Promise<void> {
vi.setSystemTime(Date.now() + GRACE_MS)
await getWorkerTerminalAutoReleaseScheduler(harness.workerRuntime()).releaseDue()
}
async function listFromHome(dispatchId: string) {
const listed = await harness.dispatchHome({
id: 'rpc_remote_list',
authToken: 'coordinator-token',
method: 'orchestration.workerList',
params: { includeRemote: true }
})
if (!listed.ok) {
throw new Error('worker-list failed')
}
const result: unknown = listed.result
const workers =
typeof result === 'object' &&
result !== null &&
'workers' in result &&
Array.isArray(result.workers)
? result.workers
: []
return workers.find(
(worker: unknown) =>
typeof worker === 'object' &&
worker !== null &&
'dispatchId' in worker &&
worker.dispatchId === dispatchId
)?.projection
}
function retainFromHome(dispatchId: string) {
return harness.dispatchHome({
id: 'rpc_remote_retain',
@@ -103,54 +71,6 @@ export function registerFederatedAutoReleaseScenarios(harness: AutoReleaseScenar
})
}
it('converges the home through worker-show after a host-side release', async () => {
const dispatchId = await settleRemotely()
await releaseDueOnHost()
await harness.dispatchHome({
id: 'rpc_remote_show_after_release',
authToken: 'coordinator-token',
method: 'orchestration.workerShow',
params: { dispatch: dispatchId }
})
expect(harness.homeDb().getWorkerDispatch(dispatchId)).toMatchObject({
stage: 'released',
agent_terminal_handle: null
})
})
it('forwards worker-retain to the host so its deadline never fires', async () => {
const dispatchId = await settleRemotely()
await expect(retainFromHome(dispatchId)).resolves.toMatchObject({
ok: true,
result: { state: 'retained', reason: 'user_requested' }
})
await releaseDueOnHost()
expect(harness.remoteCalls()).toContain('orchestration.federationRetain')
expect(harness.workerRuntime().closeTerminal).not.toHaveBeenCalled()
expect(harness.workerDb().getWorkerTerminalResourceByOwner(dispatchId)).toMatchObject({
release_state: 'retained',
auto_release_at: null
})
})
it('holds a host close while its agent works again after worker_done', async () => {
const dispatchId = await settleRemotely()
vi.spyOn(harness.workerRuntime(), 'isWorkerAgentInTurn').mockReturnValue(true)
await releaseDueOnHost()
expect(harness.workerRuntime().closeTerminal).not.toHaveBeenCalled()
expect(harness.workerDb().getWorkerTerminalResourceByOwner(dispatchId)).toMatchObject({
ownership_state: 'owned',
release_state: 'not_requested',
auto_release_at: null
})
})
function holdHostCapture() {
const read = {
handle: 'term_windows_worker',
@@ -184,30 +104,5 @@ export function registerFederatedAutoReleaseScenarios(harness: AutoReleaseScenar
expect(harness.workerDb().getWorkerTerminalArchive(dispatchId)).toBeUndefined()
})
it('keeps manual release when the home predates automatic release', async () => {
harness.setHomeOmitsAutoRelease(true)
const dispatchId = await settleRemotely()
await releaseDueOnHost()
expect(harness.workerDb().getRemoteDispatchAttachment(dispatchId)?.state).toBe('succeeded')
expect(harness.workerDb().getWorkerTerminalResourceByOwner(dispatchId)).toMatchObject({
release_state: 'not_requested',
auto_release_at: null
})
expect(harness.workerRuntime().closeTerminal).not.toHaveBeenCalled()
})
registerHomeAutoReleaseScenarios({ harness, settleRemotely, listFromHome, retainFromHome })
it('keeps worker-retain home-only for a host that predates automatic release', async () => {
harness.setWorkerAdvertisesAutoRelease(false)
const dispatchId = await harness.startRemoteWorker()
await expect(retainFromHome(dispatchId)).resolves.toMatchObject({
ok: true,
result: { state: 'retained', reason: 'no_owned_resource' }
})
expect(harness.remoteCalls()).not.toContain('orchestration.federationRetain')
})
registerHomeAutoReleaseScenarios({ harness, settleRemotely })
}
@@ -8,8 +8,6 @@ import { GRACE_MS } from './federation-auto-release-grace.test-support'
export function registerHomeAutoReleaseScenarios(args: {
harness: AutoReleaseScenarioHarness
settleRemotely: () => Promise<string>
listFromHome: (dispatchId: string) => Promise<unknown>
retainFromHome: (dispatchId: string) => Promise<unknown>
}): void {
const { harness } = args
@@ -1,58 +0,0 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { createRootDispatch } from '../../../../orchestration/db/root-dispatch-test-fixture'
import { createOrchestrationRpcHarness } from '../rpc-test-harness'
import { mapRuntimeError } from '../../../errors'
describe('implicit task-scoped message routing', () => {
const harness = createOrchestrationRpcHarness()
afterEach(() => harness.cleanup())
function setup(sender: 'coordinator' | 'worker' = 'coordinator') {
const state = harness.setup()
const ownTask = state.db.createTask({ spec: 'Sender work' })
const otherRun = state.db.createRun({
objective: 'Other Run',
coordinatorHandle: 'term_other',
coordinatorPaneKey: 'tab_other:leaf_other'
})
const otherTask = state.db.createTask({ runId: otherRun.id, spec: 'Other Run work' })
const from = sender === 'worker' ? 'term_worker' : 'term_coord'
let dispatchId: string | undefined
if (sender === 'worker') {
const paneKey = 'tab_worker:leaf_worker'
dispatchId = createRootDispatch(state.db, ownTask.id, from, paneKey).id
vi.mocked(state.runtime.getTerminalPaneKey).mockImplementation((handle) =>
handle === from ? paneKey : null
)
}
const send = (params: Record<string, unknown> = {}) =>
harness.call(
'orchestration.send',
{ from, type: 'status', subject: 'Task progress', ...params },
state.ctx
)
return { ...state, ownTask, otherTask, otherRun, from, dispatchId, send }
}
it.each(['coordinator', 'worker'] as const)(
'refuses a %s message naming another Run task before writing or waking mail',
async (sender) => {
const { db, runtime, otherTask, otherRun, activeRunId, send } = setup(sender)
const notify = vi.spyOn(runtime, 'notifyMessageArrived')
const error = await send({ payload: JSON.stringify({ taskId: otherTask.id }) }).catch(
(caught: unknown) => caught
)
expect(mapRuntimeError('req', { runtimeId: 'runtime' }, error).error).toMatchObject({
code: 'task_run_mismatch',
message: expect.stringContaining(
`Task ${otherTask.id} belongs to Run ${otherRun.id}, not the inferred Run ${activeRunId}.`
)
})
expect(db.getInbox(100)).toEqual([])
expect(notify).not.toHaveBeenCalled()
expect(db.getTask(otherTask.id)?.status).toBe('ready')
}
)
})
@@ -1,54 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import type { OrcaRuntimeService } from '../../../orca-runtime'
import { RpcDispatcher } from '../../dispatcher'
import { PAIRING_METHODS } from './pairing'
function dispatchPairing(
method: string,
params: unknown,
pairing: NonNullable<Parameters<RpcDispatcher['dispatchStreaming']>[2]>['pairing']
): Promise<Record<string, unknown>> {
return new Promise((resolve) => {
const runtime = { getRuntimeId: () => 'test-runtime' }
const dispatcher = new RpcDispatcher({
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: Pairing handlers use the supplied pairing context; the envelope reads only getRuntimeId.
runtime: runtime as OrcaRuntimeService,
methods: PAIRING_METHODS
})
void dispatcher.dispatchStreaming(
{ id: 'request-1', authToken: '', method, params },
(response) => resolve(JSON.parse(response) as Record<string, unknown>),
{ pairing }
)
})
}
describe('pairing RPC methods', () => {
it('rejects caller-selected identity and authorization metadata', async () => {
const pairing = { getEndpoints: vi.fn(), provisionRelay: vi.fn() }
for (const injected of [
{ relayDeviceId: 'attacker-device' },
{ authorization: { mode: 'relay-basis', basisConnId: 'attacker-basis' } },
{ directAuthId: 'attacker-direct' },
{ acceptedCredentialVersion: 99 }
]) {
await expect(
dispatchPairing(
'pairing.provisionRelay',
{ reqId: 'install-1', newResumeTokenHash: 'A'.repeat(43), ...injected },
pairing
)
).resolves.toMatchObject({ ok: false, error: { code: 'invalid_argument' } })
}
await expect(
dispatchPairing(
'pairing.getEndpoints',
{ installReqId: 'status-1', basisConnId: 'injected' },
pairing
)
).resolves.toMatchObject({ ok: false, error: { code: 'invalid_argument' } })
expect(pairing.provisionRelay).not.toHaveBeenCalled()
expect(pairing.getEndpoints).not.toHaveBeenCalled()
})
})
@@ -1,46 +0,0 @@
import { describe, expect, it } from 'vitest'
import { z } from 'zod'
import type { Repo } from '../../../../../shared/repo-types'
import '../../dispatcher'
import './repo'
import { makeRequest, repoDispatcher } from './repo-rpc.test-fixture'
import '../../../../../shared/protocol-version'
import '../../../../../shared/worktree-runtime-capabilities'
import '../../../../../shared/remote-runtime/remote-runtime-client-capabilities'
import '../../../../../shared/repo-search-limits'
import '../../../../../shared/ssh-target-management'
describe('repo RPC methods', () => {
it('answers repo.list snapshot reads unchanged while the repos stay the same', async () => {
let repos: Repo[] = [
{ id: 'repo-1', path: '/r', displayName: 'api', badgeColor: '#fff', addedAt: 1 }
]
const dispatcher = repoDispatcher({
getRuntimeId: () => 'test-runtime',
listVisibleRepos: () => repos
})
const snapshotIdOf = (reply: unknown) =>
z.object({ snapshotId: z.string() }).parse(reply).snapshotId
const result = async (params?: unknown) => {
const response = await dispatcher.dispatch(makeRequest('repo.list', params))
return response.ok ? response.result : null
}
const legacy = await result()
const first = await result({ afterSnapshotId: null })
const repeat = await result({ afterSnapshotId: snapshotIdOf(first) })
repos = [{ id: 'repo-1', path: '/r', displayName: 'api-2', badgeColor: '#fff', addedAt: 1 }]
const changed = await result({ afterSnapshotId: snapshotIdOf(first) })
expect(legacy).toEqual({ repos: [expect.objectContaining({ displayName: 'api' })] })
expect(first).toEqual({
repos: [expect.objectContaining({ displayName: 'api' })],
snapshotId: snapshotIdOf(first)
})
expect(repeat).toEqual({ unchanged: true, snapshotId: snapshotIdOf(first) })
expect(changed).toMatchObject({ repos: [expect.objectContaining({ displayName: 'api-2' })] })
expect(snapshotIdOf(changed)).not.toBe(snapshotIdOf(first))
})
})
@@ -1,41 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import { RpcDispatcher } from '../../../dispatcher'
import type { RpcRequest } from '../../../core'
import '../../../../orca-runtime'
import type { OrcaRuntimeService } from '../../../../orca-runtime'
import { GITLAB_METHODS } from './gitlab'
import '../../../../../../shared/rpc-contract/gitlab-params'
function makeRequest(method: string, params?: unknown): RpcRequest {
return { id: 'req-1', authToken: 'tok', method, params }
}
describe('gitlab RPC methods', () => {
// Bound excerpts before serialization: WS/relay frames over 1 MiB close the connection (#7732).
it('bounds the job trace before it crosses the transport when logExcerpt is set', async () => {
const noisyTrace = [
'section_start:1699000000:build\r\u001b[0K$ pnpm build',
...Array.from({ length: 400 }, (_, index) => `line ${index}`),
'ERROR: Job failed: exit code 1'
].join('\n')
const runtime = {
getRuntimeId: () => 'test-runtime',
getGitLabRepoJobTrace: vi.fn().mockResolvedValue({ ok: true, trace: noisyTrace })
} as unknown as OrcaRuntimeService
const dispatcher = new RpcDispatcher({ runtime, methods: GITLAB_METHODS })
const raw = await dispatcher.dispatch(
makeRequest('gitlab.jobTrace', { repo: 'id:repo-1', jobId: 99 })
)
const excerpt = await dispatcher.dispatch(
makeRequest('gitlab.jobTrace', { repo: 'id:repo-1', jobId: 99, logExcerpt: true })
)
expect((raw as { result: { trace: string } }).result.trace).toBe(noisyTrace)
const bounded = (excerpt as { result: { trace: string } }).result.trace
expect(bounded).toContain('ERROR: Job failed: exit code 1')
expect(bounded).not.toContain('section_start')
expect(bounded).not.toContain('line 0\n')
})
})
@@ -1,60 +0,0 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import '../../../shared/orchestration/orchestration-session-caller-codes'
import {
ADDRESS_X,
createSessionCallerHarness,
orchestrationRequest,
resultOf,
SESSION_X,
SESSION_Y,
sessionRecord,
type SessionCallerHarness
} from './orchestration-session-caller-test-fixture'
const hostRef = vi.hoisted((): { current: unknown } => ({ current: null }))
vi.mock('../../native-chat/agent-session-wire/host/structured-agent-session-registry', () => ({
getStructuredAgentSessionHost: () => hostRef.current
}))
describe('orchestration.callerShow: a session learns its Orca session ID from the host', () => {
let h: SessionCallerHarness
beforeEach(() => {
h = createSessionCallerHarness(hostRef)
})
afterEach(() => {
h.close()
vi.restoreAllMocks()
})
function callerShow(options: Parameters<typeof orchestrationRequest>[2]) {
return orchestrationRequest('orchestration.callerShow', {}, options)
}
it('gives the menu the Orca session ID each session of a cleared chat acts as', async () => {
const cleared = sessionRecord(SESSION_X)
h.records.set(SESSION_X, {
...cleared,
conversationCommand: {
command: 'clear',
state: 'completed',
replacementSessionId: SESSION_Y,
operationId: 'op',
callerKey: 'caller',
phase: 'committed'
}
})
for (const sessionId of [SESSION_X, SESSION_Y]) {
const shown = resultOf(
await h.dispatch(orchestrationRequest('orchestration.sessionAddress', { sessionId }))
)
const acting = resultOf(await h.dispatch(callerShow({ sessionId })))
// One derivation: the conversation's root, which the successor copies and acts as too.
expect(shown.orcaSessionId).toBe(ADDRESS_X)
expect(acting.caller).toMatchObject({ orcaSessionId: shown.orcaSessionId })
}
})
})
@@ -1,74 +0,0 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import 'zod'
import './core'
import './methods/orchestration/orchestration'
import {
ADDRESS_X,
createSessionCallerHarness,
orchestrationRequest,
idOf,
resultOf,
SESSION_X,
SESSION_Y,
sessionRecord,
type SessionCallerHarness
} from './orchestration-session-caller-test-fixture'
import './orchestration-session-caller'
import '../orchestration/addressing/orchestration-party'
const hostRef = vi.hoisted((): { current: unknown } => ({ current: null }))
vi.mock('../../native-chat/agent-session-wire/host/structured-agent-session-registry', () => ({
getStructuredAgentSessionHost: () => hostRef.current
}))
describe('orchestration session callers at the dispatch entry', () => {
let h: SessionCallerHarness
beforeEach(() => {
h = createSessionCallerHarness(hostRef)
})
afterEach(() => {
h.close()
vi.restoreAllMocks()
})
describe('a declared caller must name the session', () => {
it('accepts a /clear successor naming the address it had before the clear, and no other', async () => {
// Y continued X after a /clear, so X's address is Y's: the lineage root names the chat.
h.records.set(SESSION_X, {
...sessionRecord(SESSION_X),
conversationCommand: {
command: 'clear',
state: 'completed',
replacementSessionId: SESSION_Y,
operationId: 'op',
callerKey: 'caller',
phase: 'committed'
}
})
const run = resultOf(
await h.dispatch(
orchestrationRequest(
'orchestration.runCreate',
{ objective: 'o', from: ADDRESS_X },
{ sessionId: SESSION_Y }
)
)
).run
expect(h.db.getRunRaw(idOf(run))?.coordinator_orca_session_id).toBe(SESSION_X)
const stranger = 'orca_session_id:0b5e2d7c-9a41-4c3e-8f62-7d1a3e5b9c08'
const refused = await h.dispatch(
orchestrationRequest(
'orchestration.runCreate',
{ objective: 'o', from: stranger },
{ sessionId: SESSION_Y }
)
)
expect(refused).toMatchObject({ ok: false, error: { code: 'consumer_fenced' } })
})
})
})
@@ -1,62 +0,0 @@
import { describe, expect, it } from 'vitest'
import { OrcaRuntimeService } from '../orca-runtime'
import type { RpcRequest, RpcResponse } from './core'
import { RpcDispatcher } from './dispatcher'
import { ALL_RPC_METHODS } from './methods/rpc-method-registry'
import type { RpcCallerScope } from './rpc-caller-scope'
const PAIRED: RpcCallerScope = { kind: 'runtime-paired', grants: [] }
function request(method: string, params?: unknown): RpcRequest {
return { id: `req-${method}`, authToken: 'unused', method, params }
}
async function dispatchAs(
scope: RpcCallerScope | undefined,
method: string,
params?: unknown,
runtime = new OrcaRuntimeService()
): Promise<RpcResponse> {
return new RpcDispatcher({ runtime, methods: ALL_RPC_METHODS }).dispatch(
request(method, params),
scope ? { callerScope: scope } : undefined
)
}
function errorCode(response: RpcResponse): string | null {
return response.ok ? null : response.error.code
}
describe('paired runtime clients', () => {
it('cannot drive the desktop without a pairing-time grant', async () => {
const response = await dispatchAs(PAIRED, 'computer.click', { app: 'Finder' })
expect(errorCode(response)).toBe('forbidden')
})
it.each(['pairing.provisionRelay', 'pairing.getEndpoints', 'notifications.registerPush'])(
'are refused pairing and push administration: %s',
async (method) => {
const response = await dispatchAs(PAIRED, method, {})
expect(errorCode(response)).toBe('forbidden')
}
)
it('learn an unregistered method is missing rather than forbidden', async () => {
const response = await dispatchAs(PAIRED, 'computer.methodFromTheFuture', {})
expect(errorCode(response)).toBe('method_not_found')
})
})
describe('a pinned in-process bridge dispatcher', () => {
it('ignores a wider per-call scope', async () => {
const dispatcher = new RpcDispatcher({
runtime: new OrcaRuntimeService(),
methods: ALL_RPC_METHODS,
callerScope: PAIRED
})
const response = await dispatcher.dispatch(request('computer.click', { app: 'Finder' }), {
callerScope: { kind: 'owner' }
})
expect(errorCode(response)).toBe('forbidden')
})
})
@@ -1,55 +0,0 @@
import { existsSync, mkdtempSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
import {
createRuntimeTransportMetadata,
sweepOrphanedRuntimeSockets
} from './runtime-rpc-socket-metadata'
describe('sweepOrphanedRuntimeSockets', () => {
// Use an always-live non-runner pid (POSIX init) to distinguish own-pid skip, live sibling retention and dead sweep.
const SYNTHETIC_OWN_PID = 1
const KNOWN_DEAD_PID = 99999999
it.runIf(process.platform !== 'win32')(
'sweeps dead-pid sockets while retaining own, alive, and non-matching entries',
() => {
const userDataPath = mkdtempSync(join(tmpdir(), 'orca-sweep-'))
const ownPidSocket = join(userDataPath, `o-${SYNTHETIC_OWN_PID}-aaaa.sock`)
const aliveSocket = join(userDataPath, `o-${process.pid}-bbbb.sock`)
const deadSocket = join(userDataPath, `o-${KNOWN_DEAD_PID}-cccc.sock`)
const unrelatedFile = join(userDataPath, 'foo.sock')
writeFileSync(ownPidSocket, '')
writeFileSync(aliveSocket, '')
writeFileSync(deadSocket, '')
writeFileSync(unrelatedFile, '')
sweepOrphanedRuntimeSockets(userDataPath, SYNTHETIC_OWN_PID)
expect(existsSync(ownPidSocket)).toBe(true)
expect(existsSync(aliveSocket)).toBe(true)
expect(existsSync(deadSocket)).toBe(false)
expect(existsSync(unrelatedFile)).toBe(true)
}
)
})
describe('createRuntimeTransportMetadata', () => {
it.runIf(process.platform !== 'win32')(
'keeps the socket path within the macOS sun_path limit for a long userData path',
() => {
const userDataPath = `/Users/someone/${'x'.repeat(130)}/userdata`
const { endpoint } = createRuntimeTransportMetadata(userDataPath, 12345, 'darwin', 'rt')
// macOS listen() returns EINVAL past 103 bytes (sun_path is 104 including NUL).
expect(Buffer.byteLength(endpoint)).toBeLessThanOrEqual(103)
expect(endpoint).toMatch(/^\/tmp\/\.orca-daemon-\d+\/[0-9a-f]{12}\/o-12345-rt\.sock$/)
}
)
})
@@ -1,67 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import {
TerminalStreamOpcode,
decodeTerminalStreamFrame,
encodeTerminalStreamFrame
} from '../../../shared/terminal/stream/terminal-stream-protocol'
import { publishPtyEndpointLoss } from '../terminal/pty-endpoint-loss-signal'
import {
WRITE_UNAVAILABLE_OPCODE,
sendDesktopMultiplexSubscribe,
startDesktopMultiplexSubscribe
} from './terminal-multiplex-test-harness'
async function subscribe(capabilities: Record<string, 1>) {
const harness = startDesktopMultiplexSubscribe()
await vi.waitFor(() => expect(harness.handlers.has(0)).toBe(true))
sendDesktopMultiplexSubscribe(harness.handlers, capabilities)
await vi.waitFor(() =>
expect(
harness.messages.some((message) => JSON.parse(message).result?.type === 'subscribed')
).toBe(true)
)
harness.binaryFrames.splice(0)
return harness
}
const sawWriteUnavailable = (frames: Uint8Array[]): boolean =>
frames.some((frame) => frame[2] === WRITE_UNAVAILABLE_OPCODE)
describe('terminal multiplex daemon endpoint loss notice', () => {
it('tells a pane its daemon endpoint dropped before it types anything', async () => {
const harness = await subscribe({ ackOutput: 1, writeUnavailable: 1, endpointLossNotice: 1 })
publishPtyEndpointLoss('pty-1')
// Push endpoint death immediately; waiting for the next refused keystroke leaves the pane frozen and loses input.
expect(sawWriteUnavailable(harness.binaryFrames)).toBe(true)
})
it('keeps the unprompted frame from a client that reads it as refused input', async () => {
const harness = await subscribe({ ackOutput: 1, writeUnavailable: 1 })
publishPtyEndpointLoss('pty-1')
expect(sawWriteUnavailable(harness.binaryFrames)).toBe(false)
})
it('stops notifying once the stream unsubscribes', async () => {
const harness = await subscribe({ ackOutput: 1, writeUnavailable: 1, endpointLossNotice: 1 })
harness.handlers.get(7)?.(
decodeTerminalStreamFrame(
encodeTerminalStreamFrame({
opcode: TerminalStreamOpcode.Unsubscribe,
streamId: 7,
seq: 1,
payload: new Uint8Array()
})
)!
)
await vi.waitFor(() => expect(harness.handlers.has(7)).toBe(false))
harness.binaryFrames.splice(0)
publishPtyEndpointLoss('pty-1')
expect(sawWriteUnavailable(harness.binaryFrames)).toBe(false)
})
})
@@ -1,71 +0,0 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { OrcaRuntimeService } from '../orca-runtime'
import { RpcDispatcher } from './dispatcher'
import type { RpcRequest } from './core'
import { TERMINAL_METHODS } from './methods/terminal/terminal'
function request(method: string, params: unknown): RpcRequest {
return { id: 'request-1', authToken: 'test-token', method, params }
}
describe('OpenCode guarded terminal send', () => {
afterEach(() => vi.useRealTimers())
it('refuses a marker title left on a shell without writing notes', async () => {
vi.useFakeTimers()
const write = vi.fn(() => true)
const runtime = new OrcaRuntimeService()
runtime.setPtyController({
write,
kill: () => true,
getForegroundProcess: async () => 'zsh'
})
runtime.attachWindow(1)
runtime.syncWindowGraph(1, {
tabs: [
{
tabId: 'tab-1',
worktreeId: 'repo-1::/tmp/worktree',
title: 'OC | zsh',
activeLeafId: 'pane-1',
layout: null
}
],
leaves: [
{
tabId: 'tab-1',
worktreeId: 'repo-1::/tmp/worktree',
leafId: 'pane-1',
paneRuntimeId: 1,
ptyId: 'pty-1',
paneTitle: 'OC | zsh'
}
]
})
const [terminal] = (await runtime.listTerminals()).terminals
const dispatcher = new RpcDispatcher({ runtime, methods: TERMINAL_METHODS })
await expect(
dispatcher.dispatch(request('terminal.agentStatus', { terminal: terminal.handle }))
).resolves.toMatchObject({
ok: true,
result: { agentStatus: { isRunningAgent: false, status: null } }
})
const send = dispatcher.dispatch(
request('terminal.send', {
terminal: terminal.handle,
text: '$(touch should-not-run)',
requireAgentStatus: 'sendable',
client: { id: 'desktop-1', type: 'desktop' }
})
)
await vi.advanceTimersByTimeAsync(1_500)
await expect(send).resolves.toMatchObject({
ok: true,
result: { send: { accepted: false, bytesWritten: 0, refusedReason: 'no-agent' } }
})
expect(write).not.toHaveBeenCalled()
})
})
@@ -1,35 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { RuntimeWorktreePsResult } from '../../../shared/runtime-worktree-contracts'
import { resolveWorktreeCatalogSnapshot } from './worktree-catalog-snapshot'
function result(totalCount: number): RuntimeWorktreePsResult {
return { worktrees: [], totalCount, truncated: false }
}
describe('resolveWorktreeCatalogSnapshot', () => {
it('returns unchanged only when the caller owns the exact current snapshot', () => {
const first = resolveWorktreeCatalogSnapshot(result(1), { afterSnapshotId: null })
expect(first).toMatchObject({ totalCount: 1 })
const snapshotId = first.snapshotId
expect(resolveWorktreeCatalogSnapshot(result(1), { afterSnapshotId: snapshotId })).toEqual({
unchanged: true,
snapshotId
})
expect(resolveWorktreeCatalogSnapshot(result(1), { afterSnapshotId: 'unknown' })).toEqual({
...result(1),
snapshotId
})
})
it('derives ids from content alone, so memo state cannot change the answer', () => {
// Identical catalogs must yield identical ids whether the memo is warm or was just
// displaced — that is what makes the memo droppable and restarts safe.
const warm = resolveWorktreeCatalogSnapshot(result(1), { afterSnapshotId: null }).snapshotId
resolveWorktreeCatalogSnapshot(result(99), { afterSnapshotId: null })
expect(resolveWorktreeCatalogSnapshot(result(1), { afterSnapshotId: null }).snapshotId).toBe(
warm
)
})
})
@@ -1,62 +0,0 @@
// Layout-owner build, no window: an agent launch's early tab in a workspace main owns is written by
// main, a retry finds it, and a withdrawn launch pane is taken back by main.
import { afterEach, describe, expect, it, vi } from 'vitest'
import {
WORKTREE_ID,
setupMainOwnedWorkspace
} from '../terminal/layout/main-owned-workspace-runtime-fixture'
import { publishAgentLaunchTabEarly } from '../rpc/methods/agent-launch/agent-launch-tab-publication'
import { resetAgentLaunchPanesForTests } from '../../agent-launch/agent-launch-pane-attachment'
vi.mock('../../../shared/layout-owner-switch', () => ({ ORCA_LAYOUT_OWNER_IS_MAIN: true }))
const NEW_TAB = '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
const NEW_LEAF = '3f2504e0-4f89-41d3-9a0c-0305e82c3301'
afterEach(() => resetAgentLaunchPanesForTests())
function launchHost() {
const fixture = setupMainOwnedWorkspace()
Object.assign(fixture.runtime, {
showTerminalWorkspaceLaunchScope: async () => ({ id: WORKTREE_ID, path: '/workspace' })
})
const context = { runtime: fixture.runtime }
const launch = () =>
publishAgentLaunchTabEarly(
{
agent: 'claude',
target: { kind: 'existing', worktree: `id:${WORKTREE_ID}` },
paneKey: `${NEW_TAB}:${NEW_LEAF}`,
surface: 'terminal'
},
context
)
const tabIds = () => fixture.session().tabsByWorktree[WORKTREE_ID]?.map((tab) => tab.id) ?? []
return { fixture, launch, tabIds }
}
describe("an agent launch's early tab in a workspace main owns, with no window", () => {
it('takes the tab back when nothing will run in it', async () => {
const { launch, tabIds } = launchHost()
const early = await launch()
// Never admitted: the launch made this tab, and nothing will ever run in it.
early?.finish('agent_launch_refused')
await vi.waitFor(() => expect(tabIds()).not.toContain(NEW_TAB))
})
it('keeps a tab a retry found, since that launch made none', async () => {
const { launch, tabIds } = launchHost()
await launch()
resetAgentLaunchPanesForTests()
const retry = await launch()
retry?.finish('agent_launch_refused')
await Promise.resolve()
expect(tabIds()).toContain(NEW_TAB)
})
})
@@ -1,62 +0,0 @@
// A windowless server's held session.tabs rows across main's layout commits: what a commit keeps,
// what it pushes, and which writes the row writer may skip.
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../../shared/runtime-session-contracts'
import {
HEADLESS_LEAF_ID,
TEST_WORKTREE_ID
} from '../orca-runtime-tests/orca-runtime-test-fixtures.spec'
import {
SURFACE_TAB_ID,
surfaceRuntime
} from '../terminal/surface/terminal-surface-replies.test-fixture'
import './session-tabs-layout-moves.test-fixture'
vi.mock('../../../shared/layout-owner-switch', () => ({ ORCA_LAYOUT_OWNER_IS_MAIN: true }))
type Runtime = ReturnType<typeof surfaceRuntime>['runtime']
const held = (runtime: Runtime) => runtime.mobileSessionTabsByWorktree.get(TEST_WORKTREE_ID)
async function windowlessRows(runtime: Runtime): Promise<void> {
runtime.syncWindowGraph(HEADLESS_RUNTIME_WINDOW_ID, { tabs: [], leaves: [] })
await runtime.listMobileSessionTabs(`id:${TEST_WORKTREE_ID}`)
await vi.runAllTimersAsync()
}
describe('held session.tabs rows across layout commits (switch on)', () => {
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
it('a pane main rebound takes the new terminal once it connects, with no commit', async () => {
const { runtime, bindPane } = surfaceRuntime()
await windowlessRows(runtime)
const rowId = `${SURFACE_TAB_ID}::${HEADLESS_LEAF_ID}`
const ptyOf = () => {
const row = held(runtime)?.tabs.find((tab) => tab.id === rowId)
return row?.type === 'terminal' ? row.ptyId : undefined
}
await bindPane({
worktreeId: TEST_WORKTREE_ID,
tabId: SURFACE_TAB_ID,
leafId: HEADLESS_LEAF_ID,
ptyId: 'pty-new'
})
await vi.runAllTimersAsync()
// Not running yet: the running terminal stands.
expect(ptyOf()).toBe('pty-a')
runtime.registerPty('pty-new', TEST_WORKTREE_ID, null, {
tabId: SURFACE_TAB_ID,
leafId: HEADLESS_LEAF_ID
})
await vi.runAllTimersAsync()
expect(ptyOf()).toBe('pty-new')
})
})
@@ -1,53 +0,0 @@
import '../../orca-runtime-tests/orca-runtime-test-lifecycle.spec'
import { describe, expect, it, vi } from 'vitest'
import {
createRuntime,
syncSinglePty,
TEST_WORKTREE_ID
} from '../../orca-runtime-tests/orca-runtime-test-fixtures.spec'
import { electronMocks } from '../../orca-runtime-test-mocks/setup.spec'
import { createMobileCreateTestNotifier } from '../../orca-runtime-tests/orca-runtime-test-scenario-builders.spec'
async function createPaneTitleRuntime() {
electronMocks.BrowserWindow.fromId.mockReturnValue({ isDestroyed: () => false })
const runtime = createRuntime()
syncSinglePty(runtime)
const setPaneTitle = vi.fn(() => true)
const renameTerminal = vi.fn()
const notifier = { ...createMobileCreateTestNotifier(vi.fn()), setPaneTitle, renameTerminal }
runtime.setNotifier(notifier)
const handle = (await runtime.listTerminals()).terminals[0].handle
return { runtime, handle, setPaneTitle, renameTerminal, notifier }
}
describe('pane-scoped terminal title', () => {
it('rejects stale handles after a leaf is replaced, even if its numeric id is reused', async () => {
const { runtime, handle, setPaneTitle } = await createPaneTitleRuntime()
runtime.syncWindowGraph(1, {
tabs: [
{
tabId: 'tab-1',
worktreeId: TEST_WORKTREE_ID,
title: 'Codex',
activeLeafId: 'replacement',
layout: null
}
],
leaves: [
{
tabId: 'tab-1',
worktreeId: TEST_WORKTREE_ID,
leafId: 'replacement',
paneRuntimeId: 1,
ptyId: 'pty-2',
paneTitle: null
}
]
})
await expect(runtime.setPaneTitle(handle, 'WRONG')).rejects.toThrow('terminal_handle_stale')
await expect(runtime.setPaneTitle('unknown-handle', 'WRONG')).rejects.toThrow(
'terminal_handle_stale'
)
expect(setPaneTitle).not.toHaveBeenCalled()
})
})
@@ -1,53 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { SshConnection } from './ssh-connection'
import {
adoptSshConnection,
isSshConnectionSolelyOwnedBy,
recordSshConnectionOpened,
runAttributedToSshOwner
} from './ssh-connection-attribution'
import { unusedSshConnection } from '../../managed-server/testing/managed-host-transport.test-fixture'
const transport = (): SshConnection => unusedSshConnection()
describe('SSH transport attribution', () => {
it('lets a cancelled attempt own only the transport its own work opened', async () => {
const attempt = Symbol('a')
const opened = transport()
await runAttributedToSshOwner(attempt, async () => {
await Promise.resolve()
recordSshConnectionOpened(opened)
})
const unrelated = transport()
recordSshConnectionOpened(unrelated)
expect(isSshConnectionSolelyOwnedBy(opened, attempt)).toBe(true)
expect(isSshConnectionSolelyOwnedBy(unrelated, attempt)).toBe(false)
})
it('gives the transport up once a completed replacement connect adopts it', async () => {
const stale = Symbol('stale')
const replacement = Symbol('replacement')
const opened = transport()
await runAttributedToSshOwner(stale, async () => recordSshConnectionOpened(opened))
adoptSshConnection(opened, replacement)
expect(isSshConnectionSolelyOwnedBy(opened, stale)).toBe(false)
})
it('gives the transport up once a managed tunnel outside any attempt relies on it', async () => {
const stale = Symbol('stale')
const opened = transport()
await runAttributedToSshOwner(stale, async () => recordSshConnectionOpened(opened))
adoptSshConnection(opened)
expect(isSshConnectionSolelyOwnedBy(opened, stale)).toBe(false)
})
it('keeps the transport the attempt’s own tunnel adopted inside its decision', async () => {
const attempt = Symbol('a')
const opened = transport()
await runAttributedToSshOwner(attempt, async () => {
recordSshConnectionOpened(opened)
adoptSshConnection(opened)
})
expect(isSshConnectionSolelyOwnedBy(opened, attempt)).toBe(true)
})
})
@@ -1,70 +0,0 @@
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { getSetupTrustContent } from '../../shared/orca-hook-setup-config'
import '../../renderer/src/runtime/repo-hooks/orca-hook-trust'
import '../runtime/repositories/runtime-repository-hooks-commands'
import { loadHooks } from './hooks'
import { hashOrcaHookTrustContent } from './created-worktree-setup-trust'
// The prompt hashes the primary checkout's orca.yaml; the host hashes the created worktree's.
// Same committed file => same hash, whatever the checkout did to line endings or a BOM.
const SETUP_YAML = [
'base: &base',
' title: Dev server',
'scripts:',
' setup: |',
' pnpm install ',
' \techo "tabbed"',
'',
' echo "ünïcødé ✓"',
'defaultTabs:',
' - <<: *base',
' command: >',
' pnpm dev',
' --port 3000',
' - title: Notes',
' - command: "printf \'%s\\n\' quoted"',
'issueCommand: gh issue view',
'scripts_unrelated: ignored',
''
].join('\n')
const dirs: string[] = []
function checkout(content: string): string {
const dir = mkdtempSync(join(tmpdir(), 'orca-setup-parity-'))
dirs.push(dir)
writeFileSync(join(dir, 'orca.yaml'), content)
return dir
}
beforeEach(() => {
dirs.length = 0
})
afterEach(() => {
vi.unstubAllGlobals()
for (const dir of dirs) {
rmSync(dir, { recursive: true, force: true })
}
})
describe('approved setup hash parity between the trust prompt and the host', () => {
it('pins the digest so a format change, which would invalidate saved automation approvals, is deliberate', () => {
expect(getSetupTrustContent(loadHooks(checkout(SETUP_YAML)))).toBe(
[
'pnpm install \n\techo "tabbed"\n\necho "ünïcødé ✓"',
'# defaultTabs[1] Dev server\npnpm dev --port 3000',
// The double-quoted "\n" escape is a real newline in YAML, on both sides.
"# defaultTabs[3]\nprintf '%s\n' quoted"
].join('\n\n')
)
expect(hashOrcaHookTrustContent(getSetupTrustContent(loadHooks(checkout(SETUP_YAML))))).toBe(
PINNED_SETUP_HASH
)
})
})
const PINNED_SETUP_HASH = '112aac76dbc70758498c2b87a2dc42e77f7ce366a5b611749ec38b6757681593'
@@ -30,19 +30,4 @@ describe.skipIf(process.platform === 'win32')('archive hook deadline', () => {
expect(result.exitCode).toBeUndefined()
expect(result.output).toContain('timed out')
}, 20_000)
it('settles at the deadline even when the hook refuses to die', async () => {
const started = Date.now()
const result = await runArchive("trap '' TERM; sleep 30")
expect(result.success).toBe(false)
expect(Date.now() - started).toBeLessThan(10_000)
}, 20_000)
it('passes a hook that finishes inside its deadline', async () => {
await expect(runArchive('echo archived')).resolves.toMatchObject({ success: true })
})
it('reports an observed non-zero exit as the exit it is', async () => {
await expect(runArchive('exit 23')).resolves.toMatchObject({ success: false, exitCode: 23 })
})
})
@@ -1,49 +0,0 @@
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import '../../../shared/automations/scheduling/automation-schedule-occurrences'
import type { WslHostAutomationDue } from './wsl-host-automation-wake'
import {
readWslHostAutomationWakes,
writeWslHostAutomationWakes
} from './wsl-host-automation-wake-store'
const HOUR = 60 * 60 * 1000
const HOURLY = '0 * * * *'
/** By default the host was last seen ready an hour before the run, so the run was missed. */
function due(
nextRunAt: number,
graceHours = 12,
lastSeenReadyAt = nextRunAt - HOUR
): WslHostAutomationDue {
return {
nextRunAt,
wakeUntil: nextRunAt + graceHours * HOUR,
schedules: [{ rrule: HOURLY, dtstart: 0, missedRunGraceMinutes: graceHours * 60 }],
lastSeenReadyAt
}
}
describe('persisted wake times', () => {
let dir: string | null = null
afterEach(() => {
if (dir) {
rmSync(dir, { recursive: true, force: true })
}
})
it('round-trips and drops malformed entries', () => {
dir = mkdtempSync(join(tmpdir(), 'orca-wsl-wake-'))
writeWslHostAutomationWakes(dir, { a: due(1) })
expect(readWslHostAutomationWakes(dir)).toEqual({ a: due(1) })
writeFileSync(
join(dir, 'wsl-host-automation-wakes.json'),
JSON.stringify({ b: { nextRunAt: 1 } })
)
expect(readWslHostAutomationWakes(dir)).toEqual({})
expect(readWslHostAutomationWakes(join(dir, 'missing'))).toEqual({})
})
})
@@ -1,62 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
const { dispatchMock, closeBrowserPageMock, storeState } = vi.hoisted(() => {
const value: Record<string, unknown> = {}
return { dispatchMock: vi.fn(), closeBrowserPageMock: vi.fn(), storeState: { value } }
})
vi.mock('@/store', () => ({ useAppStore: { getState: () => storeState.value } }))
vi.mock('@/lib/workspace/tabs/workspace-tab-commands', () => ({
dispatchWorkspaceTabCommand: dispatchMock
}))
import { handleGuestWindowCloseMessage } from './browser-page-window-close'
import { BROWSER_GUEST_WINDOW_CLOSE_CHANNEL } from '../../../../../shared/browser-guest-window-close'
function seedTab(
pageId: string,
isPinned = false,
siblingPageIds: string[] = [],
browserAnnotationsByPageId: Record<string, unknown[]> = {}
): void {
storeState.value = {
closeBrowserPage: closeBrowserPageMock,
browserAnnotationsByPageId,
browserTabsByWorktree: { 'wt-1': [{ id: 'ws-1' }] },
browserPagesByWorkspace: { 'ws-1': [{ id: pageId }, ...siblingPageIds.map((id) => ({ id }))] },
unifiedTabsByWorktree: {
'wt-1': [{ id: 'tab-1', contentType: 'browser', entityId: 'ws-1', isPinned }]
}
}
}
function closeFrom(pageId: string, history: { back: boolean; forward: boolean }): void {
const webview = { canGoBack: () => history.back, canGoForward: () => history.forward }
handleGuestWindowCloseMessage(pageId, webview, { channel: BROWSER_GUEST_WINDOW_CLOSE_CHANNEL })
}
describe('window.close() from a browser page', () => {
beforeEach(() => {
dispatchMock.mockReset()
closeBrowserPageMock.mockReset()
})
it('never closes a pinned tab', () => {
seedTab('page-d', true)
closeFrom('page-d', { back: false, forward: false })
expect(dispatchMock).not.toHaveBeenCalled()
})
it('never discards unsent notes', () => {
seedTab('page-n', false, [], { 'page-n': [{ id: 'note-1' }] })
closeFrom('page-n', { back: false, forward: false })
expect(dispatchMock).not.toHaveBeenCalled()
expect(closeBrowserPageMock).not.toHaveBeenCalled()
})
it('closes only the calling page when its Orca tab holds other pages', () => {
seedTab('page-e', false, ['page-sibling'])
closeFrom('page-e', { back: false, forward: false })
expect(closeBrowserPageMock).toHaveBeenCalledWith('page-e')
expect(dispatchMock).not.toHaveBeenCalled()
})
})
@@ -1,47 +0,0 @@
import { afterEach, expect, it, vi } from 'vitest'
import type * as ConnectionOwnerModule from '@/lib/workspace/ownership/connection-owner-resolution'
// A workspace this computer owns.
vi.mock('@/lib/workspace/ownership/connection-owner-resolution', async (importOriginal) => ({
...(await importOriginal<typeof ConnectionOwnerModule>()),
getConnectionIdFromState: () => null,
getConnectionIdForFileFromState: () => null
}))
vi.mock('@/lib/files/access/user-opened-local-path', () => ({
statUserOpenedPath: vi.fn().mockResolvedValue({ isDirectory: false, escapesWorktree: false })
}))
import { useAppStore } from '@/store'
import { editorTabFileAccess } from '@/lib/files/access/local-file-access'
import { statUserOpenedPath } from '@/lib/files/access/user-opened-local-path'
import { makeWorktree } from '@/store/slices/worktrees/worktree.test-fixture'
import { openBrowserFileSource } from './browser-file-editor-open'
const initialState = useAppStore.getInitialState()
afterEach(() => {
useAppStore.setState(initialState, true)
vi.clearAllMocks()
})
it('keeps user-file access when a previewed symlink escapes the workspace', async () => {
const filePath = '/repo/docs-link/report.html'
const openFile = vi.fn()
useAppStore.setState({
openFile,
worktreesByRepo: {
repo: [makeWorktree({ id: 'wt-1', repoId: 'repo', path: '/repo', hostId: 'local' })]
}
})
vi.mocked(statUserOpenedPath).mockResolvedValueOnce({
isDirectory: false,
escapesWorktree: true
})
await openBrowserFileSource('wt-1', filePath)
const opened = openFile.mock.calls[0][0]
expect(opened).toMatchObject({ filePath, relativePath: filePath, mode: 'edit' })
expect(editorTabFileAccess(useAppStore.getState(), opened)).toEqual({ kind: 'user-file' })
})
@@ -1,58 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { SpeechModelManifest, SpeechModelState } from '../../../../shared/speech-types'
import { findSpeechModelUpdateTarget } from './speech-model-update-target'
function model(id: string, extra: Partial<SpeechModelManifest> = {}): SpeechModelManifest {
return {
id,
label: id,
type: 'transducer',
provider: 'local',
language: 'en',
languages: ['en'],
sampleRate: 16000,
streaming: false,
...extra
}
}
const catalog = [
model('parakeet'),
model('nemotron'),
model('zipformer-ko', { replacedBy: 'nemotron' }),
model('gpt', { provider: 'openai' })
]
function target(sttModel: string, states: SpeechModelState[], enabled = true) {
const found = findSpeechModelUpdateTarget({ enabled, sttModel }, catalog, states)
return found && { model: found.model.id, retired: found.retired?.id }
}
describe('findSpeechModelUpdateTarget', () => {
it('offers the update when only the old files of the selected model are on disk', () => {
const states: SpeechModelState[] = [
{ id: 'parakeet', status: 'not-downloaded', needsUpdate: true }
]
expect(target('parakeet', states)).toEqual({ model: 'parakeet', retired: undefined })
expect(target('parakeet', states, false)).toBeNull()
})
it('offers the replacement when the retired model it replaced is still downloaded', () => {
const states: SpeechModelState[] = [
{ id: 'nemotron', status: 'not-downloaded' },
{ id: 'zipformer-ko', status: 'ready' }
]
expect(target('nemotron', states)).toEqual({ model: 'nemotron', retired: 'zipformer-ko' })
expect(
target('nemotron', [
{ id: 'nemotron', status: 'ready' },
{ id: 'zipformer-ko', status: 'ready' }
])
).toBeNull()
})
it('stays hidden for cloud models and for people who never downloaded one', () => {
expect(target('gpt', [{ id: 'zipformer-ko', status: 'ready' }])).toBeNull()
expect(target('nemotron', [{ id: 'nemotron', status: 'not-downloaded' }])).toBeNull()
})
})
@@ -1,54 +0,0 @@
// @vitest-environment happy-dom
import { act, cleanup, fireEvent, render } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { StoppedWslHost } from '../wsl-host-stopped/use-stopped-wsl-host'
import { EditorFileLoadErrorView } from './EditorFileLoadErrorView'
const mocks = vi.hoisted(() => {
const stopped: { current: StoppedWslHost | null } = { current: null }
return {
stopped,
start: vi.fn<(environmentId: string) => Promise<boolean>>()
}
})
vi.mock('../wsl-host-stopped/use-stopped-wsl-host', () => ({
useStoppedWslHost: (worktreeId: string | undefined) =>
worktreeId === 'wt-wsl' ? mocks.stopped.current : null
}))
vi.mock('@/runtime/hosts/wsl/wsl-host-user-start', () => ({
startWslHostAndReloadProjects: mocks.start
}))
afterEach(() => {
cleanup()
mocks.stopped.current = null
mocks.start.mockReset()
})
describe('EditorFileLoadErrorView on a stopped WSL host', () => {
it('offers Start instead of the read error, and reloads without a wake once started', async () => {
mocks.stopped.current = { environmentId: 'wsl:ubuntu', distro: 'Ubuntu' }
mocks.start.mockResolvedValue(true)
const onRetry = vi.fn()
const onHostStarted = vi.fn()
const view = render(
<EditorFileLoadErrorView
message="The server isn't answering"
worktreeId="wt-wsl"
onRetry={onRetry}
onHostStarted={onHostStarted}
/>
)
expect(view.queryByText('Unable to load file')).toBeNull()
expect(view.getByText('Ubuntu is stopped')).toBeTruthy()
expect(mocks.start).not.toHaveBeenCalled()
await act(async () => fireEvent.click(view.getByRole('button', { name: 'Start' })))
expect(mocks.start).toHaveBeenCalledWith('wsl:ubuntu')
// Retry asks to wake the distro; after Start the reload must not.
expect(onHostStarted).toHaveBeenCalledTimes(1)
expect(onRetry).not.toHaveBeenCalled()
})
})
@@ -1,56 +0,0 @@
// @vitest-environment happy-dom
import { cleanup, fireEvent, render, waitFor } from '@testing-library/react'
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { getDefaultSettings } from '../../../../shared/constants'
import { useAppStore } from '@/store'
import { usePluginPreviewRequestStore } from '@/store/plugins/navigation/plugin-preview-request'
import { PluginFileTypeSuggestion } from './PluginFileTypeSuggestion'
const suggestForFileType = vi.fn()
const updateSettings = vi.fn().mockResolvedValue(undefined)
const openSettingsTarget = vi.fn()
const openSettingsPage = vi.fn()
beforeEach(() => {
suggestForFileType.mockResolvedValue({
marketplaceSourceId: 'official',
pluginKey: 'stablyai.orca-typst',
fileType: 'typ',
name: 'Typst'
})
vi.stubGlobal('api', { plugins: { suggestForFileType } })
useAppStore.setState({
settings: { ...getDefaultSettings('/tmp'), pluginSystemEnabled: true },
updateSettings,
openSettingsTarget,
openSettingsPage
})
})
afterEach(() => {
cleanup()
vi.unstubAllGlobals()
vi.clearAllMocks()
usePluginPreviewRequestStore.setState({ request: null })
})
it('keeps "Not now" scoped to the file type when the same editor switches files', async () => {
suggestForFileType.mockImplementation(async (fileType: string) => ({
marketplaceSourceId: 'official',
pluginKey: `samples.${fileType}`,
fileType,
name: `Plugin ${fileType}`
}))
const view = render(<PluginFileTypeSuggestion filePath="a.foo" />)
fireEvent.click(await view.findByRole('button', { name: 'Not now' }))
expect(view.queryByRole('status')).toBeNull()
view.rerender(<PluginFileTypeSuggestion filePath="a.bar" />)
expect(await view.findByText('A plugin can open .bar files: Plugin bar')).toBeTruthy()
fireEvent.click(view.getByRole('button', { name: 'Not now' }))
suggestForFileType.mockClear()
view.rerender(<PluginFileTypeSuggestion filePath="a.foo" />)
await waitFor(() => expect(suggestForFileType).not.toHaveBeenCalled())
expect(view.queryByRole('status')).toBeNull()
})
@@ -1,37 +0,0 @@
import { describe, expect, it, afterEach, vi } from 'vitest'
import { getRuntimeTargetForWorktreeOwner } from '@/lib/files/access/file-owner-runtime-target'
describe('shouldUploadRemoteEditorFileDrop', () => {
it('uses the worktree owner runtime instead of the focused runtime', () => {
expect(
getRuntimeTargetForWorktreeOwner(
{
settings: { activeRuntimeEnvironmentId: 'focused-runtime' },
repos: [{ id: 'repo-1', connectionId: null, executionHostId: 'runtime:owner-runtime' }],
worktreesByRepo: { 'repo-1': [{ id: 'wt-1', repoId: 'repo-1' }] }
},
'wt-1'
)
).toEqual({ kind: 'environment', environmentId: 'owner-runtime' })
})
})
const { rejectAppStoreAccess } = vi.hoisted(() => ({
rejectAppStoreAccess: vi.fn(() => {
throw new Error('Pure helper tests must not access the app store')
})
}))
vi.mock('@/store', () => ({
useAppStore: Object.assign(rejectAppStoreAccess, {
getState: rejectAppStoreAccess,
getInitialState: rejectAppStoreAccess,
setState: rejectAppStoreAccess,
subscribe: rejectAppStoreAccess
})
}))
afterEach(() => {
expect(rejectAppStoreAccess).not.toHaveBeenCalled()
})
@@ -1,72 +0,0 @@
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
const mocks = vi.hoisted(() => ({
readRuntimeFileContent: vi.fn(),
runtimePathsExist: vi.fn()
}))
vi.mock('@/runtime/files/reads/runtime-file-read-client', () => ({
readRuntimeFileContent: mocks.readRuntimeFileContent
}))
vi.mock('@/runtime/files/metadata/runtime-path-existence-batch', () => ({
runtimePathsExist: mocks.runtimePathsExist
}))
vi.mock('@/lib/workspace/ownership/connection-context', () => ({
getConnectionIdForFile: () => undefined
}))
vi.mock('@/lib/files/access/file-owner-runtime-target', () => {
const owner = { kind: 'environment', environmentId: 'env-1' }
return {
getRuntimeTargetForFileOwner: () => owner,
requireRuntimeTargetForFileOwner: () => owner
}
})
import { createTestStore } from '@/store/testing/app-store-test-fixture'
import { attachRestoredTabConflictScan } from './editor-restored-tab-conflict-scan'
import { getDiskBaselineSignature } from '../../../../../shared/file-write/disk-baseline-signature'
const FILE = '/repo/a.ts'
let store: ReturnType<typeof createTestStore>
let detach: () => void
// A server's file is named by its owned id, not its path.
let fileId: string
const tab = () => store.getState().openFiles.find((file) => file.id === fileId)!
beforeEach(() => {
vi.useFakeTimers()
vi.clearAllMocks()
store = createTestStore()
fileId = store.getState().openFile({
filePath: FILE,
relativePath: 'a.ts',
worktreeId: 'wt-1',
runtimeEnvironmentId: 'env-1',
language: 'typescript',
mode: 'edit'
})
store.getState().setEditorDraft(fileId, 'unsaved')
store.getState().markFileDirty(fileId, true)
store.getState().setLastKnownDiskSignature(fileId, getDiskBaselineSignature('v1'))
})
afterEach(() => {
detach()
vi.useRealTimers()
})
it('marks a dirty runtime-owned tab deleted when its host says the file is gone', async () => {
mocks.readRuntimeFileContent.mockRejectedValue(new Error('read failed'))
mocks.runtimePathsExist.mockResolvedValue([{ exists: false }])
detach = attachRestoredTabConflictScan(store)
await vi.advanceTimersByTimeAsync(0)
expect(mocks.runtimePathsExist).toHaveBeenCalledWith(
expect.objectContaining({ worktreePath: '/repo' }),
[FILE],
undefined,
{ codedAbsenceOnly: true }
)
expect(tab().externalMutation).toBe('deleted')
})
@@ -1,11 +1,7 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { describe, expect, it } from 'vitest'
import './markdown-preview-search'
import { findTextMatchRanges } from '../../../../lib/text-search/text-match-ranges'
afterEach(() => {
vi.restoreAllMocks()
})
describe('case-insensitive Markdown search offsets', () => {
it.each([
{ character: 'İ', first: 9, second: 18 },
@@ -18,17 +14,4 @@ describe('case-insensitive Markdown search offsets', () => {
{ start: second, end: second + 6 }
])
})
it('preserves whole code-point ranges for lone surrogate queries', () => {
const text = 'plain😊plain'
expect(findTextMatchRanges(text, '\ud83d')).toEqual([{ start: 5, end: 7 }])
expect(findTextMatchRanges(text, '\ude0a')).toEqual([{ start: 5, end: 7 }])
})
it('keeps character-wise Greek sigma casing in a Unicode document', () => {
expect(findTextMatchRanges('AΣ Aς Aσ', 'aσ')).toEqual([
{ start: 0, end: 2 },
{ start: 6, end: 8 }
])
})
})
@@ -3,27 +3,10 @@ import './markdown-preview-search'
import { findTextMatchRanges } from '../../../../lib/text-search/text-match-ranges'
describe('whole-word search around combining marks', () => {
it('does not match a Devanagari word inside a longer word ending in a vowel sign', () => {
expect(findTextMatchRanges('किताबें किताब', 'किताब', { wholeWord: true })).toEqual([
{ start: 8, end: 13 }
])
})
it('finds a complete decomposed accented word and preserves source code-unit offsets', () => {
const text = 'café cafe caféine'
expect(findTextMatchRanges(text, 'café', { wholeWord: true })).toEqual([{ start: 0, end: 5 }])
expect(findTextMatchRanges(text, 'cafe', { wholeWord: true })).toEqual([{ start: 6, end: 10 }])
expect(findTextMatchRanges(text, 'cafe')).toHaveLength(3)
})
it.each([
['⚠️Warning here', 'Warning'],
['✔️Done', 'Done'],
['1️⃣Step', 'Step']
])('matches a whole word right after an emoji presentation sequence in %s', (text, query) => {
const start = text.indexOf(query)
expect(findTextMatchRanges(text, query, { wholeWord: true })).toEqual([
{ start, end: start + query.length }
])
})
})
@@ -3,14 +3,6 @@ import './markdown-preview-search'
import { findTextMatchRanges } from '../../../../lib/text-search/text-match-ranges'
describe('findTextMatchRanges', () => {
it('folds uppercase Greek queries the same way as the indexed text', () => {
expect(findTextMatchRanges('ΟΣ οσ ος', 'ΟΣ')).toEqual([
{ start: 0, end: 2 },
{ start: 3, end: 5 }
])
expect(findTextMatchRanges('ΟΣ οσ', 'ΟΣ', { matchCase: true })).toEqual([{ start: 0, end: 2 }])
})
it('checks whole-word boundaries around astral letters by code point', () => {
const text = '𐐀cat cat𐐀 cat'
@@ -1,45 +0,0 @@
// @vitest-environment happy-dom
import { cleanup, render, screen } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { IpynbCellOutputs } from '../outputs/IpynbCellOutputs'
import type { IpynbCell, IpynbOutput } from './ipynb-parse'
vi.mock('@/i18n/i18n', () => ({
i18n: { language: 'en' },
translate: (_key: string, fallback: string) => fallback
}))
vi.mock('@/hooks/use-document-dark-theme', () => ({ useDocumentDarkTheme: () => true }))
vi.mock('@/lib/editor/monaco/monaco-setup', () => ({ monaco: {} }))
vi.mock('../../MonacoCodeExcerpt', () => ({
useMonacoColorizedLines: () => []
}))
function cell(kind: IpynbCell['kind'], source: string, outputs: IpynbOutput[] = []): IpynbCell {
return { id: 'cell-1', kind, language: 'python', source, executionCount: 1, outputs }
}
afterEach(cleanup)
describe('notebook outputs', () => {
it('sandboxes HTML output behind a no-network CSP and strips scripts', () => {
render(
<IpynbCellOutputs
cell={cell('code', 'html', [
{
kind: 'display',
outputType: 'display_data',
executionCount: null,
items: [{ mime: 'text/html', value: '<script>alert(1)</script><b>safe</b>' }]
}
])}
/>
)
const frame = screen.getByTitle('Notebook HTML output')
const source = frame.getAttribute('srcdoc') ?? ''
expect(frame.getAttribute('sandbox')).toBe('')
expect(source).toContain("default-src 'none'; img-src data:")
expect(source).not.toContain('<script')
expect(source).toContain('<b>safe</b>')
})
})
@@ -4,38 +4,6 @@ import { describe, expect, it, vi } from 'vitest'
import { createClaudeModelSwitchConfirmationObserver } from './claude-model-switch-confirmation'
describe('Claude model switch confirmation detection', () => {
it.each([
[
'quoted model name',
'Claude Opus 5.5',
'Set model to `Opus 5.5` and saved as your default for new sessions'
],
[
'matching requested context variant',
'Claude Opus 5.5 (1M context)',
'Set model to `Opus 5.5 (1M context)` and saved as your default for new sessions'
],
['raw model id fallback', 'claude-opus-5-5', 'Set model to Opus 5.5'],
['alias picker row', 'Opus alias', 'Set model to Opus 5.5']
])('confirms a picker label with %s', async (_name, label, output) => {
const dataObserver = { current: (_data: string): void => {} }
const observer = createClaudeModelSwitchConfirmationObserver({
ptyId: 'pty-1',
expectedModelLabel: label,
subscribeToData: (watcher) => {
dataObserver.current = watcher
return () => {}
}
})
await observer.ready
observer.arm()
observer.startDetection()
dataObserver.current(output)
await expect(observer.result).resolves.toBe('applied')
})
it('reports matching success output split across PTY chunks', async () => {
const dataObserver = { current: (_data: string): void => {} }
const unsubscribe = vi.fn(() => {})
@@ -1,41 +0,0 @@
// @vitest-environment happy-dom
import { act, cleanup, renderHook } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { Repo } from '../../../../shared/repo-types'
import { normalizeTaskSourceContext } from '../../../../shared/work-items/task-source-context'
import { useJiraComposerProject } from './use-jira-composer-project'
vi.mock('../use-jira-project-inventory', () => ({
useJiraProjectInventory: () => ({ projects: [], connected: true, error: null, loading: false })
}))
const project = { id: '10', key: 'ALP', name: 'Alpha', siteId: 'site-a' }
const other = { ...project, id: '20', key: 'BRV', name: 'Bravo' }
const repo: Repo = {
id: 'repo',
path: '/repo',
displayName: 'Alpha',
badgeColor: '',
addedAt: 0,
defaultJiraProject: project
}
const source = normalizeTaskSourceContext({ provider: 'jira', projectId: 'repo', hostId: 'local' })
afterEach(cleanup)
describe('Jira composer project defaults', () => {
it('resets All when switching between same-ID local and SSH repositories', () => {
const { result, rerender } = renderHook(
({ current }) => useJiraComposerProject(current, source, true),
{ initialProps: { current: repo } }
)
act(() => result.current.setJiraProject(null))
rerender({ current: { ...repo, executionHostId: 'ssh:target', defaultJiraProject: other } })
expect(result.current.jiraProject).toEqual(other)
})
it('resets All when switching between distinct same-host repository locations', () => {
const { result, rerender } = renderHook(
({ current }) => useJiraComposerProject(current, source, true),
{ initialProps: { current: repo } }
)
act(() => result.current.setJiraProject(null))
rerender({ current: { ...repo, path: '/other-location', defaultJiraProject: other } })
expect(result.current.jiraProject).toEqual(other)
})
})
@@ -1,64 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
vi.mock('@/lib/workspace/activation/worktree-activation', () => ({
activateAndRevealWorkspace: vi.fn()
}))
vi.mock('@/store', () => ({ useAppStore: { getState: vi.fn() } }))
import { findWorkspaceShowingFile, folderWorkspaceRows } from './plugin-view-editor-workspace'
const worktree = (id: string, path: string, extra: Record<string, unknown> = {}) => ({
id,
path,
isArchived: false,
...extra
})
describe('the workspace that shows a file', () => {
it('matches the real path when the given one goes through a symlink, preferring the deepest', () => {
const repos = [
worktree('r1::/private/tmp', '/private/tmp'),
worktree('r2::/private/tmp/sketch', '/private/tmp/sketch')
]
expect(
findWorkspaceShowingFile(
repos,
['/tmp/sketch/sample.sketch', '/private/tmp/sketch/sample.sketch'],
null
)
).toEqual({
worktreeId: 'r2::/private/tmp/sketch',
relativePath: 'sample.sketch',
filePath: '/private/tmp/sketch/sample.sketch'
})
})
it('skips remote and archived workspaces, and finds none outside every workspace', () => {
const repos = [
worktree('r1::/w', '/w', { hostId: 'ssh:box' }),
worktree('r1::/w2', '/w', { isArchived: true })
]
expect(findWorkspaceShowingFile(repos, ['/w/a.sketch'], null)).toBeNull()
expect(findWorkspaceShowingFile([], ['/w/a.sketch'], null)).toBeNull()
})
it('prefers the active workspace among equally deep ones', () => {
const repos = [worktree('a', '/w'), worktree('b', '/w')]
expect(findWorkspaceShowingFile(repos, ['/w/a.sketch'], 'b')?.worktreeId).toBe('b')
})
it('finds a local folder workspace by its tab key, never a remote one', () => {
const folder = (id: string, folderPath: string, connectionId: string | null) => ({
id,
folderPath,
connectionId,
isArchived: false
})
const rows = folderWorkspaceRows([folder('f1', '/notes', null), folder('f2', '/notes', 'box')])
expect(findWorkspaceShowingFile(rows, ['/notes/a.sketch'], null)).toEqual({
worktreeId: 'folder:f1',
relativePath: 'a.sketch',
filePath: '/notes/a.sketch'
})
})
})
@@ -1,65 +0,0 @@
// @vitest-environment happy-dom
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { act, cleanup, fireEvent, render, screen } from '@testing-library/react'
import { endComposition } from '@/lib/text-input/ime/ime-composition-event.test-support'
import { SshPortForwardDialog } from './ssh-port-forward-dialog'
const addPortForward = vi.fn(() => Promise.resolve())
beforeEach(() => {
vi.useFakeTimers()
addPortForward.mockClear()
Object.defineProperty(window, 'api', {
configurable: true,
value: { ssh: { addPortForward } }
})
})
afterEach(() => {
cleanup()
vi.useRealTimers()
})
// happy-dom has no implicit submission, so a keydown left unprevented submits the form here.
function pressEnterWithImplicitSubmit(field: HTMLElement): boolean {
const notPrevented = fireEvent.keyDown(field, { key: 'Enter', keyCode: 13 })
if (notPrevented) {
fireEvent.submit(field.closest('form')!)
}
return notPrevented
}
describe('SshPortForwardDialog IME confirmation', () => {
it.each([
{ field: 'Remote Port', value: '8080', sent: { remotePort: 8080 } },
{ field: 'Local Port', value: '18080', sent: { localPort: 18080 } },
{ field: 'Remote Host', value: '開発機', sent: { remoteHost: '開発機' } },
{ field: 'Label (optional)', value: '開発', sent: { label: '開発' } }
])('keeps the confirm redispatch in $field from submitting', async ({ field, value, sent }) => {
render(
<SshPortForwardDialog
state={{ mode: 'add', defaults: { remotePort: 3000, targetId: 'target-1' } }}
activeConnectionId="target-1"
onClose={vi.fn()}
/>
)
const input = screen.getByLabelText(field)
fireEvent.compositionStart(input)
fireEvent.keyDown(input, { key: 'Process', keyCode: 229, isComposing: true })
fireEvent.change(input, { target: { value } })
endComposition(input, value)
fireEvent.keyUp(input, { key: 'Process', keyCode: 229 })
await act(async () => {
expect(pressEnterWithImplicitSubmit(input)).toBe(false)
})
expect(addPortForward).not.toHaveBeenCalled()
await act(async () => {
expect(pressEnterWithImplicitSubmit(input)).toBe(true)
})
expect(addPortForward).toHaveBeenCalledOnce()
expect(addPortForward).toHaveBeenCalledWith(expect.objectContaining(sent))
})
})
@@ -15,22 +15,6 @@ describe('CommentMarkdown unknown HTML as text', () => {
expect(markup).not.toContain('<script>')
})
it('still sanitizes unsafe attributes and URLs on allowed HTML', () => {
const markup = renderChat('<a href="javascript:alert(1)" onclick="alert(2)">link</a>')
expect(markup).toContain('>link</a>')
expect(markup).not.toContain('javascript:')
expect(markup).not.toContain('onclick')
})
it('keeps disallowed elements inert even when they have executable attributes', () => {
const markup = renderChat('<iframe srcdoc="<script>alert(1)</script>"></iframe>')
expect(markup).toContain('&lt;iframe')
expect(markup).not.toContain('<iframe')
expect(markup).not.toContain('<script')
})
it('keeps an unknown tag inert inside a mixed HTML block', () => {
const markup = renderChat('<div>\n<iframe srcdoc="<script>alert(1)</script>"></iframe>\n</div>')
@@ -1,53 +0,0 @@
// @vitest-environment happy-dom
import { act, cleanup, fireEvent, render, renderHook, screen } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { ExecutionHostId } from '../../../../../../shared/execution-host'
const client = vi.hoisted(() => ({ windowsDesktop: true }))
vi.mock('@/lib/files/os-open/windows-path-access', () => ({
isWindowsDesktopClient: () => client.windowsDesktop
}))
import { useAddRepoWindowsDriveRefusal } from './use-add-repo-windows-drive-refusal'
const WSL_HOST: ExecutionHostId = 'runtime:wsl%3AUbuntu'
const REFUSAL = { kind: 'wsl_host_windows_drive_path', windowsPath: 'C:\\src\\app' } as const
function setup(selectable = true) {
const selectHost = vi.fn(async () => selectable)
const addLocalPath = vi.fn(async () => {})
const createStep = { setStep: vi.fn(), setCreateParent: vi.fn() }
const view = renderHook(
({ selectedHostId }: { selectedHostId: ExecutionHostId }) =>
useAddRepoWindowsDriveRefusal({
isOpen: true,
selectedHostId,
selectHost,
addLocalPath,
createStep
}),
{ initialProps: { selectedHostId: WSL_HOST } }
)
const clickAddOnThisComputer = () => {
const { unmount } = render(<>{view.result.current.notice}</>)
fireEvent.click(screen.getByRole('button', { name: 'Add on this computer' }))
unmount()
}
return { view, selectHost, addLocalPath, createStep, clickAddOnThisComputer }
}
describe('useAddRepoWindowsDriveRefusal', () => {
afterEach(() => {
cleanup()
client.windowsDesktop = true
})
it('drops the add when this computer could not be selected, so a later switch adds nothing', async () => {
const { view, addLocalPath, clickAddOnThisComputer } = setup(false)
act(() => view.result.current.showRefusal(REFUSAL))
clickAddOnThisComputer()
await act(async () => {})
view.rerender({ selectedHostId: 'local' })
expect(addLocalPath).not.toHaveBeenCalled()
})
})
@@ -1,64 +0,0 @@
// @vitest-environment happy-dom
import { act, cleanup, render } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { ProviderRateLimits } from '../../../../shared/rate-limit-types'
import { ProviderSegment } from './StatusBarProviderSegment'
vi.mock('@/i18n/i18n', () => ({
i18n: { language: 'en' },
translate: (_key: string, fallback: string, values: Record<string, string> = {}) =>
Object.entries(values).reduce(
(text, [key, value]) => text.replace(`{{${key}}}`, value),
fallback
)
}))
vi.mock('@/components/agent/icons/AgentIcon', () => ({
AgentIcon: () => null
}))
const START = Date.UTC(2026, 9, 8, 12)
const MINUTE = 60_000
function limits(usedPercent = 90): ProviderRateLimits {
return {
provider: 'antigravity',
session: null,
weekly: null,
buckets: [
{
name: 'Gemini Models · 5h Limit Remaining',
group: 'Gemini Models',
windowName: '5h Limit Remaining',
usedPercent,
windowMinutes: 300,
resetsAt: START + 90 * MINUTE + 30_000,
resetDescription: null
}
],
status: 'ok',
error: null,
updatedAt: START
}
}
describe('status-bar pool countdown', () => {
beforeEach(() => {
vi.useFakeTimers()
vi.setSystemTime(START)
})
afterEach(() => {
cleanup()
vi.useRealTimers()
})
it('starts the clock when an idle segment receives an urgent pool', () => {
const { container, rerender } = render(
<ProviderSegment p={null} compact={false} display="used" />
)
rerender(<ProviderSegment p={limits()} compact={false} display="used" />)
act(() => vi.advanceTimersByTime(30_001))
expect(container.textContent).toContain('1h 29m')
})
})
@@ -1,80 +0,0 @@
import { describe, expect, it } from 'vitest'
import { createTestStore } from '@/store/testing/app-store-test-fixture'
import type { AppState } from '../../store/types'
import type { Tab } from '../../../../shared/tab-types'
import { buildRecentTabSwitcherModel } from './recent-tab-switching'
const WT = 'wt-1'
const GROUP = 'group-1'
function tab(id: string, entityId: string, label: string): Tab {
return {
id,
entityId,
groupId: GROUP,
worktreeId: WT,
contentType: 'editor',
label,
customLabel: null,
color: null,
sortOrder: 0,
createdAt: 1
}
}
function stateWithTabs(
tabOrder: string[],
recentTabIds: string[],
activeTabId: string,
hydratingTabIds: string[] = []
): AppState {
// Include only actual group tabs; extra tabs absent from tabOrder would be appended by strip reconciliation.
const tabs = [
tab('tab-a', 'file-a', 'A'),
tab('tab-b', 'file-b', 'B'),
tab('tab-c', 'file-c', 'C')
].filter((entry) => tabOrder.includes(entry.id) || hydratingTabIds.includes(entry.id))
return {
...createTestStore().getState(),
activeBrowserTabId: null,
activeFileId: tabs.find((entry) => entry.id === activeTabId)?.entityId ?? null,
activeGroupIdByWorktree: { [WT]: GROUP },
activeTabId: null,
activeTabType: 'editor',
browserTabsByWorktree: {},
groupsByWorktree: {
[WT]: [{ id: GROUP, worktreeId: WT, activeTabId, tabOrder, recentTabIds }]
},
openFiles: tabs.map((entry) => ({
id: entry.entityId,
worktreeId: WT
})) as AppState['openFiles'],
tabBarOrderByWorktree: {},
tabsByWorktree: {},
unifiedTabsByWorktree: { [WT]: tabs }
}
}
describe('buildRecentTabSwitcherModel', () => {
it('orders tabs by MRU with the active tab first', () => {
const model = buildRecentTabSwitcherModel(
stateWithTabs(['tab-a', 'tab-b', 'tab-c'], ['tab-a', 'tab-c', 'tab-b'], 'tab-b'),
WT,
'mru'
)
expect(model?.items.map((item) => item.label)).toEqual(['B', 'C', 'A'])
expect(model?.activeIndex).toBe(0)
})
it('includes a unified tab that has not yet entered persisted group order', () => {
const model = buildRecentTabSwitcherModel(
stateWithTabs(['tab-a'], [], 'tab-a', ['tab-b']),
WT,
'sequential'
)
expect(model?.items.map((item) => item.label)).toEqual(['A', 'B'])
expect(model?.activeIndex).toBe(0)
})
})
@@ -1,67 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { withLayoutOwnerTabProps } from './tab-bar-layout-owner-props'
const mocks = vi.hoisted(
(): {
callRuntimeRpc: ReturnType<typeof vi.fn>
ownerEnvironmentId: string | null
recordFeatureInteraction: ReturnType<typeof vi.fn>
} => ({ callRuntimeRpc: vi.fn(), ownerEnvironmentId: null, recordFeatureInteraction: vi.fn() })
)
vi.mock('@/runtime/rpc/calls/runtime-rpc-call', () => ({
callRuntimeRpc: mocks.callRuntimeRpc
}))
vi.mock('@/store', () => ({
useAppStore: {
getState: () => ({
unifiedTabsByWorktree: {},
recordFeatureInteraction: mocks.recordFeatureInteraction
})
}
}))
vi.mock('@/lib/workspace/ownership/resolve-owner', () => ({
runtimeEnvironmentIdUnlessTwin: () => mocks.ownerEnvironmentId
}))
const pinnedItem = { unifiedTabId: 'tab-editor', isPinned: true }
function windowActions() {
return {
togglePinned: vi.fn<(item: typeof pinnedItem) => void>(),
makePreviewFilePermanent: vi.fn<(fileId: string, tabId?: string) => void>()
}
}
function wrap(today: ReturnType<typeof windowActions>) {
return withLayoutOwnerTabProps(today, () => 'wt-1')
}
describe('withLayoutOwnerTabProps', () => {
beforeEach(() => {
mocks.callRuntimeRpc.mockReset()
mocks.ownerEnvironmentId = null
mocks.recordFeatureInteraction.mockReset()
vi.spyOn(console, 'warn').mockImplementation(() => {})
})
it('leaves the window as it is when main refuses', async () => {
mocks.callRuntimeRpc.mockResolvedValue({ ok: false, code: 'invalid_params' })
const today = windowActions()
wrap(today).togglePinned(pinnedItem)
await vi.waitFor(() => expect(console.warn).toHaveBeenCalled())
expect(today.togglePinned).not.toHaveBeenCalled()
})
it('acts as today at once for a paired server’s workspace', () => {
mocks.ownerEnvironmentId = 'env-1'
const today = windowActions()
wrap(today).togglePinned(pinnedItem)
expect(mocks.callRuntimeRpc).not.toHaveBeenCalled()
expect(today.togglePinned).toHaveBeenCalledWith(pinnedItem)
})
})

Some files were not shown because too many files have changed in this diff Show More