diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json new file mode 100644 index 0000000..29bdd95 --- /dev/null +++ b/.cursor-plugin/marketplace.json @@ -0,0 +1,33 @@ +{ + "name": "openai-codex", + "owner": { + "name": "OpenAI" + }, + "metadata": { + "description": "Codex plugins to use in Cursor for delegation and code review.", + "version": "1.0.1", + "pluginRoot": "./plugins" + }, + "plugins": [ + { + "name": "codex", + "source": "codex", + "description": "Use Codex from Cursor to review code or delegate tasks.", + "version": "1.0.1", + "category": "developer-tools", + "tags": [ + "review", + "ai", + "codex", + "code-quality" + ], + "keywords": [ + "codex", + "openai", + "code-review", + "delegation", + "ai-assistant" + ] + } + ] +} diff --git a/README.md b/README.md index ddeeff4..9c45203 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Codex plugin for Claude Code +# Codex plugin for Claude Code & Cursor -Use Codex from inside Claude Code for code reviews or to delegate tasks to Codex. +Use Codex from inside Claude Code or Cursor for code reviews or to delegate tasks to Codex. -This plugin is for Claude Code users who want an easy way to start using Codex from the workflow +This plugin is for Claude Code and Cursor users who want an easy way to start using Codex from the workflow they already have. @@ -21,6 +21,8 @@ they already have. ## Install +### Claude Code + Add the marketplace in Claude Code: ```bash @@ -39,7 +41,19 @@ Reload plugins: /reload-plugins ``` -Then run: +### Cursor + +Add the plugin in Cursor using the `/add-plugin` command: + +``` +/add-plugin openai/codex-plugin-cc +``` + +Alternatively, browse the [Cursor Marketplace](https://cursor.com/marketplace) and install the Codex plugin from there. + +### Setup + +After installing (in either Claude Code or Cursor), run: ```bash /codex:setup diff --git a/plugins/codex/.cursor-plugin/plugin.json b/plugins/codex/.cursor-plugin/plugin.json new file mode 100644 index 0000000..331978e --- /dev/null +++ b/plugins/codex/.cursor-plugin/plugin.json @@ -0,0 +1,22 @@ +{ + "name": "codex", + "version": "1.0.1", + "description": "Use Codex from Cursor to review code or delegate tasks.", + "author": { + "name": "OpenAI" + }, + "homepage": "https://github.com/openai/codex-plugin-cc", + "repository": "https://github.com/openai/codex-plugin-cc", + "license": "Apache-2.0", + "keywords": [ + "codex", + "openai", + "code-review", + "delegation", + "ai-assistant" + ], + "skills": "./skills/", + "commands": "./commands/", + "agents": "./agents/", + "hooks": "./hooks/cursor-hooks.json" +} diff --git a/plugins/codex/hooks/cursor-hooks.json b/plugins/codex/hooks/cursor-hooks.json new file mode 100644 index 0000000..a1ad0b7 --- /dev/null +++ b/plugins/codex/hooks/cursor-hooks.json @@ -0,0 +1,23 @@ +{ + "version": 1, + "hooks": { + "sessionStart": [ + { + "command": "CLAUDE_PLUGIN_ROOT=\"${CURSOR_PLUGIN_ROOT}\" node \"${CURSOR_PLUGIN_ROOT}/scripts/cursor-session-lifecycle-hook.mjs\" sessionStart", + "timeout": 5 + } + ], + "sessionEnd": [ + { + "command": "CLAUDE_PLUGIN_ROOT=\"${CURSOR_PLUGIN_ROOT}\" node \"${CURSOR_PLUGIN_ROOT}/scripts/session-lifecycle-hook.mjs\" SessionEnd", + "timeout": 5 + } + ], + "stop": [ + { + "command": "CLAUDE_PLUGIN_ROOT=\"${CURSOR_PLUGIN_ROOT}\" node \"${CURSOR_PLUGIN_ROOT}/scripts/stop-review-gate-hook.mjs\"", + "timeout": 900 + } + ] + } +} diff --git a/plugins/codex/scripts/cursor-session-lifecycle-hook.mjs b/plugins/codex/scripts/cursor-session-lifecycle-hook.mjs new file mode 100644 index 0000000..ce1d5a8 --- /dev/null +++ b/plugins/codex/scripts/cursor-session-lifecycle-hook.mjs @@ -0,0 +1,44 @@ +#!/usr/bin/env node + +/** + * Cursor-specific sessionStart hook adapter. + * + * Cursor propagates env vars via the hook's JSON stdout `{ "env": { ... } }` + * rather than Claude Code's CLAUDE_ENV_FILE mechanism. This thin wrapper reads + * the Cursor hook input and emits the env vars the companion runtime needs for + * the rest of the session. + * + * sessionEnd and stop hooks reuse the original scripts directly (see + * cursor-hooks.json). + */ + +import fs from "node:fs"; +import process from "node:process"; + +const SESSION_ID_ENV = "CODEX_COMPANION_SESSION_ID"; + +function readHookInput() { + const raw = fs.readFileSync(0, "utf8").trim(); + if (!raw) { + return {}; + } + return JSON.parse(raw); +} + +function main() { + const input = readHookInput(); + + // Emit env vars that subsequent hooks (sessionEnd, stop) will need. + const env = {}; + + if (input.session_id) { + env[SESSION_ID_ENV] = String(input.session_id); + } + + // Cursor does not provide CLAUDE_PLUGIN_DATA; the companion runtime falls + // back to $TMPDIR/codex-companion automatically (see lib/state.mjs). + + process.stdout.write(JSON.stringify({ env })); +} + +main();