test: remove 64 low-value file, terminal and language tests (#34482)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-27 11:03:23 -07:00
committed by GitHub
co-authored by OrcaWin
parent 2a9d874e67
commit 964c64b0cc
15 changed files with 8 additions and 1451 deletions
+2 -15
View File
@@ -681,7 +681,7 @@
"invariant": "A prompt occurrence leaves the input region only when an accepted reply answers it (a current host's provider acknowledgment, or an older host's whole-write acceptance as before) or the user collapses it to a strip above the composer, which writes nothing and keeps the card mounted with its partial answer; status-backed occurrences are told apart by the host wait's start, so view toggles and remounts preserve them while real clear/replacement supersedes them, and a transcript-only one is dropped when the view stops observing it; obsolete results cannot change replacements; selector groups wait for complete writes before pacing; refusal or unknown handoff never causes replay; a card retires an unsubmitted composer send without writing under it or losing its text, and the hidden composer cannot send or interrupt; Collapse or Escape folds a card without writing, never during an in-flight answer, and a new occurrence shows expanded again; the phone blocks only Send while a card is expanded and shows one card per occurrence; cancellation stops unsent groups and active dictation can stop.",
"oracle": "After acknowledged phone replies with stale host status, the exact card disappears and Send is enabled; unknown, refused or unverifiable-settlement replies retain enabled choices, while an older host's accepted reply dismisses like an acknowledged one; a same-occurrence view toggle retains pending acknowledgment and real replacements discard it. A slow 32 KiB SSH answer completes all chunks before Enter; cancellation preserves issued bytes but omits remaining groups. Paired settlement invokes the actual provider and lost callbacks remain unknown; older hosts deliver ordinary messages, launch and selector groups once and their accepted answers dismiss as before. An answered card stays hidden across a view remount; a collapsed card is a strip that frees the composer and expands back; an identical question in a new wait shows again; a composer send caught by a new card keeps its bubble without submitting or clearing the line under it.",
"commands": [
"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/components/native-chat/NativeChatInteractiveCard.test.tsx src/renderer/src/components/native-chat/use-native-chat-interactive-send.test.tsx src/renderer/src/components/native-chat/native-chat-observed-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send-launch-draft.test.ts src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-input.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-composer.test.tsx src/renderer/src/components/native-chat/use-native-chat-prompt-card-presentation.test.ts src/renderer/src/runtime/runtime-terminal-verified-input.test.ts src/renderer/src/components/native-chat/NativeChatComposer.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.turn-status.test.tsx src/renderer/src/components/native-chat/NativeChatApprovalCard.test.tsx src/renderer/src/components/native-chat/native-chat-interactive-prompt.test.ts src/renderer/src/runtime/runtime-terminal-inspection.test.ts src/renderer/src/lib/agent-paste-draft.test.ts src/renderer/src/lib/agent-paste-draft-submit-retry.test.ts src/renderer/src/lib/agent-followup-delivery.test.ts src/main/ipc/pty/ipc/write-input-acceptance.test.ts src/main/ipc/pty/ipc/write-input-user-input.test.ts src/main/ipc/pty/ipc/write-input-chunk-yield.test.ts src/main/ipc/pty/pty-write-ipc-validation.test.ts src/main/daemon/daemon-pty-write-settlement-recovery.test.ts src/main/runtime/runtime-terminal-writer.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/runtime/rpc/terminal-send-launch-draft-resolution.test.ts src/main/runtime/terminal-send-stale-leaf-liveness.test.ts src/renderer/src/lib/agent-paste-draft-readiness-budget.test.ts tests/e2e/native-chat-ssh-delivery.unit.test.ts --maxWorkers=2",
"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/components/native-chat/NativeChatInteractiveCard.test.tsx src/renderer/src/components/native-chat/use-native-chat-interactive-send.test.tsx src/renderer/src/components/native-chat/native-chat-observed-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send-launch-draft.test.ts src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-input.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-composer.test.tsx src/renderer/src/components/native-chat/use-native-chat-prompt-card-presentation.test.ts src/renderer/src/components/native-chat/NativeChatComposer.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.turn-status.test.tsx src/renderer/src/components/native-chat/NativeChatApprovalCard.test.tsx src/renderer/src/components/native-chat/native-chat-interactive-prompt.test.ts src/renderer/src/runtime/runtime-terminal-inspection.test.ts src/renderer/src/lib/agent-paste-draft.test.ts src/renderer/src/lib/agent-paste-draft-submit-retry.test.ts src/renderer/src/lib/agent-followup-delivery.test.ts src/main/ipc/pty/ipc/write-input-acceptance.test.ts src/main/ipc/pty/ipc/write-input-user-input.test.ts src/main/ipc/pty/ipc/write-input-chunk-yield.test.ts src/main/ipc/pty/pty-write-ipc-validation.test.ts src/main/daemon/daemon-pty-write-settlement-recovery.test.ts src/main/runtime/runtime-terminal-writer.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/runtime/rpc/terminal-send-launch-draft-resolution.test.ts src/main/runtime/terminal-send-stale-leaf-liveness.test.ts src/renderer/src/lib/agent-paste-draft-readiness-budget.test.ts tests/e2e/native-chat-ssh-delivery.unit.test.ts --maxWorkers=2",
"ORCA_BACKGROUND_LAUNCH=1 mobile/node_modules/.bin/vitest run --config mobile/vitest.config.ts mobile/src/session/MobileNativeChatView.prompt-presentation.test.ts mobile/src/session/use-mobile-native-chat-controller.test.ts mobile/src/session/native-chat/input/use-mobile-native-chat-ask-dismiss.test.ts mobile/src/session/MobileNativeChatView.stop.test.ts mobile/src/session/MobileNativeChatView.failure-banner.test.ts mobile/src/session/MobileNativeChatView.rows.test.ts mobile/src/session/MobileNativeChatView.composer-lock.test.ts mobile/src/session/MobileNativeChatView.tail-follow.test.ts mobile/src/session/MobileNativeChatView.history-paging.test.ts mobile/src/session/mobile-prompt-controller.test.ts mobile/src/session/native-chat/input/mobile-native-chat-permission-send.test.ts mobile/src/session/native-chat/input/use-mobile-native-chat-cancel-ask.test.ts mobile/src/session/native-chat/input/use-mobile-native-chat-answer-send.test.ts mobile/src/session/native-chat/transcript/use-mobile-native-chat-message-send.test.ts mobile/src/session/native-chat/mobile-native-chat-send.test.ts mobile/src/session/MobileNativeChatCardHeaderAction.test.tsx mobile/src/session/native-chat/input/MobileNativeChatPromptCard.test.tsx --maxWorkers=2",
"ORCA_BACKGROUND_LAUNCH=1 pnpm test tests/e2e/cross-version-wire/cross-version-terminal-wire.unit.test.ts --maxWorkers=1",
"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/components/native-chat/NativeChatInteractiveCard.test.tsx src/renderer/src/components/native-chat/use-native-chat-interactive-send.test.tsx src/renderer/src/components/native-chat/native-chat-observed-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send-launch-draft.test.ts src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-input.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.turn-status.test.tsx src/renderer/src/components/native-chat/NativeChatApprovalCard.test.tsx src/renderer/src/components/native-chat/native-chat-interactive-prompt.test.ts src/renderer/src/runtime/runtime-terminal-inspection.test.ts src/renderer/src/lib/agent-paste-draft.test.ts src/renderer/src/lib/agent-paste-draft-submit-retry.test.ts src/renderer/src/lib/agent-followup-delivery.test.ts src/main/ipc/pty/ipc/write-input-acceptance.test.ts src/main/ipc/pty/ipc/write-input-user-input.test.ts src/main/ipc/pty/ipc/write-input-chunk-yield.test.ts src/main/ipc/pty/pty-write-ipc-validation.test.ts src/main/daemon/daemon-pty-write-settlement-recovery.test.ts --maxWorkers=2",
@@ -696,7 +696,6 @@
"src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-input.test.tsx",
"src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-composer.test.tsx",
"src/renderer/src/components/native-chat/use-native-chat-prompt-card-presentation.test.ts",
"src/renderer/src/runtime/runtime-terminal-verified-input.test.ts",
"src/renderer/src/components/native-chat/NativeChatComposer.test.tsx",
"src/renderer/src/components/native-chat/NativeChatResolvedView.turn-status.test.tsx",
"src/renderer/src/components/native-chat/NativeChatApprovalCard.test.tsx",
@@ -838,7 +837,7 @@
"runner": "local",
"platform": "macos",
"command": "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/components/native-chat/NativeChatInteractiveCard.test.tsx src/renderer/src/components/native-chat/use-native-chat-interactive-send.test.tsx src/renderer/src/components/native-chat/native-chat-observed-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send-launch-draft.test.ts src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-input.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-composer.test.tsx src/renderer/src/components/native-chat/use-native-chat-prompt-card-presentation.test.ts src/renderer/src/runtime/runtime-terminal-verified-input.test.ts src/renderer/src/components/native-chat/NativeChatComposer.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.turn-status.test.tsx src/renderer/src/components/native-chat/NativeChatApprovalCard.test.tsx src/renderer/src/components/native-chat/native-chat-interactive-prompt.test.ts src/renderer/src/runtime/runtime-terminal-inspection.test.ts src/renderer/src/lib/agent-paste-draft.test.ts src/renderer/src/lib/agent-paste-draft-submit-retry.test.ts src/renderer/src/lib/agent-followup-delivery.test.ts src/main/ipc/pty/ipc/write-input-acceptance.test.ts src/main/ipc/pty/ipc/write-input-user-input.test.ts src/main/ipc/pty/ipc/write-input-chunk-yield.test.ts src/main/ipc/pty-write-ipc-validation.test.ts src/main/daemon/daemon-pty-write-settlement-recovery.test.ts src/main/runtime/runtime-terminal-writer.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/runtime/rpc/terminal-send-launch-draft-resolution.test.ts src/main/runtime/terminal-send-stale-leaf-liveness.test.ts src/renderer/src/lib/agent-paste-draft-readiness-budget.test.ts tests/e2e/native-chat-ssh-delivery.unit.test.ts --maxWorkers=2",
"currentCommand": "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/components/native-chat/NativeChatInteractiveCard.test.tsx src/renderer/src/components/native-chat/use-native-chat-interactive-send.test.tsx src/renderer/src/components/native-chat/native-chat-observed-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send-launch-draft.test.ts src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-input.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-composer.test.tsx src/renderer/src/components/native-chat/use-native-chat-prompt-card-presentation.test.ts src/renderer/src/runtime/runtime-terminal-verified-input.test.ts src/renderer/src/components/native-chat/NativeChatComposer.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.turn-status.test.tsx src/renderer/src/components/native-chat/NativeChatApprovalCard.test.tsx src/renderer/src/components/native-chat/native-chat-interactive-prompt.test.ts src/renderer/src/runtime/runtime-terminal-inspection.test.ts src/renderer/src/lib/agent-paste-draft.test.ts src/renderer/src/lib/agent-paste-draft-submit-retry.test.ts src/renderer/src/lib/agent-followup-delivery.test.ts src/main/ipc/pty/ipc/write-input-acceptance.test.ts src/main/ipc/pty/ipc/write-input-user-input.test.ts src/main/ipc/pty/ipc/write-input-chunk-yield.test.ts src/main/ipc/pty/pty-write-ipc-validation.test.ts src/main/daemon/daemon-pty-write-settlement-recovery.test.ts src/main/runtime/runtime-terminal-writer.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/runtime/rpc/terminal-send-launch-draft-resolution.test.ts src/main/runtime/terminal-send-stale-leaf-liveness.test.ts src/renderer/src/lib/agent-paste-draft-readiness-budget.test.ts tests/e2e/native-chat-ssh-delivery.unit.test.ts --maxWorkers=2",
"currentCommand": "ORCA_BACKGROUND_LAUNCH=1 pnpm test src/renderer/src/components/native-chat/NativeChatInteractiveCard.test.tsx src/renderer/src/components/native-chat/use-native-chat-interactive-send.test.tsx src/renderer/src/components/native-chat/native-chat-observed-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send.test.ts src/renderer/src/components/native-chat/native-chat-runtime-send-launch-draft.test.ts src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-input.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.prompt-card-composer.test.tsx src/renderer/src/components/native-chat/use-native-chat-prompt-card-presentation.test.ts src/renderer/src/components/native-chat/NativeChatComposer.test.tsx src/renderer/src/components/native-chat/NativeChatResolvedView.turn-status.test.tsx src/renderer/src/components/native-chat/NativeChatApprovalCard.test.tsx src/renderer/src/components/native-chat/native-chat-interactive-prompt.test.ts src/renderer/src/runtime/runtime-terminal-inspection.test.ts src/renderer/src/lib/agent-paste-draft.test.ts src/renderer/src/lib/agent-paste-draft-submit-retry.test.ts src/renderer/src/lib/agent-followup-delivery.test.ts src/main/ipc/pty/ipc/write-input-acceptance.test.ts src/main/ipc/pty/ipc/write-input-user-input.test.ts src/main/ipc/pty/ipc/write-input-chunk-yield.test.ts src/main/ipc/pty/pty-write-ipc-validation.test.ts src/main/daemon/daemon-pty-write-settlement-recovery.test.ts src/main/runtime/runtime-terminal-writer.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/runtime/rpc/terminal-send-launch-draft-resolution.test.ts src/main/runtime/terminal-send-stale-leaf-liveness.test.ts src/renderer/src/lib/agent-paste-draft-readiness-budget.test.ts tests/e2e/native-chat-ssh-delivery.unit.test.ts --maxWorkers=2",
"result": "passed",
"durationSeconds": 14.53,
"summary": "391 tests passed across 29 explicit files after the round-4 review fix, including older-host acceptance, the inert hidden composer, collapse that keeps a partial answer and returns focus to the composer, pane-scoped card focus, wait-start occurrence identity and the pane remount signal."
@@ -10569,12 +10568,6 @@
"explicit stop, real exit status, and genuine successful completion remain distinct"
]
},
{
"file": "src/renderer/src/runtime/runtime-terminal-inspection.test.ts",
"assertions": [
"direct SSH terminals use strict main-process inspection rather than lax split IPC evidence"
]
},
{
"file": "src/renderer/src/components/terminal-pane/pty-connection-completion-and-notification.test.ts",
"assertions": [
@@ -17544,12 +17537,6 @@
"malformed frames, malformed transformed output, disposal, late parse, renderer delivery failure, and ACK transport failure release credit or close the owning stream without reordering output"
]
},
{
"file": "src/renderer/src/runtime/runtime-terminal-stream.test.ts",
"assertions": [
"drops output only from the armed stream when its replacement reuses the stream ID"
]
},
{
"file": "src/main/runtime/rpc/terminal-multiplex-flow-control.bench.test.ts",
"assertions": [
-3
View File
@@ -10677,7 +10677,6 @@
"src/renderer/src/lib/monaco-languages/register-svelte.test.ts": 121,
"src/renderer/src/lib/monaco-languages/register-vue.test.ts": 157,
"src/renderer/src/lib/monaco-languages/register-zig.test.ts": 3891,
"src/renderer/src/lib/monaco-languages/textmate-language-registration.test.ts": 37,
"src/renderer/src/lib/monaco-languages/textmate-token-provider.test.ts": 233,
"src/renderer/src/lib/monaco-languages/zig-highlighting.test.ts": 4871,
"src/renderer/src/lib/monaco-setup-steps.test.ts": 48,
@@ -11192,7 +11191,6 @@
"src/renderer/src/runtime/remote-runtime-session-tabs-inflight.test.ts": 26,
"src/renderer/src/runtime/remote-runtime-snapshot-outcome.test.ts": 226,
"src/renderer/src/runtime/remote-runtime-terminal-color-push.test.ts": 179,
"src/renderer/src/runtime/remote-runtime-terminal-end-verdict.test.ts": 278,
"src/renderer/src/runtime/remote-runtime-terminal-frame-drop-resync.test.ts": 214,
"src/renderer/src/runtime/remote-runtime-terminal-parse-backpressure.test.ts": 998,
"src/renderer/src/runtime/remote-runtime-terminal-paused-output-drop.test.ts": 169,
@@ -11263,7 +11261,6 @@
"src/renderer/src/runtime/runtime-terminal-artifact-read.test.ts": 196,
"src/renderer/src/runtime/runtime-terminal-inspection.test.ts": 1950,
"src/renderer/src/runtime/runtime-terminal-stream.test.ts": 638,
"src/renderer/src/runtime/runtime-terminal-verified-input.test.ts": 1206,
"src/renderer/src/runtime/runtime-usage-credentials-client.test.ts": 37,
"src/renderer/src/runtime/runtime-worktree-selector.test.ts": 130,
"src/renderer/src/runtime/server-browser-profile-reuse.test.ts": 1580,
@@ -1,90 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import { registerTextMateLanguage } from './textmate-language-registration'
function createMonacoMock(registeredLanguages: { id: string }[] = []) {
let tokensProviderFactory: { create: () => unknown } | undefined
const monaco = {
languages: {
getLanguages: vi.fn(() => registeredLanguages),
register: vi.fn(),
setLanguageConfiguration: vi.fn(),
registerTokensProviderFactory: vi.fn(
(_languageId: string, factory: { create: () => unknown }) => {
tokensProviderFactory = factory
return { dispose: vi.fn() }
}
)
}
}
return {
monaco,
createTokensProvider() {
if (!tokensProviderFactory) {
throw new Error('Tokens provider factory was not registered')
}
return tokensProviderFactory.create()
}
}
}
describe('registerTextMateLanguage', () => {
it('registers metadata and lazily installs the TextMate tokens provider', async () => {
const { monaco, createTokensProvider } = createMonacoMock()
const provider = {
getInitialState: vi.fn(),
tokenize: vi.fn()
}
const createTextMateTokensProvider = vi.fn(async () => provider)
const loadProviderModule = vi.fn(async () => ({ createTextMateTokensProvider }))
const loadGrammar = vi.fn()
const configuration = { comments: { lineComment: '#' } }
registerTextMateLanguage(monaco as never, {
language: {
id: 'nim',
extensions: ['.nim'],
aliases: ['Nim']
},
configuration,
loadGrammar,
loadProviderModule
})
expect(monaco.languages.register).toHaveBeenCalledWith({
id: 'nim',
extensions: ['.nim'],
aliases: ['Nim']
})
expect(monaco.languages.setLanguageConfiguration).toHaveBeenCalledWith('nim', configuration)
expect(monaco.languages.registerTokensProviderFactory).toHaveBeenCalledWith(
'nim',
expect.objectContaining({ create: expect.any(Function) })
)
expect(loadProviderModule).not.toHaveBeenCalled()
const providerPromise = createTokensProvider()
expect(createTokensProvider()).toBe(providerPromise)
await expect(providerPromise).resolves.toBe(provider)
expect(createTokensProvider()).toBe(providerPromise)
expect(loadProviderModule).toHaveBeenCalledTimes(1)
expect(createTextMateTokensProvider).toHaveBeenCalledTimes(1)
expect(createTextMateTokensProvider).toHaveBeenCalledWith({ loadGrammar })
})
it('does not register duplicate language ids', () => {
const { monaco } = createMonacoMock([{ id: 'nim' }])
registerTextMateLanguage(monaco as never, {
language: {
id: 'nim',
extensions: ['.nim']
},
loadGrammar: vi.fn()
})
expect(monaco.languages.register).not.toHaveBeenCalled()
expect(monaco.languages.registerTokensProviderFactory).not.toHaveBeenCalled()
})
})
@@ -46,14 +46,4 @@ describe('Zig highlighting through production Monaco setup', () => {
expect(tokens[6].map((token) => token.type)).toContain('keyword.zig')
expect(tokens[6].map((token) => token.type)).not.toContain('string.multiline.zig')
})
it('keeps unrelated languages and unclaimed Zig object notation unchanged', async () => {
expect(detectLanguage('build.zig.zon')).toBe('plaintext')
expect(detectLanguage('main.rs')).toBe('rust')
expect(detectLanguage('main.c')).toBe('c')
await monaco.editor.colorize('const answer = 42', 'typescript', {})
expect(
monaco.editor.tokenize('const answer = 42', 'typescript')[0].map((token) => token.type)
).toEqual(expect.arrayContaining(['keyword.ts', 'number.ts']))
})
})
@@ -1,50 +0,0 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { stubRuntimeEnvironmentBridge } from './runtime-environment-bridge-fixture'
type RuntimeSubscriptionCallbacks = {
onResponse: (response: unknown) => void
}
describe('remote runtime terminal end verdict', () => {
let callbacks: RuntimeSubscriptionCallbacks | null = null
beforeEach(() => {
vi.resetModules()
callbacks = null
stubRuntimeEnvironmentBridge({
subscribe: vi.fn(async (_args, nextCallbacks: RuntimeSubscriptionCallbacks) => {
callbacks = nextCallbacks
queueMicrotask(() => {
callbacks?.onResponse({ ok: true, result: { type: 'ready' } })
})
return { unsubscribe: vi.fn(), sendBinary: vi.fn() }
})
})
})
afterEach(() => {
vi.unstubAllGlobals()
})
it.each([
['an explicit host verdict', { verdict: 'exited' }, 'exited'],
['a legacy bare end', {}, 'unverifiable'],
['an unknown future verdict', { verdict: 'unknown' }, 'unverifiable']
])('maps %s to %s', async (_case, fields, expected) => {
const { getRemoteRuntimeTerminalMultiplexer } =
await import('./remote-runtime-terminal-multiplexer')
const onEnd = vi.fn()
const stream = await getRemoteRuntimeTerminalMultiplexer('env-1').subscribeTerminal({
terminal: 'terminal-1',
client: { id: 'desktop-1', type: 'desktop' },
callbacks: { onData: vi.fn(), onSnapshot: vi.fn(), onEnd }
})
callbacks?.onResponse({
ok: true,
result: { type: 'end', streamId: stream.streamId, ...fields }
})
expect(onEnd).toHaveBeenCalledWith(expected)
})
})
@@ -22,13 +22,6 @@ const notFoundResponse = (id: string): unknown => ({
_meta: { runtimeId: 'remote-runtime' }
})
const failedResponse = (id: string): unknown => ({
id,
ok: false,
error: { code: 'permission_denied', message: 'read-only file system' },
_meta: { runtimeId: 'remote-runtime' }
})
const statResponse = (id: string): unknown => ({
id,
ok: true,
@@ -121,66 +114,6 @@ describe('drop staging ignore file', () => {
expect(methods.indexOf('files.write')).toBeLessThan(methods.indexOf('files.commitUpload'))
})
it('leaves an existing ignore file alone', async () => {
stageOneFile()
runtimeEnvironmentCall
.mockResolvedValueOnce(statResponse('stat-orca-hit'))
.mockResolvedValueOnce(statResponse('stat-drops-hit'))
.mockResolvedValueOnce(statResponse('stat-ignore-hit'))
.mockResolvedValueOnce(notFoundResponse('stat-file-miss'))
.mockResolvedValueOnce(okResponse('commit-upload'))
.mockResolvedValueOnce(okResponse('delete-temp'))
await importExternalPathsToRuntime(CONTEXT, ['/Users/me/shot.png'], '/remote/repo/.orca/drops')
expect(calledMethods().some((call) => call.method === 'files.write')).toBe(false)
})
it('still uploads the drop when the ignore file cannot be written', async () => {
stageOneFile()
runtimeEnvironmentCall
.mockResolvedValueOnce(statResponse('stat-orca-hit'))
.mockResolvedValueOnce(statResponse('stat-drops-hit'))
.mockResolvedValueOnce(notFoundResponse('stat-ignore-miss'))
.mockResolvedValueOnce(failedResponse('write-ignore-denied'))
.mockResolvedValueOnce(notFoundResponse('stat-file-miss'))
.mockResolvedValueOnce(okResponse('commit-upload'))
.mockResolvedValueOnce(okResponse('delete-temp'))
const { results } = await importExternalPathsToRuntime(
CONTEXT,
['/Users/me/shot.png'],
'/remote/repo/.orca/drops'
)
expect(results).toEqual([expect.objectContaining({ status: 'imported' })])
})
it('recognizes the drops folder of a Windows worktree', async () => {
stageOneFile()
runtimeEnvironmentCall
.mockResolvedValueOnce(statResponse('stat-orca-hit'))
.mockResolvedValueOnce(statResponse('stat-drops-hit'))
.mockResolvedValueOnce(notFoundResponse('stat-ignore-miss'))
.mockResolvedValueOnce(okResponse('write-ignore'))
.mockResolvedValueOnce(notFoundResponse('stat-file-miss'))
.mockResolvedValueOnce(okResponse('commit-upload'))
.mockResolvedValueOnce(okResponse('delete-temp'))
await importExternalPathsToRuntime(
{ ...CONTEXT, worktreePath: 'C:\\Users\\me\\repo' },
['/Users/me/shot.png'],
'C:\\Users\\me\\repo\\.orca\\drops'
)
expect(calledMethods().filter((call) => call.method === 'files.write')).toEqual([
{
method: 'files.write',
params: expect.objectContaining({ relativePath: '.orca/drops/.gitignore', content: '*\n' })
}
])
})
// Why: the ignore step swallows its own errors, and a drop with nothing staged never re-checks.
it('reports a host that went stale during the ignore step even when nothing was staged', async () => {
fsStageExternalPathsForRuntimeUpload.mockResolvedValue({
@@ -207,17 +140,4 @@ describe('drop staging ignore file', () => {
})
).rejects.toThrow('runtime owner generation changed')
})
it('never writes an ignore file into a folder the user picked', async () => {
stageOneFile()
runtimeEnvironmentCall
.mockResolvedValueOnce(statResponse('stat-uploads-hit'))
.mockResolvedValueOnce(notFoundResponse('stat-file-miss'))
.mockResolvedValueOnce(okResponse('commit-upload'))
.mockResolvedValueOnce(okResponse('delete-temp'))
await importExternalPathsToRuntime(CONTEXT, ['/Users/me/shot.png'], '/remote/repo/uploads')
expect(calledMethods().some((call) => call.method === 'files.write')).toBe(false)
})
})
@@ -13,7 +13,6 @@ import { getDiskBaselineSignature } from '../../../shared/disk-baseline-signatur
import { advanceRuntimeEnvironmentConnectionGeneration } from '@/store/slices/runtime-status-connection-generation'
import { replaceRuntimeEnvironmentRevisions } from './runtime-environment-revision'
import {
fsWriteFile,
installRuntimeFileClientEnvironment,
runtimeEnvironmentCall,
runtimeEnvironmentTransportCall,
@@ -91,23 +90,6 @@ function writeCalls(): RuntimeRpcRequest[] {
}
describe('writeRuntimeFile disk precondition', () => {
it('sends the precondition to a local writer and returns its refusal', async () => {
fsWriteFile.mockResolvedValue({ ok: false, diskConflict: 'changed' })
const result = await writeRuntimeFile(
{ target: { kind: 'local' }, worktreeId: 'wt-1', worktreePath: '/repo' },
'/repo/file.ts',
'edited',
undefined,
precondition
)
expect(result).toEqual({ ok: false, diskConflict: 'changed' })
expect(fsWriteFile).toHaveBeenCalledWith(
expect.objectContaining({ diskPrecondition: precondition })
)
})
it('cannot write through an older server reached after a supporting server was probed', async () => {
// The shared socket reconnected to an older server between the capability verdict and the send.
serveHost({ enforcesPrecondition: true })
@@ -131,26 +113,6 @@ describe('writeRuntimeFile disk precondition', () => {
expect(unguardedWrites).toHaveLength(0)
})
it('lets a host that enforces the precondition compare at write time', async () => {
serveHost({ enforcesPrecondition: true })
runtimeEnvironmentCall.mockResolvedValue(rpcOk({ ok: false, diskConflict: 'missing' }))
const result = await writeRuntimeFile(
remoteContext,
'/remote/repo/file.ts',
'edited',
undefined,
precondition
)
expect(result).toEqual({ ok: false, diskConflict: 'missing' })
expect(writeCalls()).toHaveLength(1)
expect(writeCalls()[0]?.params).toMatchObject({ diskPrecondition: precondition })
expect(runtimeEnvironmentTransportCall).not.toHaveBeenCalledWith(
expect.objectContaining({ method: 'files.read' })
)
})
it('compares from the client before writing through an older host', async () => {
serveHost({ enforcesPrecondition: false, diskContent: 'original' })
runtimeEnvironmentCall.mockResolvedValue(rpcOk({ ok: true }))
@@ -168,28 +130,6 @@ describe('writeRuntimeFile disk precondition', () => {
expect(writeCalls()[0]?.params).not.toHaveProperty('diskPrecondition')
})
it("decides support from the write path's own status probe, one per save", async () => {
serveHost({ enforcesPrecondition: false, diskContent: 'original' })
runtimeEnvironmentCall.mockResolvedValue(rpcOk({ ok: true }))
for (let save = 0; save < 3; save += 1) {
await writeRuntimeFile(
remoteContext,
'/remote/repo/file.ts',
'edited',
undefined,
precondition
)
}
const statusCalls = runtimeEnvironmentTransportCall.mock.calls.filter(
([args]) => args.method === 'status.get'
)
// One ownership probe per save plus the read client's one-time compatibility probe.
expect(statusCalls).toHaveLength(4)
expect(writeCalls()).toHaveLength(3)
})
it('refuses without writing when an older host holds newer disk content', async () => {
serveHost({ enforcesPrecondition: false, diskContent: 'agent rewrite' })
@@ -205,22 +145,6 @@ describe('writeRuntimeFile disk precondition', () => {
expect(writeCalls()).toHaveLength(0)
})
it('skips writing through an older host whose changed disk already holds the text', async () => {
serveHost({ enforcesPrecondition: false, diskContent: 'edited' })
runtimeEnvironmentCall.mockResolvedValue(rpcOk({ ok: true }))
const result = await writeRuntimeFile(
remoteContext,
'/remote/repo/file.ts',
'edited',
undefined,
precondition
)
expect(result).toEqual({ ok: true, unchanged: true })
expect(writeCalls()).toHaveLength(0)
})
it.each(['original', 'edited'])(
'skips identical content on a v1 guarded host for an automatic save (baseline %s)',
async (baseline) => {
@@ -235,32 +159,6 @@ describe('writeRuntimeFile disk precondition', () => {
}
)
it('keeps the v1 host guard for non-identical automatic saves after comparing locally', async () => {
serveHost({ enforcesPrecondition: true, identicalNoop: false, diskContent: 'original' })
runtimeEnvironmentCall.mockResolvedValue(rpcOk({ ok: false, diskConflict: 'changed' }))
expect(
await writeRuntimeFile(remoteContext, '/remote/repo/file.ts', 'edited', undefined, {
...precondition,
requireLosslessUtf8: true
})
).toEqual({ ok: false, diskConflict: 'changed' })
expect(writeCalls()[0]?.method).toBe('files.writeIfUnchanged')
})
it('sends an explicit save straight to a v1 guarded host without reading first', async () => {
let reads = 0
serveHost({
enforcesPrecondition: true,
identicalNoop: false,
diskContent: 'edited',
onRead: () => (reads += 1)
})
runtimeEnvironmentCall.mockResolvedValue(rpcOk({ ok: true }))
await writeRuntimeFile(remoteContext, '/remote/repo/file.ts', 'edited', undefined, precondition)
expect(reads).toBe(0)
expect(writeCalls()[0]?.method).toBe('files.writeIfUnchanged')
})
it('refuses an ambiguous automatic baseline before sending to a v1 host', async () => {
serveHost({ enforcesPrecondition: true, identicalNoop: false, diskContent: 'a�' })
expect(
@@ -318,36 +216,6 @@ describe('writeRuntimeFile disk precondition', () => {
expect(writeCalls()).toHaveLength(0)
})
it('reports a file an older host can no longer send as changed', async () => {
serveHost({
enforcesPrecondition: false,
readError: 'File too large: 60.0MB exceeds 50MB limit'
})
const result = await writeRuntimeFile(
remoteContext,
'/remote/repo/file.ts',
'edited',
undefined,
{
...precondition,
allowMissing: true
}
)
expect(result).toEqual({ ok: false, diskConflict: 'changed' })
expect(writeCalls()).toHaveLength(0)
})
it('binds a guarded write to the runtime whose capabilities were probed', async () => {
serveHost({ enforcesPrecondition: true })
runtimeEnvironmentCall.mockResolvedValue(rpcOk({ ok: true }))
await writeRuntimeFile(remoteContext, '/remote/repo/file.ts', 'edited', undefined, precondition)
expect(writeCalls()[0]).toMatchObject({ expectedEnvironmentRuntimeId: 'remote-runtime' })
})
it('refuses to send when the runtime connection changes after the probe', async () => {
serveHost({
enforcesPrecondition: false,
@@ -1,8 +1,5 @@
import { describe, expect, it } from 'vitest'
import {
decodeLegacyQuickOpenInventory,
pruneLegacyInventoryCache
} from './runtime-legacy-inventory-budget'
import { decodeLegacyQuickOpenInventory } from './runtime-legacy-inventory-budget'
function inventory(count = 1) {
return {
@@ -37,28 +34,4 @@ describe('complete legacy inventory retention', () => {
value.files[0].relativePath = 'x'.repeat(65_537)
expect(() => decodeLegacyQuickOpenInventory(value)).toThrow('too large')
})
it.each([
null,
{ files: [] },
{ ...inventory(), totalCount: 0 },
{ ...inventory(), files: [{ relativePath: 12 }] }
])('rejects malformed responses %j', (value) => {
expect(() => decodeLegacyQuickOpenInventory(value)).toThrow('Invalid remote file inventory')
})
it('evicts in access order under a shared byte allowance and releases removed accounting', () => {
const cache = new Map([
['one', { retainedBytes: 60 }],
['two', { retainedBytes: 60 }]
])
pruneLegacyInventoryCache(cache, 8, 100)
expect([...cache.keys()]).toEqual(['two'])
cache.delete('two')
cache.set('three', { retainedBytes: 100 })
pruneLegacyInventoryCache(cache, 8, 100)
expect([...cache.keys()]).toEqual(['three'])
cache.set('three', { retainedBytes: 10 })
cache.set('owner-changed', { retainedBytes: 90 })
pruneLegacyInventoryCache(cache, 8, 100)
expect(cache.size).toBe(2)
})
})
@@ -164,20 +164,6 @@ describe('legacy Quick Open inventory expiry', () => {
expect(vi.getTimerCount()).toBe(1)
})
it('starts the settled deadline when the inventory arrives', async () => {
const load = queueLoad()
const pending = search()
expect(vi.getTimerCount()).toBe(0)
vi.advanceTimersByTime(5_000)
load.resolve(listing())
await pending
vi.advanceTimersByTime(29_999)
expect(cached()).toBe(true)
vi.advanceTimersByTime(1)
expect(cached()).toBe(false)
expect(vi.getTimerCount()).toBe(0)
})
it('sweeps settled responses while leaving shared pending loads valid', async () => {
call.mockResolvedValueOnce(listing('settled'))
await search('settled')
@@ -286,17 +272,6 @@ describe('legacy Quick Open inventory expiry', () => {
expect(vi.getTimerCount()).toBe(1)
})
it('retries failed requests without keeping an expiry timer for their response', async () => {
call.mockRejectedValueOnce(new Error('host failed'))
await expect(search()).rejects.toThrow('host failed')
expect(cached()).toBe(false)
expect(vi.getTimerCount()).toBe(0)
call.mockResolvedValueOnce(listing())
await search()
expect(cached()).toBe(true)
expect(vi.getTimerCount()).toBe(1)
})
it('replaces a longer armed deadline after a backward clock change and a new settlement', async () => {
const timeout = vi.spyOn(globalThis, 'setTimeout')
call.mockImplementation(async () => listing())
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { readRuntimeFileContent, readRuntimeFilePreview } from './runtime-file-read-client'
import { readRuntimeFileContent } from './runtime-file-read-client'
import { writeRuntimeFile } from './runtime-file-mutation-client'
import {
installRuntimeFileClientEnvironment,
@@ -7,7 +7,6 @@ import {
type RuntimeRpcRequest
} from './runtime-file-client-test-harness'
import { REMOTE_FILE_CHANGED_DURING_READ_MESSAGE } from './runtime-paged-file-read'
import { replaceRuntimeEnvironmentRevisions } from './runtime-environment-revision'
installRuntimeFileClientEnvironment()
@@ -168,19 +167,6 @@ describe('remote reads larger than one RPC reply', () => {
expect(methodCalls('files.readChunk').length > 0).toBe(sizeMb * MB > PREVIEW_CAP)
})
it('pages an image preview too large for one reply', async () => {
const bytes = patternedBytes(5 * MB)
serveRemoteFile('shot.png', { bytes })
const result = await readRuntimeFilePreview(
{ target: remote('shot.png').target, worktreeId: 'wt-1', worktreePath: '/remote/repo' },
'/remote/repo/shot.png'
)
expect(result).toMatchObject({ isBinary: true, isImage: true, mimeType: 'image/png' })
expect(Buffer.from(result.content, 'base64').equals(bytes)).toBe(true)
})
it('leaves a large PDF alone for readers that discard binary content', async () => {
serveRemoteFile('paper.pdf', { bytes: patternedBytes(5 * MB) })
@@ -256,43 +242,6 @@ describe('remote reads larger than one RPC reply', () => {
)
})
it('pins every call of one paged read to the pairing it started on', async () => {
replaceRuntimeEnvironmentRevisions([{ id: 'env-1', createdAt: 1, pairingRevision: 7 }])
const bytes = htmlBytes(2 * MB)
serveRemoteFile('report.html', {
bytes,
readChunk: (params, file) => {
// A re-pair mid-read must not retarget the remaining chunks.
replaceRuntimeEnvironmentRevisions([{ id: 'env-1', createdAt: 1, pairingRevision: 8 }])
return sliceChunk(params, file)
}
})
await readRuntimeFileContent(remote('report.html'))
const paged = [...methodCalls('files.stat'), ...methodCalls('files.readChunk')]
expect(paged.length).toBeGreaterThan(2)
expect(paged.every((call) => call.expectedEnvironmentPairingRevision === 7)).toBe(true)
})
it('keeps the pairing of the first read when a re-pair lands during it', async () => {
replaceRuntimeEnvironmentRevisions([{ id: 'env-1', createdAt: 1, pairingRevision: 7 }])
serveRemoteFile('report.html', { bytes: htmlBytes(2 * MB) })
const serve = runtimeEnvironmentCall.getMockImplementation()
runtimeEnvironmentCall.mockImplementation((request: RuntimeRpcRequest) => {
if (request.method === 'files.read') {
replaceRuntimeEnvironmentRevisions([{ id: 'env-1', createdAt: 1, pairingRevision: 8 }])
}
return serve?.(request)
})
await readRuntimeFileContent(remote('report.html'))
const calls = runtimeEnvironmentCall.mock.calls.map(([request]) => request)
expect(calls.length).toBeGreaterThan(3)
expect(calls.every((call) => call.expectedEnvironmentPairingRevision === 7)).toBe(true)
})
it('stops when the host never reports EOF', async () => {
const bytes = htmlBytes(2 * MB)
serveRemoteFile('report.html', {
@@ -325,13 +274,6 @@ describe('remote saves larger than one request frame', () => {
worktreePath: '/remote/repo'
}
it('refuses a save the host would answer by closing the connection', async () => {
await expect(
writeRuntimeFile(context, '/remote/repo/report.html', htmlBytes(2 * MB).toString('utf8'))
).rejects.toThrow('File is too large to save to a remote Orca server')
expect(runtimeEnvironmentCall).not.toHaveBeenCalled()
})
it('counts JSON escaping, not just characters', async () => {
await expect(
writeRuntimeFile(context, '/remote/repo/quotes.txt', '"'.repeat(400 * 1024))
@@ -1,4 +1,4 @@
import { expect, it, vi } from 'vitest'
import { expect, it } from 'vitest'
import { searchRuntimeFilePaths, listRuntimeFiles } from './runtime-file-search-client'
import {
installRuntimeFileClientEnvironment,
@@ -7,30 +7,6 @@ import {
} from './runtime-file-client-test-harness'
installRuntimeFileClientEnvironment()
it('accepts a future compatible search version rather than falling back on exact-version inequality', async () => {
runtimeEnvironmentCall.mockResolvedValue({
id: 'compat',
ok: true,
_meta: { runtimeId: 'host' },
result: {
files: [{ relativePath: 'apps/late/.env' }],
truncated: false,
quickOpenSearchVersion: 4
}
})
await expect(
searchRuntimeFilePaths(
{
target: { kind: 'environment' as const, environmentId: 'env-1' },
worktreeId: 'future-host',
worktreePath: '/host/repo'
},
{ query: '.env late' }
)
).resolves.toEqual({ files: ['apps/late/.env'], truncated: false })
expect(runtimeEnvironmentCall).toHaveBeenCalledOnce()
})
it('validates default-policy recent paths on a version-two host through complete legacy inventory', async () => {
runtimeEnvironmentCall.mockImplementation(({ method }) =>
Promise.resolve({
@@ -66,34 +42,6 @@ it('validates default-policy recent paths on a version-two host through complete
expect(fsListFiles).not.toHaveBeenCalled()
})
it('sends bounded candidates only after a compatible host advertises their semantics', async () => {
runtimeEnvironmentCall.mockImplementation(({ method }) =>
Promise.resolve({
id: 'compat',
ok: true,
_meta: { runtimeId: 'host' },
result:
method === 'files.searchPaths'
? { files: [], truncated: false, quickOpenSearchVersion: 3 }
: ['src/recent.ts']
})
)
await expect(
listRuntimeFiles(
{
target: { kind: 'environment' as const, environmentId: 'env-1' },
worktreeId: 'recent-new',
worktreePath: '/host/repo'
},
{ rootPath: '/host/repo', candidatePaths: ['src/recent.ts'], maxResults: 1 }
)
).resolves.toEqual(['src/recent.ts'])
expect(runtimeEnvironmentCall.mock.calls[1][0]).toMatchObject({
method: 'files.listAll',
params: { worktree: 'id:recent-new', candidatePaths: ['src/recent.ts'], maxResults: 1 }
})
})
it('refuses to infer recent eligibility from a truncated old-host inventory', async () => {
runtimeEnvironmentCall.mockImplementation(({ method }) =>
Promise.resolve({
@@ -125,179 +73,6 @@ it('refuses to infer recent eligibility from a truncated old-host inventory', as
expect(fsListFiles).not.toHaveBeenCalled()
})
it.each(['missing-search', 'old-search'] as const)(
'translates only unavailable inventory errors after %s',
async (route) => {
const context = {
target: { kind: 'environment' as const, environmentId: 'env-1' },
worktreeId: 'fallback-errors',
worktreePath: '/host/repo'
}
for (const code of ['method_not_found', 'forbidden', 'remote_runtime_unavailable']) {
runtimeEnvironmentCall.mockImplementation(({ method }) =>
Promise.resolve({
id: 'compat',
_meta: { runtimeId: 'host' },
...(method === 'files.searchPaths' && route === 'old-search'
? { ok: true, result: { files: [], truncated: false, quickOpenSearchVersion: 1 } }
: {
ok: false,
error: {
code: method === 'files.searchPaths' ? 'method_not_found' : code,
message: 'inventory failed'
}
})
})
)
const search = searchRuntimeFilePaths(context, { query: 'two terms' })
await (route === 'old-search'
? expect(search).resolves.toEqual({ files: [], truncated: false })
: expect(search).rejects.toThrow(
code === 'method_not_found' ? 'Update the remote host' : 'inventory failed'
))
}
}
)
it('preserves raw errors when joining a cached pending legacy inventory', async () => {
const context = {
target: { kind: 'environment' as const, environmentId: 'env-1' },
worktreeId: 'cached-errors',
worktreePath: '/host/repo'
}
const inventory = Promise.withResolvers<unknown>()
runtimeEnvironmentCall.mockImplementation(({ method }) =>
method === 'files.list'
? inventory.promise
: Promise.resolve({
id: 'compat',
ok: false,
_meta: { runtimeId: 'host' },
error: { code: 'method_not_found', message: 'search unavailable' }
})
)
const first = searchRuntimeFilePaths(context, { query: 'two terms' })
const translated = expect(first).rejects.toThrow('Update the remote host')
await vi.waitFor(() =>
expect(runtimeEnvironmentCall.mock.calls.map(([request]) => request.method)).toContain(
'files.list'
)
)
const cached = searchRuntimeFilePaths(context, { query: 'other terms' })
const raw = expect(cached).rejects.toThrow('raw cached failure')
inventory.resolve({
id: 'compat',
ok: false,
_meta: { runtimeId: 'host' },
error: { code: 'method_not_found', message: 'raw cached failure' }
})
await Promise.all([translated, raw])
expect(runtimeEnvironmentCall.mock.calls.map(([request]) => request.method)).toEqual([
'files.searchPaths',
'files.list'
])
})
it.each(['method_not_found', 'file_inventory_capacity', 'remote_runtime_unavailable'])(
'does not require optional inventory to return existing old-host punctuation matches (%s)',
async (code) => {
runtimeEnvironmentCall.mockImplementation(({ method }) =>
Promise.resolve({
id: 'compat',
_meta: { runtimeId: 'host' },
...(method === 'files.searchPaths'
? {
ok: true,
result: {
rootPath: '/host/repo',
files: [{ relativePath: 'late/package-lock.json' }],
truncated: false,
quickOpenSearchVersion: 1
}
}
: { ok: false, error: { code, message: 'inventory unavailable' } })
})
)
await expect(
searchRuntimeFilePaths(
{
target: { kind: 'environment' as const, environmentId: 'env-1' },
worktreeId: `punctuation-${code}`,
worktreePath: '/host/repo'
},
{ query: 'package-lock' }
)
).resolves.toEqual({ files: ['late/package-lock.json'], truncated: false })
expect(runtimeEnvironmentCall).toHaveBeenCalledOnce()
}
)
it.each([{ includeIgnored: false }, { followSymlinks: true }])(
'uses discovery preferences on a version-two paired host: %j',
async (options) => {
runtimeEnvironmentCall.mockResolvedValue({
id: 'compat',
_meta: { runtimeId: 'host' },
ok: true,
result: {
rootPath: '/repo',
files: [{ relativePath: 'src/file.ts' }],
truncated: false,
quickOpenSearchVersion: 2
}
})
await expect(
searchRuntimeFilePaths(
{
target: { kind: 'environment' as const, environmentId: 'env-1' },
worktreeId: 'v2-options',
worktreePath: '/repo'
},
{ query: 'file', ...options }
)
).resolves.toEqual({ files: ['src/file.ts'], truncated: false })
}
)
it('keeps inherited ignored-file visibility from disabling an older paired host', async () => {
runtimeEnvironmentCall.mockImplementation(({ method }) =>
Promise.resolve({
id: 'compat',
_meta: { runtimeId: 'host' },
ok: true,
result:
method === 'files.listAll'
? ['src/file.ts']
: {
rootPath: '/repo',
files: [{ relativePath: 'src/file.ts' }],
truncated: false,
quickOpenSearchVersion: 1
}
})
)
const context = {
target: { kind: 'environment' as const, environmentId: 'env-1' },
worktreeId: 'legacy-ignored',
worktreePath: '/repo'
}
await expect(
searchRuntimeFilePaths(context, {
query: 'file',
includeIgnored: false,
allowLegacyIncludeIgnored: true
})
).resolves.toEqual({ files: ['src/file.ts'], truncated: false })
await expect(
listRuntimeFiles(context, {
rootPath: '/repo',
includeIgnored: false,
allowLegacyIncludeIgnored: true
})
).resolves.toEqual(['src/file.ts'])
expect(runtimeEnvironmentCall.mock.calls.at(-1)?.[0].params).not.toHaveProperty('includeIgnored')
})
it('does not reuse unfiltered recent inventory after enabling supported ignore filtering', async () => {
runtimeEnvironmentCall.mockImplementation(({ method }) =>
Promise.resolve({
@@ -1,13 +1,11 @@
import { describe, expect, it, vi } from 'vitest'
import { describe, expect, it } from 'vitest'
import { writeRuntimeTerminalArtifactFile } from './runtime-terminal-artifact-write'
import {
fsWriteFile,
runtimeEnvironmentCall,
installRuntimeFileClientEnvironment,
type RuntimeRpcRequest
} from './runtime-file-client-test-harness'
import { getDiskBaselineSignature } from '../../../shared/disk-baseline-signature'
import { replaceRuntimeEnvironmentRevisions } from './runtime-environment-revision'
installRuntimeFileClientEnvironment()
@@ -55,23 +53,6 @@ function callsTo(method: string): RuntimeRpcRequest[] {
}
describe('saving a granted host file outside every workspace', () => {
it('writes through the grant when the host still holds the opened text', async () => {
runtimeEnvironmentCall.mockImplementation(async ({ method }) =>
method === 'files.readTerminalArtifact' ? read('# old') : ok({ ok: true })
)
await expect(save('# new', '# old')).resolves.toEqual({ ok: true })
expect(callsTo('files.writeTerminalArtifact')[0]?.params).toEqual({
worktree: 'id:wt-1',
grantId: 'g-1',
absolutePath: PATH,
content: '# new'
})
// Why: a host path must never become a write of this computer's same path.
expect(fsWriteFile).not.toHaveBeenCalled()
})
it('refuses to overwrite text that changed on the host', async () => {
runtimeEnvironmentCall.mockImplementation(async ({ method }) =>
method === 'files.readTerminalArtifact' ? read('# theirs') : ok({ ok: true })
@@ -81,31 +62,6 @@ describe('saving a granted host file outside every workspace', () => {
expect(callsTo('files.writeTerminalArtifact')).toHaveLength(0)
})
it('renews an expired grant and still checks the host text first', async () => {
runtimeEnvironmentCall.mockImplementation(async ({ method, params }) => {
if (method === 'files.resolveTerminalPath') {
return granted('g-2')
}
const grantId = grantIdOf(params)
if (grantId === 'g-1') {
return refused('terminal_file_grant_expired')
}
return method === 'files.readTerminalArtifact' ? read('# old') : ok({ ok: true })
})
const onGrantRenewed = vi.fn()
await expect(save('# new', '# old', onGrantRenewed)).resolves.toEqual({ ok: true })
expect(onGrantRenewed).toHaveBeenCalledWith('g-2')
expect(callsTo('files.resolveTerminalPath')[0]?.params).toEqual({
worktree: 'id:wt-1',
pathText: PATH
})
expect(callsTo('files.writeTerminalArtifact').map((c) => c.params)).toEqual([
expect.objectContaining({ grantId: 'g-2', content: '# new' })
])
})
// Why: a host change stales the grant; the renewed read must still raise the conflict banner.
it('reports a host-side change behind a stale grant as a conflict', async () => {
runtimeEnvironmentCall.mockImplementation(async ({ method, params }) => {
@@ -122,38 +78,6 @@ describe('saving a granted host file outside every workspace', () => {
expect(callsTo('files.writeTerminalArtifact')).toHaveLength(0)
})
it('reports a file deleted on its host as missing', async () => {
runtimeEnvironmentCall.mockImplementation(async () =>
refused("ENOENT: no such file or directory, open '/private/tmp/handoff.md'")
)
await expect(save('# new', '# old')).resolves.toEqual({ ok: false, diskConflict: 'missing' })
expect(callsTo('files.writeTerminalArtifact')).toHaveLength(0)
})
// Why: a same-id re-pair mid-save must not let a renewed grant write the replacement host's file.
it('pins every step of a save to the pairing it started on', async () => {
replaceRuntimeEnvironmentRevisions([{ id: 'env-1', createdAt: 1, pairingRevision: 7 }])
runtimeEnvironmentCall.mockImplementation(async ({ method, params }) => {
if (method === 'files.resolveTerminalPath') {
return granted('g-2')
}
if (grantIdOf(params) === 'g-1') {
replaceRuntimeEnvironmentRevisions([{ id: 'env-1', createdAt: 2, pairingRevision: 8 }])
return refused('terminal_file_grant_expired')
}
return method === 'files.readTerminalArtifact' ? read('# old') : ok({ ok: true })
})
await save('# new', '# old').catch(() => undefined)
const revisions = runtimeEnvironmentCall.mock.calls
.map(([call]) => call)
.filter((call) => call.method !== 'status.get')
.map((call) => call.expectedEnvironmentPairingRevision)
expect(new Set(revisions)).toEqual(new Set([7]))
})
// Why: a quoted path can spell "not found"; only the error itself proves absence.
it('surfaces a permission failure on a path that mentions not found', async () => {
runtimeEnvironmentCall.mockImplementation(async () =>
@@ -182,20 +106,6 @@ describe('saving a granted host file outside every workspace', () => {
expect(callsTo('files.writeTerminalArtifact')).toHaveLength(0)
})
// Why: a committed write whose reply was lost must still settle the save, or the next one conflicts.
it('treats a lost reply as saved when the host already holds the new text', async () => {
let written = false
runtimeEnvironmentCall.mockImplementation(async ({ method }) => {
if (method === 'files.writeTerminalArtifact') {
written = true
throw new Error('Request timed out')
}
return read(written ? '# new' : '# old')
})
await expect(save('# new', '# old')).resolves.toEqual({ ok: true })
})
it('reads back through a fresh grant when the dropped reply also revoked the old one', async () => {
let written = false
runtimeEnvironmentCall.mockImplementation(async ({ method, params }) => {
@@ -11,10 +11,6 @@ import { clearRuntimeCompatibilityCacheForTests } from './runtime-rpc-client'
import { TERMINAL_INPUT_MAX_BYTES } from '../../../shared/terminal-input'
import { useAppStore } from '../store'
import type { RemoteForegroundEvidence } from '../../../shared/foreground-process-evidence'
import {
clientOnlyUnverifiableInspection,
type ClientOnlyUnverifiableInspection
} from '../../../shared/terminal-process-inspection'
const LEAF_ID = '11111111-1111-4111-8111-111111111111'
const PANE_KEY = `tab-1:${LEAF_ID}`
@@ -47,8 +43,6 @@ describe('runtime terminal owner routing', () => {
const runtimeTransportCall = vi.fn()
const localWrite = vi.fn()
const localWriteAccepted = vi.fn()
const localForeground = vi.fn()
const localHasChildren = vi.fn()
const localInspect = vi.fn()
beforeEach(() => {
@@ -74,8 +68,6 @@ describe('runtime terminal owner routing', () => {
pty: {
write: localWrite,
writeAccepted: localWriteAccepted,
getForegroundProcess: localForeground,
hasChildProcesses: localHasChildren,
inspectProcess: localInspect
}
}
@@ -105,81 +97,6 @@ describe('runtime terminal owner routing', () => {
expect(useAppStore.getState().lastTerminalInputAtByPaneKey[PANE_KEY]).toBe(123)
})
it('sends input through the PTY owning environment instead of the active one', async () => {
expect(sendRuntimePtyInput('remote:env-1@@terminal-1', 'x', 'driving')).toBe(true)
await vi.waitFor(() => {
expect(runtimeCall).toHaveBeenCalledWith({
selector: 'env-1',
method: 'terminal.send',
params: {
terminal: 'terminal-1',
text: 'x',
client: { id: 'orca-desktop', type: 'desktop' }
},
timeoutMs: 15_000
})
})
expect(localWrite).not.toHaveBeenCalled()
})
it('inspects the PTY owning environment instead of the active one', async () => {
await expect(inspectRuntimeTerminalProcess('remote:env-1@@terminal-1')).resolves.toMatchObject({
foregroundProcess: 'bash',
hasChildProcesses: true
})
expect(runtimeCall).toHaveBeenCalledWith({
selector: 'env-1',
method: 'terminal.inspectProcess',
params: { terminal: 'terminal-1' },
timeoutMs: 15_000
})
expect(localForeground).not.toHaveBeenCalled()
expect(localHasChildren).not.toHaveBeenCalled()
})
// Forward close guards’ real-process-read option or hosts return unverifiable and confirm every idle remote Windows close (#18591).
it('forwards scanChildProcesses to the PTY owning environment', async () => {
await inspectRuntimeTerminalProcess('remote:env-1@@terminal-1', { scanChildProcesses: true })
expect(runtimeCall).toHaveBeenCalledWith({
selector: 'env-1',
method: 'terminal.inspectProcess',
params: { terminal: 'terminal-1', scanChildProcesses: true },
timeoutMs: 15_000
})
})
it('forwards scanChildProcesses alongside the incarnation fence', async () => {
await inspectRuntimeTerminalProcess('remote:env-1@@terminal-1', {
expectedIncarnationId: 'incarnation-1',
scanChildProcesses: true
})
expect(runtimeCall).toHaveBeenCalledWith({
selector: 'env-1',
method: 'terminal.inspectProcess',
params: {
terminal: 'terminal-1',
expectedIncarnationId: 'incarnation-1',
scanChildProcesses: true
},
timeoutMs: 15_000
})
})
it('omits scanChildProcesses when the caller is only polling', async () => {
await inspectRuntimeTerminalProcess('remote:env-1@@terminal-1')
expect(runtimeCall).toHaveBeenCalledWith({
selector: 'env-1',
method: 'terminal.inspectProcess',
params: { terminal: 'terminal-1' },
timeoutMs: 15_000
})
})
it('maps an old host inspection to client-only unverifiable', async () => {
runtimeCall.mockResolvedValue({
ok: true,
@@ -197,22 +114,6 @@ describe('runtime terminal owner routing', () => {
})
})
it('uses strict main-process inspection for a direct SSH PTY', async () => {
localInspect.mockResolvedValue({
foregroundProcess: 'codex',
hasChildProcesses: true,
foregroundProcessEvidence: liveEvidence('pty-1', 'codex')
})
await expect(inspectRuntimeTerminalProcess('ssh:host@@pty-1')).resolves.toMatchObject({
foregroundProcess: 'codex',
hasChildProcesses: true
})
expect(localInspect).toHaveBeenCalledExactlyOnceWith('ssh:host@@pty-1')
expect(localForeground).not.toHaveBeenCalled()
expect(localHasChildren).not.toHaveBeenCalled()
})
it('maps an old direct SSH host to client-only unverifiable', async () => {
localInspect.mockResolvedValue({
foregroundProcess: null,
@@ -261,23 +162,6 @@ describe('runtime terminal owner routing', () => {
).resolves.toMatchObject({ verdict: 'unverifiable', reason: 'timeout' })
})
it('keeps client-only unverifiable free of host metadata', () => {
type HostFieldsCannotBeConstructed = ClientOnlyUnverifiableInspection extends {
authorityGeneration?: never
observationEpoch?: never
capturedAgeMs?: never
ptyId?: never
ptyIncarnationId?: never
}
? true
: false
const typeProof: HostFieldsCannotBeConstructed = true
expect(typeProof).toBe(true)
const result = clientOnlyUnverifiableInspection('transport_loss')
expect(result).not.toHaveProperty('authorityGeneration')
expect(result).not.toHaveProperty('foregroundProcessEvidence')
})
it('still throws an unclassified programming error', async () => {
runtimeCall.mockRejectedValueOnce(new Error('inspection invariant violated'))
await expect(inspectRuntimeTerminalProcess('remote:env-1@@terminal-bug')).rejects.toThrow(
@@ -285,33 +169,6 @@ describe('runtime terminal owner routing', () => {
)
})
it('records accepted fire-and-forget runtime input against the owning pane key', async () => {
runtimeCall.mockResolvedValue({
ok: true,
result: { send: { handle: 'terminal-1', accepted: true, bytesWritten: 1 } },
_meta: { runtimeId: 'runtime-1' }
})
useAppStore.setState({
settings: { experimentalAgentHibernation: true } as never,
terminalLayoutsByTabId: {
'tab-1': {
root: { type: 'leaf', leafId: LEAF_ID },
activeLeafId: LEAF_ID,
expandedLeafId: null,
ptyIdsByLeafId: { [LEAF_ID]: 'remote:env-1@@terminal-1' }
}
}
})
expect(sendRuntimePtyInput('remote:env-1@@terminal-1', 'x', 'driving')).toBe(true)
await vi.waitFor(() => {
expect(useAppStore.getState().lastTerminalInputAtByPaneKey[PANE_KEY]).toEqual(
expect.any(Number)
)
})
})
it('attributes a delayed runtime acknowledgement to the current layout owner', async () => {
const pendingSend = Promise.withResolvers<{
ok: true
@@ -357,75 +214,6 @@ describe('runtime terminal owner routing', () => {
})
})
it('does not record declined fire-and-forget runtime input', async () => {
runtimeCall.mockResolvedValue({
ok: true,
result: { send: { handle: 'terminal-1', accepted: false, bytesWritten: 0 } },
_meta: { runtimeId: 'runtime-1' }
})
useAppStore.setState({
settings: { experimentalAgentHibernation: true } as never,
terminalLayoutsByTabId: {
'tab-1': {
root: { type: 'leaf', leafId: LEAF_ID },
activeLeafId: LEAF_ID,
expandedLeafId: null,
ptyIdsByLeafId: { [LEAF_ID]: 'remote:env-1@@terminal-1' }
}
}
})
expect(sendRuntimePtyInput('remote:env-1@@terminal-1', 'x', 'driving')).toBe(true)
await vi.waitFor(() => {
expect(runtimeCall).toHaveBeenCalled()
})
expect(useAppStore.getState().lastTerminalInputAtByPaneKey[PANE_KEY]).toBeUndefined()
})
it('reports stale remote terminal handles as rejected during verified send', async () => {
runtimeCall.mockResolvedValue({
ok: false,
error: { code: 'terminal_handle_stale', message: 'terminal_handle_stale' }
})
await expect(
sendRuntimePtyInputVerified('remote:env-1@@terminal-stale', 'x', 'driving')
).resolves.toBe(false)
})
it('reports declined remote terminal sends as rejected during verified send', async () => {
runtimeCall.mockResolvedValue({
ok: true,
result: { send: { handle: 'terminal-1', accepted: false, bytesWritten: 0 } },
_meta: { runtimeId: 'runtime-1' }
})
await expect(
sendRuntimePtyInputVerified('remote:env-1@@terminal-1', 'x', 'driving')
).resolves.toBe(false)
expect(runtimeCall).toHaveBeenCalledWith({
selector: 'env-1',
method: 'terminal.send',
params: {
terminal: 'terminal-1',
text: 'x',
client: { id: 'orca-desktop', type: 'desktop' }
},
timeoutMs: 15_000
})
})
it('uses accepted local writes for verified input', async () => {
localWriteAccepted.mockResolvedValue(true)
await expect(sendRuntimePtyInputVerified('local-pty', 'x', 'driving')).resolves.toBe(true)
expect(localWriteAccepted).toHaveBeenCalledWith('local-pty', 'x', 'driving')
expect(localWrite).not.toHaveBeenCalled()
})
it('rejects oversized fire-and-forget local input before IPC writes', () => {
const text = 'x'.repeat(TERMINAL_INPUT_MAX_BYTES + 1)
@@ -435,15 +223,6 @@ describe('runtime terminal owner routing', () => {
expect(localWriteAccepted).not.toHaveBeenCalled()
})
it('rejects oversized fire-and-forget remote input before runtime RPC', () => {
const text = 'x'.repeat(TERMINAL_INPUT_MAX_BYTES + 1)
expect(sendRuntimePtyInput('remote:env-1@@terminal-1', text, 'driving')).toBe(false)
expect(runtimeTransportCall).not.toHaveBeenCalled()
expect(localWrite).not.toHaveBeenCalled()
})
it('yields while validating large fire-and-forget local input before IPC writes', async () => {
vi.useFakeTimers()
try {
@@ -632,110 +411,4 @@ describe('runtime terminal owner routing', () => {
]
).toBe(1_000_000)
})
it('reindexes a PTY when the immutable layout identity changes', () => {
const nextLeafId = '22222222-2222-4222-8222-222222222222'
useAppStore.setState({
terminalLayoutsByTabId: {
'tab-1': {
root: { type: 'leaf', leafId: LEAF_ID },
activeLeafId: LEAF_ID,
expandedLeafId: null,
ptyIdsByLeafId: { [LEAF_ID]: 'rebound-pty' }
}
}
})
recordRuntimeTerminalInputForPtyId('rebound-pty', 123)
useAppStore.setState({
terminalLayoutsByTabId: {
'tab-2': {
root: { type: 'leaf', leafId: nextLeafId },
activeLeafId: nextLeafId,
expandedLeafId: null,
ptyIdsByLeafId: { [nextLeafId]: 'rebound-pty' }
}
}
})
recordRuntimeTerminalInputForPtyId('rebound-pty', 1_000)
expect(useAppStore.getState().lastTerminalInputAtByPaneKey).toEqual({
[PANE_KEY]: 123,
[`tab-2:${nextLeafId}`]: 1_000
})
})
it('reindexes stale owners without caching misses within the same layout identity', () => {
const nextLeafId = '22222222-2222-4222-8222-222222222222'
useAppStore.setState({
terminalLayoutsByTabId: {
'tab-1': {
root: { type: 'leaf', leafId: LEAF_ID },
activeLeafId: LEAF_ID,
expandedLeafId: null,
ptyIdsByLeafId: { [LEAF_ID]: 'rebound-pty' }
}
}
})
const layouts = useAppStore.getState().terminalLayoutsByTabId
recordRuntimeTerminalInputForPtyId('rebound-pty', 123)
recordRuntimeTerminalInputForPtyId('late-pty', 456)
const firstLayout = layouts['tab-1']
expect(firstLayout).toBeDefined()
if (!firstLayout) {
return
}
firstLayout.ptyIdsByLeafId = Object.create({ [LEAF_ID]: 'rebound-pty' })
Object.setPrototypeOf(layouts, { 'tab-1': firstLayout })
delete layouts['tab-1']
layouts['tab-2'] = {
root: { type: 'leaf', leafId: nextLeafId },
activeLeafId: nextLeafId,
expandedLeafId: null,
ptyIdsByLeafId: { [nextLeafId]: 'rebound-pty', [LEAF_ID]: 'late-pty' }
}
recordRuntimeTerminalInputForPtyId('rebound-pty', 1_000)
recordRuntimeTerminalInputForPtyId('late-pty', 2_000)
expect(useAppStore.getState().terminalLayoutsByTabId).toBe(layouts)
expect(useAppStore.getState().lastTerminalInputAtByPaneKey).toEqual({
[PANE_KEY]: 123,
[`tab-2:${nextLeafId}`]: 1_000,
[`tab-2:${LEAF_ID}`]: 2_000
})
})
it('preserves a malformed first match instead of routing a duplicate PTY', () => {
const nextLeafId = '22222222-2222-4222-8222-222222222222'
useAppStore.setState({
terminalLayoutsByTabId: {
'legacy:tab': {
root: { type: 'leaf', leafId: LEAF_ID },
activeLeafId: LEAF_ID,
expandedLeafId: null,
ptyIdsByLeafId: { [LEAF_ID]: 'duplicate-pty' }
},
'tab-2': {
root: { type: 'leaf', leafId: nextLeafId },
activeLeafId: nextLeafId,
expandedLeafId: null,
ptyIdsByLeafId: { [nextLeafId]: 'duplicate-pty' }
}
}
})
recordRuntimeTerminalInputForPtyId('duplicate-pty', 123)
expect(useAppStore.getState().lastTerminalInputAtByPaneKey).toEqual({})
})
it('reports success after fallback fire-and-forget writes when local acceptance cannot be verified', async () => {
localWriteAccepted.mockResolvedValue(false)
await expect(sendRuntimePtyInputVerified('local-pty', 'x', 'driving')).resolves.toBe(true)
expect(localWriteAccepted).toHaveBeenCalledWith('local-pty', 'x', 'driving')
expect(localWrite).toHaveBeenCalledWith('local-pty', 'x', 'driving')
})
})
@@ -11,36 +11,10 @@ import {
_getRemoteRuntimeTerminalMultiplexerCountForTest,
resetRemoteRuntimeTerminalMultiplexersForTests
} from './remote-runtime-terminal-multiplexer'
import {
getRemoteRuntimePtyEnvironmentId,
getRemoteRuntimeTerminalHandle,
subscribeToRuntimeTerminalData
} from './runtime-terminal-stream'
import { toRemoteRuntimePtyId } from '../../../shared/remote-runtime/remote-runtime-pty-id'
import { subscribeToRuntimeTerminalData } from './runtime-terminal-stream'
import { stubRuntimeEnvironmentBridge } from './runtime-environment-bridge-fixture'
describe('remote runtime terminal ids', () => {
it('encodes and decodes the owning runtime environment', () => {
const ptyId = toRemoteRuntimePtyId('terminal:one', 'env-1')
expect(ptyId).toBe('remote:env-1@@terminal%3Aone')
expect(getRemoteRuntimePtyEnvironmentId(ptyId)).toBe('env-1')
expect(getRemoteRuntimeTerminalHandle(ptyId)).toBe('terminal:one')
})
it('keeps legacy remote ids readable', () => {
expect(getRemoteRuntimePtyEnvironmentId('remote:terminal-1')).toBeNull()
expect(getRemoteRuntimeTerminalHandle('remote:terminal-1')).toBe('terminal-1')
})
it('treats malformed encoded ids as invalid instead of throwing', () => {
const malformed = 'remote:%E0%A4%A@@terminal-1'
expect(getRemoteRuntimePtyEnvironmentId(malformed)).toBeNull()
expect(getRemoteRuntimeTerminalHandle(malformed)).toBeNull()
})
})
describe('remote runtime terminal data subscriptions', () => {
const runtimeSubscribe = vi.fn()
const sendBinary = vi.fn()
@@ -347,168 +321,6 @@ describe('remote runtime terminal multiplex ACK gate', () => {
vi.resetModules()
})
it('holds and releases ACKs for selected remote terminal streams only', async () => {
const { getRemoteRuntimeTerminalMultiplexer, resetRemoteRuntimeTerminalMultiplexersForTests } =
await import('./remote-runtime-terminal-multiplexer')
resetRemoteRuntimeTerminalMultiplexersForTests()
const multiplexer = getRemoteRuntimeTerminalMultiplexer('env-ack-gate')
const heldTerminal = await multiplexer.subscribeTerminal({
terminal: 'terminal-held',
client: { id: 'desktop-held', type: 'desktop' },
callbacks: {
onData: vi.fn(),
onSnapshot: vi.fn()
}
})
const liveTerminal = await multiplexer.subscribeTerminal({
terminal: 'terminal-live',
client: { id: 'desktop-live', type: 'desktop' },
callbacks: {
onData: vi.fn(),
onSnapshot: vi.fn()
}
})
await vi.waitFor(() => expect(sendBinary).toHaveBeenCalledTimes(2))
const heldStreamId = heldTerminal.streamId
const liveStreamId = liveTerminal.streamId
const gate = (
window as typeof window & {
__remoteTerminalMultiplexAckGate?: {
hold: (terminals: string[]) => void
release: () => void
snapshot: () => {
heldTerminalCount: number
heldStreamCount: number
heldAckChars: number
releasedAckChars: number
}
}
}
).__remoteTerminalMultiplexAckGate
expect(gate).toBeDefined()
gate?.hold(['terminal-held'])
sendBinary.mockClear()
callbacks?.onBinary?.(
encodeTerminalStreamFrame({
opcode: TerminalStreamOpcode.Output,
streamId: heldStreamId,
seq: 1,
payload: encodeTerminalStreamText('held-output')
})
)
callbacks?.onBinary?.(
encodeTerminalStreamFrame({
opcode: TerminalStreamOpcode.Output,
streamId: liveStreamId,
seq: 2,
payload: encodeTerminalStreamText('live-output')
})
)
await vi.waitFor(() =>
expect(
sendBinary.mock.calls
.map((call) => decodeTerminalStreamFrame(call[0]))
.filter((frame) => frame?.opcode === TerminalStreamOpcode.Ack)
).toHaveLength(1)
)
const immediateAckFrames = sendBinary.mock.calls
.map((call) => decodeTerminalStreamFrame(call[0]))
.filter((frame) => frame?.opcode === TerminalStreamOpcode.Ack)
expect(immediateAckFrames).toHaveLength(1)
expect(immediateAckFrames[0]?.streamId).toBe(liveStreamId)
expect(gate?.snapshot()).toMatchObject({
heldTerminalCount: 1,
heldStreamCount: 1,
heldAckChars: 'held-output'.length
})
gate?.release()
await vi.waitFor(() =>
expect(
sendBinary.mock.calls
.map((call) => decodeTerminalStreamFrame(call[0]))
.filter((frame) => frame?.opcode === TerminalStreamOpcode.Ack)
).toHaveLength(2)
)
const allAckFrames = sendBinary.mock.calls
.map((call) => decodeTerminalStreamFrame(call[0]))
.filter((frame) => frame?.opcode === TerminalStreamOpcode.Ack)
const releasedAck = allAckFrames.find((frame) => frame?.streamId === heldStreamId)
expect(releasedAck && decodeTerminalStreamJson(releasedAck.payload)).toEqual({
bytes: 'held-output'.length
})
expect(gate?.snapshot()).toMatchObject({
heldTerminalCount: 0,
heldStreamCount: 0,
heldAckChars: 0,
releasedAckChars: 'held-output'.length
})
heldTerminal.close()
liveTerminal.close()
})
it('drops output only from the armed stream when its replacement reuses the stream ID', async () => {
const { getRemoteRuntimeTerminalMultiplexer, resetRemoteRuntimeTerminalMultiplexersForTests } =
await import('./remote-runtime-terminal-multiplexer')
resetRemoteRuntimeTerminalMultiplexersForTests()
const oldData = vi.fn()
const oldStream = await getRemoteRuntimeTerminalMultiplexer(
'env-output-drop-gate'
).subscribeTerminal({
terminal: 'terminal-reused-stream-id',
client: { id: 'desktop-old', type: 'desktop' },
callbacks: { onData: oldData, onSnapshot: vi.fn() }
})
const gate = (
window as typeof window & {
__remoteTerminalMultiplexAckGate?: {
dropOutputUntilResubscribe: (terminals: string[]) => number
release: () => void
}
}
).__remoteTerminalMultiplexAckGate
expect(gate?.dropOutputUntilResubscribe(['terminal-reused-stream-id'])).toBe(1)
callbacks?.onBinary?.(
encodeTerminalStreamFrame({
opcode: TerminalStreamOpcode.Output,
streamId: oldStream.streamId,
seq: 7,
payload: encodeTerminalStreamText('dropped')
})
)
expect(oldData).not.toHaveBeenCalled()
oldStream.close()
const replacementData = vi.fn()
const replacement = await getRemoteRuntimeTerminalMultiplexer(
'env-output-drop-gate'
).subscribeTerminal({
terminal: 'terminal-reused-stream-id',
client: { id: 'desktop-new', type: 'desktop' },
callbacks: { onData: replacementData, onSnapshot: vi.fn() }
})
expect(replacement.streamId).toBe(oldStream.streamId)
callbacks?.onBinary?.(
encodeTerminalStreamFrame({
opcode: TerminalStreamOpcode.Output,
streamId: replacement.streamId,
seq: 9,
payload: encodeTerminalStreamText('delivered')
})
)
expect(replacementData).toHaveBeenCalledWith('delivered', { seq: 9, rawLength: 9 })
gate?.release()
replacement.close()
})
it('applies mid-session recovery snapshots without re-subscribing', async () => {
const { getRemoteRuntimeTerminalMultiplexer } =
await import('./remote-runtime-terminal-multiplexer')
@@ -1,125 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { sendRuntimePtyInputVerified } from './runtime-terminal-verified-input'
import {
createCompatibleRuntimeStatusResponseIfNeeded,
type RuntimeEnvironmentCallRequest
} from './runtime-compatibility-test-fixture'
import { clearRuntimeCompatibilityCacheForTests } from './runtime-rpc-client'
const REMOTE_PTY = 'remote:env-1@@terminal-1'
const runtimeSend = vi.fn()
const localWrite = vi.fn()
const localWriteAccepted = vi.fn()
beforeEach(() => {
clearRuntimeCompatibilityCacheForTests()
vi.clearAllMocks()
vi.stubGlobal('window', {
api: {
runtimeEnvironments: {
call: (args: RuntimeEnvironmentCallRequest) =>
createCompatibleRuntimeStatusResponseIfNeeded(args) ?? runtimeSend(args)
},
pty: { write: localWrite, writeAccepted: localWriteAccepted }
}
})
})
function hostReply(send: Record<string, unknown>) {
runtimeSend.mockResolvedValue({
ok: true,
result: { send: { handle: 'terminal-1', bytesWritten: 1, ...send } },
_meta: { runtimeId: 'runtime-1' }
})
}
describe('verified input that requires provider settlement', () => {
it.each([
['older host whole-write', { accepted: true }, true],
['acknowledged', { accepted: true, writeSettlement: { outcome: 'accepted' } }, true],
[
'refused',
{ accepted: false, writeSettlement: { outcome: 'refused', reason: 'endpoint_disconnected' } },
false
]
] as const)('reads the %s remote verdict', async (_label, send, accepted) => {
hostReply(send)
await expect(
sendRuntimePtyInputVerified(REMOTE_PTY, 'x', 'driving', {
requireWriteSettlement: true
})
).resolves.toBe(accepted)
expect(runtimeSend).toHaveBeenCalledWith(
expect.objectContaining({
method: 'terminal.send',
params: expect.objectContaining({ requireWriteSettlement: true })
})
)
})
it('rejects a remote send whose settlement is unverifiable, without a fallback write', async () => {
hostReply({
accepted: false,
writeSettlement: {
outcome: 'unverifiable',
reason: 'transport_settlement_lost',
bytesHandedToTransport: true
}
})
await expect(
sendRuntimePtyInputVerified(REMOTE_PTY, 'x', 'driving', {
requireWriteSettlement: true
})
).rejects.toThrow('acknowledgment unavailable')
expect(localWrite).not.toHaveBeenCalled()
expect(runtimeSend).toHaveBeenCalledOnce()
})
})
describe('local verified input', () => {
it('keeps the fire-and-forget fallback for ordinary input the provider cannot accept', async () => {
localWriteAccepted.mockResolvedValue(false)
await expect(sendRuntimePtyInputVerified('ssh:conn-1@@pty-1', 'x', 'driving')).resolves.toBe(
true
)
expect(localWriteAccepted).toHaveBeenCalledWith('ssh:conn-1@@pty-1', 'x', 'driving')
expect(localWrite).toHaveBeenCalledWith('ssh:conn-1@@pty-1', 'x', 'driving')
})
it('never falls back to an unacknowledged write when settlement is required', async () => {
const settled = { requireWriteSettlement: true } as const
localWriteAccepted.mockResolvedValueOnce(true)
await expect(
sendRuntimePtyInputVerified('ssh:conn-1@@pty-1', 'answer', 'driving', settled)
).resolves.toBe(true)
localWriteAccepted.mockResolvedValueOnce(false)
await expect(
sendRuntimePtyInputVerified('ssh:conn-1@@pty-1', '1', 'driving', settled)
).resolves.toBe(false)
localWriteAccepted.mockRejectedValueOnce(new Error('acknowledgment unavailable'))
await expect(
sendRuntimePtyInputVerified('ssh:conn-1@@pty-1', '\r', 'driving', settled)
).rejects.toThrow('acknowledgment unavailable')
expect(localWriteAccepted).toHaveBeenCalledWith('ssh:conn-1@@pty-1', '\r', 'driving', settled)
expect(localWrite).not.toHaveBeenCalled()
})
})
describe('owner of the PTY', () => {
it('never dials a server for a remote id that names no owner', async () => {
localWriteAccepted.mockResolvedValue(false)
// Why: this id used to reach whichever server was focused, even when another one owned it.
await sendRuntimePtyInputVerified('remote:terminal-1', 'x', 'driving', {
requireWriteSettlement: true
})
expect(runtimeSend).not.toHaveBeenCalled()
})
it('sends to the server the id names', async () => {
hostReply({ accepted: true })
await sendRuntimePtyInputVerified(REMOTE_PTY, 'x', 'driving')
expect(runtimeSend).toHaveBeenCalledWith(
expect.objectContaining({ selector: 'env-1', method: 'terminal.send' })
)
})
})