diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json index eeb99c5b135..3bb4a42b7d5 100644 --- a/config/scripts/ci-shard-timings.json +++ b/config/scripts/ci-shard-timings.json @@ -1391,7 +1391,6 @@ "src/main/browser/sessions/browser-session-registry-startup-metadata.test.ts": 478, "src/main/browser/sessions/browser-session-registry.persistence.test.ts": 1132, "src/main/browser/sessions/browser-session-registry.test.ts": 883, - "src/main/browser/sessions/requests/browser-session-request-decisions.test.ts": 44, "src/main/browser/identity/browser-session-ua-cloudflare-live.electron.test.ts": 312, "src/main/browser/identity/browser-session-ua-wire-identity-cross-context.electron.test.ts": 7167, "src/main/browser/identity/browser-session-ua-wire-identity.electron.test.ts": 8280, @@ -7263,7 +7262,6 @@ "src/renderer/src/components/automations/AutomationDetail.test.tsx": 833, "src/renderer/src/components/automations/AutomationEditorDialogFooter.test.tsx": 465, "src/renderer/src/components/automations/AutomationEditorPromptEditor.test.tsx": 396, - "src/renderer/src/components/automations/AutomationEditorSettingsSidebar.test.tsx": 1193, "src/renderer/src/components/automations/AutomationHostBadges.test.tsx": 561, "src/renderer/src/components/automations/AutomationHostFilterNotice.test.tsx": 552, "src/renderer/src/components/automations/AutomationListEmptyView.test.tsx": 419, @@ -7347,7 +7345,6 @@ "src/renderer/src/components/automations/external-automation-list-entries.test.ts": 57, "src/renderer/src/components/automations/external-automation-scope-gating.test.ts": 67, "src/renderer/src/components/automations/external-automation-scope-keys.test.ts": 53, - "src/renderer/src/components/automations/external-automation-source-availability.test.ts": 205, "src/renderer/src/components/automations/use-automation-host-catalog-readoption.test.tsx": 802, "src/renderer/src/components/automations/use-automation-host-catalog.test.tsx": 920, "src/renderer/src/components/automations/use-automation-list-focus-recovery.test.tsx": 229, @@ -8783,7 +8780,6 @@ "src/renderer/src/components/settings/appearance/chat/AppearanceChatSection.test.tsx": 1633, "src/renderer/src/components/settings/appearance/AppearancePane.test.tsx": 2066, "src/renderer/src/components/settings/artifacts/ArtifactsSettingsPane.test.tsx": 862, - "src/renderer/src/components/settings/browser/routing/BrowserClientHostedRemoteSetting.test.tsx": 841, "src/renderer/src/components/settings/browser/BrowserPane.search-catalog.test.tsx": 774, "src/renderer/src/components/settings/browser/profiles/BrowserProfileRow.google-cookie-clear.test.tsx": 27636, "src/renderer/src/components/settings/browser/BrowserSitePermissionsSetting.test.tsx": 739, @@ -8797,7 +8793,6 @@ "src/renderer/src/components/settings/cli/install/CliSection.test.tsx": 2135, "src/renderer/src/lib/skill-runtime-command.test.ts": 1670, "src/renderer/src/components/settings/agents/behavior/CodexHistorySharingSetting.test.tsx": 539, - "src/renderer/src/components/settings/accounts/codex/CodexLoginLinkNotice.test.tsx": 494, "src/renderer/src/components/settings/source-control/CommitMessageAiPane.test.tsx": 3099, "src/renderer/src/components/settings/developer-permissions/DeveloperPermissionsPane.test.tsx": 2135, "src/renderer/src/components/settings/virtual-machines/runtimes/EphemeralVmRuntimesSection.test.tsx": 2270, @@ -8816,7 +8811,6 @@ "src/renderer/src/components/settings/mobile/MobilePane.test.tsx": 1581, "src/renderer/src/components/settings/advanced/network/NodeDistMirrorDialog.test.tsx": 2412, "src/renderer/src/components/settings/notifications/NotificationHostToggles.test.tsx": 646, - "src/renderer/src/components/settings/notifications/NotificationsPane.test.tsx": 1898, "src/renderer/src/components/settings/orchestration/OrchestrationPane.test.tsx": 2437, "src/renderer/src/components/settings/orchestration/OrchestrationSkillAgentCoverage.test.tsx": 320, "src/renderer/src/components/plugins/list/PluginsSettingsSection.lifecycle.test.tsx": 5402, @@ -9507,7 +9501,6 @@ "src/renderer/src/components/terminal-pane/TerminalPaneNativeChatPortal.test.tsx": 416, "src/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.react185.test.tsx": 1251, "src/renderer/src/components/terminal-pane/TerminalPaneRecoveryPortals.test.tsx": 670, - "src/renderer/src/components/terminal-pane/TerminalPaneResumeInChatButton.test.tsx": 581, "src/renderer/src/components/terminal-pane/TerminalProcessExitOverlay.test.tsx": 481, "src/renderer/src/components/terminal-pane/TerminalRemoteRuntimeReconnectBanner.test.tsx": 812, "src/renderer/src/components/terminal-pane/TerminalSleepingPaneOverlay.test.tsx": 407, @@ -9660,7 +9653,6 @@ "src/renderer/src/components/terminal-pane/pty-connection/deferred-session-reattach-startup-snapshot.test.ts": 1830, "src/renderer/src/components/terminal-pane/pty-connection/deferred-session-reattach-wsl-distro-stopped-hold.test.ts": 2517, "src/renderer/src/components/terminal-pane/pty-connection/disposed-spawn-retention.test.ts": 84, - "src/renderer/src/components/terminal-pane/pty-connection/empty-reattach-retire-evidence.test.ts": 63, "src/renderer/src/components/terminal-pane/pty-connection/exited-split-pane-close.test.ts": 48, "src/renderer/src/components/terminal-pane/pty-connection/foreground-output-budgets.test.ts": 41, "src/renderer/src/components/terminal-pane/pty-connection/foreground-output-scan.test.ts": 92, @@ -9687,7 +9679,6 @@ "src/renderer/src/components/terminal-pane/pty-connection/unbound-pane-spawn-recovery.test.ts": 53, "src/renderer/src/components/terminal-pane/pty-connection/unserved-ssh-pane-bridge.test.ts": 70, "src/renderer/src/components/terminal-pane/pty-connection/write-pty-output-idle-reset.test.ts": 157, - "src/renderer/src/components/terminal-pane/pty-connection/write-pty-output-to-xterm-startup-callback.test.ts": 116, "src/renderer/src/components/terminal-pane/pty-dispatcher-delivery-interest.test.ts": 132, "src/renderer/src/components/terminal-pane/pty-dispatcher-delivery-resync.test.ts": 85, "src/renderer/src/components/terminal-pane/pty-dispatcher-pi-routing.test.ts": 1362, @@ -10052,7 +10043,6 @@ "src/renderer/src/components/terminal/tab-type-cycle.test.ts": 60, "src/renderer/src/components/terminal/terminal-close-incarnation.test.ts": 42, "src/renderer/src/components/terminal/terminal-provider-snapshot-bound-pty-ids.test.ts": 1982, - "src/renderer/src/components/terminal/terminal-provider-snapshot-capability-resettlement.test.ts": 277, "src/renderer/src/components/terminal/terminal-provider-snapshot-capability.test.ts": 68, "src/renderer/src/components/terminal/terminal-tab-actions-unified-close.test.ts": 1831, "src/renderer/src/components/terminal/terminal-tab-actions-unrouted-close.test.ts": 589, @@ -10663,7 +10653,6 @@ "src/renderer/src/lib/simulator-pane-shutdown-scheduler.test.ts": 1679, "src/renderer/src/lib/simulator-tab-layout-owner.test.ts": 2398, "src/renderer/src/lib/simulator-tab-palette-activation.test.ts": 1903, - "src/renderer/src/lib/sleeping-agent-pane-ownership.test.ts": 66, "src/renderer/src/lib/sleeping-agent-session-launch-windows-quoting.test.ts": 547, "src/renderer/src/lib/smart-github-submit.test.ts": 112, "src/renderer/src/lib/source-control-remote-error.test.ts": 340, @@ -11650,7 +11639,6 @@ "src/shared/darwin-terminal-names-real-ps.test.ts": 42, "src/shared/darwin-terminal-names.test.ts": 267, "src/shared/darwin-terminal-naming-single-flight.test.ts": 69, - "src/shared/agent-launch/choices/default-agent-settings.test.ts": 31, "src/shared/device-key-proof.test.ts": 112, "src/shared/dictation-audio-meter.test.ts": 49, "src/shared/dictation-transcript-spacing.test.ts": 48, @@ -12605,7 +12593,6 @@ "src/shared/wsl-login-shell-nushell.test.ts": 66, "src/shared/wsl-paths.test.ts": 48, "src/shared/zcode-missing-tui.test.ts": 51, - "src/shared/zcode-orchestration-contract.test.ts": 247, "src/shared/zod-salvage-absence.test.ts": 96, "src/wsl-guest/agent-hook-canonical-status.test.ts": 2770, "src/wsl-guest/agent-hook-envelope-publication.test.ts": 348, diff --git a/src/main/agent-hooks/server/program-status/hook-precedence.test.ts b/src/main/agent-hooks/server/program-status/hook-precedence.test.ts index a58857d563f..abaabfbff81 100644 --- a/src/main/agent-hooks/server/program-status/hook-precedence.test.ts +++ b/src/main/agent-hooks/server/program-status/hook-precedence.test.ts @@ -29,33 +29,6 @@ const report = (payload: Omit): ParsedAgentS }) describe('programStatusHookYieldEndsAt', () => { - it('applies when no hook row speaks for the pane', () => { - expect(programStatusHookYieldEndsAt(undefined, report({ state: 'working' }))).toBeUndefined() - expect( - programStatusHookYieldEndsAt(row({ state: 'working' }, {}, 'osc'), report({ state: 'done' })) - ).toBeUndefined() - expect( - programStatusHookYieldEndsAt( - row({ state: 'done' }, { providerSessionOnly: true }), - report({ state: 'working' }) - ) - ).toBeUndefined() - }) - - it('yields to a live hook row of the same agent until its hooks fall silent', () => { - const hook = row({ state: 'working', agentType: 'claude' }) - expect(programStatusHookYieldEndsAt(hook, report({ state: 'done', agentType: 'claude' }))).toBe( - NOW + SILENCE - ) - }) - - it('keeps yielding through a long silent tool call that the program agrees with', () => { - const hook = row({ state: 'working', agentType: 'claude' }) - expect( - programStatusHookYieldEndsAt(hook, report({ state: 'working', agentType: 'claude' })) - ).toBe(Infinity) - }) - it('keeps a turn the hooks settled from a later block unless the program worked since', () => { const hook = row({ state: 'done', agentType: 'antigravity' }) const block = report({ state: 'waiting', agentType: 'antigravity' }) @@ -104,19 +77,4 @@ describe('programStatusHookYieldEndsAt', () => { ) } }) - - it('yields to a mid-turn hook row under another app id, not to a finished one', () => { - expect( - programStatusHookYieldEndsAt( - row({ state: 'working', agentType: 'openclaude' }), - report({ state: 'done', agentType: 'claude' }) - ) - ).toBe(NOW + SILENCE) - expect( - programStatusHookYieldEndsAt( - row({ state: 'done', agentType: 'claude' }), - report({ state: 'working', agentType: 'terraform' }) - ) - ).toBeUndefined() - }) }) diff --git a/src/main/agent-launch/agent-launch-opencode-model.test.ts b/src/main/agent-launch/agent-launch-opencode-model.test.ts index 36961d181cd..1a753719ea4 100644 --- a/src/main/agent-launch/agent-launch-opencode-model.test.ts +++ b/src/main/agent-launch/agent-launch-opencode-model.test.ts @@ -1,10 +1,6 @@ import { describe, expect, it, vi } from 'vitest' -import recordings from '../../shared/fixtures/source-control-launch-recordings.json' import type { AgentLaunchIntent } from '../../shared/agent-launch/contracts/agent-launch-intent' import { executeAgentLaunch } from './agent-launch-executor' -import { toAgentLaunchPreferences } from '../../shared/agent-launch/choices/agent-launch-preferences' -import { assertOpenCodeModelLaunchPreferencesAbsent } from '../opencode/opencode-model-startup-plan' -import { agentPermissionChoices } from '../../shared/agent-launch/permissions/tui-agent-permission-choice' function harness() { const readSettings = vi.fn(() => { @@ -63,33 +59,6 @@ const creating: AgentLaunchIntent = { } describe('OpenCode model preferences on unsupported launch placements', () => { - it('keeps own selectable without projecting a meaningless permission into either terminal guard', async () => { - const sessionOptions = { permissionMode: 'own' } - const projected = toAgentLaunchPreferences(sessionOptions, 'opencode') - expect(agentPermissionChoices('opencode')).toContain('own') - expect(projected).toBeUndefined() - // Workspace creation consumes this projection through the same unchanged broad guard. - expect(() => assertOpenCodeModelLaunchPreferencesAbsent('opencode', projected)).not.toThrow() - for (const intent of [reused, creating]) { - const h = harness() - await expect(h.run({ ...intent, sessionOptions })).resolves.toBeDefined() - } - }) - - it('refuses the real OpenCode model readback on a reused terminal before prompt delivery', async () => { - const model = recordings.opencode.update.message.params.update.configOptions.find( - (option) => option.category === 'model' - )?.currentValue - expect(model).toBe('opencode/big-pickle') - const h = harness() - await expect(h.run({ ...reused, sessionOptions: { model } })).rejects.toMatchObject({ - code: 'capability_unsupported' - }) - expect(h.createTerminal).not.toHaveBeenCalled() - expect(h.createWorktree).not.toHaveBeenCalled() - expect(h.deliverPrompt).not.toHaveBeenCalled() - }) - it.each([reused, creating])( 'preserves definitive refusal without creating or delivering when the route settings read throws', async (intent) => { diff --git a/src/main/browser/cdp/input/agent-input-focus-guard.test.ts b/src/main/browser/cdp/input/agent-input-focus-guard.test.ts index c67ab7550fe..48836788989 100644 --- a/src/main/browser/cdp/input/agent-input-focus-guard.test.ts +++ b/src/main/browser/cdp/input/agent-input-focus-guard.test.ts @@ -19,7 +19,6 @@ vi.mock('electron', () => ({ })) import { - AGENT_INPUT_FOCUS_GUARD_CHANNEL, AGENT_INPUT_FOCUS_GUARD_READY_CHANNEL, guardPaneFocusForAgentInput } from './agent-input-focus-guard' @@ -48,21 +47,6 @@ describe('guardPaneFocusForAgentInput', () => { vi.useRealTimers() }) - it('resolves when the pane is ready and ends the guard once', async () => { - const { sent, renderer } = fakeRenderer(7, true) - - const release = await guardPaneFocusForAgentInput(renderer, 'page-1') - release() - release() - - expect(sent.map(({ channel, data }) => [channel, data.active])).toEqual([ - [AGENT_INPUT_FOCUS_GUARD_CHANNEL, true], - [AGENT_INPUT_FOCUS_GUARD_CHANNEL, false] - ]) - expect(sent[0].data.token).toBe(sent[1].data.token) - expect(ipcListeners.get(AGENT_INPUT_FOCUS_GUARD_READY_CHANNEL)).toEqual([]) - }) - it('refuses the input and ends the guard when the pane never answers', async () => { vi.useFakeTimers() const { sent, renderer } = fakeRenderer(7, false) diff --git a/src/main/browser/client-hosts/lifecycle/paired-runtime-browser-client-host-identity-wiring.test.ts b/src/main/browser/client-hosts/lifecycle/paired-runtime-browser-client-host-identity-wiring.test.ts index 655396dd4de..041f5b8dde3 100644 --- a/src/main/browser/client-hosts/lifecycle/paired-runtime-browser-client-host-identity-wiring.test.ts +++ b/src/main/browser/client-hosts/lifecycle/paired-runtime-browser-client-host-identity-wiring.test.ts @@ -121,23 +121,4 @@ describe('client host hosting identity wiring', () => { await hostingIdentityForLaunch(mkdtempSync(join(tmpdir(), 'orca-host-wiring-'))) ).not.toBe(await hostingIdentityForLaunch(mkdtempSync(join(tmpdir(), 'orca-host-wiring-')))) }) - - it('attaches under the identity already stamped into the first window', async () => { - await launch(mkdtempSync(join(tmpdir(), 'orca-host-wiring-'))) - - // Windows receive the hosting id before pairing; the lease must reuse it. - const { getBrowserClientHostId } = await import('./browser-client-host-id') - const stamped = getBrowserClientHostId() - - expect(await hostingIdentity()).toBe(stamped) - }) - - it('keeps hosting on a process-local identity when no profile was ever resolved', async () => { - vi.resetModules() - createHostCallbacks.length = 0 - hostOptions.length = 0 - - const { getBrowserClientHostId } = await import('./browser-client-host-id') - expect(await hostingIdentity()).toBe(getBrowserClientHostId()) - }) }) diff --git a/src/main/browser/client-pages/renderer/browser-client-page-metadata-transport.test.ts b/src/main/browser/client-pages/renderer/browser-client-page-metadata-transport.test.ts index 07acdc4e690..56ab833b2ab 100644 --- a/src/main/browser/client-pages/renderer/browser-client-page-metadata-transport.test.ts +++ b/src/main/browser/client-pages/renderer/browser-client-page-metadata-transport.test.ts @@ -50,16 +50,6 @@ describe('browser client page metadata transport', () => { ) }) - it('refuses to publish once nothing is bound', async () => { - const transport = new BrowserClientPageMetadataTransport() - const sender = { sendPageMetadataRequest: vi.fn() } - transport.bind(sender) - transport.unbind(sender) - - await expect(transport.publish(PARAMS)).rejects.toBeInstanceOf(RemoteRuntimeClientError) - expect(sender.sendPageMetadataRequest).not.toHaveBeenCalled() - }) - it('leaves a replacement bound when the host it replaced unbinds', async () => { const transport = new BrowserClientPageMetadataTransport() const outgoing = { sendPageMetadataRequest: vi.fn() } @@ -76,22 +66,6 @@ describe('browser client page metadata transport', () => { }) describe('browser client page metadata routing', () => { - it('publishes through the transport of the environment that owns the page', async () => { - const owning = new BrowserClientPageMetadataTransport() - const other = new BrowserClientPageMetadataTransport() - const owningSend = vi.fn().mockResolvedValue(answered({ accepted: true })) - const otherSend = vi.fn() - owning.bind({ sendPageMetadataRequest: owningSend }) - other.bind({ sendPageMetadataRequest: otherSend }) - registerBrowserClientPageMetadataTransport('environment-a', owning) - registerBrowserClientPageMetadataTransport('environment-b', other) - - await expect(publishBrowserClientPageMetadata('environment-a', PARAMS)).resolves.toEqual({ - accepted: true - }) - expect(otherSend).not.toHaveBeenCalled() - }) - // Another environment detects accidental fallback to any registered transport. it('fails a publish for an environment that hosts nothing while another one does', async () => { const elsewhere = new BrowserClientPageMetadataTransport() diff --git a/src/main/browser/extensions/declarative-net-request/session/browser-extension-dnr-frames.test.ts b/src/main/browser/extensions/declarative-net-request/session/browser-extension-dnr-frames.test.ts index 914db01e920..f132f16584b 100644 --- a/src/main/browser/extensions/declarative-net-request/session/browser-extension-dnr-frames.test.ts +++ b/src/main/browser/extensions/declarative-net-request/session/browser-extension-dnr-frames.test.ts @@ -78,27 +78,4 @@ describe('declarativeNetRequest frame state', () => { expect([1, 2].map((node) => blocked(engine, tracker, node))).toEqual([true, true]) expect(tracker.topOrigin(TAB)).toBe('https://shop.example') }) - - it('tracks top origins without an engine and resolves tab ids once per document', () => { - let resolved = 0 - let registered = false - const tracker = new DnrFrameTracker(() => { - resolved++ - return registered ? 11 : -1 - }) - // A restored tab's first requests come before Orca's window lists it. - expect(tracker.tabIdFor(11)).toBe(-1) - registered = true - resolved = 0 - expect([tracker.tabIdFor(11), tracker.tabIdFor(11), tracker.tabIdFor(undefined)]).toEqual([ - 11, 11, -1 - ]) - expect(resolved).toBe(1) - tracker.commit(null, 11, asFrame(frame(1, 'https://a.example')), 'https://a.example/') - expect(tracker.topOrigin(11)).toBe('https://a.example') - tracker.tabIdFor(11) - expect(resolved).toBe(2) - tracker.forgetContents(11) - expect(tracker.topOrigin(11)).toBeNull() - }) }) diff --git a/src/main/browser/extensions/tabs-and-windows/browser-extension-window-model.test.ts b/src/main/browser/extensions/tabs-and-windows/browser-extension-window-model.test.ts index 012d584f0ee..a28abda9bca 100644 --- a/src/main/browser/extensions/tabs-and-windows/browser-extension-window-model.test.ts +++ b/src/main/browser/extensions/tabs-and-windows/browser-extension-window-model.test.ts @@ -50,12 +50,6 @@ const profileB = { name: 'b' } as unknown as Electron.Session const focus = (window: Electron.BrowserWindow): boolean => window.emit('focus') describe("a profile's extension windows", () => { - it('track the main window while extensions are off, so turning them on finds it', () => { - const main = new BrowserWindow() - model.trackBrowserExtensionMainWindow(main) - expect(model.getBrowserExtensionMainWindow()).toBe(main) - }) - it("never include another profile's popout, in lookups or events", () => { const main = new BrowserWindow() model.trackBrowserExtensionMainWindow(main) diff --git a/src/main/browser/extensions/web-store/browser-extension-webstore-download.test.ts b/src/main/browser/extensions/web-store/browser-extension-webstore-download.test.ts index b63bb10664a..624f0a6535f 100644 --- a/src/main/browser/extensions/web-store/browser-extension-webstore-download.test.ts +++ b/src/main/browser/extensions/web-store/browser-extension-webstore-download.test.ts @@ -89,14 +89,6 @@ describe('Web Store download request ownership', () => { expect(signals[0].aborted).toBe(true) }) - it('still rejects an invalid package after consuming its complete response', async () => { - const { fetcher, signals } = responseFetcher(new Response('bad')) - - await expect(downloadWebStoreCrx(EXTENSION_ID, { fetcher })).rejects.toThrow('Not a CRX file') - expect(signals).toHaveLength(1) - expect(signals[0].aborted).toBe(true) - }) - it('keeps an overlapping healthy icon alive until its own bytes finish', async () => { let finishHealthy = (): void => {} const healthyResponse = new Response( diff --git a/src/main/browser/guest-lifecycle/input/browser-guest-wheel-zoom-scroll.test.ts b/src/main/browser/guest-lifecycle/input/browser-guest-wheel-zoom-scroll.test.ts index 63a2f2162fb..9972052cba4 100644 --- a/src/main/browser/guest-lifecycle/input/browser-guest-wheel-zoom-scroll.test.ts +++ b/src/main/browser/guest-lifecycle/input/browser-guest-wheel-zoom-scroll.test.ts @@ -56,18 +56,6 @@ describe('guest before-mouse-event forwarding', () => { return mouse } - it('reports a press into the page and steps history on a side-button release', () => { - expect(trigger(false, sideButton('mouseDown', 'back'))).not.toHaveBeenCalled() - expect(trigger(false, sideButton('mouseUp', 'back'))).not.toHaveBeenCalled() - trigger(false, sideButton('mouseUp', 'forward')) - - expect(rendererSend.mock.calls).toEqual([ - ['ui:browserPagePointerDown', { browserPageId: 'tab-1' }], - ['ui:browserHistoryNavigate', { browserPageId: 'tab-1', direction: 'back' }], - ['ui:browserHistoryNavigate', { browserPageId: 'tab-1', direction: 'forward' }] - ]) - }) - it('leaves presses an agent makes in the page to the page alone', () => { agentInjection.active = true try { @@ -79,32 +67,6 @@ describe('guest before-mouse-event forwarding', () => { expect(rendererSend).not.toHaveBeenCalled() }) - it('forwards plain wheel deltas only for an active preset', () => { - const preventDefault = trigger(true, { deltaX: 24, deltaY: 120 }) - - expect(preventDefault).toHaveBeenCalledTimes(1) - expect(rendererSend).toHaveBeenCalledWith('ui:scrollBrowserPage', { - browserPageId: 'tab-1', - deltaX: 24, - deltaY: 120 - }) - - trigger(false, { deltaY: 120 }) - expect(rendererSend).toHaveBeenCalledTimes(1) - }) - - it('ignores zero deltas and preserves ctrl-wheel zoom routing', () => { - const zeroPreventDefault = trigger(true, {}) - expect(zeroPreventDefault).not.toHaveBeenCalled() - - const zoomPreventDefault = trigger(true, { modifiers: ['ctrl'], deltaY: -120 }) - expect(zoomPreventDefault).toHaveBeenCalledTimes(1) - expect(rendererSend).toHaveBeenLastCalledWith('ui:zoomBrowserPage', { - browserPageId: 'tab-1', - direction: 'in' - }) - }) - it('leaves fitting presets and host-edge wheels to the guest page', () => { setupGuestMouseWheelZoomForwarding({ browserTabId: 'tab-1', diff --git a/src/main/browser/sessions/requests/browser-session-request-decisions.test.ts b/src/main/browser/sessions/requests/browser-session-request-decisions.test.ts deleted file mode 100644 index 9f1ef01e3aa..00000000000 --- a/src/main/browser/sessions/requests/browser-session-request-decisions.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' - -import { - answerBrowserSessionBeforeRequest, - installBrowserSessionHeadersReceived, - setBrowserSessionRequestDecider, - watchDecisionBlockedMainFrames, - type BrowserSessionRequestDecider -} from './browser-session-request-decisions' - -import { setBrowserSessionWebRequestObserver } from './browser-session-web-request-observer' - -type Listener = (details: unknown, callback: (response: unknown) => void) => void - -function fakeSession() { - const listeners: Record = {} - const register = - (event: string) => - (...args: unknown[]): void => { - const listener = args.at(-1) - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the guard only registers a listener function here. - listeners[event] = typeof listener === 'function' ? (listener as Listener) : null - } - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the code under test touches only these webRequest members. - const session = { - webRequest: { - onBeforeRequest: vi.fn(register('onBeforeRequest')), - onHeadersReceived: vi.fn(register('onHeadersReceived')) - } - } as unknown as Electron.Session - const fire = (event: string, details: unknown): Promise => - new Promise((resolve) => listeners[event]?.(details, resolve)) - return { session, fire } -} - -function decider(overrides: Partial): BrowserSessionRequestDecider { - return { - beforeRequest: () => null, - beforeSendHeaders: (_session, _details, headers) => headers, - headersReceived: () => null, - ...overrides - } -} - -// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: a request carries only the fields these handlers read. -const request = { - id: 1, - url: 'https://ads.example/a.js', - method: 'GET', - resourceType: 'script', - referrer: '', - timestamp: 0, - webContentsId: 3 -} as Electron.OnBeforeRequestListenerDetails - -afterEach(() => setBrowserSessionRequestDecider(null)) - -describe('browser session request decisions', () => { - it('answers with the decision, waits for a held one, and fails open', async () => { - const { session } = fakeSession() - const answer = (): Promise => - new Promise((resolve) => answerBrowserSessionBeforeRequest(session, request, resolve)) - await expect(answer()).resolves.toEqual({}) - setBrowserSessionRequestDecider(decider({ beforeRequest: () => ({ cancel: true }) })) - await expect(answer()).resolves.toEqual({ cancel: true }) - setBrowserSessionRequestDecider( - decider({ beforeRequest: async () => ({ redirectURL: 'https://safe.example/' }) }) - ) - await expect(answer()).resolves.toEqual({ redirectURL: 'https://safe.example/' }) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - setBrowserSessionRequestDecider( - decider({ - beforeRequest: () => { - throw new Error('boom') - } - }) - ) - await expect(answer()).resolves.toEqual({}) - }) - - it('tells the guest when the decider blocks its main frame', async () => { - const { session } = fakeSession() - const blocked = vi.fn() - const stop = watchDecisionBlockedMainFrames(3, blocked) - setBrowserSessionRequestDecider(decider({ beforeRequest: async () => ({ cancel: true }) })) - const page = { ...request, resourceType: 'mainFrame', url: 'https://blocked.example/' } as const - await new Promise((resolve) => answerBrowserSessionBeforeRequest(session, page, resolve)) - await new Promise((resolve) => answerBrowserSessionBeforeRequest(session, request, resolve)) - expect(blocked.mock.calls).toEqual([['https://blocked.example/']]) - stop() - await new Promise((resolve) => answerBrowserSessionBeforeRequest(session, page, resolve)) - expect(blocked).toHaveBeenCalledOnce() - }) - - it('installs one onHeadersReceived that reports to observers and applies the decision', async () => { - const { session, fire } = fakeSession() - const observed = vi.fn() - setBrowserSessionWebRequestObserver(observed) - installBrowserSessionHeadersReceived(session) - installBrowserSessionHeadersReceived(session) - expect(session.webRequest.onHeadersReceived).toHaveBeenCalledOnce() - await expect(fire('onHeadersReceived', request)).resolves.toEqual({}) - setBrowserSessionRequestDecider(decider({ headersReceived: () => ({ cancel: true }) })) - await expect(fire('onHeadersReceived', request)).resolves.toEqual({ cancel: true }) - expect(observed).toHaveBeenCalledWith(session, 'onHeadersReceived', request) - }) -}) diff --git a/src/main/runtime/orchestration-opencode-model-host.test.ts b/src/main/runtime/orchestration-opencode-model-host.test.ts index 6e8875d2e28..68a67b4b681 100644 --- a/src/main/runtime/orchestration-opencode-model-host.test.ts +++ b/src/main/runtime/orchestration-opencode-model-host.test.ts @@ -61,17 +61,6 @@ describe('OpenCode worker model execution host', () => { promptMode: 'submit' }) }) - it('checks only the version route for a model in a local folder', async () => { - expect(await probe(host())).toBe(true) - expect(probeOpenCodeLaunchCapabilities).toHaveBeenCalledExactlyOnceWith({ - command: '/tmp/private-opencode', - agent: 'opencode', - cwd: '/tmp/folder', - env: expect.objectContaining({ OPENCODE_CONFIG_DIR: '/tmp/private-config' }), - hostIdentity: 'host-1' - }) - expect(resolveOpenCodeDirectModelExecutable).not.toHaveBeenCalled() - }) it('refuses an unsafe version before model discovery or worker creation', async () => { vi.mocked(probeOpenCodeLaunchCapabilities).mockResolvedValue({ version: '2.0.14', diff --git a/src/renderer/src/components/automations/AutomationEditorSettingsSidebar.test.tsx b/src/renderer/src/components/automations/AutomationEditorSettingsSidebar.test.tsx deleted file mode 100644 index 0f59e56df4b..00000000000 --- a/src/renderer/src/components/automations/AutomationEditorSettingsSidebar.test.tsx +++ /dev/null @@ -1,80 +0,0 @@ -// @vitest-environment happy-dom - -import { cleanup, fireEvent, render, screen } from '@testing-library/react' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { AGENT_CATALOG } from '@/lib/agent-catalog' -import type { AutomationDraft } from './AutomationEditorDialog' -import { AutomationEditorSettingsSidebar } from './AutomationEditorSettingsSidebar' - -// Why: only the Agent field is under test; the sibling fields own their own coverage. -vi.mock('./AutomationProjectCombobox', () => ({ default: () => null })) -vi.mock('./AutomationWorkspaceField', () => ({ AutomationWorkspaceField: () => null })) -vi.mock('./AutomationSessionField', () => ({ AutomationSessionField: () => null })) -vi.mock('./AutomationSchedulePicker', () => ({ AutomationSchedulePicker: () => null })) -vi.mock('./AutomationMissedRunGraceField', () => ({ AutomationMissedRunGraceField: () => null })) -vi.mock('./AutomationPrecheckFields', () => ({ AutomationPrecheckFields: () => null })) -vi.mock('./AutomationSetupDecisionField', () => ({ AutomationSetupDecisionField: () => null })) -vi.mock('./AutomationDestinationField', () => ({ AutomationDestinationField: () => null })) -vi.mock('./AutomationExtraAgentArgsField', () => ({ AutomationExtraAgentArgsField: () => null })) - -const DRAFT: AutomationDraft = { - name: '', - prompt: '', - agentId: 'codex', - extraAgentArgs: '', - projectId: '', - workspaceMode: 'existing', - workspaceId: '', - baseBranch: '', - reuseSession: false, - precheckCommand: '', - precheckTimeoutSeconds: '30', - preset: 'weekly', - time: '09:15', - dayOfWeek: '5', - customSchedule: '', - missedRunGraceMinutes: '720', - savedSchedule: null, - scheduleWarning: null -} - -function renderSidebar(onDraftChange: (updater: (d: AutomationDraft) => AutomationDraft) => void) { - return render( - repoId} - repoMap={new Map()} - worktrees={[]} - settings={null} - draft={DRAFT} - visibleAgents={AGENT_CATALOG} - pickerTriggerClassName="" - segmentedGroupClassName="" - segmentedItemClassName="" - onProjectChange={vi.fn()} - onDraftChange={onDraftChange} - onSetupDecisionTouched={vi.fn()} - /> - ) -} - -afterEach(cleanup) - -describe('AutomationEditorSettingsSidebar agent picker', () => { - it('offers agents only, never Blank Terminal', () => { - const onDraftChange = vi.fn() - renderSidebar(onDraftChange) - - fireEvent.click(screen.getByRole('combobox')) - - expect(screen.queryByRole('option', { name: 'Blank Terminal' })).toBeNull() - fireEvent.click(screen.getByRole('option', { name: 'Claude' })) - expect(onDraftChange).toHaveBeenCalledTimes(1) - const updater = onDraftChange.mock.calls[0][0] - expect(updater(DRAFT).agentId).toBe('claude') - }) -}) diff --git a/src/renderer/src/components/automations/external-automation-source-availability.test.ts b/src/renderer/src/components/automations/external-automation-source-availability.test.ts deleted file mode 100644 index fc4fa55ee37..00000000000 --- a/src/renderer/src/components/automations/external-automation-source-availability.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { ExternalAutomationManager } from '../../../../shared/automations-types' -import { getExternalAutomationActionDisabledMessage } from './external-automation-source-availability' - -function manager(overrides: Partial = {}): ExternalAutomationManager { - return { - id: 'openclaw-local', - provider: 'openclaw', - label: 'OpenClaw', - targetLabel: 'Local Mac', - target: { type: 'local' }, - status: 'unavailable', - error: null, - canManage: false, - jobs: [], - ...overrides - } -} - -describe('external automation action availability', () => { - it('explains disabled local automation actions when the source tool is missing', () => { - expect( - getExternalAutomationActionDisabledMessage({ - manager: manager({ - error: 'OpenClaw jobs were found, but the openclaw CLI is not on PATH.' - }) - }) - ).toBe('OpenClaw jobs were found, but the openclaw CLI is not on PATH.') - }) - - it('explains disabled SSH automation actions before the host is connected', () => { - expect( - getExternalAutomationActionDisabledMessage({ - manager: manager({ - target: { type: 'ssh', connectionId: 'devbox' }, - error: 'SSH target is not connected.' - }), - providerLabel: 'OpenClaw', - sshStatus: 'disconnected' - }) - ).toBe('Connect this SSH host before managing OpenClaw automations.') - }) - - it('explains disabled SSH automation actions while the host is connecting', () => { - expect( - getExternalAutomationActionDisabledMessage({ - manager: manager({ - target: { type: 'ssh', connectionId: 'devbox' }, - error: 'SSH target is not connected.' - }), - sshStatus: 'deploying-relay' - }) - ).toBe('Wait for this SSH host to finish connecting.') - }) - - it('explains disabled SSH automation actions when the remote source tool is missing', () => { - expect( - getExternalAutomationActionDisabledMessage({ - manager: manager({ - target: { type: 'ssh', connectionId: 'devbox' }, - error: 'OpenClaw CLI is not on the remote PATH.' - }), - sshStatus: 'connected' - }) - ).toBe('OpenClaw CLI is not on the remote PATH.') - }) - - it('keeps concrete remote source errors when SSH status is unavailable to the caller', () => { - expect( - getExternalAutomationActionDisabledMessage({ - manager: manager({ - target: { type: 'ssh', connectionId: 'devbox' }, - error: 'OpenClaw CLI is not on the remote PATH.' - }) - }) - ).toBe('OpenClaw CLI is not on the remote PATH.') - }) - - it('explains disabled actions while another automation action is running', () => { - expect( - getExternalAutomationActionDisabledMessage({ - manager: manager({ canManage: true }), - actionInProgress: true - }) - ).toBe('Another automation action is still running.') - }) -}) diff --git a/src/renderer/src/components/feature-tips/ChatUiHereFeatureTipVisual.test.tsx b/src/renderer/src/components/feature-tips/ChatUiHereFeatureTipVisual.test.tsx index 4076f58cdb3..1f85c62b958 100644 --- a/src/renderer/src/components/feature-tips/ChatUiHereFeatureTipVisual.test.tsx +++ b/src/renderer/src/components/feature-tips/ChatUiHereFeatureTipVisual.test.tsx @@ -67,12 +67,4 @@ describe('chat tip visual lifetime', () => { expect(vi.getTimerCount()).toBe(0) expect(container.innerHTML).toBe(finished) }) - - it('starts as a complete still with reduced motion and no timer', () => { - vi.useFakeTimers() - motion(true) - const { container } = render() - expect(vi.getTimerCount()).toBe(0) - expect(container.querySelectorAll('[data-on="true"]').length).toBeGreaterThan(10) - }) }) diff --git a/src/renderer/src/components/settings/accounts/codex/CodexLoginLinkNotice.test.tsx b/src/renderer/src/components/settings/accounts/codex/CodexLoginLinkNotice.test.tsx deleted file mode 100644 index 6c05addf70d..00000000000 --- a/src/renderer/src/components/settings/accounts/codex/CodexLoginLinkNotice.test.tsx +++ /dev/null @@ -1,87 +0,0 @@ -// @vitest-environment happy-dom - -import { cleanup, fireEvent, render, waitFor } from '@testing-library/react' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { i18n } from '../../../../i18n/i18n' -import { CodexLoginLinkNotice } from './CodexLoginLinkNotice' - -const AUTH_URL = 'https://auth.openai.com/oauth/authorize?client_id=orca&state=abc123' - -type LinkListener = (url: string | null) => void - -function stubApi(pendingUrl: string | null): { - listeners: LinkListener[] - writeClipboardText: ReturnType - openUrl: ReturnType -} { - const listeners: LinkListener[] = [] - const writeClipboardText = vi.fn(() => Promise.resolve()) - const openUrl = vi.fn(() => Promise.resolve()) - Object.defineProperty(globalThis, 'api', { - configurable: true, - value: { - codexAccounts: { - getPendingLoginUrl: () => Promise.resolve(pendingUrl), - onPendingLoginUrlChanged: (listener: LinkListener) => { - listeners.push(listener) - return () => { - listeners.splice(listeners.indexOf(listener), 1) - } - } - }, - ui: { writeClipboardText }, - shell: { openUrl } - } - }) - return { listeners, writeClipboardText, openUrl } -} - -afterEach(() => { - cleanup() - Reflect.deleteProperty(globalThis, 'api') -}) - -describe('CodexLoginLinkNotice', () => { - beforeEach(async () => { - await i18n.changeLanguage('en') - }) - - it('shows the link of a login that was already running when Settings opened', async () => { - stubApi(AUTH_URL) - const { container } = render() - await waitFor(() => expect(container.textContent).toContain(AUTH_URL)) - }) - - it('copies the link and opens it in the default browser on request', async () => { - const { listeners, writeClipboardText, openUrl } = stubApi(null) - const { container } = render() - await waitFor(() => expect(listeners.length).toBe(1)) - - listeners[0](AUTH_URL) - await waitFor(() => expect(container.textContent).toContain('Copy link')) - - const button = (label: string): HTMLButtonElement => { - const found = Array.from(container.querySelectorAll('button')).find((candidate) => - candidate.textContent?.includes(label) - ) - expect(found).not.toBeUndefined() - return found! - } - - fireEvent.click(button('Copy link')) - await waitFor(() => expect(writeClipboardText).toHaveBeenCalledWith(AUTH_URL)) - await waitFor(() => expect(container.textContent).toContain('Copied')) - - fireEvent.click(button('Open')) - expect(openUrl).toHaveBeenCalledWith(AUTH_URL) - }) - - it('drops the link once the login ends', async () => { - const { listeners } = stubApi(AUTH_URL) - const { container } = render() - await waitFor(() => expect(container.textContent).toContain(AUTH_URL)) - - listeners[0](null) - await waitFor(() => expect(container.textContent).toBe('')) - }) -}) diff --git a/src/renderer/src/components/settings/browser/routing/BrowserClientHostedRemoteSetting.test.tsx b/src/renderer/src/components/settings/browser/routing/BrowserClientHostedRemoteSetting.test.tsx deleted file mode 100644 index 627c9546210..00000000000 --- a/src/renderer/src/components/settings/browser/routing/BrowserClientHostedRemoteSetting.test.tsx +++ /dev/null @@ -1,68 +0,0 @@ -// @vitest-environment happy-dom -// @vitest-environment happy-dom -import { cleanup, fireEvent, render, screen } from '@testing-library/react' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { TooltipProvider } from '../../../ui/tooltip' -import { BrowserClientHostedRemoteSetting } from './BrowserClientHostedRemoteSetting' -import { getBrowserPaneSearchEntries } from '../browser-search' -import { matchesSettingsSearch } from '../../search/settings-search' -import { getBrowserClientHostedRemoteTitle } from './browser-client-hosted-remote-copy' -import type { GlobalSettings } from '../../../../../../shared/global-settings-types' - -vi.mock('../../../../store/index', () => ({ - useAppStore: (selector: (state: { settingsSearchQuery: string }) => unknown) => - selector({ settingsSearchQuery: '' }) -})) - -function renderSetting( - settings: Pick, - updateSettings: (updates: Partial) => void = vi.fn() -): void { - render( - - - - ) -} - -describe('BrowserClientHostedRemoteSetting', () => { - afterEach(() => { - cleanup() - }) - - it('defaults to this-device rendering when the profile predates the flag', () => { - renderSetting({}) - expect(screen.getByRole('radio', { name: 'This device' }).getAttribute('aria-checked')).toBe( - 'true' - ) - expect(screen.getByText(/new pages only/i)).toBeTruthy() - }) - - it('reads an explicit opt-out as server-streamed rendering', () => { - renderSetting({ browserClientHostedRemoteEnabled: false }) - expect( - screen.getByRole('radio', { name: 'Server (streamed)' }).getAttribute('aria-checked') - ).toBe('true') - }) - - it('writes the chosen placement through the global settings path', () => { - const updateSettings = vi.fn() - renderSetting({ browserClientHostedRemoteEnabled: true }, updateSettings) - fireEvent.click(screen.getByRole('radio', { name: 'Server (streamed)' })) - expect(updateSettings).toHaveBeenLastCalledWith({ browserClientHostedRemoteEnabled: false }) - fireEvent.click(screen.getByRole('radio', { name: 'This device' })) - expect(updateSettings).toHaveBeenLastCalledWith({ browserClientHostedRemoteEnabled: true }) - }) - - it('is findable from settings search by its own title', () => { - const entry = getBrowserPaneSearchEntries({ isMac: false }).find( - (candidate) => candidate.title === getBrowserClientHostedRemoteTitle() - ) - - expect(entry).toBeDefined() - expect(matchesSettingsSearch(getBrowserClientHostedRemoteTitle(), entry ?? [])).toBe(true) - expect(matchesSettingsSearch('placement', entry ?? [])).toBe(true) - expect(matchesSettingsSearch('new pages only', entry ?? [])).toBe(true) - expect(matchesSettingsSearch('unrelated setting query', entry ?? [])).toBe(false) - }) -}) diff --git a/src/renderer/src/components/settings/mobile/pairing/MobilePairingQrSection.test.tsx b/src/renderer/src/components/settings/mobile/pairing/MobilePairingQrSection.test.tsx index 9d62603a9c0..bb50061c2c0 100644 --- a/src/renderer/src/components/settings/mobile/pairing/MobilePairingQrSection.test.tsx +++ b/src/renderer/src/components/settings/mobile/pairing/MobilePairingQrSection.test.tsx @@ -3,7 +3,6 @@ import '@testing-library/jest-dom/vitest' import { cleanup, render, screen } from '@testing-library/react' -import userEvent from '@testing-library/user-event' import { afterEach, describe, expect, it, vi } from 'vitest' import { MobilePairingQrSection } from './MobilePairingQrSection' @@ -14,31 +13,6 @@ vi.mock('@/i18n/i18n', () => ({ afterEach(cleanup) describe('MobilePairingQrSection', () => { - it('shows and copies the pairing URL when QR encoding fails', async () => { - const writeClipboardText = vi.fn().mockResolvedValue(undefined) - Object.defineProperty(window, 'api', { - configurable: true, - value: { ui: { writeClipboardText } } - }) - render( - - ) - - expect(screen.getByRole('alert')).toHaveTextContent('couldn’t be rendered as a QR code') - await userEvent.click(screen.getByRole('button', { name: 'Copy pairing code' })) - expect(writeClipboardText).toHaveBeenCalledWith('orca://pair?code=copy-fallback') - }) - it('moves focus to the copy action when a pairing code becomes ready', () => { const props = { qrDataUrl: null, diff --git a/src/renderer/src/components/settings/notifications/NotificationsPane.test.tsx b/src/renderer/src/components/settings/notifications/NotificationsPane.test.tsx deleted file mode 100644 index 131f16e745c..00000000000 --- a/src/renderer/src/components/settings/notifications/NotificationsPane.test.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { createGlobalSettingsFixture } from '../../../../../shared/global-settings-test-fixture' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' - -import type { GlobalSettings } from '../../../../../shared/global-settings-types' -import type { NotificationDispatchRequest } from '../../../../../shared/notification-settings-types' - -import { sendNotificationSettingsTestNotification } from './notification-settings-copy' - -const { toastError, toastMessage, toastSuccess } = vi.hoisted(() => ({ - toastError: vi.fn(), - toastMessage: vi.fn(), - toastSuccess: vi.fn() -})) - -vi.mock('sonner', () => ({ - toast: { - error: toastError, - message: toastMessage, - success: toastSuccess - } -})) - -function createSettings(): GlobalSettings { - return createGlobalSettingsFixture({ - notifications: { - enabled: true, - agentTaskComplete: true, - agentNeedsInput: true, - terminalBell: true, - suppressWhenFocused: true, - customSoundId: 'system', - customSoundPath: null, - customSoundVolume: 50, - mutedNotificationSourceIds: [], - notifyHiddenWorkspaces: false - } - }) -} - -describe('NotificationsPane', () => { - beforeEach(() => { - toastError.mockClear() - toastMessage.mockClear() - toastSuccess.mockClear() - }) - - afterEach(() => { - vi.unstubAllGlobals() - }) - - it('uses native main-process delivery even when renderer permission is stale denied on macOS', async () => { - const notifications = { - getPermissionStatus: vi.fn(async () => ({ - supported: true, - platform: 'darwin' as NodeJS.Platform, - requested: true - })), - dispatch: vi.fn(async (_args: NotificationDispatchRequest) => ({ delivered: true })), - playSound: vi.fn(), - openSystemSettings: vi.fn(), - requestPermission: vi.fn() - } - vi.stubGlobal('window', { - Notification: { permission: 'denied' }, - api: { - notifications, - shell: { pickAudio: vi.fn() } - } - }) - - await sendNotificationSettingsTestNotification(createSettings().notifications, 50) - - // Probe main-process Electron delivery; renderer permission state can remain stale after macOS settings change. - expect(notifications.dispatch).toHaveBeenCalledWith({ - source: 'test', - requireDisplayConfirmation: true - }) - expect(toastError).not.toHaveBeenCalled() - expect(toastSuccess).not.toHaveBeenCalled() - expect(toastMessage).toHaveBeenCalledWith( - 'Test notification requested', - expect.objectContaining({ - description: 'If no macOS banner appeared, enable Allow notifications for Orca.', - action: expect.objectContaining({ label: 'Open Settings' }) - }) - ) - - const toastOptions = toastMessage.mock.calls[0]?.[1] as - | { action?: { onClick?: () => void } } - | undefined - toastOptions?.action?.onClick?.() - expect(notifications.openSystemSettings).toHaveBeenCalledTimes(1) - }) -}) diff --git a/src/renderer/src/components/terminal-pane/TerminalPaneResumeInChatButton.test.tsx b/src/renderer/src/components/terminal-pane/TerminalPaneResumeInChatButton.test.tsx deleted file mode 100644 index 903f3795db3..00000000000 --- a/src/renderer/src/components/terminal-pane/TerminalPaneResumeInChatButton.test.tsx +++ /dev/null @@ -1,86 +0,0 @@ -// @vitest-environment happy-dom -import { cleanup, fireEvent, render, screen } from '@testing-library/react' -import { afterEach, beforeEach, expect, it, vi } from 'vitest' -import { TooltipProvider } from '@/components/ui/tooltip' -import { TerminalPaneResumeInChatButton } from './TerminalPaneResumeInChatButton' -import type { CliChatResumeSource } from '../tab-bar/cli-chat-resume-source' - -const LOCAL_SOURCE: CliChatResumeSource = { - tabId: 'tab-1', - workspaceId: 'wt-1', - paneKey: 'tab-1:leaf', - agent: 'claude', - providerSessionId: 'provider-1', - executionHostId: 'local' -} - -const mocks = vi.hoisted(() => { - const source: { current: CliChatResumeSource | null } = { current: null } - return { source, resolve: vi.fn(), run: vi.fn(), pending: false } -}) -vi.mock('@/store', () => ({ - useAppStore: (selector: (state: Record) => unknown) => selector({}) -})) -vi.mock('../tab-bar/cli-chat-resume-source', () => ({ - resolveCliChatResumeSource: (_state: unknown, args: unknown) => { - mocks.resolve(args) - return mocks.source.current - } -})) -vi.mock('../tab-bar/cli-chat-resume-run', () => ({ - runCliChatResume: mocks.run, - useCliChatResumePending: () => mocks.pending -})) -beforeEach(() => { - mocks.source.current = LOCAL_SOURCE -}) -afterEach(cleanup) - -it('dispatches the exact pane with owner-opening intent and shares pending', () => { - const { rerender } = render( - - - - ) - fireEvent.click(screen.getByRole('button', { name: 'Continue in Chat UI' })) - expect(mocks.resolve).toHaveBeenCalledWith({ - tab: { id: 'tab-1', worktreeId: 'wt-1' }, - paneKey: 'tab-1:leaf' - }) - expect(mocks.run).toHaveBeenCalledWith(LOCAL_SOURCE, true) - mocks.pending = true - rerender( - - - - ) - expect(screen.getByRole('button').getAttribute('aria-busy')).toBe('true') - expect(screen.getByRole('button').hasAttribute('disabled')).toBe(true) -}) - -it('keeps an older host visible but disabled, telling the user to update it', async () => { - mocks.pending = false - mocks.run.mockClear() - mocks.source.current = { - ...LOCAL_SOURCE, - executionHostId: 'runtime:server-1', - hostUpdateRequired: true - } - render( - - - - ) - const button = screen.getByRole('button', { - name: 'Continue in Chat UI. Update Orca on this host to continue in Chat UI.' - }) - expect(button.hasAttribute('disabled')).toBe(true) - const trigger = button.parentElement - if (trigger) { - fireEvent.focus(trigger) - } - expect( - (await screen.findAllByText('Update Orca on this host to continue in Chat UI.')).length - ).toBeGreaterThan(0) - expect(mocks.run).not.toHaveBeenCalled() -}) diff --git a/src/renderer/src/components/terminal-pane/pty-connection/empty-reattach-retire-evidence.test.ts b/src/renderer/src/components/terminal-pane/pty-connection/empty-reattach-retire-evidence.test.ts deleted file mode 100644 index bc51518b5a9..00000000000 --- a/src/renderer/src/components/terminal-pane/pty-connection/empty-reattach-retire-evidence.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { hasEmptyReattachRetireEvidence } from './empty-reattach-retire-evidence' -import { isHibernationDoneRecord } from '../../../../../shared/hibernation-done-record' -import type { SleepingAgentSessionRecord } from '../../../../../shared/agent-session/lifecycle/agent-session-resume' -import type { ColdRestoreAgentResumeStartup } from './fresh-spawn-types' - -function note(overrides: Partial = {}): SleepingAgentSessionRecord { - return { - paneKey: 'tab-1:leaf-1', - worktreeId: 'wt-1', - agent: 'codex', - providerSession: { key: 'session_id', id: 'conv-1' }, - prompt: '', - state: 'done', - capturedAt: 1, - updatedAt: 1, - ...overrides - } -} - -function resumeStartup( - record: SleepingAgentSessionRecord | null, - useLiveEntry = false -): ColdRestoreAgentResumeStartup { - return { - command: 'codex resume conv-1', - agent: 'codex', - resumeOrigin: 'saved', - resumeProviderSession: { key: 'session_id', id: 'conv-1' }, - launchConfig: { agentArgs: '', agentEnv: {} }, - launchToken: 'token-1', - useLiveEntry, - hasSleepingRecord: record !== null, - sleepingRecordEntry: record ? { paneKey: record.paneKey, record } : null - } -} - -const WORKTREE_SLEEP_DONE = note({ origin: 'worktree-sleep' }) - -describe('isHibernationDoneRecord', () => { - it.each([ - ['a legacy originless done note', true, note()], - ['a worktree-sleep done note', true, WORKTREE_SLEEP_DONE], - ['a live done note (the idle anchor of a running pane)', false, note({ origin: 'live' })], - [ - 'a live done note marked not interrupted', - false, - note({ origin: 'live', interrupted: false }) - ], - ['a quit done note', false, note({ origin: 'quit' })], - [ - 'a worktree-sleep note still working', - false, - note({ origin: 'worktree-sleep', state: 'working' }) - ] - ])('%s -> %s', (_label, expected, record) => { - expect(isHibernationDoneRecord(record)).toBe(expected) - }) -}) - -describe('hasEmptyReattachRetireEvidence', () => { - it.each([ - ['a local pty', 'local-pty-1'], - ['a local daemon session id', 'wt-1@@daemon-session-1'] - ])('retires %s under a hibernation done note', (_label, ptyId) => { - expect(hasEmptyReattachRetireEvidence(ptyId, resumeStartup(WORKTREE_SLEEP_DONE))).toBe(true) - }) - - it('never retires a remote runtime pty, whose disconnect leaves the host PTY alive', () => { - expect( - hasEmptyReattachRetireEvidence('remote:env-1@@term_1', resumeStartup(WORKTREE_SLEEP_DONE)) - ).toBe(false) - }) - - it.each([ - ['no resume startup', undefined], - ['a startup resuming the live entry', resumeStartup(WORKTREE_SLEEP_DONE, true)], - ['a startup without a sleeping note', resumeStartup(null)], - ['a live done note', resumeStartup(note({ origin: 'live' }))] - ])('keeps a local pty with %s', (_label, startup) => { - expect(hasEmptyReattachRetireEvidence('local-pty-1', startup)).toBe(false) - }) -}) diff --git a/src/renderer/src/components/terminal-pane/pty-connection/write-pty-output-to-xterm-startup-callback.test.ts b/src/renderer/src/components/terminal-pane/pty-connection/write-pty-output-to-xterm-startup-callback.test.ts deleted file mode 100644 index fd5e2d2bc7c..00000000000 --- a/src/renderer/src/components/terminal-pane/pty-connection/write-pty-output-to-xterm-startup-callback.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { bindWritePtyOutputToXterm } from './write-pty-output-to-xterm' -import { createTerminalInputEchoDelay } from './terminal-input-echo-delay' -import { TerminalIdleCursorReset } from '../terminal-idle-cursor-reset' - -const writeTerminalOutput = vi.hoisted(() => vi.fn()) -const forceFullViewportPresent = vi.hoisted(() => vi.fn()) - -vi.mock('@/lib/pane-manager/pane-terminal-output-scheduler', () => ({ - writeTerminalOutput -})) - -vi.mock('@/lib/pane-manager/terminal-render-pause-release', () => ({ - forceFullViewportPresent -})) - -vi.mock('@/lib/pane-manager/terminal-delivery-credit', () => ({ - takeCurrentTerminalDeliveryCredit: vi.fn(() => undefined) -})) - -function createSession(startupOnParsed: () => void) { - const terminal = {} - return { - kittyKeyboardModes: { scan: vi.fn() }, - resetHiddenOutputRestoreIfPtyChanged: vi.fn(), - transport: { getPtyId: vi.fn(() => 'pty-1') }, - canUseHiddenOutputSnapshot: vi.fn(() => false), - shouldSnapshotHiddenCodexOutput: false, - shouldProtectNativeWindowsSynchronizedOutput: true, - shouldApplyNativeWindowsRewriteRefresh: false, - synchronizedForegroundMarkerTail: '', - synchronizedForegroundOutputActive: true, - synchronizedForegroundFrameInteractive: false, - synchronizedForegroundInteractivePresentPending: true, - lastTerminalInputAt: 0, - inputEchoDelay: createTerminalInputEchoDelay(), - idleCursorReset: new TerminalIdleCursorReset(), - scheduleForegroundGridDriftCheck: vi.fn(), - shouldForceForegroundRenderRefresh: vi.fn(() => ({ refresh: false, inPlaceRewrite: false })), - isLatencySensitiveForegroundOutput: vi.fn(() => false), - shouldRefreshForegroundSynchronously: false, - beforeTerminalOutputWrite: undefined, - markHiddenOutputRestoreNeeded: vi.fn(), - startupTiming: { - firstWrite: vi.fn(() => ({ beforeWrite: vi.fn(), onParsed: startupOnParsed })) - }, - writePtyOutputToXterm: vi.fn(), - pane: { terminal } - } -} - -describe('bindWritePtyOutputToXterm startup callbacks', () => { - it('composes startup timing and synchronized-frame presentation callbacks', () => { - const startupOnParsed = vi.fn() - const session = createSession(startupOnParsed) - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the fixture supplies exactly the fields read by this isolated binding test. - bindWritePtyOutputToXterm(session as never) - - session.writePtyOutputToXterm?.('\x1b[?2026hframe', true, { liveStartupBatch: true }) - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the scheduler mock receives the binding's documented options object. - const options = writeTerminalOutput.mock.calls[0]?.[2] as { - onParsed?: () => void - } - options.onParsed?.() - - expect(startupOnParsed).toHaveBeenCalledOnce() - expect(forceFullViewportPresent).toHaveBeenCalledWith(session.pane.terminal) - }) -}) diff --git a/src/renderer/src/components/terminal/terminal-provider-snapshot-capability-resettlement.test.ts b/src/renderer/src/components/terminal/terminal-provider-snapshot-capability-resettlement.test.ts deleted file mode 100644 index 614fca6a4cc..00000000000 --- a/src/renderer/src/components/terminal/terminal-provider-snapshot-capability-resettlement.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** Unknown capabilities retain panes during outages but must be re-asked after recovery to release eviction exemptions. */ -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { PTY_SESSION_ID_SEPARATOR } from '../../../../shared/pty-session-id-format' -import { isEvictionExemptTerminalPty } from '../terminal-pane/terminal-hidden-worktree-retention' -import { - clearTerminalProviderSnapshotCapabilities, - synchronizeTerminalProviderSnapshotCapabilities, - terminalProviderHasAuthoritativeSnapshot -} from './terminal-provider-snapshot-capability' - -const WORKTREE_ID = 'wt-resettlement' -const PTY_ID = `${WORKTREE_ID}${PTY_SESSION_ID_SEPARATOR}session-1` - -async function exhaustRetryBudget( - resolver: (ids: string[]) => Promise<{ id: string; authoritative: boolean | null }[]>, - startMs: number -): Promise { - const livePtyIds = [PTY_ID] - let nowMs = startMs - // 8 attempts across the 1/2/4/8/16/30/30s ladder, plus slack iterations. - for (let attempt = 0; attempt < 12; attempt += 1) { - const retryDelayMs = await synchronizeTerminalProviderSnapshotCapabilities( - livePtyIds, - resolver, - nowMs - ) - if (retryDelayMs === null) { - break - } - nowMs += retryDelayMs + 1 - } - return nowMs -} - -describe('terminal provider snapshot capability re-settlement', () => { - beforeEach(() => clearTerminalProviderSnapshotCapabilities()) - - it('keeps an unknown-capability pty exempt during the outage (safety)', async () => { - const failingResolver = vi.fn(async () => { - throw new Error('daemon unavailable') - }) - await synchronizeTerminalProviderSnapshotCapabilities([PTY_ID], failingResolver, 1_000) - - expect(failingResolver).toHaveBeenCalled() - expect(terminalProviderHasAuthoritativeSnapshot(PTY_ID)).toBe(false) - expect(isEvictionExemptTerminalPty(PTY_ID, WORKTREE_ID)).toBe(true) - }) - - it('re-consults a recovered resolver after the retry budget and clears the exemption', async () => { - const failingResolver = vi.fn(async () => { - throw new Error('daemon unavailable') - }) - const settledAtMs = await exhaustRetryBudget(failingResolver, 1_000) - expect(isEvictionExemptTerminalPty(PTY_ID, WORKTREE_ID)).toBe(true) - - const healthyResolver = vi.fn(async (ids: string[]) => - ids.map((id) => ({ id, authoritative: true })) - ) - // Allow slow re-ask after recovery; a fresh PTY set also models ordinary tab churn. - const recoveredAtMs = settledAtMs + 10 * 60_000 - await synchronizeTerminalProviderSnapshotCapabilities([PTY_ID], healthyResolver, recoveredAtMs) - const secondPassMs = recoveredAtMs + 10 * 60_000 - await synchronizeTerminalProviderSnapshotCapabilities([PTY_ID], healthyResolver, secondPassMs) - - expect(healthyResolver).toHaveBeenCalled() - expect(terminalProviderHasAuthoritativeSnapshot(PTY_ID)).toBe(true) - expect(isEvictionExemptTerminalPty(PTY_ID, WORKTREE_ID)).toBe(false) - }) -}) diff --git a/src/renderer/src/lib/foreground-terminal-tabs.test.ts b/src/renderer/src/lib/foreground-terminal-tabs.test.ts index b8e000d8e21..767547ef5ce 100644 --- a/src/renderer/src/lib/foreground-terminal-tabs.test.ts +++ b/src/renderer/src/lib/foreground-terminal-tabs.test.ts @@ -13,19 +13,6 @@ afterEach(() => { }) describe('foreground terminal tabs', () => { - it('keeps duplicate visible terminal tab claims until every token unregisters', () => { - const unregisterFirst = registerVisibleTerminalTab('tab-visible') - const unregisterSecond = registerVisibleTerminalTab('tab-visible') - - expect(getForegroundTerminalTabIds()).toEqual(['tab-visible']) - - unregisterFirst() - expect(getForegroundTerminalTabIds()).toEqual(['tab-visible']) - - unregisterSecond() - expect(getForegroundTerminalTabIds()).toEqual([]) - }) - it('refreshes last-seen when explicit foreground ids leave the combined foreground set', () => { vi.useFakeTimers() vi.setSystemTime(1_000) diff --git a/src/renderer/src/lib/sleeping-agent-pane-ownership.test.ts b/src/renderer/src/lib/sleeping-agent-pane-ownership.test.ts deleted file mode 100644 index 95723f2db73..00000000000 --- a/src/renderer/src/lib/sleeping-agent-pane-ownership.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { SleepingAgentSessionRecord } from '../../../shared/agent-session/lifecycle/agent-session-resume' - -function note(overrides: Partial = {}): SleepingAgentSessionRecord { - return { - paneKey: 'tab-1:leaf-1', - worktreeId: 'wt-1', - agent: 'codex', - providerSession: { key: 'session_id', id: 'conv-1' }, - prompt: '', - state: 'done', - capturedAt: 1, - updatedAt: 1, - ...overrides - } -} - -describe('recordPaneIsOwnedByPreservedPane: a pane its host kept asleep', () => { - const layout = { - 'tab-1': { - root: { type: 'leaf' as const, leafId: '11111111-1111-4111-8111-111111111111' }, - activeLeafId: '11111111-1111-4111-8111-111111111111', - expandedLeafId: null - } - } - const paneKey = 'tab-1:11111111-1111-4111-8111-111111111111' - const state = { - activeWorktreeId: 'wt-other', - tabsByWorktree: { 'wt-1': [{ id: 'tab-1' }] }, - ptyIdsByTabId: {}, - terminalLayoutsByTabId: layout - } - - it('owns its unfinished session while deferred, so a sweep does not launch it again', async () => { - const { setPaneSpawnDeferral, clearPaneSpawnDeferral } = - await import('./pane-spawn-deferral-registry') - const { recordPaneIsOwnedByPreservedPane } = await import('./sleeping-agent-pane-ownership') - const record = note({ paneKey, tabId: 'tab-1', origin: 'quit' }) - - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the predicate reads only these four store maps. - expect(recordPaneIsOwnedByPreservedPane(record, state as never)).toBe(false) - setPaneSpawnDeferral(paneKey, { reason: 'live_cap', resume: () => {} }) - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the predicate reads only these four store maps. - expect(recordPaneIsOwnedByPreservedPane(record, state as never)).toBe(true) - clearPaneSpawnDeferral(paneKey) - }) - - it('owns a legacy-keyed session while its pane holds the resume until shown', async () => { - const { holdPaneResumeUntilShown, releasePaneResumeHold } = - await import('./pane-spawn-deferral-registry') - const { recordPaneIsOwnedByPreservedPane } = await import('./sleeping-agent-pane-ownership') - const record = note({ paneKey: 'tab-1:2', tabId: 'tab-1', origin: 'quit' }) - const holding = (): boolean => true - const legacyState = { ...state, sleepingAgentSessionsByPaneKey: { 'tab-1:2': record } } - - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the predicate reads only these five store maps. - expect(recordPaneIsOwnedByPreservedPane(record, legacyState as never)).toBe(false) - holdPaneResumeUntilShown('tab-1:2', holding) - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the predicate reads only these five store maps. - expect(recordPaneIsOwnedByPreservedPane(record, legacyState as never)).toBe(true) - releasePaneResumeHold('tab-1:2', holding) - }) -}) diff --git a/src/shared/agent-launch/catalog/tui-agent-selection.test.ts b/src/shared/agent-launch/catalog/tui-agent-selection.test.ts index c92f5e62d37..63ff0cd663e 100644 --- a/src/shared/agent-launch/catalog/tui-agent-selection.test.ts +++ b/src/shared/agent-launch/catalog/tui-agent-selection.test.ts @@ -1,21 +1,7 @@ import { describe, expect, it } from 'vitest' -import { - haveSameDisabledTuiAgents, - normalizeDisabledTuiAgents, - pickTuiAgent -} from './tui-agent-selection' +import { normalizeDisabledTuiAgents, pickTuiAgent } from './tui-agent-selection' describe('pickTuiAgent', () => { - it('uses an installed preferred agent', () => { - expect(pickTuiAgent('codex', ['claude', 'codex'])).toBe('codex') - }) - - it('falls back in desktop catalog order when the preference is absent or stale', () => { - expect(pickTuiAgent(null, ['cursor', 'codex'])).toBe('codex') - expect(pickTuiAgent('gemini', ['cursor', 'codex'])).toBe('codex') - expect(pickTuiAgent(null, ['continue', 'command-code'])).toBe('command-code') - }) - it('respects the explicit blank terminal preference', () => { expect(pickTuiAgent('blank', ['cursor', 'claude'])).toBeNull() }) @@ -34,11 +20,3 @@ describe('normalizeDisabledTuiAgents', () => { ]) }) }) - -describe('haveSameDisabledTuiAgents', () => { - it('compares the normalized disabled-agent sets', () => { - expect(haveSameDisabledTuiAgents(['codex', 'claude'], ['claude', 'codex'])).toBe(true) - expect(haveSameDisabledTuiAgents(['codex', 'unknown'], ['codex'])).toBe(true) - expect(haveSameDisabledTuiAgents(['codex'], ['claude'])).toBe(false) - }) -}) diff --git a/src/shared/agent-launch/choices/default-agent-settings.test.ts b/src/shared/agent-launch/choices/default-agent-settings.test.ts deleted file mode 100644 index 580afea5091..00000000000 --- a/src/shared/agent-launch/choices/default-agent-settings.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildDefaultAgentSettingsUpdate } from './default-agent-settings' - -describe('default agent settings', () => { - it.each(['blank', 'claude', null] as const)( - 'clears the retired setup-only flag for %s', - (agent) => { - expect(buildDefaultAgentSettingsUpdate(agent)).toEqual({ - defaultTuiAgent: agent, - newWorkspaceSetupOnly: false - }) - } - ) -}) diff --git a/src/shared/agent-launch/startup/dsh-startup.spec.ts b/src/shared/agent-launch/startup/dsh-startup.spec.ts deleted file mode 100644 index c25a66c259f..00000000000 --- a/src/shared/agent-launch/startup/dsh-startup.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildAgentStartupPlan } from './tui-agent-startup' -import { TUI_AGENT_CONFIG } from '../catalog/tui-agent-config' - -describe('DSH first launch', () => { - it.each(['darwin', 'linux', 'win32'] as const)( - 'plans the current workspace with task input deferred on %s', - (platform) => { - const plan = buildAgentStartupPlan({ - agent: 'dsh', - prompt: 'Review this folder', - cmdOverrides: {}, - platform - }) - expect(plan?.launchCommand).toContain('dsh-tui .') - expect(plan?.launchCommand).not.toContain('Review this folder') - expect(TUI_AGENT_CONFIG.dsh.promptInjectionMode).toBe('stdin-after-start') - expect(TUI_AGENT_CONFIG.dsh.draftPasteReadySignal).toBe('dsh-composer-prompt') - } - ) -}) diff --git a/src/shared/agent-launch/startup/freebuff-launch.spec.ts b/src/shared/agent-launch/startup/freebuff-launch.spec.ts deleted file mode 100644 index d8bf5be793a..00000000000 --- a/src/shared/agent-launch/startup/freebuff-launch.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildAgentDraftLaunchPlan, buildAgentStartupPlan } from './tui-agent-startup' -import { - isExpectedAgentProcess, - recognizeAgentProcess -} from '../../agent-status/process/agent-process-recognition' -import { pickTuiAgent } from '../catalog/tui-agent-selection' - -describe('Freebuff terminal launches', () => { - it.each(['darwin', 'linux', 'win32'] as const)( - 'plans task text as a follow-up to the interactive launch on %s', - (platform) => { - const prompt = '--help\nFix "quoted" paths and $HOME handling' - const plan = buildAgentStartupPlan({ - agent: 'freebuff', - prompt, - cmdOverrides: {}, - platform - }) - expect(plan).toMatchObject({ - launchCommand: 'freebuff', - expectedProcess: 'freebuff', - followupPrompt: prompt - }) - expect( - buildAgentDraftLaunchPlan({ - agent: 'freebuff', - draft: prompt, - cmdOverrides: {}, - platform - }) - ).toBeNull() - } - ) - - it('uses the same launch contract on SSH hosts', () => { - expect( - buildAgentStartupPlan({ - agent: 'freebuff', - prompt: 'Inspect this folder', - cmdOverrides: {}, - platform: 'linux', - isRemote: true - }) - ).toMatchObject({ launchCommand: 'freebuff', followupPrompt: 'Inspect this folder' }) - }) - - it.each(['/usr/local/bin/freebuff', 'C:\\tools\\freebuff.exe'])( - 'recognizes %s separately from Codebuff', - (processName) => { - expect(recognizeAgentProcess(processName)?.agent).toBe('freebuff') - expect(isExpectedAgentProcess(processName, 'codebuff')).toBe(false) - } - ) - - it('honors independent installation and disabled-agent preferences', () => { - expect(pickTuiAgent('freebuff', ['freebuff', 'codebuff'])).toBe('freebuff') - expect(pickTuiAgent(null, ['freebuff'])).toBe('freebuff') - expect(pickTuiAgent('freebuff', ['freebuff', 'codebuff'], ['freebuff'])).toBe('codebuff') - }) -}) diff --git a/src/shared/agent-launch/startup/freebuff-startup.spec.ts b/src/shared/agent-launch/startup/freebuff-startup.spec.ts deleted file mode 100644 index 65806790af4..00000000000 --- a/src/shared/agent-launch/startup/freebuff-startup.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildAgentStartupPlan } from './tui-agent-startup' - -describe('Freebuff startup', () => { - it('keeps Freebuff command overrides separate from Codebuff', () => { - const cmdOverrides = { freebuff: 'freebuff --debug' } - const freebuff = buildAgentStartupPlan({ - agent: 'freebuff', - prompt: '', - allowEmptyPromptLaunch: true, - cmdOverrides, - platform: 'linux', - isRemote: true - }) - const codebuff = buildAgentStartupPlan({ - agent: 'codebuff', - prompt: '', - allowEmptyPromptLaunch: true, - cmdOverrides, - platform: 'linux', - isRemote: true - }) - - expect(freebuff).toMatchObject({ - launchCommand: 'freebuff --debug', - expectedProcess: 'freebuff', - followupPrompt: null - }) - expect(codebuff).toMatchObject({ launchCommand: 'codebuff', expectedProcess: 'codebuff' }) - }) -}) diff --git a/src/shared/agent-launch/startup/omp-fresh-launch.spec.ts b/src/shared/agent-launch/startup/omp-fresh-launch.spec.ts index ce5df60be07..1ec2aa49f33 100644 --- a/src/shared/agent-launch/startup/omp-fresh-launch.spec.ts +++ b/src/shared/agent-launch/startup/omp-fresh-launch.spec.ts @@ -3,14 +3,6 @@ import { withFreshOmpLaunch } from './omp-fresh-launch' import { buildAgentStartupPlan } from './tui-agent-startup' describe('OMP fresh launch intent', () => { - it.each(['omp', 'omp launch', 'omp --model provider/model', 'omp --config user.yml'])( - '%s adds the final overlay', - (command) => { - expect(withFreshOmpLaunch(command, 'posix')).toContain( - `${command} --config "$ORCA_OMP_FRESH_CONFIG"` - ) - } - ) it.each([ 'omp --resume id', 'omp -r id', @@ -38,12 +30,6 @@ describe('OMP fresh launch intent', () => { const command = 'omp --model foo&' expect(withFreshOmpLaunch(command, shell)).toBe(command) }) - it('quotes the host config path for each Windows shell', () => { - expect(withFreshOmpLaunch('omp', 'powershell')).toContain( - 'omp --config "$env:ORCA_OMP_FRESH_CONFIG"' - ) - expect(withFreshOmpLaunch('omp', 'cmd')).toContain('omp --config "%~$ORCA_OMP_FRESH_CONFIG:!"') - }) it('keeps fresh intent out of saved resume command and environment', () => { const plan = buildAgentStartupPlan({ agent: 'omp', @@ -55,14 +41,4 @@ describe('OMP fresh launch intent', () => { expect(JSON.stringify(plan?.launchConfig)).not.toContain('ORCA_OMP_FRESH_CONFIG') expect(plan?.env).toBeUndefined() }) - it('requires host-owned configuration for fresh SSH launches', () => { - const plan = buildAgentStartupPlan({ - agent: 'omp', - prompt: 'new task', - cmdOverrides: {}, - platform: 'linux', - isRemote: true - }) - expect(plan?.launchCommand).toContain('test -f "$ORCA_OMP_FRESH_CONFIG"') - }) }) diff --git a/src/shared/agent-launch/startup/qoder-cn-launch-recipe.spec.ts b/src/shared/agent-launch/startup/qoder-cn-launch-recipe.spec.ts deleted file mode 100644 index 7b2202ec376..00000000000 --- a/src/shared/agent-launch/startup/qoder-cn-launch-recipe.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildAgentStartupPlan } from './tui-agent-startup' -import { buildAgentResumeStartupPlan } from './tui-agent-resume-startup' - -describe('Qoder China launch recipe identity', () => { - it.each(['darwin', 'linux', 'win32'] as const)( - 'preserves the official China executable on %s', - (platform) => { - const plan = buildAgentStartupPlan({ - agent: 'qoder-cn', - prompt: 'fixture', - cmdOverrides: {}, - platform - }) - expect(plan?.agent).toBe('qoder-cn') - expect(plan?.launchCommand).toBe("qoderclicn --prompt-interactive 'fixture'") - expect( - buildAgentResumeStartupPlan({ - agent: 'qoder-cn', - providerSession: { key: 'session_id', id: 'fixture-session' }, - cmdOverrides: {}, - platform - })?.launchCommand - ).toBe("qoderclicn '--resume' 'fixture-session'") - } - ) - - it.each(['darwin', 'linux', 'win32'] as const)( - 'preserves an explicitly configured shared-binary --cn recipe on %s', - (platform) => { - const cmdOverrides = { 'qoder-cn': 'qodercli --cn' } - const plan = buildAgentStartupPlan({ - agent: 'qoder-cn', - prompt: 'fixture', - cmdOverrides, - platform - }) - expect(plan?.agent).toBe('qoder-cn') - expect(plan?.launchCommand).toBe("qodercli --cn --prompt-interactive 'fixture'") - expect( - buildAgentResumeStartupPlan({ - agent: 'qoder-cn', - providerSession: { key: 'session_id', id: 'fixture-session' }, - cmdOverrides, - platform - })?.launchCommand - ).toBe("qodercli --cn '--resume' 'fixture-session'") - } - ) -}) diff --git a/src/shared/agent-launch/startup/tui-agent-prompt-transport.spec.ts b/src/shared/agent-launch/startup/tui-agent-prompt-transport.spec.ts deleted file mode 100644 index afbd5c26891..00000000000 --- a/src/shared/agent-launch/startup/tui-agent-prompt-transport.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** Pin the pre-launch transport predicate to buildAgentStartupPlan’s followupPrompt verdict for every agent so table drift cannot lose prompts. */ - -import { describe, expect, it } from 'vitest' -import { TUI_AGENT_CONFIG } from '../catalog/tui-agent-config' -import { agentPromptRidesLaunchCommand, buildAgentStartupPlan } from './tui-agent-startup' -import type { TuiAgent } from '../catalog/tui-agent' - -// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the config is declared as a total record over TuiAgent, so its own keys are that union. -const ALL_AGENTS = Object.keys(TUI_AGENT_CONFIG) as TuiAgent[] - -const PROMPT = 'summarize the diff' - -function planFor(agent: TuiAgent) { - return buildAgentStartupPlan({ - agent, - prompt: PROMPT, - cmdOverrides: {}, - platform: 'darwin' - }) -} - -describe('the prompt-transport predicate against the plan it predicts', () => { - // An empty agent list would make the contract vacuously pass. - - it('puts the prompt in the launch command exactly when it says it does', () => { - for (const agent of ALL_AGENTS) { - const plan = planFor(agent) - if (!agentPromptRidesLaunchCommand(agent)) { - // The command must not smuggle the text in some other way. - expect(plan!.launchCommand).not.toContain(PROMPT) - expect(plan!.followupPrompt).toBe(PROMPT) - continue - } - // Hermes hands long text through an env var, so the command names the variable, not the text. - const carried = - plan!.launchCommand.includes(PROMPT) || - Object.values(plan!.env ?? {}).some((value) => value.includes(PROMPT)) - expect(carried, `${agent} claims its launch command carries the prompt`).toBe(true) - } - }) -}) diff --git a/src/shared/agent-launch/startup/tui-agent-startup-copilot-resume.spec.ts b/src/shared/agent-launch/startup/tui-agent-startup-copilot-resume.spec.ts deleted file mode 100644 index 11e3139c9c9..00000000000 --- a/src/shared/agent-launch/startup/tui-agent-startup-copilot-resume.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildAgentResumeStartupPlan } from './tui-agent-resume-startup' - -const SESSION = { key: 'session_id' as const, id: '940237d9-c712-48e8-bca1-fd75fc4a8d4b' } - -describe('Copilot resume startup plan', () => { - it('uses the documented joined --resume form', () => { - const plan = buildAgentResumeStartupPlan({ - agent: 'copilot', - providerSession: SESSION, - cmdOverrides: {}, - agentArgs: '--yolo', - platform: 'darwin' - }) - - expect(plan?.launchCommand).toBe(`copilot '--yolo' '--resume=${SESSION.id}'`) - }) - - it('quotes the resume argv for cmd.exe', () => { - const plan = buildAgentResumeStartupPlan({ - agent: 'copilot', - providerSession: SESSION, - cmdOverrides: {}, - agentArgs: '--yolo', - platform: 'win32', - shell: 'cmd' - }) - - // Why: cmd.exe treats single quotes as literal characters. - expect(plan?.launchCommand).toBe(`copilot "--yolo" "--resume=${SESSION.id}"`) - }) - - it('honors a command override', () => { - const plan = buildAgentResumeStartupPlan({ - agent: 'copilot', - providerSession: SESSION, - cmdOverrides: { copilot: 'copilot --banner' }, - platform: 'linux' - }) - - expect(plan?.launchCommand).toBe(`copilot --banner '--resume=${SESSION.id}'`) - }) -}) diff --git a/src/shared/agent-launch/startup/tui-agent-startup-kiro-resume.test.ts b/src/shared/agent-launch/startup/tui-agent-startup-kiro-resume.test.ts index 892786b9b6e..7109eebe267 100644 --- a/src/shared/agent-launch/startup/tui-agent-startup-kiro-resume.test.ts +++ b/src/shared/agent-launch/startup/tui-agent-startup-kiro-resume.test.ts @@ -2,23 +2,6 @@ import { describe, expect, it } from 'vitest' import { buildAgentResumeStartupPlan } from './tui-agent-resume-startup' describe('Kiro cold restore', () => { - it.each([ - ['darwin', 'posix', "kiro-cli chat --tui '--trust-all-tools' '--resume-id' 'session-1'"], - ['linux', 'posix', "kiro-cli chat --tui '--trust-all-tools' '--resume-id' 'session-1'"], - ['win32', 'powershell', "kiro-cli chat --tui '--trust-all-tools' '--resume-id' 'session-1'"], - ['win32', 'cmd', 'kiro-cli chat --tui "--trust-all-tools" "--resume-id" "session-1"'] - ] as const)('appends only the resume selector on %s/%s', (platform, shell, expected) => { - const plan = buildAgentResumeStartupPlan({ - agent: 'kiro', - providerSession: { key: 'session_id', id: 'session-1' }, - cmdOverrides: {}, - agentArgs: '--trust-all-tools', - platform, - shell - }) - expect(plan?.launchCommand).toBe(expected) - }) - it('preserves the captured engine and agent selection on a remote host', () => { const plan = buildAgentResumeStartupPlan({ agent: 'kiro', diff --git a/src/shared/agent-launch/startup/tui-agent-startup.test.ts b/src/shared/agent-launch/startup/tui-agent-startup.test.ts index f7d16841011..83fd973e36c 100644 --- a/src/shared/agent-launch/startup/tui-agent-startup.test.ts +++ b/src/shared/agent-launch/startup/tui-agent-startup.test.ts @@ -4,17 +4,11 @@ import './agent-resume-launch-command.spec' import './agent-startup-plan-inputs.spec' import './agent-startup-plan-inputs-extra-agent-args.spec' import './automation-extra-agent-args.spec' -import './dsh-startup.spec' -import './freebuff-launch.spec' -import './freebuff-startup.spec' import './omp-fresh-launch.spec' import './opencode-startup-prompt.spec' import './opencode2-resume-launch-mode.spec' -import './qoder-cn-launch-recipe.spec' import './tui-agent-fork-startup.spec' import '../choices/tui-agent-launch-defaults.spec' -import './tui-agent-prompt-transport.spec' -import './tui-agent-startup-copilot-resume.spec' import './tui-agent-startup-hermes.spec' import './tui-agent-startup-session-options.spec' import './tui-agent-startup-shell.spec' diff --git a/src/shared/agent-launch/startup/tui-agent-startup.ts b/src/shared/agent-launch/startup/tui-agent-startup.ts index 0313c8dad4c..ebfea2a5b7d 100644 --- a/src/shared/agent-launch/startup/tui-agent-startup.ts +++ b/src/shared/agent-launch/startup/tui-agent-startup.ts @@ -197,7 +197,7 @@ export function buildAgentStartupPlan(args: { } } -/** Predict the builder’s null-followupPrompt verdict before choosing a launch surface; derive from the same injection table and pin every agent in tui-agent-prompt-transport.spec.ts. +/** Predict the builder’s null-followupPrompt verdict before choosing a launch surface; derive from the same injection table. * All modes except stdin-after-start carry the prompt through the launch command; Hermes may reference an env carrier instead of literal prompt argv. */ export function agentPromptRidesLaunchCommand(agent: TuiAgent): boolean { return TUI_AGENT_CONFIG[agent].promptInjectionMode !== 'stdin-after-start' diff --git a/src/shared/codebuddy-agent.test.ts b/src/shared/codebuddy-agent.test.ts index a1d589ac44b..0da0fc8ca10 100644 --- a/src/shared/codebuddy-agent.test.ts +++ b/src/shared/codebuddy-agent.test.ts @@ -30,15 +30,6 @@ describe('CodeBuddy harness', () => { expect(rows[5]?.providerSession?.id).toBe('codebuddy-verification') }) - it.each([ - 'codebuddy', - 'cbc', - 'C:\\Tools\\codebuddy.cmd', - 'node /usr/lib/node_modules/@tencent-ai/codebuddy-code/dist/codebuddy.js' - ])('recognizes interactive %s', (command) => { - expect(recognizeAgentProcessFromCommandLine(command)?.agent).toBe('codebuddy') - }) - it('excludes print runs and resumes the original provider session', () => { for (const flag of ['--print', '--serve', '--acp', '--bg', '--background']) { expect(recognizeAgentProcessFromCommandLine(`codebuddy ${flag}`)).toBeNull() diff --git a/src/shared/orca-cli-command-name.test.ts b/src/shared/orca-cli-command-name.test.ts index 047997175a8..b72de8525ec 100644 --- a/src/shared/orca-cli-command-name.test.ts +++ b/src/shared/orca-cli-command-name.test.ts @@ -10,11 +10,6 @@ describe('Claude Agent Teams launch name on the launching host', () => { expect(getTuiAgentLaunchCommand(agentTeams, 'linux')).toBe('orca claude-teams') }) - it('keeps the orca-ide rename on a Linux desktop', () => { - installFakeAppEnvironment({ getCliLauncherPath: undefined }) - expect(getTuiAgentLaunchCommand(agentTeams, 'linux')).toBe('orca-ide claude-teams') - }) - it('keeps the orca-ide rename for WSL under a Windows server', () => { installFakeAppEnvironment({ getCliLauncherPath: () => 'C:\\Users\\u\\.orca\\cli\\bin\\orca.exe' diff --git a/src/shared/require-tui-agent-config.test.ts b/src/shared/require-tui-agent-config.test.ts index 5b2a2aa4752..b956aeb6632 100644 --- a/src/shared/require-tui-agent-config.test.ts +++ b/src/shared/require-tui-agent-config.test.ts @@ -3,18 +3,6 @@ import type { TuiAgent } from './agent-launch/catalog/tui-agent' import { requireTuiAgentConfig } from './require-tui-agent-config' describe('requireTuiAgentConfig', () => { - it('returns the config for a known agent', () => { - expect(requireTuiAgentConfig('codex').preflightTrust).toBe('codex') - }) - - it('names the unknown id instead of throwing a property-of-undefined error', () => { - // A custom-agent id persisted by a branch build, read back by one without the feature. - const stale = 'custom-agent:codex:b2e1ff6f-8932-413a-9133-edffa44e0ee9' as TuiAgent - expect(() => requireTuiAgentConfig(stale)).toThrow( - `Unknown agent "${stale}". This version of Orca has no such agent — pick a different agent and try again.` - ) - }) - it('rejects a prototype key that Object.hasOwn keeps off the config', () => { expect(() => requireTuiAgentConfig('toString' as TuiAgent)).toThrow(/Unknown agent "toString"/) }) diff --git a/src/shared/rpc-contract/agent-launch-params-account-env.test.ts b/src/shared/rpc-contract/agent-launch-params-account-env.test.ts index 078c89c680d..fb180e3f40a 100644 --- a/src/shared/rpc-contract/agent-launch-params-account-env.test.ts +++ b/src/shared/rpc-contract/agent-launch-params-account-env.test.ts @@ -16,11 +16,6 @@ describe('agent.launch accountEnv wire compatibility', () => { expect(parsed.accountEnv).toEqual(ACCOUNT_ENV) }) - it('leaves an older client launch unchanged on a new host', () => { - const parsed = AgentLaunch.parse(BASE) - expect(parsed).not.toHaveProperty('accountEnv') - }) - it('stays outside the replay fingerprint', () => { const withEnv = AgentLaunch.parse({ ...BASE, accountEnv: ACCOUNT_ENV }) expect(computeAgentLaunchFingerprint(withEnv)).toBe( diff --git a/src/shared/rpc-contract/agent-launch-params-native-chat-default.test.ts b/src/shared/rpc-contract/agent-launch-params-native-chat-default.test.ts index cb1852be476..a2cad6d7d0a 100644 --- a/src/shared/rpc-contract/agent-launch-params-native-chat-default.test.ts +++ b/src/shared/rpc-contract/agent-launch-params-native-chat-default.test.ts @@ -1,19 +1,10 @@ import { describe, expect, it } from 'vitest' -import { AgentLaunch, AgentLaunchReplay } from './agent-launch-params' +import { AgentLaunch } from './agent-launch-params' import { computeAgentLaunchFingerprint } from '../agent-launch/contracts/agent-launch-operation' const BASE = { agent: 'claude', target: { kind: 'existing', worktree: 'id:wt-1' } } -const OPERATION_ID = '1760000000000-0123456789abcdef0123456789abcdef' describe('agent.launch nativeChatDefault wire compatibility', () => { - it('carries the caller default on a new host, for both launch methods', () => { - expect(AgentLaunch.parse({ ...BASE, nativeChatDefault: true }).nativeChatDefault).toBe(true) - expect( - AgentLaunchReplay.parse({ ...BASE, operationId: OPERATION_ID, nativeChatDefault: false }) - .nativeChatDefault - ).toBe(false) - }) - it('stays outside the replay fingerprint', () => { expect( computeAgentLaunchFingerprint(AgentLaunch.parse({ ...BASE, nativeChatDefault: true })) diff --git a/src/shared/zcode-orchestration-contract.test.ts b/src/shared/zcode-orchestration-contract.test.ts deleted file mode 100644 index aad91b41730..00000000000 --- a/src/shared/zcode-orchestration-contract.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildAgentStartupPlan } from './agent-launch/startup/tui-agent-startup' - -describe('ZCode orchestration and send-to-agent contract', () => { - it('keeps the prompt out of the launch command and hands it back as a follow-up', () => { - const plan = buildAgentStartupPlan({ - agent: 'zcode', - prompt: 'refactor the parser', - cmdOverrides: {}, - platform: 'darwin' - }) - expect(plan?.launchCommand).toBe('zcode') - expect(plan?.launchCommand).not.toContain('refactor the parser') - expect(plan?.followupPrompt).toBe('refactor the parser') - }) - - it('carries a mode chosen through agent args onto the launch command', () => { - const plan = buildAgentStartupPlan({ - agent: 'zcode', - prompt: '', - cmdOverrides: {}, - platform: 'darwin', - allowEmptyPromptLaunch: true, - agentArgs: '--mode plan' - }) - expect(plan?.launchCommand).toBe("zcode '--mode' 'plan'") - }) -})