Opencode port - #758
Opencode port#758TheEdoRan wants to merge 8 commits into
Conversation
…ion hooks and app-server broker These pieces are Claude Code specific (Stop/SessionStart hooks, ~/.claude transcripts) or exist only to share one codex app-server across Claude subprocesses. The OpenCode port runs the runtime in-process, so every call spawns a private app-server, which was already the fallback path. Claude-Session: https://claude.ai/code/session_01GNChFVosaQLobNrkMvGs16
…ests Moves plugins/codex/scripts/lib to lib/, the companion CLI to lib/commands.mjs, and commands/agents/skills/prompts/schemas to the root. Removes .claude-plugin manifests and the tsc typecheck that needed the Codex CLI at build time. The app-server client now reports itself as OpenCode and reads its version from package.json. Claude-Session: https://claude.ai/code/session_01GNChFVosaQLobNrkMvGs16
… in-process, cancel via AbortController
Handlers in lib/commands.mjs now take (argv, ctx) and return
{ payload, rendered, exitStatus } so an OpenCode tool can call them
in-process. cli.mjs is a thin printer for local use and the test suite.
Background jobs run as an unawaited promise in the host process instead
of a detached node worker (process.execPath is the opencode binary under
Bun). Cancel aborts the job's own app-server client instead of killing a
process group, which would have hit the OpenCode server itself. Session
scoping is passed explicitly instead of read from an env var, and state
lives under $XDG_DATA_HOME/opencode/codex-plugin (CODEX_PLUGIN_DATA_DIR
overrides it).
Claude-Session: https://claude.ai/code/session_01GNChFVosaQLobNrkMvGs16
…s and the codex-rescue subagent index.mjs registers commands, the subagent and the skills directory from the config hook, exposes the runtime as in-process tools so every OpenCode model can call it, scopes jobs to the root session so a rescue subtask's jobs show up in the parent's /codex-status, and prunes a session's jobs on session.deleted. Command and agent prompts are rewritten around the tools instead of Bash and Claude-only tool names. Claude-Session: https://claude.ai/code/session_01GNChFVosaQLobNrkMvGs16
…am in NOTICE, bump to 1.1.0 Claude-Session: https://claude.ai/code/session_01GNChFVosaQLobNrkMvGs16
…plugin start Background jobs run inside the OpenCode server, so a one-shot opencode run takes them down with it. Running records now carry the host pid and the plugin sweeps stale queued/running jobs whose host is gone when it loads. README documents that background jobs need the TUI or serve. Claude-Session: https://claude.ai/code/session_01GNChFVosaQLobNrkMvGs16
…ted publishing - Replace package-lock.json with pnpm-lock.yaml and pin pnpm 11 via packageManager - Pin Node 24 in .node-version - Add Changesets config and a minor changeset so the first release is 0.1.0 - Replace pull-request-ci.yml with ci.yml (tests plus changeset status on PRs) - Add release.yml: on push to main, test, open the version PR, publish via OIDC - Remove the bump-version script and its test, Changesets owns versioning now - Rename every install reference to @theedoran/codex-plugin-oc - Describe the fork and credit the OpenAI Codex team in README and NOTICE Claude-Session: https://claude.ai/code/session_01GNChFVosaQLobNrkMvGs16
|
Sorry, I didn't mean to open the PR here, I mixed up the URLs. Please ignore this PR. Thanks, and sorry again. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 836a520eef
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| for (const job of jobs) { | ||
| if (job.sessionId === sessionId) { | ||
| activeJobs.get(job.id)?.abort(); | ||
| } | ||
| } | ||
| saveState(workspaceRoot, { jobs: remaining }); |
There was a problem hiding this comment.
Prevent deleted active jobs from being recreated
When a deleted session has an active job, abort() only initiates asynchronous cancellation and saveState() immediately removes the job. The still-running runTrackedJob() catch handler then observes no stored record and calls upsertJob(), recreating the deleted job as a sessionless cancelled entry (and recreating its job file). This leaves stale state after deleting a session; cleanup must wait for the run to unwind or prevent its completion handler from persisting removed jobs.
Useful? React with 👍 / 👎.
| const client = await CodexAppServerClient.connect(cwd); | ||
| const onAbort = () => { | ||
| client.close().catch(() => {}); | ||
| }; | ||
| } | ||
|
|
||
| async function requestExternalAgentSessionImport(client, params) { | ||
| const previousHandler = client.notificationHandler; | ||
| let timeout = null; | ||
| let resolveCompleted; | ||
| let rejectCompleted; | ||
| const completed = new Promise((resolve, reject) => { | ||
| resolveCompleted = resolve; | ||
| rejectCompleted = reject; | ||
| }); | ||
| void completed.catch(() => {}); | ||
|
|
||
| client.setNotificationHandler((message) => { | ||
| if (message.method === EXTERNAL_AGENT_IMPORT_COMPLETED) { | ||
| resolveCompleted(); | ||
| return; | ||
| } | ||
| previousHandler?.(message); | ||
| }); | ||
| timeout = setTimeout(() => { | ||
| rejectCompleted(new Error("Timed out waiting for Codex to finish importing the Claude session.")); | ||
| }, EXTERNAL_AGENT_IMPORT_TIMEOUT_MS); | ||
|
|
||
| signal?.addEventListener("abort", onAbort, { once: true }); |
There was a problem hiding this comment.
Recheck cancellation after app-server startup
If the OpenCode abort signal fires while CodexAppServerClient.connect() is awaiting app-server initialization, no listener has been registered yet. Registering a listener on the already-aborted signal afterward does not invoke it, so an Esc/cancel during a slow startup is ignored and the Codex run proceeds; if initialization hangs, it cannot be interrupted at all. Attach cancellation before awaiting initialization or recheck signal.aborted immediately afterward and close the client.
Useful? React with 👍 / 👎.
No description provided.