105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
/** Model and ACP rendering for persistent terminal tool results. */
|
|
|
|
interface RenderedSessionStatusRunning {
|
|
kind: 'running'
|
|
}
|
|
|
|
interface RenderedSessionStatusExited {
|
|
kind: 'exited'
|
|
exitCode: number | null
|
|
signal: string | null
|
|
}
|
|
|
|
type RenderedSessionStatus = RenderedSessionStatusRunning | RenderedSessionStatusExited
|
|
|
|
interface RenderedSessionSnapshot {
|
|
sessionId: string
|
|
name?: string
|
|
type: string
|
|
pid?: number
|
|
status: RenderedSessionStatus
|
|
}
|
|
|
|
interface RenderedSpawnResult extends RenderedSessionSnapshot {
|
|
motd: string
|
|
}
|
|
|
|
interface RenderedSendResult {
|
|
viewport: string
|
|
waitReason: 'stdin_read' | 'inferred_idle' | 'timeout' | 'session_exit'
|
|
sessionStatus: RenderedSessionStatus
|
|
truncated: boolean
|
|
}
|
|
|
|
interface RenderedSendRead {
|
|
delta: string
|
|
truncated: boolean
|
|
}
|
|
|
|
interface RenderedReadResult {
|
|
text: string
|
|
totalLines: number
|
|
lineBegin: number
|
|
lineEnd: number
|
|
truncated: boolean
|
|
}
|
|
|
|
/**
|
|
* Render one created session and its bounded MOTD.
|
|
* @param result - published spawn result.
|
|
* @returns Model-facing session acknowledgement.
|
|
*/
|
|
export function renderSpawn(result: RenderedSpawnResult): string {
|
|
const label = result.name === undefined ? result.sessionId : `${result.sessionId} (${result.name})`
|
|
return `started terminal session ${label} [type: ${result.type}]\n${result.motd || '(no startup output)'}`
|
|
}
|
|
|
|
/**
|
|
* Render one settled interactive send.
|
|
* @param result - settled send outcome.
|
|
* @returns Terminal output plus wait/session markers.
|
|
*/
|
|
export function renderSend(result: RenderedSendResult): string {
|
|
const output = result.viewport || '(no new output)'
|
|
const status = result.sessionStatus.kind === 'running'
|
|
? 'running'
|
|
: `exited code=${result.sessionStatus.exitCode ?? 'null'} signal=${result.sessionStatus.signal ?? 'null'}`
|
|
return `${output}\n[wait: ${result.waitReason}]\n[session: ${status}]${result.truncated ? '\n[output truncated]' : ''}`
|
|
}
|
|
|
|
/**
|
|
* Render one incremental background operation read.
|
|
* @param read - consuming operation delta.
|
|
* @returns Delta plus truncation marker when needed.
|
|
*/
|
|
export function renderSendRead(read: RenderedSendRead): string {
|
|
return `${read.delta}${read.truncated ? `${read.delta.endsWith('\n') || read.delta.length === 0 ? '' : '\n'}[output truncated]` : ''}`
|
|
}
|
|
|
|
/**
|
|
* Render one bounded historical page.
|
|
* @param result - retained scrollback page.
|
|
* @returns Page text plus pagination and truncation markers.
|
|
*/
|
|
export function renderRead(result: RenderedReadResult): string {
|
|
const output = result.text || '(no retained output)'
|
|
return `${output}\n[lines: ${result.lineBegin}-${result.lineEnd} of ${result.totalLines}]${result.truncated ? '\n[output truncated]' : ''}`
|
|
}
|
|
|
|
/**
|
|
* Render owner-visible live sessions.
|
|
* @param sessions - fresh owner-scoped snapshots.
|
|
* @returns One line per session or the empty marker.
|
|
*/
|
|
export function renderList(sessions: readonly RenderedSessionSnapshot[]): string {
|
|
if (sessions.length === 0) return '(no terminal sessions)'
|
|
return sessions.map((session) => {
|
|
const name = session.name === undefined ? '' : ` (${session.name})`
|
|
const pid = session.pid === undefined ? '' : ` pid=${session.pid}`
|
|
const status = session.status.kind === 'running'
|
|
? 'running'
|
|
: `exited code=${session.status.exitCode ?? 'null'} signal=${session.status.signal ?? 'null'}`
|
|
return `${session.sessionId}${name} [${session.type}] ${status}${pid}`
|
|
}).join('\n')
|
|
}
|