mirror of
https://github.com/stablyai/orca.git
synced 2026-09-25 16:02:38 +00:00
* perf(terminal): activate splits before cwd resolution * test(terminal): prove split focus before cwd publish * fix(terminal): release stale split cwd fence * test(terminal): add visible split activation latency benchmark * docs(reliability): clarify split benchmark provenance * fix: preserve deferred split handoffs across remounts * fix: fence late deferred split closes * docs(reliability): record exact split benchmark runs * test(reliability): fail benchmark on artifact write errors * test(reliability): attribute split activation phases * docs(reliability): record schema-v2 split benchmark * refactor(terminal): collapse duplicated split-handoff and write-queue paths - Drop the discardDeferredSplitPaneHandoff alias for its identical clear twin. - Fold the deferred-cwd resolve/reject settle handlers into one applier. - Extract settlePaneCwdDeferredSpawn for the repeated read-clear-write pattern. - Share one head-index FIFO primitive between the ordinary and reply queues. * fix(terminal): stop retaining a promise reaction per acknowledged write Racing every accepted write against one queue-lifetime cancel promise kept a reaction record alive until that promise settled: 200k acknowledged writes retained 88.6MB, now 0.1MB. Give each in-flight write its own cancel, and split the shared FIFO primitive into its own module. Also sanitize the split-latency benchmark report at its single serialization point so shared artifacts no longer carry the machine-local repo path or unbounded cleanup error text. * fix(terminal): settle deferred split input when the spawn is abandoned An abandoned deferred spawn returns before transport.connect(), so nothing drained the pre-connect buffer: sendInputAccepted's promise never settled and a paste into that pane hung forever. Clear the buffer on the abandon fence. Also re-derive the pre-connect retention cap from the clipboard-paste ceiling rather than the 16MB single-write ceiling; it is held twice per pane across up to 64 deferred splits, so 5.59M code units guarded the wrong thing. * fix(terminal): release the deferred cwd fence on a rejected reattach A daemon createOrAttach can turn an apparent fresh spawn into a reattach; when that reattach is refused the spawn ends with deferredSplitSpawn/pendingCwd still set, permanently arming the pre-bind detach refusal. The release no-ops when a PTY did bind, so it only fires where the fence would otherwise leak. The stale-generation return above is deliberately left alone: a newer connect already owns the pane there, and the fence is not generation-scoped.
194 lines
6.3 KiB
TypeScript
194 lines
6.3 KiB
TypeScript
import type { ElectronApplication } from '@stablyai/playwright-test'
|
|
import type { SplitLatencyMainProbeEvent } from './terminal-split-activation-latency-phases'
|
|
|
|
type MainProbeInvokeHandler = (event: unknown, args: Record<string, unknown>) => unknown
|
|
|
|
type SplitLatencyMainProbeState = {
|
|
events: SplitLatencyMainProbeEvent[]
|
|
nextOperationId: number
|
|
cwdHandler: MainProbeInvokeHandler
|
|
spawnHandler: MainProbeInvokeHandler
|
|
writeAcceptedHandler: MainProbeInvokeHandler
|
|
originalCwdHandler: MainProbeInvokeHandler
|
|
originalSpawnHandler: MainProbeInvokeHandler
|
|
originalWriteAcceptedHandler: MainProbeInvokeHandler
|
|
writeListener: (event: unknown, args: { id?: unknown; data?: unknown }) => void
|
|
}
|
|
|
|
export async function installSplitLatencyMainProbe(
|
|
electronApp: ElectronApplication
|
|
): Promise<void> {
|
|
await electronApp.evaluate(({ ipcMain }) => {
|
|
const scope = globalThis as typeof globalThis & {
|
|
__terminalSplitLatencyMainProbe?: SplitLatencyMainProbeState
|
|
}
|
|
if (scope.__terminalSplitLatencyMainProbe) {
|
|
throw new Error('Terminal split latency main probe is already installed')
|
|
}
|
|
const handlers = (
|
|
ipcMain as unknown as { _invokeHandlers?: Map<string, MainProbeInvokeHandler> }
|
|
)._invokeHandlers
|
|
const originalCwdHandler = handlers?.get('pty:getCwd')
|
|
const originalSpawnHandler = handlers?.get('pty:spawn')
|
|
const originalWriteAcceptedHandler = handlers?.get('pty:writeAccepted')
|
|
if (
|
|
!handlers ||
|
|
!originalCwdHandler ||
|
|
!originalSpawnHandler ||
|
|
!originalWriteAcceptedHandler
|
|
) {
|
|
throw new Error('Terminal split latency main probe could not find PTY invoke handlers')
|
|
}
|
|
const state = {
|
|
events: [],
|
|
nextOperationId: 1,
|
|
originalCwdHandler,
|
|
originalSpawnHandler,
|
|
originalWriteAcceptedHandler
|
|
} as unknown as SplitLatencyMainProbeState
|
|
state.cwdHandler = async (event, args) => {
|
|
const operationId = state.nextOperationId++
|
|
const ptyId = typeof args?.id === 'string' ? args.id : null
|
|
state.events.push({
|
|
kind: 'cwd-request',
|
|
operationId,
|
|
atEpochMs: Date.now(),
|
|
ptyId,
|
|
writeChannel: null
|
|
})
|
|
try {
|
|
return await state.originalCwdHandler(event, args)
|
|
} finally {
|
|
state.events.push({
|
|
kind: 'cwd-settled',
|
|
operationId,
|
|
atEpochMs: Date.now(),
|
|
ptyId,
|
|
writeChannel: null
|
|
})
|
|
}
|
|
}
|
|
state.spawnHandler = async (event, args) => {
|
|
const operationId = state.nextOperationId++
|
|
state.events.push({
|
|
kind: 'pty-spawn-request',
|
|
operationId,
|
|
atEpochMs: Date.now(),
|
|
ptyId: null,
|
|
writeChannel: null
|
|
})
|
|
try {
|
|
const result = await state.originalSpawnHandler(event, args)
|
|
const ptyId =
|
|
result && typeof result === 'object' && 'id' in result && typeof result.id === 'string'
|
|
? result.id
|
|
: null
|
|
state.events.push({
|
|
kind: 'pty-spawn-result',
|
|
operationId,
|
|
atEpochMs: Date.now(),
|
|
ptyId,
|
|
writeChannel: null
|
|
})
|
|
return result
|
|
} catch (error) {
|
|
state.events.push({
|
|
kind: 'pty-spawn-result',
|
|
operationId,
|
|
atEpochMs: Date.now(),
|
|
ptyId: null,
|
|
writeChannel: null
|
|
})
|
|
throw error
|
|
}
|
|
}
|
|
state.writeListener = (_event, args) => {
|
|
if (args?.data !== '\r') {
|
|
return
|
|
}
|
|
state.events.push({
|
|
kind: 'pty-write-cr',
|
|
operationId: null,
|
|
atEpochMs: Date.now(),
|
|
ptyId: typeof args.id === 'string' ? args.id : null,
|
|
writeChannel: 'pty:write'
|
|
})
|
|
}
|
|
state.writeAcceptedHandler = (event, args) => {
|
|
if (args?.data === '\r') {
|
|
state.events.push({
|
|
kind: 'pty-write-cr',
|
|
operationId: null,
|
|
atEpochMs: Date.now(),
|
|
ptyId: typeof args.id === 'string' ? args.id : null,
|
|
writeChannel: 'pty:writeAccepted'
|
|
})
|
|
}
|
|
return state.originalWriteAcceptedHandler(event, args)
|
|
}
|
|
handlers.set('pty:getCwd', state.cwdHandler)
|
|
handlers.set('pty:spawn', state.spawnHandler)
|
|
handlers.set('pty:writeAccepted', state.writeAcceptedHandler)
|
|
ipcMain.prependListener('pty:write', state.writeListener)
|
|
scope.__terminalSplitLatencyMainProbe = state
|
|
})
|
|
}
|
|
|
|
export async function resetSplitLatencyMainProbe(electronApp: ElectronApplication): Promise<void> {
|
|
await electronApp.evaluate(() => {
|
|
const state = (
|
|
globalThis as typeof globalThis & {
|
|
__terminalSplitLatencyMainProbe?: SplitLatencyMainProbeState
|
|
}
|
|
).__terminalSplitLatencyMainProbe
|
|
if (!state) {
|
|
throw new Error('Terminal split latency main probe is not installed')
|
|
}
|
|
state.events.length = 0
|
|
})
|
|
}
|
|
|
|
export async function readSplitLatencyMainProbe(
|
|
electronApp: ElectronApplication
|
|
): Promise<SplitLatencyMainProbeEvent[]> {
|
|
return electronApp.evaluate(() => {
|
|
const state = (
|
|
globalThis as typeof globalThis & {
|
|
__terminalSplitLatencyMainProbe?: SplitLatencyMainProbeState
|
|
}
|
|
).__terminalSplitLatencyMainProbe
|
|
if (!state) {
|
|
throw new Error('Terminal split latency main probe is not installed')
|
|
}
|
|
return [...state.events]
|
|
})
|
|
}
|
|
|
|
export async function disposeSplitLatencyMainProbe(
|
|
electronApp: ElectronApplication
|
|
): Promise<void> {
|
|
await electronApp.evaluate(({ ipcMain }) => {
|
|
const scope = globalThis as typeof globalThis & {
|
|
__terminalSplitLatencyMainProbe?: SplitLatencyMainProbeState
|
|
}
|
|
const state = scope.__terminalSplitLatencyMainProbe
|
|
if (!state) {
|
|
return
|
|
}
|
|
const handlers = (
|
|
ipcMain as unknown as { _invokeHandlers?: Map<string, MainProbeInvokeHandler> }
|
|
)._invokeHandlers
|
|
if (handlers?.get('pty:getCwd') === state.cwdHandler) {
|
|
handlers.set('pty:getCwd', state.originalCwdHandler)
|
|
}
|
|
if (handlers?.get('pty:spawn') === state.spawnHandler) {
|
|
handlers.set('pty:spawn', state.originalSpawnHandler)
|
|
}
|
|
if (handlers?.get('pty:writeAccepted') === state.writeAcceptedHandler) {
|
|
handlers.set('pty:writeAccepted', state.originalWriteAcceptedHandler)
|
|
}
|
|
ipcMain.removeListener('pty:write', state.writeListener)
|
|
delete scope.__terminalSplitLatencyMainProbe
|
|
})
|
|
}
|