Files
orca/src/main/daemon/daemon-pty-adapter.ts
T
mirror 34fa2cd5ca
Skill update round trip / roundtrip (false, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, latest) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
source snapshot 2026-09-02
2026-09-02 02:03:16 +08:00

123 lines
4.7 KiB
TypeScript

import { DaemonPtyDaemonRecovery } from './daemon-pty-daemon-recovery'
import { supportsMode2031UnsubscribeFact, type DaemonEvent } from './types'
import type { IPtyProvider } from '../providers/types'
export class DaemonPtyAdapter extends DaemonPtyDaemonRecovery implements IPtyProvider {
protected setupEventRouting(): void {
if (this.removeEventListener) {
return
}
this.removeEventListener = this.client.onEvent((raw) => {
const event = raw as DaemonEvent
if (event.type !== 'event') {
return
}
if (event.event === 'data') {
this.markSessionDirty(event.sessionId)
// oxlint-disable-next-line unicorn/no-useless-spread -- copy-safe: listeners may unsubscribe during iteration
for (const listener of [...this.dataListeners]) {
listener({
id: event.sessionId,
data: event.payload.data,
...((event.payload.rawLength ?? event.payload.sequenceChars) === undefined
? {}
: { sequenceChars: event.payload.rawLength ?? event.payload.sequenceChars }),
...(event.payload.transformed ? { transformed: true } : {}),
...(event.payload.seq === undefined ? {} : { seq: event.payload.seq })
})
}
} else if (event.event === 'sessionBackgroundMarker') {
this.emitBackgroundStreamEvent({
id: event.sessionId,
kind: 'backgroundMarker',
background: event.payload.background,
...(event.payload.scanSeedAnsi !== undefined
? { scanSeedAnsi: event.payload.scanSeedAnsi }
: {}),
...(event.payload.mode2031PendingSubscribe
? { mode2031PendingSubscribe: true as const }
: {})
})
} else if (event.event === 'dataGap') {
this.emitBackgroundStreamEvent({
id: event.sessionId,
kind: 'dataGap',
droppedChars: event.payload.droppedChars,
...(event.payload.sequenceChars === undefined
? {}
: { sequenceChars: event.payload.sequenceChars })
})
} else if (event.event === 'transientFact') {
// Why (#9993): a preserved pre-v29 daemon can retain a stale relay tracker. Its
// unretractable subscribe is harmful; an unsubscribe is always safe to forward.
if (
event.payload.kind === '2031-subscribe' &&
!supportsMode2031UnsubscribeFact(this.protocolVersion)
) {
return
}
this.emitBackgroundStreamEvent({
id: event.sessionId,
kind: 'transientFact',
fact: event.payload
})
} else if (event.event === 'exit') {
const currentIncarnationId = this.sessionIncarnations.get(event.sessionId)
const pendingOperations = new Set([
...(this.pendingSpawnOperationsBySessionId.get(event.sessionId) ?? []),
...this.pendingClaimSpawnOperations
])
for (const operation of pendingOperations) {
if (operation.ignoreNextExit) {
operation.ignoreNextExit = false
continue
}
const exits = operation.exitsBySessionId.get(event.sessionId) ?? []
exits.push(
event.payload.incarnationId
? { code: event.payload.code, incarnationId: event.payload.incarnationId }
: { code: event.payload.code }
)
operation.exitsBySessionId.set(event.sessionId, exits)
}
// Keep a raced exit available to the in-flight spawn even when the
// adapter still remembers the predecessor's generation. Only the
// generation currently published by this adapter may clear state or
// notify listeners.
if (
currentIncarnationId !== undefined &&
event.payload.incarnationId !== currentIncarnationId
) {
return
}
this.clearExitedSessionState(
event.sessionId,
event.payload.code,
event.payload.incarnationId
)
// oxlint-disable-next-line unicorn/no-useless-spread -- copy-safe: listeners may unsubscribe during iteration
for (const listener of [...this.exitListeners]) {
listener({
id: event.sessionId,
code: event.payload.code,
...(event.payload.incarnationId ? { incarnationId: event.payload.incarnationId } : {}),
...(event.payload.cause ? { cause: event.payload.cause } : {})
})
}
}
})
}
async closeStartupQueryAuthority(id: string): Promise<number> {
if (!this.supportsStartupIngress) {
return 0
}
const result = await this.client.request<{ appliedSeq: number }>('closeStartupQueryAuthority', {
sessionId: id
})
return result.appliedSeq
}
}