mirror of
https://github.com/stablyai/orca.git
synced 2026-09-21 16:02:20 +00:00
`src/preload/api-types.ts` was 3,752 raw lines (3,533 counted, 11.8x the 300-line budget) behind an `eslint-disable max-lines`. Almost all of it was a single `PreloadApi` object type whose ~83 namespace properties were declared inline, so any IPC surface change meant editing one 2,600-line type. Give each namespace a named type in its own module under `src/preload/api/` (`pty-api.ts`, `filesystem-api.ts`, `github-pull-request-api.ts`, ...) and recompose `PreloadApi` from those names. `api-types.ts` keeps the `declare global` Window augmentation and re-exports every moved name, so all 52 import sites are untouched. Two shapes needed care to stay type-identical rather than merely compatible: - Three keys (`gh`, `git`, `ui`) are composed from two modules each. A plain intersection is NOT identical to the original flat object literal, so those use a `Merged<T>` mapped type; a negative control confirmed that dropping it fails the parity assertion. - Keys whose module groups several namespaces use indexed access (`fs: FilesystemApi['fs']`) to preserve exact identity and source order. `config/tsconfig.web.json` and `tsconfig.tc.web.json` enumerate files by path, so they need `src/preload/api/**/*` alongside the existing `api-types.ts` seed or the web projects fail TS6307. Verified by exact type identity, not assignability: 41 assertions of the form `Equals<Now.X, Before.X>` against a frozen pre-split snapshot, covering every exported name, plus a per-key pass over all 83 `PreloadApi` keys. All three projects typecheck clean with those assertions active. Verification note: these tsconfigs are `composite: true`, and `tsc --noEmit` will reuse a stale `.tsbuildinfo` and report clean for a state that genuinely fails. Every result above was produced after deleting the buildinfo, including a negative control confirming the gate still fails on deliberate drift. Drops the `max-lines` bypass and its baseline entry (ratchet 346 -> 345).
225 lines
9.8 KiB
TypeScript
225 lines
9.8 KiB
TypeScript
import type {
|
|
AgentProviderSessionMetadata,
|
|
SleepingAgentLaunchConfig
|
|
} from '../../shared/agent-session-resume'
|
|
import type { StartupCommandDelivery } from '../../shared/codex-startup-delivery'
|
|
import type { ProjectExecutionRuntimeResolution } from '../../shared/project-execution-runtime'
|
|
import type { PtyListedSession } from '../../shared/pty-listed-session'
|
|
import type { PtyMainDeliveryDiagnostics } from '../../shared/pty-delivery-diagnostics'
|
|
import type { PtyModelRestoreNeededEvent } from '../../shared/pty-model-restore-marker'
|
|
import type {
|
|
PtyRendererDeliveryHealthReply,
|
|
PtyRendererDeliveryStateReport
|
|
} from '../../shared/pty-renderer-delivery-health'
|
|
import type { AgentKind, LaunchSource, RequestKind } from '../../shared/telemetry-events'
|
|
import type { TerminalSideEffectBatch } from '../../shared/terminal-side-effect-facts'
|
|
import type { TerminalViewAttributes } from '../../shared/terminal-view-attributes'
|
|
import type { TuiAgent } from '../../shared/types'
|
|
import type { PtyManagementApi } from './pty-management-api'
|
|
|
|
export type PtyApi = {
|
|
spawn: (opts: {
|
|
cols: number
|
|
rows: number
|
|
cwd?: string
|
|
cwdFallback?: 'worktree'
|
|
env?: Record<string, string>
|
|
envToDelete?: string[]
|
|
command?: string
|
|
commandDelivery?: 'renderer' | 'provider'
|
|
launchConfig?: SleepingAgentLaunchConfig
|
|
resumeProviderSession?: AgentProviderSessionMetadata
|
|
launchToken?: string
|
|
launchAgent?: TuiAgent
|
|
startupCommandDelivery?: StartupCommandDelivery
|
|
connectionId?: string | null
|
|
worktreeId?: string
|
|
sessionId?: string
|
|
// Why: lets a single tab open in a different shell than the user's default.
|
|
shellOverride?: string
|
|
projectRuntime?: ProjectExecutionRuntimeResolution
|
|
terminalColorQueryReplies?: { foreground?: string; background?: string }
|
|
// Why: mark the PTY hidden before its first byte so the delivery gate owns spawn-time queries (terminal-query-authority.md §races).
|
|
initiallyHidden?: boolean
|
|
// Why: main sync-flushes the (worktreeId,tabId,leafId→ptyId) binding before pty:spawn returns to close a SIGKILL race (INVESTIGATION.md).
|
|
tabId?: string
|
|
leafId?: string
|
|
// Why: main fires `agent_started` only on spawn success, so launch metadata rides this field (telemetry-plan.md §Agent launch semantics).
|
|
telemetry?: { agent_kind: AgentKind; launch_source: LaunchSource; request_kind: RequestKind }
|
|
}) => Promise<{
|
|
id: string
|
|
launchAgent?: TuiAgent
|
|
launchConfig?: SleepingAgentLaunchConfig
|
|
snapshot?: string
|
|
snapshotCols?: number
|
|
snapshotRows?: number
|
|
snapshotPrefixAnsi?: string
|
|
snapshotFrameAnsi?: string
|
|
snapshotFrameRestoreAnsi?: string
|
|
snapshotKittyKeyboardFlags?: number
|
|
snapshotSeq?: number
|
|
isReattach?: boolean
|
|
isAlternateScreen?: boolean
|
|
replay?: string
|
|
sessionExpired?: boolean
|
|
coldRestore?: { scrollback: string; cwd: string; cols?: number; rows?: number }
|
|
startupCwdFallback?: { kind: 'worktree'; cwd: string }
|
|
agentResumeUnavailable?: true
|
|
}>
|
|
write: (id: string, data: string) => void
|
|
writeAccepted: (id: string, data: string) => Promise<boolean>
|
|
onWriteUnavailable?: (callback: (payload: { id: string }) => void) => () => void
|
|
resize: (id: string, cols: number, rows: number) => void
|
|
claimViewport: (id: string, cols: number, rows: number) => void
|
|
reportGeometry: (id: string, cols: number, rows: number) => void
|
|
signal: (id: string, signal: string) => void
|
|
clearBuffer: (id: string) => void
|
|
kill: (id: string, opts?: { keepHistory?: boolean }) => Promise<void>
|
|
ackColdRestore: (id: string) => void
|
|
ackData: (id: string, charCount: number, processedChars?: number) => void
|
|
onDeliveryResyncRequest: (callback: (payload: { requestId: number }) => void) => () => void
|
|
respondDeliveryResync: (payload: {
|
|
requestId: number
|
|
processedCharsByPty: Record<string, number>
|
|
}) => void
|
|
/** Renderer-initiated delivery health/heal lane over invoke — reaches main
|
|
* even when every main→renderer push channel is dead (field wedge). */
|
|
reportRendererDeliveryState: (
|
|
report: PtyRendererDeliveryStateReport
|
|
) => Promise<PtyRendererDeliveryHealthReply>
|
|
/** Live pty:data listener count on the preload emitter (sync) — heal-time
|
|
* discriminator between a detached listener and a dead channel. */
|
|
getPtyDataListenerCount: () => number
|
|
/** One-shot signal that this page's pty:data dispatcher is registered, so
|
|
* main can release sends held during the load/reload boot window. */
|
|
rendererDispatcherReady: () => void
|
|
setActiveRendererPty: (id: string, active: boolean) => void
|
|
setRendererPtyVisible: (id: string, visible: boolean) => void
|
|
/** Hidden-delivery gate (Phase 4): hidden=true lets main drop renderer
|
|
* byte delivery after model ingestion; reveal restores from snapshots. */
|
|
setHiddenRendererPty: (id: string, hidden: boolean) => void
|
|
/** Ref-counted-on-the-renderer delivery-interest signal that suppresses
|
|
* the hidden-delivery gate while any raw-byte consumer is registered. */
|
|
setPtyDeliveryInterest: (id: string, interested: boolean) => void
|
|
/** View-attribute bridge (Phase 5 slice 2): app-global composed terminal
|
|
* appearance push backing main's hidden-PTY OSC/DSR color replies. */
|
|
publishTerminalViewAttributes: (attributes: TerminalViewAttributes) => void
|
|
hasChildProcesses: (id: string) => Promise<boolean>
|
|
getForegroundProcess: (id: string) => Promise<string | null>
|
|
inspectProcess: (id: string) => Promise<{
|
|
foregroundProcess: string | null
|
|
hasChildProcesses: boolean
|
|
unavailable?: true
|
|
}>
|
|
confirmForegroundProcess: (id: string) => Promise<string | null>
|
|
getCwd: (id: string) => Promise<string>
|
|
getSize: (id: string) => Promise<{ cols: number; rows: number } | null>
|
|
listSessions: () => Promise<PtyListedSession[]>
|
|
getAuthoritativeBufferSnapshotCapabilities?: (
|
|
ids: string[]
|
|
) => Promise<{ id: string; authoritative: boolean | null }[]>
|
|
hasPty: (id: string) => Promise<boolean | null>
|
|
getMainBufferSnapshot: (
|
|
id: string,
|
|
opts?: { scrollbackRows?: number }
|
|
) => Promise<{
|
|
data: string
|
|
frameRestoreAnsi?: string
|
|
cols: number
|
|
rows: number
|
|
cwd?: string | null
|
|
seq?: number
|
|
/** Start of main's pending renderer-delivery queue at snapshot time
|
|
* (equals `seq` when empty) — bounds the renderer's post-restore
|
|
* duplicate window. */
|
|
pendingDeliveryStartSeq?: number
|
|
source?: 'headless' | 'renderer'
|
|
alternateScreen?: boolean
|
|
/** Authoritative normal buffer paired with an alternate-screen frame. */
|
|
scrollbackAnsi?: string
|
|
/** Trailing incomplete escape the emulator ingested; the restorer must
|
|
* write it after its post-replay resets, last before live chunks. */
|
|
pendingEscapeTailAnsi?: string
|
|
/** Effective kitty flags the snapshot owner proved at `seq`. Absent means
|
|
* unknown; consumers must not turn that into a known `0`. */
|
|
kittyKeyboardFlags?: number
|
|
} | null>
|
|
getRendererDeliveryDebugSnapshot: () => Promise<{
|
|
pendingPtyCount: number
|
|
pendingChars: number
|
|
maxPendingCharsByPty: number
|
|
rendererInFlightPtyCount: number
|
|
rendererInFlightChars: number
|
|
maxRendererInFlightCharsByPty: number
|
|
activeRendererPtyCount: number
|
|
flushScheduled: boolean
|
|
peakPendingChars: number
|
|
peakMaxPendingCharsByPty: number
|
|
peakRendererInFlightChars: number
|
|
peakMaxRendererInFlightCharsByPty: number
|
|
ackGatedFlushSkipCount: number
|
|
hiddenDeliveryGatedPtyCount: number
|
|
hiddenDeliveryGatedVisiblePtyCount: number
|
|
hiddenDeliveryGatedActivePtyCount: number
|
|
deliveryInterestPtyCount: number
|
|
hiddenDeliveryDroppedChars: number
|
|
hiddenDeliveryDroppedChunks: number
|
|
pendingDroppedChars: number
|
|
diagnostics: PtyMainDeliveryDiagnostics
|
|
rendererLifecycleResetCount: number
|
|
lastLifecycleResetClearedChars: number
|
|
rendererPtyDispatcherReady: boolean
|
|
rendererDispatcherReadyForcedCount: number
|
|
}>
|
|
resetRendererDeliveryDebug: () => Promise<void>
|
|
onData: (
|
|
callback: (data: {
|
|
id: string
|
|
data: string
|
|
seq?: number
|
|
rawLength?: number
|
|
transformed?: boolean
|
|
background?: boolean
|
|
droppedOutput?: boolean
|
|
}) => void
|
|
) => () => void
|
|
onReplay: (callback: (data: { id: string; data: string }) => void) => () => void
|
|
/** Out-of-band main→renderer signal that renderer-bound bytes were
|
|
* dropped (hidden-delivery gate / pending cap); the pane restores from
|
|
* the model snapshot. Never delivered in-band on pty:data. */
|
|
onModelRestoreNeeded: (callback: (event: PtyModelRestoreNeededEvent) => void) => () => void
|
|
/** Batched derived side-effect facts for PTYs whose bytes transit local
|
|
* main. */
|
|
onSideEffect: (callback: (batch: TerminalSideEffectBatch) => void) => () => void
|
|
/** Title-only replay snapshot for (re)attach; attention facts never replay. */
|
|
getSideEffectSnapshot: (id: string) => Promise<TerminalSideEffectBatch | null>
|
|
onExit: (
|
|
callback: (data: { id: string; code: number; preserveRendererBinding?: boolean }) => void
|
|
) => () => void
|
|
onSpawned: (callback: (data: { id: string }) => void) => () => void
|
|
onSerializeBufferRequest: (
|
|
callback: (data: {
|
|
requestId: string
|
|
ptyId: string
|
|
opts?: { scrollbackRows?: number; altScreenForcesZeroRows?: boolean }
|
|
}) => void
|
|
) => () => void
|
|
onClearBufferRequest: (callback: (data: { ptyId: string }) => void) => () => void
|
|
sendSerializedBuffer: (
|
|
requestId: string,
|
|
snapshot: {
|
|
data: string
|
|
cols: number
|
|
rows: number
|
|
seq?: number
|
|
lastTitle?: string
|
|
kittyKeyboardFlags?: number
|
|
} | null
|
|
) => void
|
|
declarePendingPaneSerializer: (paneKey: string) => Promise<number>
|
|
settlePaneSerializer: (paneKey: string, gen: number) => Promise<void>
|
|
clearPendingPaneSerializer: (paneKey: string, gen: number) => Promise<void>
|
|
reportRendererSerializerReady?: (ptyId: string) => Promise<void>
|
|
management: PtyManagementApi
|
|
}
|