diff --git a/packages/opencode/src/cli/cmd/run/footer.ts b/packages/opencode/src/cli/cmd/run/footer.ts index d2bc60169a..b80b85efee 100644 --- a/packages/opencode/src/cli/cmd/run/footer.ts +++ b/packages/opencode/src/cli/cmd/run/footer.ts @@ -232,14 +232,18 @@ export class RunFooter implements FooterApi { }), this.renderer as unknown as Parameters[1], ).catch(() => { - if (!this.destroyed && !this.renderer.isDestroyed) { + if (!this.isGone) { this.close() } }) } public get isClosed(): boolean { - return this.closed || this.destroyed || this.renderer.isDestroyed + return this.closed || this.isGone + } + + private get isGone(): boolean { + return this.destroyed || this.renderer.isDestroyed } public onPrompt(fn: (input: RunPrompt) => void): () => void { @@ -263,7 +267,7 @@ export class RunFooter implements FooterApi { public event(next: FooterEvent): void { if (next.type === "catalog") { - if (this.destroyed || this.renderer.isDestroyed) { + if (this.isGone) { return } @@ -279,7 +283,7 @@ export class RunFooter implements FooterApi { } if (next.type === "stream.subagent") { - if (this.destroyed || this.renderer.isDestroyed) { + if (this.isGone) { return } @@ -294,7 +298,7 @@ export class RunFooter implements FooterApi { } private patch(next: FooterPatch): void { - if (this.destroyed || this.renderer.isDestroyed) { + if (this.isGone) { return } @@ -328,7 +332,7 @@ export class RunFooter implements FooterApi { } private present(view: FooterView): void { - if (this.destroyed || this.renderer.isDestroyed) { + if (this.isGone) { return } @@ -341,7 +345,7 @@ export class RunFooter implements FooterApi { // updates. Actual flush happens on the next microtask, so a burst of events // from one reducer pass becomes a single ordered drain. public append(commit: StreamCommit): void { - if (this.destroyed || this.renderer.isDestroyed) { + if (this.isGone) { return } @@ -372,7 +376,7 @@ export class RunFooter implements FooterApi { } public idle(): Promise { - if (this.destroyed || this.renderer.isDestroyed) { + if (this.isGone) { return Promise.resolve() } @@ -382,7 +386,7 @@ export class RunFooter implements FooterApi { } return this.flushing.then(async () => { - if (this.destroyed || this.renderer.isDestroyed) { + if (this.isGone) { return } @@ -449,7 +453,7 @@ export class RunFooter implements FooterApi { } private syncRows = (value: number): void => { - if (this.destroyed || this.renderer.isDestroyed) { + if (this.isGone) { return } @@ -548,7 +552,7 @@ export class RunFooter implements FooterApi { this.clearInterruptTimer() this.interruptTimeout = setTimeout(() => { this.interruptTimeout = undefined - if (this.destroyed || this.renderer.isDestroyed || this.state().phase !== "running") { + if (this.isGone || this.state().phase !== "running") { return } @@ -569,7 +573,7 @@ export class RunFooter implements FooterApi { this.clearExitTimer() this.exitTimeout = setTimeout(() => { this.exitTimeout = undefined - if (this.destroyed || this.renderer.isDestroyed || this.isClosed) { + if (this.isGone || this.isClosed) { return } @@ -642,7 +646,7 @@ export class RunFooter implements FooterApi { // spacing, and progressive markdown/code settling so direct mode can append // immutable transcript rows without rewriting history. private flush(): void { - if (this.destroyed || this.renderer.isDestroyed || this.queue.length === 0) { + if (this.isGone || this.queue.length === 0) { this.queue.length = 0 return } diff --git a/packages/opencode/src/cli/cmd/run/session-data.ts b/packages/opencode/src/cli/cmd/run/session-data.ts index b2d3e1e3d0..eb17e910db 100644 --- a/packages/opencode/src/cli/cmd/run/session-data.ts +++ b/packages/opencode/src/cli/cmd/run/session-data.ts @@ -248,6 +248,10 @@ function queueFooter(data: SessionData): FooterOutput { } } +function queueOut(data: SessionData, commits: SessionCommit[]): SessionDataOutput { + return out(data, commits, queueFooter(data)) +} + function upsert(list: T[], item: T) { const idx = list.findIndex((entry) => entry.id === item.id) if (idx === -1) { @@ -574,47 +578,44 @@ function replay(data: SessionData, commits: SessionCommit[], messageID: string, } } -function startTool(part: ToolPart): SessionCommit { +function toolCommit( + part: ToolPart, + next: Pick & { toolError?: string }, +): SessionCommit { return { kind: "tool", - text: toolStatus(part), - phase: "start", source: "tool", messageID: part.messageID, partID: part.id, tool: part.tool, part, - toolState: "running", + ...next, } } +function startTool(part: ToolPart): SessionCommit { + return toolCommit(part, { + text: toolStatus(part), + phase: "start", + toolState: "running", + }) +} + function doneTool(part: ToolPart): SessionCommit { - return { - kind: "tool", + return toolCommit(part, { text: "", phase: "final", - source: "tool", - messageID: part.messageID, - partID: part.id, - tool: part.tool, - part, toolState: "completed", - } + }) } function failTool(part: ToolPart, text: string): SessionCommit { - return { - kind: "tool", + return toolCommit(part, { text, phase: "final", - source: "tool", - messageID: part.messageID, - partID: part.id, - tool: part.tool, - part, toolState: "error", toolError: text, - } + }) } // Emits "interrupted" final entries for all in-flight parts. Called when a turn is aborted. @@ -879,7 +880,7 @@ export function reduceSessionData(input: SessionDataInput): SessionDataOutput { } upsert(data.permissions, enrichPermission(data, event.properties)) - return out(data, commits, queueFooter(data)) + return queueOut(data, commits) } if (event.type === "permission.replied") { @@ -891,7 +892,7 @@ export function reduceSessionData(input: SessionDataInput): SessionDataOutput { return out(data, commits) } - return out(data, commits, queueFooter(data)) + return queueOut(data, commits) } if (event.type === "question.asked") { @@ -900,7 +901,7 @@ export function reduceSessionData(input: SessionDataInput): SessionDataOutput { } upsert(data.questions, event.properties) - return out(data, commits, queueFooter(data)) + return queueOut(data, commits) } if (event.type === "question.replied" || event.type === "question.rejected") { @@ -912,7 +913,7 @@ export function reduceSessionData(input: SessionDataInput): SessionDataOutput { return out(data, commits) } - return out(data, commits, queueFooter(data)) + return queueOut(data, commits) } if (event.type === "session.error") {