mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
Improve Codex App review URL discoverability (#966)
This commit is contained in:
@@ -2,7 +2,12 @@ import { describe, expect, test } from "bun:test";
|
||||
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { handleSaveNotes, handleServerReady, writeServerReadyMetadata } from "./shared-handlers";
|
||||
import {
|
||||
handleSaveNotes,
|
||||
handleServerReady,
|
||||
isCodexDesktopHost,
|
||||
writeServerReadyMetadata,
|
||||
} from "./shared-handlers";
|
||||
|
||||
function saveNotesRequest(body: unknown): Request {
|
||||
return new Request("http://localhost/api/save-notes", {
|
||||
@@ -104,15 +109,30 @@ describe("writeServerReadyMetadata", () => {
|
||||
});
|
||||
|
||||
describe("handleServerReady", () => {
|
||||
test("detects the Codex Desktop app host", () => {
|
||||
expect(isCodexDesktopHost({ __CFBundleIdentifier: "com.openai.codex" })).toBe(true);
|
||||
expect(isCodexDesktopHost({ __CFBundleIdentifier: "com.apple.Terminal" })).toBe(false);
|
||||
});
|
||||
|
||||
test("does not open a browser when host-plugin mode handles it", async () => {
|
||||
let opened = false;
|
||||
const originalBundleIdentifier = process.env.__CFBundleIdentifier;
|
||||
process.env.__CFBundleIdentifier = "com.apple.Terminal";
|
||||
|
||||
await handleServerReady("http://localhost:12345", false, 12345, {
|
||||
skipBrowserOpen: true,
|
||||
openBrowser: async () => {
|
||||
opened = true;
|
||||
},
|
||||
});
|
||||
try {
|
||||
await handleServerReady("http://localhost:12345", false, 12345, {
|
||||
skipBrowserOpen: true,
|
||||
openBrowser: async () => {
|
||||
opened = true;
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
if (originalBundleIdentifier === undefined) {
|
||||
delete process.env.__CFBundleIdentifier;
|
||||
} else {
|
||||
process.env.__CFBundleIdentifier = originalBundleIdentifier;
|
||||
}
|
||||
}
|
||||
|
||||
expect(opened).toBe(false);
|
||||
});
|
||||
@@ -141,10 +161,12 @@ describe("handleServerReady", () => {
|
||||
const writes: string[] = [];
|
||||
let opened = "";
|
||||
const original = process.stderr.write.bind(process.stderr);
|
||||
const originalBundleIdentifier = process.env.__CFBundleIdentifier;
|
||||
(process.stderr as { write: unknown }).write = (chunk: unknown) => {
|
||||
writes.push(String(chunk));
|
||||
return true;
|
||||
};
|
||||
process.env.__CFBundleIdentifier = "com.apple.Terminal";
|
||||
try {
|
||||
await handleServerReady("http://localhost:3000", false, 3000, {
|
||||
openBrowser: async (u: string) => {
|
||||
@@ -154,11 +176,40 @@ describe("handleServerReady", () => {
|
||||
});
|
||||
} finally {
|
||||
(process.stderr as { write: unknown }).write = original;
|
||||
if (originalBundleIdentifier === undefined) {
|
||||
delete process.env.__CFBundleIdentifier;
|
||||
} else {
|
||||
process.env.__CFBundleIdentifier = originalBundleIdentifier;
|
||||
}
|
||||
}
|
||||
expect(writes.join("")).not.toContain("http://localhost:3000");
|
||||
expect(opened).toBe("http://localhost:3000");
|
||||
});
|
||||
|
||||
test("prints the URL for a local Codex Desktop session even when the browser opens", async () => {
|
||||
const writes: string[] = [];
|
||||
const originalWrite = process.stderr.write.bind(process.stderr);
|
||||
const originalBundleIdentifier = process.env.__CFBundleIdentifier;
|
||||
(process.stderr as { write: unknown }).write = (chunk: unknown) => {
|
||||
writes.push(String(chunk));
|
||||
return true;
|
||||
};
|
||||
process.env.__CFBundleIdentifier = "com.openai.codex";
|
||||
try {
|
||||
await handleServerReady("http://localhost:3000", false, 3000, {
|
||||
openBrowser: async () => true,
|
||||
});
|
||||
} finally {
|
||||
(process.stderr as { write: unknown }).write = originalWrite;
|
||||
if (originalBundleIdentifier === undefined) {
|
||||
delete process.env.__CFBundleIdentifier;
|
||||
} else {
|
||||
process.env.__CFBundleIdentifier = originalBundleIdentifier;
|
||||
}
|
||||
}
|
||||
expect(writes.join("")).toContain("http://localhost:3000");
|
||||
});
|
||||
|
||||
// Regression: a local session whose browser can't be opened (headless box,
|
||||
// devcontainer with no display) must still surface the URL, or the agent
|
||||
// hangs at waitForDecision with the user having no link to visit.
|
||||
|
||||
@@ -177,6 +177,10 @@ export function writeServerReadyMetadata(readyFile: string, metadata: ServerRead
|
||||
appendFileSync(readyFile, `${JSON.stringify(metadata)}\n`, "utf8");
|
||||
}
|
||||
|
||||
export function isCodexDesktopHost(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
return env.__CFBundleIdentifier === "com.openai.codex";
|
||||
}
|
||||
|
||||
/** Attempt to open the browser for the session URL. */
|
||||
export async function handleServerReady(
|
||||
url: string,
|
||||
@@ -203,6 +207,8 @@ export async function handleServerReady(
|
||||
process.stderr.write(
|
||||
`\n Plannotator session ready — open on your local machine (forward port ${port} if needed):\n ${url}\n\n`,
|
||||
);
|
||||
} else if (isCodexDesktopHost()) {
|
||||
process.stderr.write(`\n Plannotator session ready:\n ${url}\n\n`);
|
||||
}
|
||||
|
||||
const skipBrowserOpen = options.skipBrowserOpen ?? process.env.PLANNOTATOR_SKIP_BROWSER_OPEN === "1";
|
||||
|
||||
Reference in New Issue
Block a user