mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* [comment audit] Align legacy failure-read counts with cached display * [comment audit] Condense shared provider lifecycle and browser recovery comments [skip ci] * [comment audit] Condense shared generation, path and preview comments [skip ci] * [comment audit] Condense host, file and Git contract rationale [skip ci] * [comment audit] Tighten Git lifecycle and provider contract comments [skip ci] * [comment audit] Clarify shared host authority and launch isolation [skip ci] * [comment audit] simplify local access mobile and native chat contracts [skip ci] * [comment audit] simplify native chat presentation and state contracts [skip ci] * [comment audit] simplify native runtime and provider contracts [skip ci] * [comment audit] simplify migration and orchestration contracts [skip ci] * [comment audit] simplify plugin trust and process capture rationale [skip ci] * [comment audit] simplify terminal delivery and remote compatibility rationale [skip ci] * [comment audit] clarify remote recovery and launch wire rationale [skip ci] * [comment audit] shorten shared RPC compatibility and runtime evidence comments [skip ci] * [comment audit] simplify secure storage shell startup and sidebar rationale [skip ci] * [comment audit] clarify sidebar, skill and SSH invariants [skip ci] * [comment audit] condense structured chat delivery and timing rationale [skip ci] * [comment audit] condense terminal replay and telemetry invariants [skip ci] * [comment audit] clarify launch permission and terminal delivery rationale [skip ci] * [comment audit] clarify workspace ownership and layout contracts [skip ci] * [comment audit] wait for fitted and painted SSH terminal links * [comment audit] clarify layout persistence and session ownership [skip ci] * [comment audit] clarify host routing and workspace lifecycle contracts [skip ci] * [comment audit] clarify startup persistence and app lifetime comments [skip ci] * [comment audit] clarify recovery and activity boundaries [skip ci] * [comment audit] condense activity and artifact invariants [skip ci] * [comment audit] condense automation authority contracts [skip ci] * [comment audit] simplify automation scheduling and history contracts [skip ci] * [comment audit] clarify browser chrome and annotation lifecycles [skip ci] * [comment audit] clarify browser routing and retained guest ownership [skip ci] * [comment audit] clarify browser recovery and document ownership comments [skip ci] * [comment audit] restore hosted runners required by native IME fixtures * [comment audit] shorten preview, palette and dashboard invariants [skip ci] * [comment audit] clarify terminal preview, dashboard and retention comments [skip ci] * [comment audit] clarify diff-note recovery and editor lifecycle comments [skip ci] * [comment audit] shorten rich-text and combined-diff ownership comments [skip ci] * [comment audit] shorten autosave, draft recovery and model ownership comments [skip ci] * [comment audit] shorten save-queue, notebook and Markdown constraints [skip ci] * [comment audit] shorten Monaco, PDF and rich Markdown safeguards [skip ci] * [comment audit] clarify rich Markdown source and selection safeguards [skip ci] * [comment audit] clarify editor loading and emulator stream lifetimes [skip ci] * [comment audit] trim emulator and feature tour narration [skip ci] * [comment audit] clarify floating workspace and GitHub cache ownership [skip ci] * [comment audit] trim provider controls and Linear filter explanations [skip ci] * [comment audit] clarify pairing and chat resume lifetimes [skip ci] * [comment audit] clarify chat delivery and transcript lifetimes [skip ci] * [comment audit] clarify session options and host-owned status [skip ci] * [comment audit] clarify draft durability and live-status precedence [skip ci] * [comment audit] Trim chat send and model ownership explanations [skip ci] * [comment audit] Shorten transcript ownership and send recovery comments [skip ci] * [comment audit] Simplify native chat composer and transcript hook comments [skip ci] * [comment audit] Shorten native chat scroll and structured session explanations [skip ci] * [comment audit] Trim workspace picker and onboarding commentary [skip ci] * [comment audit] Simplify pet rendering, review cache and quick open comments [skip ci] * [comment audit] Trim sidebar and session history explanations [skip ci] * [comment audit] Condense session resume and review checks comments [skip ci] * [comment audit] Shorten checks state and file explorer refresh comments [skip ci] * [comment audit] Trim plugin bridge and source-control action rationale [skip ci] * [comment audit] Trim source-control listing and review rationale [skip ci] * [comment audit] Shorten sidebar lifecycle and explorer safeguards [skip ci] * [comment audit] Condense Settings account and appearance rationale [skip ci] * [comment audit] Trim pairing and repository Settings explanations [skip ci] * [comment audit] Condense Settings search SSH and terminal safeguards [skip ci] * [comment audit] Shorten Settings voice and provider ownership comments [skip ci] * [comment audit] Condense Settings draft persistence and host-state rationale [skip ci] * [comment audit] Trim Settings hooks and sidebar setup rationale [skip ci] * [comment audit] Condense sidebar deletion and board-filter safeguards [skip ci] * [comment audit] Condense worktree cards, host ownership and Markdown contracts [skip ci] * [comment audit] Condense sidebar drag, folder and filtering contracts [skip ci] * [comment audit] Condense sidebar parity, sleep and host ownership contracts [skip ci] * [comment audit] Prune focus-read baseline after comment cleanup * [comment audit] Clarify sidebar visibility, board drops and agent evidence [skip ci] * [comment audit] Tighten sidebar listing, drag and reveal contracts [skip ci] * [comment audit] Clarify viewport geometry and skill update safeguards [skip ci] * [comment audit] Tighten skill inventory, usage and host status comments [skip ci] * [comment audit] Clarify usage ownership and resource kill safeguards [skip ci] * [comment audit] Tighten tab selection, rename and search contracts [skip ci] * [comment audit] Tighten tab-strip geometry and drag ownership comments [skip ci] * [comment audit] Tighten Tasks recovery, pagination and mutation comments [skip ci] * [comment audit] Tighten provider loading and terminal recovery comments [skip ci] * [comment audit] Tighten completion, cadence and PTY ownership comments [skip ci] * [comment audit] Clarify terminal restore and parked-pane boundaries [skip ci] * [comment audit] Tighten PTY startup and replay explanations [skip ci] * [comment audit] Clarify PTY identity and delivery ownership [skip ci] * [comment audit] Shorten remote reconnect and input replay rationale [skip ci] * [comment audit] Condense terminal parking clipboard and file link comments [skip ci] * [comment audit] Clarify IME ownership and trim trace history [skip ci] * [comment audit] Shorten pane recovery and parked watcher explanations [skip ci] * [comment audit] Condense snapshot replay and visibility recovery rationale [skip ci] * [comment audit] Shorten terminal parking and keyboard ownership rationale [skip ci] * [comment audit] Trim renderer lifecycle and menu rationale [skip ci] * [comment audit] Condense workspace cleanup ownership and settlement notes [skip ci] * [comment audit] Clarify renderer hook evidence and source ownership [skip ci] * [comment audit] Tighten IPC ownership and reconnect explanations [skip ci] * [comment audit] Trim renderer focus, paste and attention comments [skip ci] * [comment audit] Shorten scroll, locale and agent lifecycle comments [skip ci] * [comment audit] Trim agent launch, resume and ownership commentary [skip ci] * [comment audit] Shorten account, browser and editor comments [skip ci] * [comment audit] Clarify host-mirror waits, previews and input ownership [skip ci] * [comment audit] Condense launch recovery and editor tokenization comments [skip ci] * [comment audit] Condense workspace selection and terminal pane rationale [skip ci] * [comment audit] Condense terminal fitting and rendering recovery comments [skip ci] * [comment audit] Condense terminal input and host routing explanations [skip ci] * [comment audit] Condense ownership and sleeping-session recovery rationale [skip ci] * [comment audit] Condense structured launch and terminal link explanations [skip ci] * [comment audit] Condense terminal ownership and workspace file routing rationale [skip ci] * [comment audit] Condense session persistence and workspace activation rationale [skip ci] * [comment audit] Condense workspace routing and browser ownership rationale [skip ci] * [comment audit] Condense mirror recovery and layout authority rationale [skip ci] * [comment audit] Condense runtime transport and file safety rationale [skip ci] * [comment audit] Condense runtime graph and structured session rationale [skip ci] * [comment audit] Condense browser creation and remote tab recovery rationale [skip ci] * [comment audit] Condense snapshot authority and publisher recovery rationale [skip ci] * [comment audit] Condense frame, startup and provider cache rationale [skip ci] * [comment audit] Condense host twin and agent lifecycle rationale [skip ci] * [comment audit] Condense browser authority and editor cleanup rationale [skip ci] * [comment audit] Condense editor buffer identity and review cache rationale [skip ci] * [comment audit] Condense provider lifetime and repository ownership rationale [skip ci] * [comment audit] Condense reconnect, hydration and terminal retirement rationale [skip ci] * [comment audit] Condense recovery, reconciliation and persistence rationale [skip ci] * [comment audit] Condense cleanup ownership and listing admission rationale [skip ci] * [comment audit] Condense teardown ordering and terminal ownership rationale [skip ci] * [comment audit] Condense recovery ledger and web host-boundary rationale [skip ci] * [comment audit] Condense web reconnect and credential lifecycle rationale [skip ci] * [comment audit] Condense cloud rollout and assignment safety rationale [skip ci] * [comment audit] Condense relay session and database recovery rationale [skip ci] * [comment audit] Condense relay placement and protocol compatibility rationale [skip ci] * [comment audit] Condense build and packaging constraints [skip ci] * [comment audit] Condense CI gates and validation isolation rationale [skip ci] * [comment audit] Condense catalog identity and browser validation rationale [skip ci] * [comment audit] Condense mobile browser and frame-budget rationale [skip ci] * [comment audit] Shorten mobile route and browser test explanations [skip ci] * [comment audit] Condense editor and session seam test rationale [skip ci] * [comment audit] Trim session and terminal closure history [skip ci] * [comment audit] Shorten terminal browser and census explanations [skip ci] * [comment audit] Preserve root-only E2E diagnostic baseline * [comment audit] Condense mobile seam and HTML preview test rationale [skip ci] * [comment audit] Condense preview instrumentation and render harness rationale [skip ci] * [comment audit] Condense bundle contracts and native-build constraints [skip ci] * [comment audit] Shorten native packaging and CI routing rationale [skip ci] * [comment audit] Condense release tooling and benchmark constraints [skip ci] * [comment audit] Condense packaging and platform gate rationale [skip ci] * [comment audit] Shorten mobile route and history rationale [skip ci] * [comment audit] Condense mobile browser and component rationale [skip ci] * [comment audit] Shorten drawer and workspace-form rationale [skip ci] * [comment audit] Trim mobile review and editor-document explanations [skip ci] * [comment audit] Condense editor lifecycle and Markdown explanations [skip ci] * [comment audit] Trim mobile file, diagnostics and dictation commentary [skip ci] * [comment audit] Simplify mobile host-list and workspace-view explanations [skip ci] * [comment audit] Clarify mobile shell lifetime and bridge delivery constraints [skip ci] * [comment audit] Condense bridge stream, native request and audio rationale [skip ci] * [comment audit] Reduce bridge schema and page-client commentary [skip ci] * [comment audit] Tighten mobile page bridge contracts [skip ci] * [comment audit] Clarify mobile cache and session constraints [skip ci] * [comment audit] Condense mobile route and lifecycle rationale [skip ci] * [comment audit] Tighten mobile shell hook timing rationale [skip ci] * [comment audit] Clarify route handoff and notification compatibility [skip ci] * [comment audit] Clarify push registration and dictation cleanup constraints [skip ci] * [comment audit] Condense keyboard geometry and native media ownership rationale [skip ci] * [comment audit] Tighten mobile chat scroll and composer concurrency rationale [skip ci] * [comment audit] Condense mobile reply compatibility and upload ownership rationale [skip ci] * [comment audit] Condense optimistic echo and scroll ownership rationale [skip ci] * [comment audit] Tighten stream replay and queued session ownership rationale [skip ci] * [comment audit] Condense mobile composer and reply-schema constraints [skip ci] * [comment audit] Clarify mobile transcript recovery and session ownership [skip ci] * [comment audit] Clarify mobile queue and source-control compatibility [skip ci] * [comment audit] Condense storage and task launch constraints [skip ci] * [comment audit] Clarify task schemas and terminal document ownership [skip ci] * [comment audit] Tighten terminal input and viewport rationale [skip ci] * [comment audit] Shorten terminal and RPC recorder contracts [skip ci] * [comment audit] Condense recorder engine and connection contracts [skip ci] * [comment audit] Shorten host credential and relay recovery comments [skip ci] * [comment audit] Tighten pairing recovery and bundle transport rationale [skip ci] * [comment audit] Clarify RPC delivery and workspace catalog boundaries [skip ci] * [comment audit] Condense catalog and relay entry contracts [skip ci] * [comment audit] Shorten shutdown and SSH relay delivery contracts [skip ci] * [comment audit] Condense WSL relay and E2E regression rationale [skip ci] * [comment audit] Shorten cross-version harness and renderer fixture explanations [skip ci] * [comment audit] Condense paired-host and E2E lifecycle rationale [skip ci] * [comment audit] Shorten layout oracle and regression explanations [skip ci] * [comment audit] Condense paired recovery and ownership regression contracts [skip ci] * [comment audit] Shorten restart, sidebar and SSH lifecycle contracts [skip ci] * [comment audit] Condense terminal rendering and IME regression rationale [skip ci] * [comment audit] Shorten terminal recovery and benchmark contracts [skip ci] * [comment audit] Condense tooling and Windows lifecycle proof rationale [skip ci] * [comment audit] Condense workflow routing and release rationale [skip ci] * [comment audit] Condense mobile security and installer contracts [skip ci] * [comment audit] Shorten native rationale and stylesheet workarounds [skip ci] * [comment audit] Shorten Windows visibility probe rationale [skip ci] * [comment audit] Condense embedded release and signing rationale [skip ci] * [comment audit] Retain current main test behavior in final reconciliation [skip ci] * [comment audit] Complete final comment review across current source inventory * [comment audit] Handle consolidated audit reports before final CI * [comment audit] Preserve credential storage census detail [skip ci] * [comment audit] Scale broad changed E2E selections with verified timing shards * [comment audit] Align E2E assertions with browser close and settled session metadata * [comment audit] Match existing E2Es to current resource and windowing contracts * [comment audit] Observe the shared server outage notice in reconnect coverage * [comment audit] Make existing renderer probes measure settled tab and PTY work * [comment audit] Align palette E2E selector with task search * [comment audit] Refresh remaining palette search selectors * [comment audit] Keep selector correction within selected audit specs * [comment audit] Await emoji fixture settings inside renderer evaluation * [comment audit] Cancel fixture fit retries between terminal tests --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
295 lines
9.8 KiB
TypeScript
295 lines
9.8 KiB
TypeScript
/** Command Code lacks hooks, so scrape rendered status/composer text. Main emits facts under side-effect authority; renderer retains remote-PTY/kill-switch observation. */
|
|
import {
|
|
cleanCommandCodePromptCandidate,
|
|
isCommandCodeIdlePromptCandidate
|
|
} from './command-code-prompt-text'
|
|
import { stripTerminalControl } from './terminal-control-stripping'
|
|
import { escapeRegex } from './string-utils'
|
|
import { ownRetainedString } from './own-retained-string'
|
|
|
|
type CommandCodeOutputStatusDetector = {
|
|
observe: (data: string) => boolean
|
|
}
|
|
|
|
const RECENT_TEXT_LIMIT = 300
|
|
const STATUS_SCAN_TEXT_LIMIT = 4096
|
|
const COMMAND_CODE_STATUS_GLYPH_RE_SOURCE = '[·○◇☆✧⌘✻⎿]'
|
|
// Command Code 0.27.3 randomizes active LLM labels from this list; partial examples miss real turns.
|
|
const COMMAND_CODE_LLM_STATUS_WORDS = [
|
|
'Thinking',
|
|
'Pondering',
|
|
'Contemplating',
|
|
'Reasoning',
|
|
'Reflecting',
|
|
'Considering',
|
|
'Deliberating',
|
|
'Analyzing',
|
|
'Evaluating',
|
|
'Examining',
|
|
'Inspecting',
|
|
'Investigating',
|
|
'Reviewing',
|
|
'Researching',
|
|
'Studying',
|
|
'Exploring',
|
|
'Mapping',
|
|
'Tracing',
|
|
'Parsing',
|
|
'Processing',
|
|
'Calculating',
|
|
'Computing',
|
|
'Synthesizing',
|
|
'Planning',
|
|
'Outlining',
|
|
'Sketching',
|
|
'Drafting',
|
|
'Composing',
|
|
'Crafting',
|
|
'Building',
|
|
'Assembling',
|
|
'Constructing',
|
|
'Designing',
|
|
'Formulating',
|
|
'Structuring',
|
|
'Organizing',
|
|
'Preparing',
|
|
'Refining',
|
|
'Polishing',
|
|
'Honing',
|
|
'Tuning',
|
|
'Aligning',
|
|
'Connecting',
|
|
'Resolving',
|
|
'Weaving',
|
|
'Threading',
|
|
'Sculpting',
|
|
'Crystallizing',
|
|
'Channeling',
|
|
'Conjuring',
|
|
'Brewing',
|
|
'Working',
|
|
'Cogitating',
|
|
'Ruminating',
|
|
'Hypothesizing',
|
|
'Conceptualizing',
|
|
'Philosophizing',
|
|
'Deciphering',
|
|
'Demystifying',
|
|
'Articulating',
|
|
'Illuminating',
|
|
'Elaborating',
|
|
'Orchestrating',
|
|
'Choreographing',
|
|
'Architecting',
|
|
'Calibrating',
|
|
'Materializing',
|
|
'Visualizing',
|
|
'Harmonizing',
|
|
'Contemplificating',
|
|
'Supercalifragilisting',
|
|
'Bibbidibobbidibooing',
|
|
'Abracadabraing',
|
|
'Hocuspocusing',
|
|
'Razzmatazzing'
|
|
] as const
|
|
|
|
const LLM_STATUS_WORDS_RE_SOURCE = COMMAND_CODE_LLM_STATUS_WORDS.map(escapeRegex).join('|')
|
|
const ACTIVE_LLM_STATUS_RE = new RegExp(
|
|
`(?:^|[\\r\\n])\\s*(?:${COMMAND_CODE_STATUS_GLYPH_RE_SOURCE}\\s*)?(?:${LLM_STATUS_WORDS_RE_SOURCE})\\b(?:…|\\.\\.\\.)`
|
|
)
|
|
const ACTIVE_EXECUTION_STATUS_RE = new RegExp(
|
|
`(?:^|[\\r\\n])\\s*(?:${COMMAND_CODE_STATUS_GLYPH_RE_SOURCE}\\s*)?(?:Executing:\\s+\\S|Running\\s*\\()`
|
|
)
|
|
const IDLE_PROMPT_RE = /(?:^|[\r\n])\s*[\u276F>]\s+Ask your question\.\.\./
|
|
const SEMVER_NUMBER_RE_SOURCE = '(?:0|[1-9]\\d*)'
|
|
const SEMVER_PRERELEASE_IDENTIFIER_RE_SOURCE = '(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)'
|
|
const SEMVER_BUILD_IDENTIFIER_RE_SOURCE = '[0-9A-Za-z-]+'
|
|
const COMMAND_CODE_BANNER_RE = new RegExp(
|
|
`(?:^|[\\r\\n])[ \\t]*#[ \\t]+Command Code[ \\t]+v` +
|
|
`${SEMVER_NUMBER_RE_SOURCE}\\.${SEMVER_NUMBER_RE_SOURCE}\\.${SEMVER_NUMBER_RE_SOURCE}` +
|
|
`(?:-${SEMVER_PRERELEASE_IDENTIFIER_RE_SOURCE}(?:\\.${SEMVER_PRERELEASE_IDENTIFIER_RE_SOURCE})*)?` +
|
|
`(?:\\+${SEMVER_BUILD_IDENTIFIER_RE_SOURCE}(?:\\.${SEMVER_BUILD_IDENTIFIER_RE_SOURCE})*)?` +
|
|
`(?=[ \\t]*[\\r\\n])`
|
|
)
|
|
|
|
function cleanPromptCandidate(value: string): string {
|
|
return cleanCommandCodePromptCandidate(stripTerminalControl(value))
|
|
}
|
|
|
|
function isIdlePromptCandidate(value: string): boolean {
|
|
return isCommandCodeIdlePromptCandidate(value)
|
|
}
|
|
|
|
function isCommandCodeLaunchCommand(command: string | null | undefined): boolean {
|
|
if (!command) {
|
|
return false
|
|
}
|
|
return /(?:^|[\s;&|])(?:command-code|commandcode|cmdc)(?:\s|$)/.test(command)
|
|
}
|
|
|
|
function rawTextMayContainCommandCodeBanner(rawText: string): boolean {
|
|
// All panes observe this; a no-false-negative letter prefilter avoids control stripping on unrelated panes, including ANSI-split words.
|
|
return rawText.includes('C') && rawText.includes('o') && rawText.includes('d')
|
|
}
|
|
|
|
// Control stripping only removes bytes; without raw # the banner regex cannot match.
|
|
const BANNER_REQUIRED_RAW_CHAR = '#'
|
|
|
|
/** Whole carry/chunk prefilter over-admits relative to windows that drop middle content; it cannot turn a match into a miss. */
|
|
function rawChunkMayContainCommandCodeBanner(previousRawText: string, data: string): boolean {
|
|
return (
|
|
data.includes(BANNER_REQUIRED_RAW_CHAR) || previousRawText.includes(BANNER_REQUIRED_RAW_CHAR)
|
|
)
|
|
}
|
|
|
|
function appendRecentRawText(previousRawText: string, data: string): string {
|
|
if (data.length >= RECENT_TEXT_LIMIT) {
|
|
return ownRetainedString(data.slice(-RECENT_TEXT_LIMIT))
|
|
}
|
|
return (previousRawText + data).slice(-RECENT_TEXT_LIMIT)
|
|
}
|
|
|
|
function buildStatusScanRawText(prefix: string, data: string): string {
|
|
const boundedPrefix =
|
|
prefix.length > RECENT_TEXT_LIMIT + 1 ? prefix.slice(-(RECENT_TEXT_LIMIT + 1)) : prefix
|
|
const dataBudget = STATUS_SCAN_TEXT_LIMIT - boundedPrefix.length
|
|
|
|
if (dataBudget <= 0) {
|
|
return boundedPrefix.slice(-STATUS_SCAN_TEXT_LIMIT)
|
|
}
|
|
if (data.length <= dataBudget) {
|
|
return boundedPrefix + data
|
|
}
|
|
|
|
const headBudget = Math.max(0, Math.floor((dataBudget - 1) / 2))
|
|
const tailBudget = Math.max(0, dataBudget - headBudget - 1)
|
|
const head = headBudget > 0 ? data.slice(0, headBudget) : ''
|
|
const tail = tailBudget > 0 ? data.slice(-tailBudget) : ''
|
|
// Megabyte pasted echoes need only boundary/recent context; scan head/tail windows instead of stripping the entire payload.
|
|
return `${boundedPrefix}${head}\n${tail}`
|
|
}
|
|
|
|
function patternOverlapsSanitizedText(
|
|
pattern: RegExp,
|
|
previousTextLength: number,
|
|
combinedText: string
|
|
): boolean {
|
|
const re = new RegExp(pattern.source, 'g')
|
|
for (const match of combinedText.matchAll(re)) {
|
|
const start = match.index ?? 0
|
|
if (start + match[0].length > previousTextLength) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type StatusScanContext = {
|
|
combinedText: string
|
|
previousTextLength: number
|
|
combinedTextWithChunkBoundary: string
|
|
previousTextWithChunkBoundaryLength: number
|
|
}
|
|
|
|
function patternOverlapsStatusContext(pattern: RegExp, context: StatusScanContext): boolean {
|
|
return (
|
|
patternOverlapsSanitizedText(pattern, context.previousTextLength, context.combinedText) ||
|
|
patternOverlapsSanitizedText(
|
|
pattern,
|
|
context.previousTextWithChunkBoundaryLength,
|
|
context.combinedTextWithChunkBoundary
|
|
)
|
|
)
|
|
}
|
|
|
|
function isActiveStatusText(context: StatusScanContext): boolean {
|
|
return (
|
|
patternOverlapsStatusContext(ACTIVE_LLM_STATUS_RE, context) ||
|
|
patternOverlapsStatusContext(ACTIVE_EXECUTION_STATUS_RE, context)
|
|
)
|
|
}
|
|
|
|
function isIdlePromptText(context: StatusScanContext): boolean {
|
|
return patternOverlapsStatusContext(IDLE_PROMPT_RE, context)
|
|
}
|
|
|
|
export function createCommandCodeOutputStatusDetector(args: {
|
|
startupCommand?: string | null
|
|
/** Seed parked watchers after the banner scrolls away, arming an existing turn and retaining its prompt for idle completion. */
|
|
inFlightTurn?: { prompt: string } | null
|
|
onWorking: (prompt: string) => void
|
|
onDone?: (prompt: string) => void
|
|
}): CommandCodeOutputStatusDetector {
|
|
let hasSeenCommandCodeUi =
|
|
isCommandCodeLaunchCommand(args.startupCommand) || Boolean(args.inFlightTurn)
|
|
let lastSubmittedPrompt = args.inFlightTurn?.prompt ?? ''
|
|
let recentRawText = ''
|
|
|
|
return {
|
|
observe(data: string): boolean {
|
|
const previousRawText = recentRawText
|
|
recentRawText = appendRecentRawText(previousRawText, data)
|
|
// Prefilter before window builds so unrelated panes avoid two ~4KB strings per chunk.
|
|
if (!hasSeenCommandCodeUi && !rawChunkMayContainCommandCodeBanner(previousRawText, data)) {
|
|
return false
|
|
}
|
|
const scanRawText = buildStatusScanRawText(previousRawText, data)
|
|
const scanRawTextWithChunkBoundary = previousRawText
|
|
? buildStatusScanRawText(`${previousRawText}\n`, data)
|
|
: scanRawText
|
|
|
|
if (!hasSeenCommandCodeUi) {
|
|
if (!rawTextMayContainCommandCodeBanner(scanRawText)) {
|
|
return false
|
|
}
|
|
const scanText = stripTerminalControl(scanRawText)
|
|
const scanTextWithChunkBoundary = stripTerminalControl(scanRawTextWithChunkBoundary)
|
|
const previousTextWithChunkBoundaryLength = previousRawText
|
|
? stripTerminalControl(`${previousRawText}\n`).length
|
|
: 0
|
|
if (
|
|
!COMMAND_CODE_BANNER_RE.test(scanText) &&
|
|
!COMMAND_CODE_BANNER_RE.test(
|
|
scanTextWithChunkBoundary.slice(previousTextWithChunkBoundaryLength)
|
|
)
|
|
) {
|
|
return false
|
|
}
|
|
hasSeenCommandCodeUi = true
|
|
}
|
|
|
|
const scanText = stripTerminalControl(scanRawText)
|
|
const scanTextWithChunkBoundary = stripTerminalControl(scanRawTextWithChunkBoundary)
|
|
const previousTextLength = previousRawText ? stripTerminalControl(previousRawText).length : 0
|
|
const previousTextWithChunkBoundaryLength = previousRawText
|
|
? stripTerminalControl(`${previousRawText}\n`).length
|
|
: 0
|
|
const statusContext: StatusScanContext = {
|
|
combinedText: scanText,
|
|
previousTextLength,
|
|
combinedTextWithChunkBoundary: scanTextWithChunkBoundary,
|
|
previousTextWithChunkBoundaryLength
|
|
}
|
|
for (const promptMatch of scanText.matchAll(
|
|
/(?:^|[\r\n])\s*[\u276F>]\s+([^\r\n]+)(?=[\r\n])/g
|
|
)) {
|
|
const prompt = cleanPromptCandidate(promptMatch[1] ?? '')
|
|
if (prompt && !isIdlePromptCandidate(prompt)) {
|
|
lastSubmittedPrompt = prompt
|
|
}
|
|
}
|
|
// Without prompt-start hooks, active words detect submitted/no-tool turns that otherwise jump idle to done.
|
|
if (isActiveStatusText(statusContext)) {
|
|
args.onWorking(lastSubmittedPrompt)
|
|
return true
|
|
}
|
|
// No-tool turns may omit Stop; idle composer lets the connection settle-check and complete the current row.
|
|
if (lastSubmittedPrompt && isIdlePromptText(statusContext)) {
|
|
args.onDone?.(lastSubmittedPrompt)
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
}
|