mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 01:27:35 +00:00
48 lines
2.0 KiB
TypeScript
48 lines
2.0 KiB
TypeScript
// Pure: turn raw composer text into the exact PTY bytes to write. Shared so the
|
|
// desktop and phone composers deliver a message as the same bytes.
|
|
|
|
import {
|
|
sanitizeBracketedPasteText,
|
|
wrapTerminalBracketedPasteText
|
|
} from './terminal-bracketed-paste-text'
|
|
|
|
// Why: carriage return (not \n) is what xterm/agent composers treat as the
|
|
// submit/Enter key over a PTY.
|
|
const SUBMIT = '\r'
|
|
|
|
/** True when the draft spans more than one line (so it needs bracketed-paste
|
|
* wrapping). A trailing newline alone still counts as multi-line. */
|
|
export function isMultilineDraft(text: string): boolean {
|
|
return /[\r\n]/.test(text)
|
|
}
|
|
|
|
/** The carriage-return submit byte, exported so send paths can write Enter as a
|
|
* SEPARATE pty write after the framed body (see buildNativeChatPasteBytes). */
|
|
export const NATIVE_CHAT_SUBMIT = SUBMIT
|
|
|
|
/**
|
|
* Compute the bytes for `text` WITHOUT the trailing submit:
|
|
* - single-line → `text`
|
|
* - multi-line → `\x1b[200~…\x1b[201~` (bracketed-paste wrapped, no submit)
|
|
*
|
|
* Why split the submit out: agent TUIs treat a framed paste that carries a
|
|
* trailing `\r` in the SAME pty write as part of the paste body rather than an
|
|
* Enter, so the text lands in the input box but never sends. Callers write this
|
|
* body first, then write `NATIVE_CHAT_SUBMIT` as a separate, slightly-delayed
|
|
* write (mirrors orca-runtime's writeTerminalAction Enter handling).
|
|
*/
|
|
export function buildNativeChatPasteBytes(text: string): string {
|
|
if (isMultilineDraft(text)) {
|
|
return wrapTerminalBracketedPasteText(text)
|
|
}
|
|
// Why: sanitize even unframed text so pasted scrollback cannot carry a raw
|
|
// terminal escape into the agent composer.
|
|
return sanitizeBracketedPasteText(text)
|
|
}
|
|
|
|
/** Image attachments must look like a real terminal image paste to Claude/Codex
|
|
* TUIs. A plain typed path (or @file mention) is treated as text/file-read. */
|
|
export function buildNativeChatImagePasteBytes(filePath: string): string {
|
|
return wrapTerminalBracketedPasteText(filePath)
|
|
}
|