Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions commands/adversarial-review.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description = "Runs a steerable review that questions the chosen implementation and design"
prompt = """
You are the adversarial-review command handler for the Codex plugin on Antigravity CLI.
Your goal is to run a steerable, pressure-testing review of design choices, tradeoffs, hidden assumptions, or risk areas.

Please find the companion script `codex-companion.mjs` under the `plugins/codex/scripts/` directory in the current workspace.
Execute the following command using the `run_command` tool:
`node "<path to codex-companion.mjs>" adversarial-review {{args}}`

Present the review results exactly as-is to the user.
"""
11 changes: 11 additions & 0 deletions commands/cancel.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description = "Cancel an ongoing background Codex job"
prompt = """
You are the cancel command handler for the Codex plugin on Antigravity CLI.
Your goal is to cancel a running background job.

Please find the companion script `codex-companion.mjs` under the `plugins/codex/scripts/` directory in the current workspace.
Execute the following command using the `run_command` tool:
`node "<path to codex-companion.mjs>" cancel {{args}}`

Present the output exactly as-is to the user.
"""
21 changes: 21 additions & 0 deletions commands/rescue.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
description = "Delegate investigation, an explicit fix request, or follow-up rescue work to the Codex rescue process"
prompt = """
You are the rescue command handler for the Codex plugin on Antigravity CLI.
Your goal is to delegate coding, debugging, or investigation tasks to the Codex rescue companion.

Please find the companion script `codex-companion.mjs` under the `plugins/codex/scripts/` directory in the current workspace.

First, check if there is a resumable rescue candidate from the current session by running:
`node "<path to codex-companion.mjs>" task-resume-candidate --json`

If the result shows a candidate is available, ask the user if they want to:
1. "Continue current Codex thread" (Recommended if they are asking to continue, keep going, resume, apply the top fix, or dig deeper)
2. "Start a new Codex thread" (Recommended otherwise)

Then, run the task using the `run_command` tool:
`node "<path to codex-companion.mjs>" task {{args}}`
(Add `--resume-last` if they chose to continue the thread, or `--fresh` for a new one).

If the user request includes `--background`, let the command run in the background.
Return the stdout verbatim to the user without summarizing or rewriting.
"""
11 changes: 11 additions & 0 deletions commands/result.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description = "Fetch and display the final result of a completed background Codex job"
prompt = """
You are the result command handler for the Codex plugin on Antigravity CLI.
Your goal is to fetch and print the final result of a background job.

Please find the companion script `codex-companion.mjs` under the `plugins/codex/scripts/` directory in the current workspace.
Execute the following command using the `run_command` tool:
`node "<path to codex-companion.mjs>" result {{args}}`

Present the output exactly as-is to the user.
"""
11 changes: 11 additions & 0 deletions commands/review.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description = "Runs a normal Codex review on your current work"
prompt = """
You are the review command handler for the Codex plugin on Antigravity CLI.
Your goal is to run a normal, read-only Codex review on the current uncommitted changes or branch comparison.

Please find the companion script `codex-companion.mjs` under the `plugins/codex/scripts/` directory in the current workspace.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve companion script from extension install path

This prompt tells the model to find plugins/codex/scripts/ under the current workspace, but Gemini extensions are loaded from the extension install directory (e.g. ~/.gemini/extensions/<name>), not from the project root. In a standard gemini extensions install flow, the workspace usually does not contain that path, so /review cannot locate codex-companion.mjs and fails before running Codex.

Useful? React with 👍 / 👎.

Execute the following command using the `run_command` tool:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use Gemini's shell tool name in command prompts

Gemini CLI custom commands expose the shell executor as run_shell_command (per the Gemini shell-tool docs), not run_command; instructing the handler to use a non-existent tool means /review can fail at execution time with an unknown-tool path instead of invoking codex-companion.mjs. This affects normal Gemini extension installs where these TOML prompts are the runtime contract for command execution.

Useful? React with 👍 / 👎.

`node "<path to codex-companion.mjs>" review {{args}}`

Present the review results exactly as-is to the user.
"""
14 changes: 14 additions & 0 deletions commands/setup.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
description = "Check whether the local Codex CLI is ready and optionally toggle the stop-time review gate"
prompt = """
You are the setup command handler for the Codex plugin on Antigravity CLI.
Your goal is to run the setup process.

Please find the companion script `codex-companion.mjs` under the `plugins/codex/scripts/` directory in the current workspace.
Execute the following command using the `run_command` tool:
`node "<path to codex-companion.mjs>" setup --json {{args}}`

After executing the command:
1. Parse the JSON output returned by the command.
2. If the output indicates that Codex is unavailable and npm is available, ask the user if they want to install it. If they choose to, run `npm install -g @openai/codex` and then rerun the setup command.
3. Present the setup results beautifully to the user.
"""
11 changes: 11 additions & 0 deletions commands/status.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description = "Check progress on ongoing or completed background Codex jobs"
prompt = """
You are the status command handler for the Codex plugin on Antigravity CLI.
Your goal is to check the progress or status of background jobs.

Please find the companion script `codex-companion.mjs` under the `plugins/codex/scripts/` directory in the current workspace.
Execute the following command using the `run_command` tool:
`node "<path to codex-companion.mjs>" status {{args}}`

Present the output exactly as-is to the user.
"""
6 changes: 6 additions & 0 deletions gemini-extension.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "codex",
"version": "1.0.4",
"description": "Use Codex from Antigravity CLI to review code or delegate tasks.",
"contextFileName": "GEMINI.md"
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "@openai/codex-plugin-cc",
"name": "@openai/codex-plugin-agy",
"version": "1.0.4",
"private": true,
"type": "module",
"description": "Use Codex from Claude Code to review code or delegate tasks.",
"description": "Use Codex from Antigravity CLI to review code or delegate tasks.",
"license": "Apache-2.0",
"engines": {
"node": ">=18.18.0"
Expand Down
10 changes: 5 additions & 5 deletions plugins/codex/prompts/stop-review-gate.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<task>
Run a stop-gate review of the previous Claude turn.
Only review the work from the previous Claude turn.
Only review it if Claude actually did code changes in that turn.
Run a stop-gate review of the previous Antigravity turn.
Only review the work from the previous Antigravity turn.
Only review it if Antigravity actually did code changes in that turn.
Pure status, setup, or reporting output does not count as reviewable work.
For example, the output of /codex:setup or /codex:status does not count.
Only direct edits made in that specific turn count.
If the previous Claude turn was only a status update, a summary, a setup/login check, a review result, or output from a command that did not itself make direct edits in that turn, return ALLOW immediately and do no further work.
If the previous Antigravity turn was only a status update, a summary, a setup/login check, a review result, or output from a command that did not itself make direct edits in that turn, return ALLOW immediately and do no further work.
Challenge whether that specific work and its design choices should ship.

{{CLAUDE_RESPONSE_BLOCK}}
Expand All @@ -27,7 +27,7 @@ Use BLOCK only if the previous turn made code changes and you found something th

<grounding_rules>
Ground every blocking claim in the repository context or tool outputs you inspected during this run.
Do not treat the previous Claude response as proof that code changes happened; verify that from the repository state before you block.
Do not treat the previous Antigravity response as proof that code changes happened; verify that from the repository state before you block.
Do not block based on older edits from earlier turns when the immediately previous turn did not itself make direct edits.
</grounding_rules>

Expand Down
6 changes: 3 additions & 3 deletions plugins/codex/scripts/codex-companion.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const DEFAULT_STATUS_WAIT_TIMEOUT_MS = 240000;
const DEFAULT_STATUS_POLL_INTERVAL_MS = 2000;
const VALID_REASONING_EFFORTS = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
const MODEL_ALIASES = new Map([["spark", "gpt-5.3-codex-spark"]]);
const STOP_REVIEW_TASK_MARKER = "Run a stop-gate review of the previous Claude turn.";
const STOP_REVIEW_TASK_MARKER = "Run a stop-gate review of the previous Antigravity turn.";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep stop-gate marker aligned with prompt template text

buildTaskRunMetadata now detects stop-gate runs by looking for "Run a stop-gate review of the previous Antigravity turn.", but the shipped prompt template still starts with "Run a stop-gate review of the previous Claude turn." (plugins/codex/prompts/stop-review-gate.md). Because of this mismatch, stop-hook tasks are no longer tagged as Codex Stop Gate Review and are recorded as generic Codex Task, which changes status/reporting behavior and breaks the stop-gate flow expectations.

Useful? React with 👍 / 👎.


function printUsage() {
console.log(
Expand Down Expand Up @@ -289,7 +289,7 @@ function isActiveJobStatus(status) {
}

function getCurrentClaudeSessionId() {
return process.env[SESSION_ID_ENV] ?? null;
return process.env[SESSION_ID_ENV] ?? process.env.ANTIGRAVITY_TRAJECTORY_ID ?? process.env.GEMINI_TRAJECTORY_ID ?? null;
}

function filterJobsForCurrentClaudeSession(jobs) {
Expand Down Expand Up @@ -538,7 +538,7 @@ function buildTaskRunMetadata({ prompt, resumeLast = false }) {
if (!resumeLast && String(prompt ?? "").includes(STOP_REVIEW_TASK_MARKER)) {
return {
title: "Codex Stop Gate Review",
summary: "Stop-gate review of previous Claude turn"
summary: "Stop-gate review of previous Antigravity turn"
};
}

Expand Down
2 changes: 1 addition & 1 deletion plugins/codex/scripts/lib/app-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const BROKER_BUSY_RPC_CODE = -32001;
/** @type {ClientInfo} */
const DEFAULT_CLIENT_INFO = {
title: "Codex Plugin",
name: "Claude Code",
name: "Antigravity CLI",
version: PLUGIN_MANIFEST.version ?? "0.0.0"
};

Expand Down
4 changes: 2 additions & 2 deletions plugins/codex/scripts/lib/codex.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { BROKER_BUSY_RPC_CODE, BROKER_ENDPOINT_ENV, CodexAppServerClient } from
import { loadBrokerSession } from "./broker-lifecycle.mjs";
import { binaryAvailable } from "./process.mjs";

const SERVICE_NAME = "claude_code_codex_plugin";
const SERVICE_NAME = "antigravity_cli_codex_plugin";
const TASK_THREAD_PREFIX = "Codex Companion Task";
const DEFAULT_CONTINUE_PROMPT =
"Continue from the current thread state. Pick the next highest-value step and follow through until the task is resolved.";
Expand Down Expand Up @@ -815,7 +815,7 @@ export function getSessionRuntimeStatus(env = process.env, cwd = process.cwd())
return {
mode: "shared",
label: "shared session",
detail: "This Claude session is configured to reuse one shared Codex runtime.",
detail: "This Antigravity session is configured to reuse one shared Codex runtime.",
endpoint
};
}
Expand Down
3 changes: 2 additions & 1 deletion plugins/codex/scripts/lib/job-control.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export function sortJobsNewestFirst(jobs) {
}

function getCurrentSessionId(options = {}) {
return options.env?.[SESSION_ID_ENV] ?? process.env[SESSION_ID_ENV] ?? null;
const env = options.env ?? process.env;
return env[SESSION_ID_ENV] ?? env.ANTIGRAVITY_TRAJECTORY_ID ?? env.GEMINI_TRAJECTORY_ID ?? null;
}

function filterJobsForCurrentSession(jobs, options = {}) {
Expand Down
2 changes: 1 addition & 1 deletion plugins/codex/scripts/lib/state.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import path from "node:path";
import { resolveWorkspaceRoot } from "./workspace.mjs";

const STATE_VERSION = 1;
const PLUGIN_DATA_ENV = "CLAUDE_PLUGIN_DATA";
const PLUGIN_DATA_ENV = process.env.ANTIGRAVITY_PLUGIN_DATA ? "ANTIGRAVITY_PLUGIN_DATA" : (process.env.GEMINI_PLUGIN_DATA ? "GEMINI_PLUGIN_DATA" : "CLAUDE_PLUGIN_DATA");
const FALLBACK_STATE_ROOT_DIR = path.join(os.tmpdir(), "codex-companion");
const STATE_FILE_NAME = "state.json";
const JOBS_DIR_NAME = "jobs";
Expand Down
2 changes: 1 addition & 1 deletion plugins/codex/scripts/lib/tracked-jobs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function createJobLogFile(workspaceRoot, jobId, title) {

export function createJobRecord(base, options = {}) {
const env = options.env ?? process.env;
const sessionId = env[options.sessionIdEnv ?? SESSION_ID_ENV];
const sessionId = env[options.sessionIdEnv ?? SESSION_ID_ENV] ?? env.ANTIGRAVITY_TRAJECTORY_ID ?? env.GEMINI_TRAJECTORY_ID ?? null;
return {
...base,
createdAt: nowIso(),
Expand Down
7 changes: 4 additions & 3 deletions plugins/codex/scripts/session-lifecycle-hook.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { loadState, resolveStateFile, saveState } from "./lib/state.mjs";
import { resolveWorkspaceRoot } from "./lib/workspace.mjs";

export const SESSION_ID_ENV = "CODEX_COMPANION_SESSION_ID";
const PLUGIN_DATA_ENV = "CLAUDE_PLUGIN_DATA";
const PLUGIN_DATA_ENV = process.env.ANTIGRAVITY_PLUGIN_DATA ? "ANTIGRAVITY_PLUGIN_DATA" : (process.env.GEMINI_PLUGIN_DATA ? "GEMINI_PLUGIN_DATA" : "CLAUDE_PLUGIN_DATA");

function readHookInput() {
const raw = fs.readFileSync(0, "utf8").trim();
Expand All @@ -32,10 +32,11 @@ function shellEscape(value) {
}

function appendEnvVar(name, value) {
if (!process.env.CLAUDE_ENV_FILE || value == null || value === "") {
const envFile = process.env.ANTIGRAVITY_ENV_FILE || process.env.GEMINI_ENV_FILE || process.env.CLAUDE_ENV_FILE;
if (!envFile || value == null || value === "") {
return;
}
fs.appendFileSync(process.env.CLAUDE_ENV_FILE, `export ${name}=${shellEscape(value)}\n`, "utf8");
fs.appendFileSync(envFile, `export ${name}=${shellEscape(value)}\n`, "utf8");
}

function cleanupSessionJobs(cwd, sessionId) {
Expand Down
10 changes: 5 additions & 5 deletions plugins/codex/scripts/stop-review-gate-hook.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { resolveWorkspaceRoot } from "./lib/workspace.mjs";
const STOP_REVIEW_TIMEOUT_MS = 15 * 60 * 1000;
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
const ROOT_DIR = path.resolve(SCRIPT_DIR, "..");
const STOP_REVIEW_TASK_MARKER = "Run a stop-gate review of the previous Claude turn.";
const STOP_REVIEW_TASK_MARKER = "Run a stop-gate review of the previous Antigravity turn.";

function readHookInput() {
const raw = fs.readFileSync(0, "utf8").trim();
Expand Down Expand Up @@ -48,11 +48,11 @@ function filterJobsForCurrentSession(jobs, input = {}) {
function buildStopReviewPrompt(input = {}) {
const lastAssistantMessage = String(input.last_assistant_message ?? "").trim();
const template = loadPromptTemplate(ROOT_DIR, "stop-review-gate");
const claudeResponseBlock = lastAssistantMessage
? ["Previous Claude response:", lastAssistantMessage].join("\n")
const antigravityResponseBlock = lastAssistantMessage
? ["Previous Antigravity response:", lastAssistantMessage].join("\n")
: "";
return interpolateTemplate(template, {
CLAUDE_RESPONSE_BLOCK: claudeResponseBlock
CLAUDE_RESPONSE_BLOCK: antigravityResponseBlock
});
}

Expand Down Expand Up @@ -141,7 +141,7 @@ function runStopReview(cwd, input = {}) {

function main() {
const input = readHookInput();
const cwd = input.cwd || process.env.CLAUDE_PROJECT_DIR || process.cwd();
const cwd = input.cwd || process.env.ANTIGRAVITY_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.CLAUDE_PROJECT_DIR || process.cwd();
const workspaceRoot = resolveWorkspaceRoot(cwd);
const config = getConfig(workspaceRoot);

Expand Down
2 changes: 1 addition & 1 deletion tests/fake-codex-fixture.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ function structuredReviewPayload(prompt) {
}

function taskPayload(prompt, resume) {
if (prompt.includes("<task>") && prompt.includes("Only review the work from the previous Claude turn.")) {
if (prompt.includes("<task>") && prompt.includes("Only review the work from the previous Antigravity turn.")) {
if (BEHAVIOR === "adversarial-clean") {
return "ALLOW: No blocking issues found in the previous turn.";
}
Expand Down
17 changes: 15 additions & 2 deletions tests/runtime.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from "node:path";
import test from "node:test";
import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import { fileURLToPath } from "node:url";
import { fileURLToPath, pathToFileURL } from "node:url";

import { buildEnv, installFakeCodex } from "./fake-codex-fixture.mjs";
import { initGitRepo, makeTempDir, run } from "./helpers.mjs";
Expand Down Expand Up @@ -44,6 +44,18 @@ test("setup reports ready when fake codex is installed and authenticated", () =>
assert.equal(payload.sessionRuntime.mode, "direct");
});

test("app-server module loads from the shipped plugin directory", async () => {
const installRoot = makeTempDir();
const installedPluginRoot = path.join(installRoot, "codex");
fs.cpSync(PLUGIN_ROOT, installedPluginRoot, { recursive: true });

const moduleUrl = pathToFileURL(path.join(installedPluginRoot, "scripts", "lib", "app-server.mjs"));
moduleUrl.search = `?test=${Date.now()}`;
const appServerModule = await import(moduleUrl.href);

assert.equal(typeof appServerModule.CodexAppServerClient?.connect, "function");
});

test("setup is ready without npm when Codex is already installed and authenticated", () => {
const binDir = makeTempDir();
installFakeCodex(binDir);
Expand Down Expand Up @@ -1829,7 +1841,8 @@ test("stop hook runs a stop-time review task and blocks on findings when the rev
const fakeState = JSON.parse(fs.readFileSync(fakeStatePath, "utf8"));
assert.match(fakeState.lastTurnStart.prompt, /<task>/i);
assert.match(fakeState.lastTurnStart.prompt, /<compact_output_contract>/i);
assert.match(fakeState.lastTurnStart.prompt, /Only review the work from the previous Claude turn/i);
assert.match(fakeState.lastTurnStart.prompt, /Only review the work from the previous Antigravity turn/i);
assert.match(fakeState.lastTurnStart.prompt, /Previous Antigravity response:/);
assert.match(fakeState.lastTurnStart.prompt, /I completed the refactor and updated the retry logic\./);

const status = run("node", [SCRIPT, "status"], {
Expand Down
22 changes: 22 additions & 0 deletions tests/tests/broker-endpoint.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import test from "node:test";
import assert from "node:assert/strict";

import { createBrokerEndpoint, parseBrokerEndpoint } from "../plugins/codex/scripts/lib/broker-endpoint.mjs";

test("createBrokerEndpoint uses Unix sockets on non-Windows platforms", () => {
const endpoint = createBrokerEndpoint("/tmp/cxc-12345", "darwin");
assert.equal(endpoint, "unix:/tmp/cxc-12345/broker.sock");
assert.deepEqual(parseBrokerEndpoint(endpoint), {
kind: "unix",
path: "/tmp/cxc-12345/broker.sock"
});
});

test("createBrokerEndpoint uses named pipes on Windows", () => {
const endpoint = createBrokerEndpoint("C:\\\\Temp\\\\cxc-12345", "win32");
assert.equal(endpoint, "pipe:\\\\.\\pipe\\cxc-12345-codex-app-server");
assert.deepEqual(parseBrokerEndpoint(endpoint), {
kind: "pipe",
path: "\\\\.\\pipe\\cxc-12345-codex-app-server"
});
});
Loading