mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 08:03:20 +00:00
fix(terminal): commit the adopted-claim reattach grid and reject non-integer provider grids
Review follow-ups. The runtime spawn path's adopted-claim branch returned before the size commit, so an adoption attaching to a live session kept whatever the caller requested; it now commits and reflows like every other reattach. The grid validator requires integers so a malformed provider grid falls through to the cached size instead of reaching xterm.
This commit is contained in:
@@ -98,6 +98,16 @@ describe('resolveCommittedPtySize', () => {
|
||||
).toEqual(CACHED)
|
||||
})
|
||||
|
||||
it('rejects a non-integer provider grid as unproven', () => {
|
||||
expect(
|
||||
resolveCommittedPtySize({
|
||||
result: { isReattach: true, snapshotCols: 120.5, snapshotRows: 40 },
|
||||
requested: REQUESTED,
|
||||
cachedBeforeAttach: CACHED
|
||||
})
|
||||
).toEqual(CACHED)
|
||||
})
|
||||
|
||||
it('takes the request only when nothing better exists', () => {
|
||||
expect(
|
||||
resolveCommittedPtySize({
|
||||
|
||||
@@ -6,8 +6,8 @@ export type PtyGrid = { cols: number; rows: number }
|
||||
function positiveGrid(cols: unknown, rows: unknown): PtyGrid | undefined {
|
||||
return typeof cols === 'number' &&
|
||||
typeof rows === 'number' &&
|
||||
Number.isFinite(cols) &&
|
||||
Number.isFinite(rows) &&
|
||||
Number.isInteger(cols) &&
|
||||
Number.isInteger(rows) &&
|
||||
cols > 0 &&
|
||||
rows > 0
|
||||
? { cols, rows }
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ptySizes } from '../delivery/visibility-state'
|
||||
import { commitRuntimePtySpawn } from './spawn-commit'
|
||||
import { createRuntimePtySpawnState, type RuntimePtySpawnArgs } from './spawn-state'
|
||||
import type { PtyRuntimeControllerDeps } from './controller-deps'
|
||||
|
||||
const PTY_ID = 'orca-pty-adopted'
|
||||
const LIVE_GRID = { cols: 211, rows: 57 }
|
||||
|
||||
function makeRuntime() {
|
||||
return {
|
||||
registerPreAllocatedHandleForPty: vi.fn(),
|
||||
registerPty: vi.fn(),
|
||||
reflowHeadlessTerminalToPtyGrid: vi.fn(),
|
||||
seedHeadlessTerminal: vi.fn(),
|
||||
noteTerminalSpawnCommand: vi.fn()
|
||||
}
|
||||
}
|
||||
|
||||
describe('runtime spawn commit: adopted agent-session claim', () => {
|
||||
afterEach(() => {
|
||||
ptySizes.delete(PTY_ID)
|
||||
})
|
||||
|
||||
it('commits the live grid from the adoption reply before the early return', async () => {
|
||||
const runtime = makeRuntime()
|
||||
const deps = { runtime, store: undefined, options: {} } as unknown as PtyRuntimeControllerDeps
|
||||
const args = { cols: 120, rows: 40, worktreeId: 'wt-1' } as unknown as RuntimePtySpawnArgs
|
||||
const ctx = createRuntimePtySpawnState(deps, args)
|
||||
ctx.result = {
|
||||
id: PTY_ID,
|
||||
isReattach: true,
|
||||
snapshotCols: LIVE_GRID.cols,
|
||||
snapshotRows: LIVE_GRID.rows,
|
||||
agentSessionEnsure: {
|
||||
disposition: 'adopted',
|
||||
owner: {
|
||||
claim: { kind: 'terminal' },
|
||||
generation: 'g1',
|
||||
phase: 'live',
|
||||
ptyId: PTY_ID,
|
||||
surface: { worktreeId: 'wt-1', tabId: 'tab-1', leafId: 'leaf-1', terminalHandle: 'h1' }
|
||||
}
|
||||
}
|
||||
} as unknown as typeof ctx.result
|
||||
|
||||
await commitRuntimePtySpawn(ctx)
|
||||
|
||||
expect(ptySizes.get(PTY_ID)).toEqual(LIVE_GRID)
|
||||
expect(runtime.reflowHeadlessTerminalToPtyGrid).toHaveBeenCalledWith(
|
||||
PTY_ID,
|
||||
LIVE_GRID.cols,
|
||||
LIVE_GRID.rows
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
import { commitAttachedPtySize } from '../delivery/attached-pty-size'
|
||||
import type { RuntimePtySpawnState } from './spawn-state'
|
||||
|
||||
/** Record the settled grid for a runtime-path spawn; `result` is passed explicitly because the
|
||||
* adopted-claim branch commits with `isReattach` forced on before it returns early. */
|
||||
export function commitRuntimePtySize(
|
||||
ctx: RuntimePtySpawnState,
|
||||
result: RuntimePtySpawnState['result']
|
||||
): void {
|
||||
commitAttachedPtySize({
|
||||
result,
|
||||
requested: { cols: ctx.args.cols, rows: ctx.args.rows },
|
||||
cachedBeforeAttach: ctx.sessionSizeBeforeAttach,
|
||||
reflowHeadlessTerminalToPtyGrid: ctx.deps.runtime?.reflowHeadlessTerminalToPtyGrid?.bind(
|
||||
ctx.deps.runtime
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isValidTerminalTabId } from '../../../../shared/terminal-tab-id'
|
||||
import { ptyOwnership, ptyIncarnationById, deletePtyOwnership } from '../provider/ownership-state'
|
||||
import { ptySizes } from '../delivery/visibility-state'
|
||||
import { commitAttachedPtySize } from '../delivery/attached-pty-size'
|
||||
import { commitRuntimePtySize } from './spawn-commit-pty-size'
|
||||
import {
|
||||
shouldSkipCodexHomeEnvForWindowsShell,
|
||||
recordCodexPaneAccountForSpawn,
|
||||
@@ -87,6 +87,9 @@ export async function commitRuntimePtySpawn(ctx: RuntimePtySpawnState) {
|
||||
...(ctx.env ? { launchEnv: ctx.env } : {})
|
||||
})
|
||||
}
|
||||
// Why: an adoption attaches to a live session too, and this branch returns before the
|
||||
// normal commit site; without this the cache keeps whatever the caller requested.
|
||||
commitRuntimePtySize(ctx, { ...ctx.result, isReattach: true })
|
||||
// Why: the adopted branch returns before the normal settle site, so the
|
||||
// reservation must be resolved here or every later spawn for this pane
|
||||
// awaits a promise that never settles.
|
||||
@@ -126,14 +129,7 @@ export async function commitRuntimePtySpawn(ctx: RuntimePtySpawnState) {
|
||||
if (!ctx.hostSessionBinding) {
|
||||
persistSshLease()
|
||||
}
|
||||
commitAttachedPtySize({
|
||||
result: ctx.result,
|
||||
requested: { cols: args.cols, rows: args.rows },
|
||||
cachedBeforeAttach: ctx.sessionSizeBeforeAttach,
|
||||
reflowHeadlessTerminalToPtyGrid: ctx.deps.runtime?.reflowHeadlessTerminalToPtyGrid?.bind(
|
||||
ctx.deps.runtime
|
||||
)
|
||||
})
|
||||
commitRuntimePtySize(ctx, ctx.result)
|
||||
if (ctx.effectiveSessionAppId !== undefined && ctx.effectiveSessionAppId !== ctx.result.id) {
|
||||
ptySizes.delete(ctx.effectiveSessionAppId)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user