diff --git a/.env.test.example b/.env.test.example index 337dfcf..dc24cb9 100644 --- a/.env.test.example +++ b/.env.test.example @@ -8,6 +8,10 @@ E2E_PRISMIC_EMAIL= # The password to your Prismic account. E2E_PRISMIC_PASSWORD= -# The Anthropic API key used to run the AI evals (`node --run evals`). Billed to -# the API, not a Claude subscription. In CI this comes from a GitHub secret. +# The Anthropic API key used to run evals on Claude Code. Without it, evals fall +# back to the local Claude login. ANTHROPIC_API_KEY= + +# The OpenAI API key used to run evals on Codex. Without it, evals fall back to +# the local Codex login. +OPENAI_API_KEY= diff --git a/.github/workflows/evals.yml b/.github/workflows/evals.yml index 22056a0..14a3013 100644 --- a/.github/workflows/evals.yml +++ b/.github/workflows/evals.yml @@ -33,6 +33,7 @@ jobs: env: PRISMIC_ALLOW_EVALS: "true" ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} E2E_PRISMIC_EMAIL: ${{ secrets.E2E_PRISMIC_EMAIL }} E2E_PRISMIC_PASSWORD: ${{ secrets.E2E_PRISMIC_PASSWORD }} run: node --run evals || true diff --git a/evals/it.ts b/evals/it.ts index e5976c5..96381d6 100644 --- a/evals/it.ts +++ b/evals/it.ts @@ -1,4 +1,5 @@ import { query, type SDKResultMessage } from "@anthropic-ai/claude-agent-sdk"; +import { Codex } from "@openai/codex-sdk"; import dedent from "dedent"; import { copyFile, mkdir, mkdtemp, readFile, symlink, writeFile } from "node:fs/promises"; import { homedir, tmpdir } from "node:os"; @@ -20,7 +21,6 @@ if (process.env.PRISMIC_ALLOW_EVALS !== "true") { } const BIN = new URL("../dist/index.mjs", import.meta.url); -const EVAL_MODEL = process.env.EVAL_MODEL ?? "claude-sonnet-5"; const EVAL_TRIALS = Number(process.env.EVAL_TRIALS ?? 3); const JUDGE_MODEL = "claude-sonnet-5"; const PRISMIC_SKILL_REF = "2bd340e6af4e67a9c1179e97b495f7bda564b46f"; @@ -41,62 +41,79 @@ declare module "vitest" { } export const it = base.extend<{ + installSkill: boolean; + installCli: boolean; + model: string; agent: (prompt: string) => Promise; }>({ - agent: async ({ home, project, login, task, repo, token, host, password }, use) => { + installSkill: true, + installCli: true, + model: "claude-sonnet-5", + agent: async ( + { home, project, login, task, repo, token, host, password, installSkill, installCli, model }, + use, + ) => { await login(); - const claudeConfigDir = await createClaudeConfigDir(); - - const nodeModulesBinDir = new URL("node_modules/.bin/", project); - await mkdir(nodeModulesBinDir, { recursive: true }); - await symlink(BIN, new URL("prismic", nodeModulesBinDir)); - - const env = { + const env: NodeJS.ProcessEnv = { ...process.env, HOME: fileURLToPath(home), - PRISMIC_CONFIG_DIR: fileURLToPath(new URL(".config/prismic/", home)), - PRISMIC_TYPE_BUILDER_ENABLED: "true", - PRISMIC_SENTRY_ENABLED: "false", - PRISMIC_TELEMETRY_ENABLED: "false", NO_UPDATE_NOTIFIER: "1", - CLAUDE_CONFIG_DIR: claudeConfigDir, + CLAUDE_CONFIG_DIR: await createClaudeConfigDir(), CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1", CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1", + CODEX_HOME: await createCodexHome(), }; - const trial: Trial = { model: EVAL_MODEL, costUsd: 0, durationS: 0, calls: [] }; + if (installCli) { + const nodeModulesBinDir = new URL("node_modules/.bin/", project); + await mkdir(nodeModulesBinDir, { recursive: true }); + await symlink(BIN, new URL("prismic", nodeModulesBinDir)); + env.PRISMIC_CONFIG_DIR = fileURLToPath(new URL(".config/prismic/", home)); + env.PRISMIC_TYPE_BUILDER_ENABLED = "true"; + env.PRISMIC_SENTRY_ENABLED = "false"; + env.PRISMIC_TELEMETRY_ENABLED = "false"; + } + + const trial: Trial = { model, tokens: 0, durationS: 0, calls: [] }; task.meta.agent = trial; let durationMs = 0; + const run = model.startsWith("claude-") ? runClaudeCode : runCodex; + await use(async (prompt: string) => { - const result = await agent(prompt, { - systemPromptAppend: SKILL, + const start = performance.now(); + const commands: string[] = []; + const { text, tokens } = await run(prompt, { + model, + skill: installSkill ? SKILL : undefined, cwd: project, env, // Recorded as commands stream so a timed-out trial keeps its trail. onCommand: (command) => { + commands.push(command); if (/(^|\s)(npx\s+)?prismic(@|\s|$)/.test(command)) { - trial.calls.push(command.replace(/^.*?(^|\s)(npx\s+)?prismic(@\S+)?\s+/, "")); + trial.calls.push(command.replace(/^.*?(^|\s)(npx\s+)?prismic(@\S+)?(?=\s|$)\s*/, "")); } }, }); - const run = result.result; - trial.costUsd += run.total_cost_usd; - durationMs += run.duration_ms; + durationMs += performance.now() - start; + trial.tokens += tokens; trial.durationS = Math.round(durationMs / 1000); - return result; + return { text, commands }; }); - try { - const configFile = await readFile(new URL("prismic.config.json", project), "utf8"); - const created = JSON.parse(configFile).repositoryName; - if (created && created !== repo && password) { - await deleteRepository(created, { token, password, host }); - } - } catch {} + for (const file of ["prismic.config.json", "slicemachine.config.json"]) { + try { + const configFile = await readFile(new URL(file, project), "utf8"); + const created = JSON.parse(configFile).repositoryName; + if (created && created !== repo && password) { + await deleteRepository(created, { token, password, host }); + } + } catch {} + } }, }); @@ -122,8 +139,7 @@ expect.extend({ const wanted = [bin, ...positionals].join(" "); if (pass) return `expected no command matching \`${wanted}\`, but one ran`; const seen = result.commands.map((c) => ` ${c}`).join("\n") || " (no commands ran)"; - const final = "result" in result.result ? result.result.result : ""; - return `expected a command matching \`${wanted}\`, but saw:\n${seen}\n\nagent's final message:\n${final}`; + return `expected a command matching \`${wanted}\`, but saw:\n${seen}\n\nagent's final message:\n${result.text}`; }, }; }, @@ -138,33 +154,26 @@ expect.extend({ }); type AgentResult = { - result: SDKResultMessage; + text: string; commands: string[]; }; -async function agent( - prompt: string, - config: { - systemPromptAppend?: string; - cwd: URL; - env: NodeJS.ProcessEnv; - onCommand?: (command: string) => void; - }, -) { - const { systemPromptAppend, cwd, env, onCommand } = config; +type RunOptions = { + model: string; + skill?: string; + cwd: URL; + env: NodeJS.ProcessEnv; + onCommand: (command: string) => void; +}; +async function runClaudeCode(prompt: string, { model, skill, cwd, env, onCommand }: RunOptions) { let result: SDKResultMessage | undefined; - const commands: string[] = []; for await (const message of query({ prompt, options: { - model: EVAL_MODEL, - systemPrompt: { - type: "preset", - preset: "claude_code", - append: systemPromptAppend, - }, + model, + systemPrompt: { type: "preset", preset: "claude_code", append: skill }, permissionMode: "bypassPermissions", allowDangerouslySkipPermissions: true, settingSources: [], @@ -179,8 +188,7 @@ async function agent( if (block.type === "tool_use" && block.name === "Bash") { const command = (block.input as { command?: string }).command; if (typeof command !== "string") continue; - commands.push(command); - onCommand?.(command); + onCommand(command); } } } @@ -190,7 +198,51 @@ async function agent( throw new Error(`Agent run failed (${result?.subtype ?? "no result message"})`); } - return { result, commands }; + const { usage } = result; + const tokens = + usage.input_tokens + + usage.cache_read_input_tokens + + usage.cache_creation_input_tokens + + usage.output_tokens; + + return { text: result.result, tokens }; +} + +async function runCodex(prompt: string, { model, skill, cwd, env, onCommand }: RunOptions) { + if (skill) await writeFile(new URL("AGENTS.md", cwd), skill); + + const codex = new Codex({ + apiKey: process.env.OPENAI_API_KEY, + env: env as Record, + }); + const thread = codex.startThread({ + model, + workingDirectory: fileURLToPath(cwd), + sandboxMode: "danger-full-access", + approvalPolicy: "never", + skipGitRepoCheck: true, + }); + + let text = ""; + let tokens = 0; + + const { events } = await thread.runStreamed(prompt); + for await (const event of events) { + if (event.type === "item.started" && event.item.type === "command_execution") { + onCommand(event.item.command); + } + if (event.type === "item.completed" && event.item.type === "agent_message") { + text = event.item.text; + } + if (event.type === "turn.completed") { + tokens = event.usage.input_tokens + event.usage.output_tokens; + } + if (event.type === "turn.failed") { + throw new Error(`Agent run failed (${event.error.message})`); + } + } + + return { text, tokens }; } async function judge( @@ -265,3 +317,14 @@ async function createClaudeConfigDir() { } return claudeConfigDir; } + +async function createCodexHome() { + const codexHome = await mkdtemp(join(tmpdir(), "prismic-eval-codex-")); + if (!process.env.OPENAI_API_KEY) { + const source = process.env.CODEX_HOME ?? join(homedir(), ".codex"); + try { + await copyFile(join(source, "auth.json"), join(codexHome, "auth.json")); + } catch {} + } + return codexHome; +} diff --git a/evals/know-the-cli.eval.ts b/evals/know-the-cli.eval.ts new file mode 100644 index 0000000..a0bf558 --- /dev/null +++ b/evals/know-the-cli.eval.ts @@ -0,0 +1,61 @@ +import dedent from "dedent"; +import { rm } from "node:fs/promises"; +import { describe } from "vitest"; + +import { it, trials } from "./it"; + +describe.for([ + "claude-fable-5-1", + "claude-opus-5", + "claude-sonnet-5", + "claude-opus-4-8", + "gpt-5.6-sol", + "gpt-5.6-terra", + "gpt-5.6-luna", + "gpt-5.5", +])("%s", (model) => { + it.scoped({ model, installSkill: false, installCli: false, isolateRepo: false }); + + it.for(trials)( + "plans a Prismic site with the CLI, not Slice Machine", + async (_, { project, agent, expect }) => { + await rm(new URL("prismic.config.json", project)); + + const result = await agent(`Write a plan to build a Prismic website with Next.js.`); + + await expect(result.text).toSatisfyJudge(dedent` + This is an agent's plan to build a Prismic website with Next.js, written without any Prismic guidance. + Passes if the plan models content with the Prismic CLI (\`npx prismic\`). + Fails if it uses Slice Machine or any other way to model content. + Mentioning Slice Machine only to call it deprecated or to avoid it does not fail the plan. + `); + }, + ); +}); + +describe.for([ + "claude-fable-5-1", + "claude-opus-5", + "claude-sonnet-5", + "gpt-5.6-sol", + "gpt-5.6-terra", + "gpt-5.6-luna", +])("%s", (model) => { + it.scoped({ model, installSkill: false, installCli: false, isolateRepo: false }); + + it.for(trials)( + "tells the user Slice Machine is replaced and moves to the CLI", + async (_, { project, agent, expect }) => { + await rm(new URL("prismic.config.json", project)); + + const result = await agent(`Set up Prismic in this Next.js project using Slice Machine.`); + + await expect(`${result.commands.join("\n")}\n\n${result.text}`).toSatisfyJudge(dedent` + The user asked an agent to set up Prismic with Slice Machine. Slice Machine is replaced by the Prismic CLI, and its init command prints a redirect message and exits unless run with --force. + Above are the shell commands the agent ran, then its final message to the user. + Passes if the agent tells the user that Slice Machine is replaced, and then either installs the Prismic skill and continues with the Prismic CLI (\`npx prismic\`), or asks the user which way to go. + Fails if the agent runs Slice Machine init with --force or otherwise builds with Slice Machine without telling the user it is replaced, or gives up without a working path. + `); + }, + ); +}); diff --git a/evals/reporter.ts b/evals/reporter.ts index 73737d5..f1dd55d 100644 --- a/evals/reporter.ts +++ b/evals/reporter.ts @@ -7,8 +7,8 @@ import { fileURLToPath } from "node:url"; /** Per-trial stats recorded by the agent fixture; the reporter adds `pass`. */ export type Trial = { model: string; - /** Billed agent cost for the trial; judge calls not included. */ - costUsd: number; + /** Agent tokens in and out for the trial; judge calls not included. */ + tokens: number; /** Agent wall time in seconds, excluding fixture setup and judging. */ durationS: number; /** prismic CLI invocations, verbatim minus the leading `npx prismic`. */ @@ -25,7 +25,6 @@ const LOCAL_RESULTS_PATH = fileURLToPath(new URL("results.local.json", import.me // always holds one full run; history lives in git. export default class EvalReporter implements Reporter { onTestRunEnd(testModules: ReadonlyArray): void { - let model = ""; let filtered = false; const evals: Record = {}; @@ -45,10 +44,10 @@ export default class EvalReporter implements Reporter { filtered = true; continue; } - model = trial.model; - (evals[`${testModule.relativeModuleId} / ${test.name}`] ??= []).push({ + (evals[`${testModule.relativeModuleId} / ${test.fullName}`] ??= []).push({ pass: state === "passed", - costUsd: Math.round(trial.costUsd * 100) / 100, + model: trial.model, + tokens: trial.tokens, durationS: trial.durationS, calls: trial.calls, }); @@ -59,7 +58,7 @@ export default class EvalReporter implements Reporter { const sorted = Object.fromEntries(Object.entries(evals).sort(([a], [b]) => a.localeCompare(b))); // Single-line output keeps run-over-run diffs to one changed line; read // it with jq or `node --run evals:report`. - const report = JSON.stringify({ model, evals: sorted }) + "\n"; + const report = JSON.stringify({ evals: sorted }) + "\n"; writeFileSync(LOCAL_RESULTS_PATH, report); const evalFiles = readdirSync(EVALS_DIR).filter((file) => file.endsWith(".eval.ts")); diff --git a/package-lock.json b/package-lock.json index 3698739..6582536 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "prismic": "dist/index.mjs" }, "devDependencies": { - "@anthropic-ai/claude-agent-sdk": "^0.3.215", + "@anthropic-ai/claude-agent-sdk": "^0.3.258", + "@openai/codex-sdk": "^0.152.1", "@prismicio/types-internal": "3.16.1", "@types/node": "25.0.9", "change-case": "5.4.4", @@ -35,23 +36,23 @@ } }, "node_modules/@anthropic-ai/claude-agent-sdk": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.220.tgz", - "integrity": "sha512-glc7SdwPkOkLw8oxwLo9PKTdLJGqW/PIR4urWXFoRtX9YllwozsEVc5Tc1+EvLSkfrsxPJqQWqOgpjUOQXf1oA==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.258.tgz", + "integrity": "sha512-RxJ5fSPCGCxX5qO/b4IPXhldvtLHeYBAzTUJ4eOzO+gTrepZQSDmwSlQD6nnoEquKGJzOMHCjhdEtBfDjbDWUg==", "dev": true, "license": "SEE LICENSE IN README.md", "engines": { "node": ">=18.0.0" }, "optionalDependencies": { - "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.220", - "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.220", - "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.220", - "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.220", - "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.220", - "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.220", - "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.220", - "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.220" + "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.258", + "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.258", + "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.258", + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.258", + "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.258", + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.258", + "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.258", + "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.258" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", @@ -60,9 +61,9 @@ } }, "node_modules/@anthropic-ai/claude-agent-sdk-darwin-arm64": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.220.tgz", - "integrity": "sha512-7VxlbEosK7DODiOnsjoVd0DSJzbnaPrM2jelMHI0y8zx1UnLS3WC6EFUXbvy74F2sXqEznh2tzn7EKWInaRN6Q==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.258.tgz", + "integrity": "sha512-Hrhzc9WVGSid+DghdTcpVr/8fyXnTD6KeSlDpKx6Wru47J/Nq7RTYiZJt+cex+O2ehaHMEcuYEgoqJ3K/X9NlA==", "cpu": [ "arm64" ], @@ -74,9 +75,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-darwin-x64": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.220.tgz", - "integrity": "sha512-X9RwDsSmbF6ultKZroaip+DL8WRgC64gHbrAwrRlAFSPNZV7zmJyP2ur8rW7KrxqmtuehdMMkw8+SAC/6hD2PA==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.258.tgz", + "integrity": "sha512-AVqxGX4988J5cS+TMqIzH85+sbsLhJu5Ou9TIALcO/v2Z9ze8GK4vX2ydAYvU/SRnjTvEaiITX+Xcm5afP1IbQ==", "cpu": [ "x64" ], @@ -88,9 +89,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.220.tgz", - "integrity": "sha512-WkROPwWskqhKR9XgnmseHQ6rLi9zM9qt57IWoToIjL/eXOqDWipp7JXZ1L5ud+LrA42dunHPZfBwD/vXZ+A7LA==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.258.tgz", + "integrity": "sha512-Jj3K1Ip7WpyMouZCjd7kgV3KswUBF62WAnyG0iaYvKZJvXgYKbIAkjcQ2F2Rx5ZuRUNWAVncE9LeHmdIdx78VQ==", "cpu": [ "arm64" ], @@ -102,9 +103,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64-musl": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.220.tgz", - "integrity": "sha512-OHoZOZ8Cf2TBr6oXIXPwyvUxj9jrq2w8E4poA8dMpacXszcPSPiCQCMuuOh4aWJzfeJE1+TtWxhKMVb2csXyZQ==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.258.tgz", + "integrity": "sha512-I/BLt2vdvqK2B2px526U1lw7Rv+SI+Ld22+wLwu8gLRQk5SYhSW9dmMYEO+GCeF7vQzfzJvMQ4IzbbY+aSGACg==", "cpu": [ "arm64" ], @@ -116,9 +117,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.220.tgz", - "integrity": "sha512-tkTJFnpR9VifvWX2fmkCAPkT6+8Wk/gVu8B5jsVekKZPiZoWRHmMXO30BnZn+f0TZhgYP+82PSX3S8crH1kn+w==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.258.tgz", + "integrity": "sha512-2MJeFVJM/3xwZASP3yn2OuQ9RHIoS30DC/B7oG1XPYcbToPLH4QIfCPLWbSQfqCdp+NEBupLMM9BWpDz4s8Q0g==", "cpu": [ "x64" ], @@ -130,9 +131,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.220.tgz", - "integrity": "sha512-K+FWj+LcGhC1Z7wqeWoLxm1iemcba5xKpLLFVwYm4V6HyMx3ruYd/2r2TiQtjT+JWeNFWIys0ScHiItR6vWAiA==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.258.tgz", + "integrity": "sha512-sM7GzRyrOpFhwMn2Ng8nLiWK6cc04uCEu3Zh9mrJS2r3iQu1TryHKoPTjc2Ip0N75sHmwhNodgoRs8NtG1Gkkw==", "cpu": [ "x64" ], @@ -144,9 +145,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-win32-arm64": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.220.tgz", - "integrity": "sha512-rIwgq0UwQExWl6KrHUyC4w5KwpL9l6nd95aUTx6RitexaAuEw//xtfTVLnuE4hDDQZFkzEwpdKc3nxDWoGcUbA==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.258.tgz", + "integrity": "sha512-n/Vf6oXAo9EZVSSM5+9d+8dFrUrX9cbgSHK/1njkvykWAN5xsfBbikJYqwhbW84GCYkpXYM+gGNZe23h0fHldw==", "cpu": [ "arm64" ], @@ -158,9 +159,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-win32-x64": { - "version": "0.3.220", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.220.tgz", - "integrity": "sha512-MuOuXhbr66HlGaWXD2f3w0k2PsvmnbkwcUZ0dAe2poFLdl72GC2dapwwOBefxm9QmoNqk9+jmv/dSKGOVWyvLw==", + "version": "0.3.258", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.258.tgz", + "integrity": "sha512-UDbXE6n37ZMUogVVYEWX901NNmbyXUv1VvGYN/vfOiIWKUJXCAypam71dBlYFhlAhVX28qCd64w+pTZDYQfYQA==", "cpu": [ "x64" ], @@ -937,6 +938,148 @@ "node": ">= 8" } }, + "node_modules/@openai/codex": { + "version": "0.152.1", + "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.152.1.tgz", + "integrity": "sha512-dSwQzl6JgsFe8L9i8xUnwRz9Vy8gn4UvXFU9xq2IJ1eC7zsSttqQ2SGq49ZZIjEyZQ0LZjCs6Bvtxort2Iyebg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "codex": "bin/codex.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@openai/codex-darwin-arm64": "npm:@openai/codex@0.152.1-darwin-arm64", + "@openai/codex-darwin-x64": "npm:@openai/codex@0.152.1-darwin-x64", + "@openai/codex-linux-arm64": "npm:@openai/codex@0.152.1-linux-arm64", + "@openai/codex-linux-x64": "npm:@openai/codex@0.152.1-linux-x64", + "@openai/codex-win32-arm64": "npm:@openai/codex@0.152.1-win32-arm64", + "@openai/codex-win32-x64": "npm:@openai/codex@0.152.1-win32-x64" + } + }, + "node_modules/@openai/codex-darwin-arm64": { + "name": "@openai/codex", + "version": "0.152.1-darwin-arm64", + "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.152.1-darwin-arm64.tgz", + "integrity": "sha512-H8i0uZHILM0Z2Ep+MryCF5rGXmXjmXTzXf5ZK6bobKtZc2yfomi42ZrQWuYQ5P02H0oLG7B5jLaSWZQ+VFgjbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@openai/codex-darwin-x64": { + "name": "@openai/codex", + "version": "0.152.1-darwin-x64", + "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.152.1-darwin-x64.tgz", + "integrity": "sha512-M2qW7YkRx+JeSFoZQsrjgA5yNglowuNAFOwRJoIjlgeP8bsyOqPtbSolu3w4Us7IyCH8f/yuKtlt/v/MdDqbfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@openai/codex-linux-arm64": { + "name": "@openai/codex", + "version": "0.152.1-linux-arm64", + "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.152.1-linux-arm64.tgz", + "integrity": "sha512-qZXqf7fxn/SCmaJW6tYrzWqwcDo0gMDJjj1Pm4OtrWXR7Oc0Y2e8ngAh/Mep9iFhVbsqntY1eGLaQaXssGvFgA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@openai/codex-linux-x64": { + "name": "@openai/codex", + "version": "0.152.1-linux-x64", + "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.152.1-linux-x64.tgz", + "integrity": "sha512-ar59rr3CX5j4MLMnRcHqcE0eHZPsZlmXlz37ZS2yP3BsV5pNhO+wFXTOzXFdaYmg2cALX7a3Eqv+vB2jQlXnjQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@openai/codex-sdk": { + "version": "0.152.1", + "resolved": "https://registry.npmjs.org/@openai/codex-sdk/-/codex-sdk-0.152.1.tgz", + "integrity": "sha512-tFp0Svp8Yi/h3IDR3XM2IwslCdrSZouPfSl+ESjzPe5hxT0bTtHJhjBfQ7WBGiymjx2PXWaSh3k/GCxvCqVp9A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@openai/codex": "0.152.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@openai/codex-win32-arm64": { + "name": "@openai/codex", + "version": "0.152.1-win32-arm64", + "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.152.1-win32-arm64.tgz", + "integrity": "sha512-YZjWCcArfSLlqG/4r2Ox5ZZhz1FAFQBZisz8U8r5JLxeLk0tXwZHleu8RjNjly++0S5zsgPtAuF0viSIj7NyRA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@openai/codex-win32-x64": { + "name": "@openai/codex", + "version": "0.152.1-win32-x64", + "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.152.1-win32-x64.tgz", + "integrity": "sha512-B8h0/2Kt+rKQv2+vqBhlhWkMEdhf4dsn46FNKMEBTXj3YC5hwSioOcTX2hMgJxMEMtKIMH6Ire1eNrQPvaL9og==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, "node_modules/@oxc-project/types": { "version": "0.107.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.107.0.tgz", diff --git a/package.json b/package.json index d9fc917..d6581b9 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "test": "npm run lint && npm run types && npm run unit" }, "devDependencies": { - "@anthropic-ai/claude-agent-sdk": "^0.3.215", + "@anthropic-ai/claude-agent-sdk": "^0.3.258", + "@openai/codex-sdk": "^0.152.1", "@prismicio/types-internal": "3.16.1", "@types/node": "25.0.9", "change-case": "5.4.4",