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.

Use the companion script from the installed Gemini extension at `${HOME}/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs`.
Execute the following command using the `run_shell_command` tool:
`node "${HOME}/.gemini/extensions/codex/plugins/codex/scripts/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.

Use the companion script from the installed Gemini extension at `${HOME}/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs`.
Execute the following command using the `run_shell_command` tool:
`node "${HOME}/.gemini/extensions/codex/plugins/codex/scripts/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.

Use the companion script from the installed Gemini extension at `${HOME}/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs`.

First, check if there is a resumable rescue candidate from the current session by running:
`node "${HOME}/.gemini/extensions/codex/plugins/codex/scripts/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_shell_command` tool:
`node "${HOME}/.gemini/extensions/codex/plugins/codex/scripts/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.

Use the companion script from the installed Gemini extension at `${HOME}/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs`.
Execute the following command using the `run_shell_command` tool:
`node "${HOME}/.gemini/extensions/codex/plugins/codex/scripts/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.

Use the companion script from the installed Gemini extension at `${HOME}/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs`.
Execute the following command using the `run_shell_command` tool:
`node "${HOME}/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs" review {{args}}`
Comment on lines +6 to +8
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 Point Gemini commands to the expected extension-root script

All new Gemini command TOMLs hardcode ~/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs, but this commit’s own command contract/test expects the companion at ~/.gemini/extensions/codex/scripts/codex-companion.mjs (tests/commands.test.mjs, “Gemini TOML commands…”). As shipped, /codex:* command handlers can resolve a non-existent path and fail with ENOENT before invoking Codex, and CI already catches this mismatch.

Useful? React with 👍 / 👎.


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.

Use the companion script from the installed Gemini extension at `${HOME}/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs`.
Execute the following command using the `run_shell_command` tool:
`node "${HOME}/.gemini/extensions/codex/plugins/codex/scripts/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.

Use the companion script from the installed Gemini extension at `${HOME}/.gemini/extensions/codex/plugins/codex/scripts/codex-companion.mjs`.
Execute the following command using the `run_shell_command` tool:
`node "${HOME}/.gemini/extensions/codex/plugins/codex/scripts/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",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add Gemini manifest to version bump targets

The new gemini-extension.json introduces its own version field, but the release automation still only bumps/checks package.json, package-lock.json, plugins/codex/.claude-plugin/plugin.json, and .claude-plugin/marketplace.json (see scripts/bump-version.mjs TARGETS). After the next release bump, this file will remain stale, so Gemini installs can report outdated extension metadata even when the rest of the plugin is versioned correctly.

Useful? React with 👍 / 👎.

"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
15 changes: 13 additions & 2 deletions plugins/codex/scripts/lib/state.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import path from "node:path";
import { resolveWorkspaceRoot } from "./workspace.mjs";

const STATE_VERSION = 1;
const PLUGIN_DATA_ENV = "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 Expand Up @@ -38,7 +37,19 @@ export function resolveStateDir(cwd) {
const slugSource = path.basename(workspaceRoot) || "workspace";
const slug = slugSource.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "workspace";
const hash = createHash("sha256").update(canonicalWorkspaceRoot).digest("hex").slice(0, 16);
const pluginDataDir = process.env[PLUGIN_DATA_ENV];

let pluginDataEnv = "CLAUDE_PLUGIN_DATA";
if (process.env.ANTIGRAVITY_TRAJECTORY_ID) {
pluginDataEnv = "ANTIGRAVITY_PLUGIN_DATA";
} else if (process.env.GEMINI_TRAJECTORY_ID) {
pluginDataEnv = "GEMINI_PLUGIN_DATA";
} else if (process.env.CLAUDE_SESSION_ID || process.env.CODEX_COMPANION_SESSION_ID) {
pluginDataEnv = "CLAUDE_PLUGIN_DATA";
} else {
pluginDataEnv = process.env.CLAUDE_PLUGIN_DATA ? "CLAUDE_PLUGIN_DATA" : (process.env.GEMINI_PLUGIN_DATA ? "GEMINI_PLUGIN_DATA" : "ANTIGRAVITY_PLUGIN_DATA");
}

const pluginDataDir = process.env[pluginDataEnv];
const stateRoot = pluginDataDir ? path.join(pluginDataDir, "state") : FALLBACK_STATE_ROOT_DIR;
return path.join(stateRoot, `${slug}-${hash}`);
}
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.CLAUDE_PLUGIN_DATA ? "CLAUDE_PLUGIN_DATA" : (process.env.GEMINI_PLUGIN_DATA ? "GEMINI_PLUGIN_DATA" : "ANTIGRAVITY_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.CLAUDE_ENV_FILE || process.env.GEMINI_ENV_FILE || process.env.ANTIGRAVITY_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.CLAUDE_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.ANTIGRAVITY_PROJECT_DIR || process.cwd();
const workspaceRoot = resolveWorkspaceRoot(cwd);
const config = getConfig(workspaceRoot);

Expand Down
12 changes: 12 additions & 0 deletions scripts/bump-version.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ const TARGETS = [
}
]
},
{
file: "gemini-extension.json",
values: [
{
label: "version",
get: (json) => json.version,
set: (json, version) => {
json.version = version;
}
}
]
},
{
file: ".claude-plugin/marketplace.json",
values: [
Expand Down
5 changes: 5 additions & 0 deletions tests/bump-version.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ function makeVersionFixture() {
name: "codex",
version: "1.0.2"
});
writeJson(path.join(root, "gemini-extension.json"), {
name: "codex",
version: "1.0.2"
});
writeJson(path.join(root, ".claude-plugin", "marketplace.json"), {
metadata: {
version: "1.0.2"
Expand Down Expand Up @@ -67,6 +71,7 @@ test("bump-version updates every release manifest", () => {
assert.equal(readJson(path.join(root, "package-lock.json")).version, "1.2.3");
assert.equal(readJson(path.join(root, "package-lock.json")).packages[""].version, "1.2.3");
assert.equal(readJson(path.join(root, "plugins", "codex", ".claude-plugin", "plugin.json")).version, "1.2.3");
assert.equal(readJson(path.join(root, "gemini-extension.json")).version, "1.2.3");
assert.equal(readJson(path.join(root, ".claude-plugin", "marketplace.json")).metadata.version, "1.2.3");
assert.equal(readJson(path.join(root, ".claude-plugin", "marketplace.json")).plugins[0].version, "1.2.3");
});
Expand Down
28 changes: 28 additions & 0 deletions tests/commands.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,34 @@ function read(relativePath) {
return fs.readFileSync(path.join(PLUGIN_ROOT, relativePath), "utf8");
}

function readRoot(relativePath) {
return fs.readFileSync(path.join(ROOT, relativePath), "utf8");
}

test("Gemini TOML commands use the installed extension companion with the Gemini shell tool", () => {
const commandDir = path.join(ROOT, "commands");
const commandFiles = fs.readdirSync(commandDir).filter((file) => file.endsWith(".toml")).sort();

assert.deepEqual(commandFiles, [
"adversarial-review.toml",
"cancel.toml",
"rescue.toml",
"result.toml",
"review.toml",
"setup.toml",
"status.toml"
]);

for (const file of commandFiles) {
const source = readRoot(path.join("commands", file));
assert.doesNotMatch(source, /run_command/);
assert.match(source, /plugins\/codex\/scripts/);
assert.doesNotMatch(source, /current workspace/);
assert.match(source, /run_shell_command/);
assert.match(source, /\$\{HOME\}\/\.gemini\/extensions\/codex\/plugins\/codex\/scripts\/codex-companion\.mjs/);
}
});

test("review command uses AskUserQuestion and background Bash while staying review-only", () => {
const source = read("commands/review.md");
assert.match(source, /AskUserQuestion/);
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
Loading