diff --git a/packages/coding-agent/test/bash-executor.test.ts b/packages/coding-agent/test/bash-executor.test.ts index 33e7b75ff..bc9ce9c61 100644 --- a/packages/coding-agent/test/bash-executor.test.ts +++ b/packages/coding-agent/test/bash-executor.test.ts @@ -438,6 +438,13 @@ exit 64 env: { PATH: Bun.env.PATH ?? "", HOME: shellDir, + // The command runs through an interactive login zsh, which loads the + // system `/etc/zshrc`. On macOS that pulls in + // `/etc/zshrc_Apple_Terminal`, and under Apple Terminal it appends + // "Saving session..." lines to the captured output on exit. `HOME` + // does not isolate a system-level file; this is the opt-out Apple + // documents in that script. + SHELL_SESSIONS_DISABLE: "1", }, prefix: undefined, }); diff --git a/packages/coding-agent/test/modes/components/status-line/component.test.ts b/packages/coding-agent/test/modes/components/status-line/component.test.ts index a2f3392f9..3bdb4c832 100644 --- a/packages/coding-agent/test/modes/components/status-line/component.test.ts +++ b/packages/coding-agent/test/modes/components/status-line/component.test.ts @@ -4,6 +4,14 @@ import { StatusLineComponent } from "../../../../src/modes/components/status-lin import { getThemeByName, setThemeInstance } from "../../../../src/modes/theme/theme"; import type { AgentSession } from "../../../../src/session/agent-session"; +// The cost assertions below care about how the two costs are rendered, not about +// terminal width. The status line also shows the cwd and git branch, so a long +// checkout path or branch name eats the budget and pushes the cost segment out +// at a realistic 120 columns. Render these two cases wide enough that the +// segment always fits, and let the width-sensitive behavior stay covered by the +// truncation tests that target it directly. +const WIDE_ENOUGH_FOR_COST_SEGMENT = 400; + function makeSessionWithLastMessage( lastMessage: unknown, prewalkArmed: boolean = false, @@ -102,7 +110,7 @@ describe("StatusLineComponent", () => { }) as unknown as AgentSession, ); - const stripped = statusLine.getTopBorder(120).content.replace(/\x1b\[[0-9;]*m/g, ""); + const stripped = statusLine.getTopBorder(WIDE_ENOUGH_FOR_COST_SEGMENT).content.replace(/\x1b\[[0-9;]*m/g, ""); expect(stripped).toContain("$2.67 (sub) + $0.41 (adv)"); }); @@ -114,7 +122,7 @@ describe("StatusLineComponent", () => { }) as unknown as AgentSession, ); - const stripped = statusLine.getTopBorder(120).content.replace(/\x1b\[[0-9;]*m/g, ""); + const stripped = statusLine.getTopBorder(WIDE_ENOUGH_FOR_COST_SEGMENT).content.replace(/\x1b\[[0-9;]*m/g, ""); expect(stripped).toContain("$2.67 (sub)"); expect(stripped).not.toContain("(adv)"); }); diff --git a/packages/coding-agent/test/status-line-path.test.ts b/packages/coding-agent/test/status-line-path.test.ts index a238b606e..2660b4c1f 100644 --- a/packages/coding-agent/test/status-line-path.test.ts +++ b/packages/coding-agent/test/status-line-path.test.ts @@ -5,9 +5,17 @@ import * as path from "node:path"; import type { SegmentContext } from "@oh-my-pi/pi-coding-agent/modes/components/status-line/segments"; import { renderSegment } from "@oh-my-pi/pi-coding-agent/modes/components/status-line/segments"; import { initTheme, theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme"; -import { getProjectDir, removeSyncWithRetries, setProjectDir } from "@oh-my-pi/pi-utils"; +import { getProjectDir, pathIsWithin, removeSyncWithRetries, setProjectDir } from "@oh-my-pi/pi-utils"; const originalProjectDir = getProjectDir(); +const SCRATCH_ROOT_PREFIXES: readonly string[] = [ + os.tmpdir(), + path.join(os.homedir(), "tmp"), + "/tmp", + "/var/tmp", + "/private/tmp", + "/private/var/tmp", +]; beforeAll(async () => { await initTheme(); }); @@ -78,6 +86,17 @@ function expectContentToContainPath(content: string, expected: string): void { expect(content).toContain(expected); } +// `createFakeHome` needs a directory outside every scratch root, and the only +// location it can rely on is the checkout itself. `SCRATCH_ROOTS` in +// `status-line/segments.ts` is a module-load constant covering `/tmp`, +// `/var/tmp` and their `/private` twins, so a checkout inside one of them — +// a CI scratch workspace, or a clone under `/tmp` — makes the fake home look +// like scratch and renders the scratch icon instead of the folder icon. The +// constant is frozen at import time and `os.tmpdir()` is already mocked +// elsewhere in this file, so there is no seam to redirect it; the two tests +// that need a non-scratch home skip instead of asserting the wrong icon. +const CHECKOUT_IS_SCRATCH = SCRATCH_ROOT_PREFIXES.some(root => pathIsWithin(root, originalProjectDir)); + function createFakeHome(): { home: string; projectsRoot: string } { const homeRoot = path.join(originalProjectDir, ".wt"); fs.mkdirSync(homeRoot, { recursive: true }); @@ -89,7 +108,7 @@ function createFakeHome(): { home: string; projectsRoot: string } { } describe("status line path segment", () => { - it("strips the Projects root for symlink-equivalent aliases", () => { + it.skipIf(CHECKOUT_IS_SCRATCH)("strips the Projects root for symlink-equivalent aliases", () => { if (process.platform === "win32") return; const { home, projectsRoot } = createFakeHome(); @@ -174,7 +193,7 @@ describe("status line path segment", () => { } }); - it("keeps the folder icon for paths outside any scratch root", () => { + it.skipIf(CHECKOUT_IS_SCRATCH)("keeps the folder icon for paths outside any scratch root", () => { const { home, projectsRoot } = createFakeHome(); const realProjectDir = fs.mkdtempSync(path.join(projectsRoot, "omp-status-line-real-")); try {