diff --git a/packages/coding-agent/test/acp-agent.test.ts b/packages/coding-agent/test/acp-agent.test.ts index ba558077b..78900cd54 100644 --- a/packages/coding-agent/test/acp-agent.test.ts +++ b/packages/coding-agent/test/acp-agent.test.ts @@ -127,6 +127,10 @@ class FakeAgentSession { customMessageOptions: Array<{ streamingBehavior?: "steer" | "followUp"; queueChipText?: string } | undefined> = []; skillsSettings = { enableSkillCommands: true }; skills: Array<{ name: string; description: string; filePath: string; baseDir: string; source: string }> = []; + refreshSkillsCalls = 0; + async refreshSkills(): Promise { + this.refreshSkillsCalls++; + } planModeState: PlanModeState | undefined; waitForIdleCalls = 0; waitForIdleBlocker: (() => Promise) | undefined; diff --git a/packages/coding-agent/test/acp-disconnect.test.ts b/packages/coding-agent/test/acp-disconnect.test.ts deleted file mode 100644 index 5b14b2a6c..000000000 --- a/packages/coding-agent/test/acp-disconnect.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { describe, expect, it } from "bun:test"; -import { runAcpMode } from "@oh-my-pi/pi-coding-agent/modes/acp/acp-mode"; -import { postmortem } from "@oh-my-pi/pi-utils"; - -const childFlag = "--acp-eof-child"; -const childFlagIndex = process.argv.indexOf(childFlag); -if (childFlagIndex >= 0) { - const marker = process.argv[childFlagIndex + 1]; - if (!marker) throw new Error("Missing cleanup marker path"); - const releaseCleanup = Promise.withResolvers(); - process.once("SIGUSR2", releaseCleanup.resolve); - postmortem.register("acp-eof-test", async () => { - process.stderr.write("cleanup started\n"); - await releaseCleanup.promise; - await Bun.write(marker, "cleanup complete"); - }); - await runAcpMode(async () => { - throw new Error("Session factory is unused by the EOF harness"); - }); -} - -describe("ACP stdio disconnect", () => { - it("awaits postmortem cleanup before exiting on client EOF", async () => { - const marker = `/tmp/omp-acp-eof-${process.pid}-${Date.now()}`; - const child = Bun.spawn([process.execPath, import.meta.path, childFlag, marker], { - stdin: "pipe", - stdout: "pipe", - stderr: "pipe", - }); - try { - child.stdin.end(); - const stderrReader = child.stderr.getReader(); - const started = await stderrReader.read(); - stderrReader.releaseLock(); - expect(new TextDecoder().decode(started.value)).toBe("cleanup started\n"); - child.kill("SIGUSR2"); - const [exitCode, stdout] = await Promise.all([child.exited, new Response(child.stdout).text()]); - expect(stdout).toBe(""); - expect(exitCode).toBe(0); - expect(await Bun.file(marker).text()).toBe("cleanup complete"); - } finally { - try { - child.kill("SIGUSR2"); - } catch { - // Already exited after completing teardown. - } - await child.exited; - await Bun.file(marker) - .delete() - .catch(() => {}); - } - }); -}); diff --git a/packages/coding-agent/test/core/python-executor-streaming.test.ts b/packages/coding-agent/test/core/python-executor-streaming.test.ts index c31695500..e0c2bb55f 100644 --- a/packages/coding-agent/test/core/python-executor-streaming.test.ts +++ b/packages/coding-agent/test/core/python-executor-streaming.test.ts @@ -5,7 +5,9 @@ import { FakeKernel } from "./helpers"; describe("executePythonWithKernel streaming", () => { it("truncates large output and tracks totals", async () => { - const largeOutput = "a".repeat(DEFAULT_MAX_BYTES + 128); + // Many short lines overflow the output window (single over-wide lines are + // column-capped instead and no longer count as window truncation). + const largeOutput = `${"a".repeat(100)}\n`.repeat(Math.ceil((DEFAULT_MAX_BYTES * 4) / 101)); const kernel = new FakeKernel( { status: "ok", cancelled: false, timedOut: false, stdinRequested: false }, options => options?.onChunk?.(largeOutput), diff --git a/packages/coding-agent/test/interactive-mode-plan-review.test.ts b/packages/coding-agent/test/interactive-mode-plan-review.test.ts index 7590f3a58..fb50cdcca 100644 --- a/packages/coding-agent/test/interactive-mode-plan-review.test.ts +++ b/packages/coding-agent/test/interactive-mode-plan-review.test.ts @@ -363,7 +363,9 @@ describe("InteractiveMode plan review rendering", () => { overlay.handleInput("\x1b"); await expect(choice).resolves.toBeUndefined(); - expect(overlayHandle.hide).toHaveBeenCalled(); + // showPlanReview no longer hides on settle: the plan-approval caller fuses + // #hidePlanReview() with the replacement paint to avoid stale-buffer flicker. + expect(overlayHandle.hide).not.toHaveBeenCalled(); }); it("Refine with no annotations silently aborts approval and returns to the editor", async () => { diff --git a/packages/coding-agent/test/modes/controllers/event-controller-idle-compaction.test.ts b/packages/coding-agent/test/modes/controllers/event-controller-idle-compaction.test.ts index bc8b57d68..fa98f82c2 100644 --- a/packages/coding-agent/test/modes/controllers/event-controller-idle-compaction.test.ts +++ b/packages/coding-agent/test/modes/controllers/event-controller-idle-compaction.test.ts @@ -72,6 +72,7 @@ function createContext( streamingMessage: undefined, pendingTools: new Map(), flushPendingModelSwitch: async () => {}, + flushPendingCommandOutput: () => {}, ui: { requestRender: vi.fn() }, chatContainer: { removeChild: vi.fn() }, statusContainer: { clear: vi.fn() }, diff --git a/packages/coding-agent/test/modes/controllers/event-controller-loader-recovery.test.ts b/packages/coding-agent/test/modes/controllers/event-controller-loader-recovery.test.ts index 1db01437f..b9545ad03 100644 --- a/packages/coding-agent/test/modes/controllers/event-controller-loader-recovery.test.ts +++ b/packages/coding-agent/test/modes/controllers/event-controller-loader-recovery.test.ts @@ -52,6 +52,7 @@ function createContext(options: { terminalProgress?: boolean } = {}) { }, statusLine: { invalidate: vi.fn(), markActivityStart: vi.fn(), markActivityEnd: vi.fn() }, updateEditorTopBorder: vi.fn(), + flushPendingCommandOutput: vi.fn(), pendingTools: new Map(), hideThinkingBlock: false, setWorkingMessage: vi.fn(), diff --git a/packages/coding-agent/test/modes/controllers/event-controller-superseded-agent-end.test.ts b/packages/coding-agent/test/modes/controllers/event-controller-superseded-agent-end.test.ts index 0dc1867d4..ef10eabe3 100644 --- a/packages/coding-agent/test/modes/controllers/event-controller-superseded-agent-end.test.ts +++ b/packages/coding-agent/test/modes/controllers/event-controller-superseded-agent-end.test.ts @@ -19,6 +19,7 @@ function createContext() { settings: { get: () => false }, statusLine: { invalidate: vi.fn(), markActivityStart: vi.fn(), markActivityEnd: vi.fn() }, updateEditorTopBorder: vi.fn(), + flushPendingCommandOutput: vi.fn(), pendingTools: new Map(), hideThinkingBlock: false, setWorkingMessage: vi.fn(), diff --git a/packages/coding-agent/test/modes/utils/render-initial-messages.test.ts b/packages/coding-agent/test/modes/utils/render-initial-messages.test.ts index 5f5ceb529..b09ae6dc4 100644 --- a/packages/coding-agent/test/modes/utils/render-initial-messages.test.ts +++ b/packages/coding-agent/test/modes/utils/render-initial-messages.test.ts @@ -150,7 +150,9 @@ function makeRenderCtx(transcript: SessionContext): { ctx: InteractiveModeContex updateEditorTopBorder: vi.fn(), ui: { requestRender: vi.fn(), imageBudget: undefined }, resetTranscript: () => chatContainer.clear(), - settings: { get: () => false }, + // Rebuild paths honor terminal.showImages since the native-image work; + // keep it on so the image-replay contracts below stay meaningful. + settings: { get: (key: string) => key === "terminal.showImages" }, toolOutputExpanded: false, hideThinkingBlock: false, focusedAgentId: undefined,