merge: reconcile latest Codex runner target qualification

Preserve the user-approved Codex Linux ARM64 default and keep Claude automatic selection limited to Apple Silicon.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-12 10:50:42 -05:00
commit 5f0b898e9e
25 files changed
+371 -99

No files matched your search

@@ -9,7 +9,7 @@ vi.mock("./environment-config.js", () => ({ resolveEnvironmentDriverConfigForRun
vi.mock("@paperclipai/adapter-utils/ssh", () => ({ runSshCommand: state.ssh }));
import { agentRunnerAvailability, resolveAgentRunnerTargetForCompany, resolveNewAgentRunner, resolveNewAgentRunnerForCompany } from "./agent-runner-selection.js";
const target = { driver: "local", platform: "linux", architecture: "x64" };
const qualifiedTargets = [target, { driver: "local", platform: "darwin", architecture: "arm64" }, { driver: "local", platform: "darwin", architecture: "x64" }];
const qualifiedTargets = [target, { driver: "local", platform: "linux", architecture: "arm64" }, { driver: "local", platform: "darwin", architecture: "arm64" }, { driver: "local", platform: "darwin", architecture: "x64" }];
describe("server-owned Codex runner selection", () => {
beforeEach(() => { state.disabled = []; state.overridden.clear(); state.settings = {}; state.getEnvironment.mockReset(); state.bindings.mockReset().mockResolvedValue([]); state.managedEnvironment.mockReset(); state.ssh.mockReset().mockResolvedValue({ stdout: "Linux\nx86_64\n" }); state.resolveEnvironment.mockReset().mockResolvedValue({ driver: "ssh", config: {} }); });
@@ -34,7 +34,7 @@ describe("server-owned Codex runner selection", () => {
expect(resolveNewAgentRunner({ adapterType: "paperclip_runner", runner: "legacy", adapterConfig: { provider: "codex", codexPermissionMode: "never", lifecycleMode: "per_turn", dangerouslyBypassApprovalsAndSandbox: false } }))
.toEqual({ adapterType: "codex_local", adapterConfig: { dangerouslyBypassApprovalsAndSandbox: false } });
});
it.each([{ platform: "win32", architecture: "x64" }, { platform: "linux", architecture: "arm64" }, { platform: "darwin", architecture: "ia32" }])("keeps unqualified $platform/$architecture targets legacy while preserving explicit native profiles", ({ platform, architecture }) => {
it.each([{ platform: "win32", architecture: "x64" }, { platform: "linux", architecture: "arm" }, { platform: "darwin", architecture: "ia32" }])("keeps unqualified $platform/$architecture targets legacy while preserving explicit native profiles", ({ platform, architecture }) => {
const input = { adapterType: "codex_local", target: { driver: "local", platform, architecture } };
expect(resolveNewAgentRunner(input).adapterType).toBe("codex_local");
expect(() => resolveNewAgentRunner({ ...input, runner: "paperclip" })).toThrow("unavailable");
@@ -80,13 +80,15 @@ describe("server-owned Codex runner selection", () => {
state.ssh.mockResolvedValue({ stdout: "Linux\naarch64\n" });
const result = await resolveNewAgentRunnerForCompany({} as never, "company", { adapterType: "codex_local", defaultEnvironmentId: null });
expect(state.getEnvironment).toHaveBeenCalledWith("default"); expect(state.bindings).toHaveBeenCalledWith("default");
expect(result.adapterType).toBe("codex_local");
expect(result.adapterType).toBe("paperclip_runner");
});
it.each([
["Linux\nx86_64\n", "paperclip", "paperclip_runner"],
["Darwin\narm64\n", "paperclip", "paperclip_runner"],
["Darwin\nx86_64\n", "paperclip", "paperclip_runner"],
["Linux\naarch64\n", "legacy", "codex_local"],
["Linux\naarch64\n", "paperclip", "paperclip_runner"],
["Linux\narm64\n", "paperclip", "paperclip_runner"],
["Linux\narmv7l\n", "legacy", "codex_local"],
])("uses the same selected SSH target for discovery and saving (%s)", async (stdout, expectedRunner, expectedAdapter) => {
state.getEnvironment.mockResolvedValue({ id: "selected", driver: "ssh", status: "active", config: {} });
state.ssh.mockResolvedValue({ stdout });
@@ -122,7 +124,7 @@ describe("Codex creation runner contract", () => {
});
it("qualifies only the Codex daemon targets shipped in public server packages", () => {
for (const { platform, architecture } of qualifiedTargets) expect(paperclipRunnerSupportsPlatform("codex_local", platform, architecture)).toBe(true);
for (const [platform, architecture] of [["darwin", "ia32"], ["linux", "arm64"], ["win32", "x64"], ["win32", "arm64"], ["freebsd", "x64"]]) expect(paperclipRunnerSupportsPlatform("codex_local", platform, architecture)).toBe(false);
for (const [platform, architecture] of [["darwin", "ia32"], ["linux", "arm"], ["win32", "x64"], ["win32", "arm64"], ["freebsd", "x64"]]) expect(paperclipRunnerSupportsPlatform("codex_local", platform, architecture)).toBe(false);
expect(paperclipRunnerSupportsPlatform("claude_local", "darwin", "arm64")).toBe(true);
});
it("keeps auto out of saved update defaults and validates request intent", () => {
@@ -41,8 +41,8 @@ function targetPlatform(platform: string, architecture: string) {
}
describe.skipIf(process.platform === "win32")("local browser subscription login", () => {
it.each([false, true])("uses the selected Codex command with its credential home and ambient HOME/cwd (legacy Linux ARM64: %s)", async (legacy) => {
if (legacy) targetPlatform("linux", "arm64");
it.each([false, true])("uses the selected Codex command with its credential home and ambient HOME/cwd (legacy Linux ARM32: %s)", async (legacy) => {
if (legacy) targetPlatform("linux", "arm");
const home = await fakeCli("codex", [
'[ "$1 $2" = "login --device-auth" ] || exit 11',
'[ "$HOME" = "$CLAUDE_CONFIG_DIR" ] && [ "$HOME" != "$CODEX_HOME" ] && [ "$CODEX_HOME" = "$PAPERCLIP_TEST_LOGIN_CODEX_HOME" ] || exit 12',
@@ -66,7 +66,7 @@ describe.skipIf(process.platform === "win32")("local browser subscription login"
expect(login.code).toBe("ABCD-EFGHJ");
});
it.each([["linux", "x64"], ["darwin", "arm64"], ["darwin", "x64"]] as const)("reports an unavailable Codex CLI on %s/%s without revealing private details", async (platform, architecture) => {
it.each([["linux", "x64"], ["linux", "arm64"], ["darwin", "arm64"], ["darwin", "x64"]] as const)("reports an unavailable Codex CLI on %s/%s without revealing private details", async (platform, architecture) => {
targetPlatform(platform, architecture);
const home = await fakeCli("codex", 'echo invoked > "$CODEX_HOME/unreviewed-cli"');
const failure = new Error("private-installation-path-or-provider-output");
@@ -79,8 +79,8 @@ describe.skipIf(process.platform === "win32")("local browser subscription login"
expect(login.authorizationUrl).toBeUndefined();
});
it("reports a missing Linux ARM64 Codex CLI without revealing the host PATH", async () => {
targetPlatform("linux", "arm64");
it("reports a missing Linux ARM32 Codex CLI without revealing the host PATH", async () => {
targetPlatform("linux", "arm");
const home = await fakeCli("codex", "exit 0");
process.env.PATH = "/usr/bin:/bin";
const login = startLocalBrowserLogin("openai", home);
@@ -5,6 +5,7 @@ import path from "node:path";
import { runSetupTokenLogin } from "@paperclipai/adapter-claude-local/server";
import { runDeviceLogin } from "@paperclipai/adapter-codex-local/server";
import { ensureCommandResolvable, resolveCommandForLogs } from "@paperclipai/adapter-utils/server-utils";
import { paperclipRunnerSupportsPlatform } from "@paperclipai/shared";
import { resolveCodexCommand } from "../vendor/paperclip-runner/index.js";
export type LocalBrowserLoginState = {
@@ -56,10 +57,9 @@ export function startLocalBrowserLogin(provider: "anthropic" | "openai", home: s
async start(_command: string, onData: (chunk: string) => void): Promise<{ exitCode: number | null }> {
let executable = "claude";
if (provider === "openai") {
// Linux ARM64 retains its supported legacy CLI path; it is not a
// qualified native runner target. Other hosts prefer the installed
// dependency, then an existing CLI when the dependency is absent.
const legacyPlatform = process.platform === "linux" && process.arch === "arm64";
// Native targets use the same owned Codex resolution as execution.
// Other platforms retain the legacy CLI lookup.
const legacyPlatform = !paperclipRunnerSupportsPlatform("codex_local", process.platform, process.arch);
try {
if (legacyPlatform) {
await ensureCommandResolvable("codex", home, process.env);