Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cc",
"version": "1.5.3",
"version": "1.5.4",
"description": "Claude Code Plugin for Codex. Delegate code reviews, investigations, tracked tasks, and transcript transfers from inside Codex.",
"author": {
"name": "CBEPX",
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
- run: npm run typecheck
- run: npm run typecheck:tests
- run: npm run test:cross-platform
- run: npm run test:lifecycle-contract

macos-full:
name: Full CI (macos-latest)
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

## [Unreleased]

## v1.5.4

### Added

- Add a read-only `setup --check` preflight with runtime source, plugin version, config path, workspace diagnostics, and explicit pending hook-trust reporting.
- Add the task-specific `--wait-timeout-ms` flag while retaining `--timeout-ms` as a deprecated compatibility alias.

### Changed

- Make review and rescue forwarding poll a yielded shell session to command exit and treat only exit code 0 as success; exit 124 remains retrievable work and other failures keep their original diagnostics.

### Fixed

- Track the detached worker separately from its Claude child so a leader PID exit cannot auto-reap a live worker, publish parent worker metadata through a queued-only CAS, preserve unresolved child handles as `cancel_failed`, and prevent late progress writers from overwriting terminal state.
- Announce failed, cancel-failed, and unknown background outcomes instead of silently surfacing completed jobs only, while marking rendered foreground outcomes viewed through a terminal-only CAS.
- Resolve resume candidates and execution through the same owner-scoped policy, accept completed or failed tasks, ignore foreign active tasks, and pass only a real Claude session ID to `claude --resume`; direct CLI callers must provide the owner session ID, while the rescue skill supplies its routed marker-derived owner.
- Classify Fable model-credit limits and authentication expiry with actionable output instead of generic failures.
- Write setup changes to `config.toml` through the existing atomic, symlink-aware writer.

## v1.5.3

### Fixed
Expand Down
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ It follows the shape of [openai/codex-plugin-cc](https://github.com/openai/codex
Install the fork release from the CBEPX marketplace snapshot:

```bash
codex plugin marketplace add CBEPX/cc-plugin-codex --ref v1.5.3
codex plugin marketplace add CBEPX/cc-plugin-codex --ref v1.5.4
codex plugin add cc@cbepx
```

Expand All @@ -59,8 +59,8 @@ The optional `npx` helper can install this fork release and enable the required
```bash
CC_PLUGIN_CODEX_MARKETPLACE_NAME=cbepx \
CC_PLUGIN_CODEX_MARKETPLACE_SOURCE=CBEPX/cc-plugin-codex \
CC_PLUGIN_CODEX_MARKETPLACE_REF=v1.5.3 \
npx -y https://github.com/CBEPX/cc-plugin-codex/releases/download/v1.5.3/cc-plugin-codex-1.5.3.tgz install
CC_PLUGIN_CODEX_MARKETPLACE_REF=v1.5.4 \
npx -y https://github.com/CBEPX/cc-plugin-codex/releases/download/v1.5.4/cc-plugin-codex-1.5.4.tgz install
```

On Windows, prefer the marketplace path or the `npx` helper. The shell-script helper below is POSIX-only.
Expand Down Expand Up @@ -200,7 +200,8 @@ $cc:rescue --model sonnet --effort medium investigate the flaky test
| `--model <model>` | Claude model (`opus`, `sonnet`, `haiku`, `fable`, or full ID; defaults to `opus`). Aliases are resolved by Claude Code; a full ID pins a version. |
| `--effort <level>` | Reasoning effort: `low`, `medium`, `high`, `xhigh`, `max` (default: `xhigh` for opus, `high` for sonnet, unset for haiku and fable) |
| `--prompt-file <path>` | Read task description from a file |
| `--timeout-ms <ms>` | Foreground observer timeout before returning a retrievable job |
| `--wait-timeout-ms <ms>` | Foreground observer timeout before returning a retrievable job |
| `--timeout-ms <ms>` | Deprecated alias for `--wait-timeout-ms` |

**Resume behavior:** If you don't pass `--resume` or `--fresh`, rescue checks for a resumable Claude session and asks once whether to continue or start fresh. Your phrasing guides the recommendation — "continue the last run" → resume, "start over" → fresh.

Expand Down Expand Up @@ -257,11 +258,12 @@ $cc:cancel task-abc123 # cancel a running job

```text
$cc:setup # verify everything
$cc:setup --check # read-only readiness check
$cc:setup --enable-review-gate # turn on stop-time review gate
$cc:setup --disable-review-gate # turn it off
```

Setup checks Claude Code availability, native plugin hook feature gates, and review-gate state. If Claude Code isn't installed, it offers to install it.
Setup checks Claude Code availability, native plugin hook feature gates, and review-gate state. `--check` reports required repairs without changing config or hook trust. If Claude Code isn't installed, setup offers to install it.
This is also the repair path for marketplace-installed copies of the plugin: `$cc:setup` confirms `[features].hooks = true` and `[features].plugin_hooks = true`, then trusts this plugin's current native hook hashes so Codex loads the bundled hooks from the active plugin cache.

## Background Jobs
Expand Down Expand Up @@ -334,7 +336,7 @@ The review gate is an **optional** stop-time hook. When enabled, pressing Ctrl+C
Install from the fork's marketplace snapshot:

```bash
codex plugin marketplace add CBEPX/cc-plugin-codex --ref v1.5.3
codex plugin marketplace add CBEPX/cc-plugin-codex --ref v1.5.4
codex plugin add cc@cbepx
```

Expand All @@ -355,8 +357,8 @@ This fork does not install from the upstream Sendbird marketplace. Use the CBEPX
```bash
CC_PLUGIN_CODEX_MARKETPLACE_NAME=cbepx \
CC_PLUGIN_CODEX_MARKETPLACE_SOURCE=CBEPX/cc-plugin-codex \
CC_PLUGIN_CODEX_MARKETPLACE_REF=v1.5.3 \
npx -y https://github.com/CBEPX/cc-plugin-codex/releases/download/v1.5.3/cc-plugin-codex-1.5.3.tgz install
CC_PLUGIN_CODEX_MARKETPLACE_REF=v1.5.4 \
npx -y https://github.com/CBEPX/cc-plugin-codex/releases/download/v1.5.4/cc-plugin-codex-1.5.4.tgz install
```

After install, run:
Expand Down Expand Up @@ -386,7 +388,7 @@ $cc:setup
Re-run the fork marketplace install flow, pinned to the release you want:

```bash
codex plugin marketplace add CBEPX/cc-plugin-codex --ref v1.5.3
codex plugin marketplace add CBEPX/cc-plugin-codex --ref v1.5.4
codex plugin add cc@cbepx
```

Expand Down
29 changes: 18 additions & 11 deletions hooks/unread-result-hook.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import { fileURLToPath } from "node:url";

import { readHookInput } from "./lib/hook-input.mjs";
import { cleanupAfterOfficialUninstall } from "./lib/plugin-install-guard.mjs";
import { getConfig, listJobs, patchJob, writeTurnBaseline } from "../scripts/lib/state.mjs";
import {
getConfig,
listJobs,
patchJob,
TERMINAL_JOB_STATUSES,
writeTurnBaseline,
} from "../scripts/lib/state.mjs";
import { getWorkingTreeFingerprint } from "../scripts/lib/git.mjs";
import { nowIso, SESSION_ID_ENV } from "../scripts/lib/tracked-jobs.mjs";
import { resolveWorkspaceRoot } from "../scripts/lib/workspace.mjs";
Expand All @@ -26,7 +32,7 @@ function isExplicitClaudeStatusRequest(prompt) {
}

function summarizeJob(job) {
const parts = [job.id];
const parts = [job.id, job.status];
if (job.kindLabel) parts.push(job.kindLabel);
if (job.summary) parts.push(job.summary);
return parts.join(" | ");
Expand All @@ -37,33 +43,34 @@ function buildAdditionalContext(jobs) {
const remaining = jobs.length - listed.length;
const intro =
jobs.length === 1
? "A Claude Code background job from this session has finished and has not been surfaced yet."
: `${jobs.length} Claude Code background jobs from this session have finished and have not been surfaced yet.`;
? "A Claude Code background job from this session reached a terminal state and has not been surfaced yet."
: `${jobs.length} Claude Code background jobs from this session reached a terminal state and have not been surfaced yet.`;

const guidance =
jobs.length === 1
? `Before handling the new request, briefly mention that ${jobs[0].id} finished and ask whether the user wants to inspect its result first or continue with the new request. If they want the result, direct them to \`$cc:result ${jobs[0].id}\`. If the user is clearly asking about this finished work already, answer that directly instead of asking again. Do not bring this completion up again automatically after this turn.`
: "Before handling the new request, briefly mention that these Claude Code jobs finished and ask whether the user wants to inspect them first or continue with the new request. If they want to inspect them, direct them to `$cc:status` first, then `$cc:result <job-id>` for a specific finished job. If the user is clearly asking about this finished work already, answer that directly instead of asking again. Do not bring these completions up again automatically after this turn.";
? `Before handling the new request, briefly mention that ${jobs[0].id} reached ${jobs[0].status} and ask whether the user wants to inspect its result first or continue with the new request. If they want the result, direct them to \`$cc:result ${jobs[0].id}\`. If the user is clearly asking about this work already, answer that directly instead of asking again. Do not bring this outcome up again automatically after this turn.`
: "Before handling the new request, briefly mention that these Claude Code jobs reached terminal states and ask whether the user wants to inspect them first or continue with the new request. If they want to inspect them, direct them to `$cc:status` first, then `$cc:result <job-id>` for a specific job. If the user is clearly asking about this work already, answer that directly instead of asking again. Do not bring these outcomes up again automatically after this turn.";

return [
intro,
"",
"Finished jobs:",
"Terminal jobs:",
...listed,
...(remaining > 0 ? [`- and ${remaining} more finished Claude Code job(s)`] : []),
...(remaining > 0 ? [`- and ${remaining} more terminal Claude Code job(s)`] : []),
"",
guidance,
].join("\n");
}

function selectUnreadCompletedJobs(workspaceRoot, sessionId) {
function selectUnreadTerminalJobs(workspaceRoot, sessionId) {
if (!sessionId) {
return [];
}

return listJobs(workspaceRoot)
.filter((job) => job.sessionId === sessionId)
.filter((job) => job.status === "completed")
.filter((job) => TERMINAL_JOB_STATUSES.has(job.status))
.filter((job) => job.status !== "cancelled")
.filter((job) => !job.resultViewedAt)
.filter((job) => !job.notifiedAt)
.sort((left, right) =>
Expand Down Expand Up @@ -125,7 +132,7 @@ async function main() {
return;
}

const jobs = selectUnreadCompletedJobs(workspaceRoot, sessionId);
const jobs = selectUnreadTerminalJobs(workspaceRoot, sessionId);
if (jobs.length === 0) {
return;
}
Expand Down
8 changes: 5 additions & 3 deletions internal-skills/cli-runtime/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ Task defaults:
- Use a structured file-write path to create that prompt file when possible. Do not solve shell quoting by wrapping the same long task inside another brittle inline shell command.
- If the tool output includes stderr progress chatter and a final stdout-style result, ignore the progress chatter and preserve only the final stdout-equivalent result text.
- Return the stdout of the `task` command exactly as-is.
- Run the companion command as one blocking foreground shell-tool call, not as a background terminal/session.
- Do not request a shell session id, poll a shell session later, or return before the companion command exits.
- If the available shell tool is `exec_command`, call it once in non-interactive mode and wait for command exit in that same call.
- Run the companion command in the foreground; do not add shell backgrounding such as `&`, `nohup`, or detached `spawn`.
- If the shell tool returns a session id, keep polling that same session until the companion command exits.
- Exit code 0 is the only successful completion.
- Exit code 124 means the job is still running; return the companion output without claiming it finished.
- For any other non-zero exit code or shell-tool error, return the raw companion output or diagnostic without a success notification.
- If the parent supplied a non-empty parent thread id for background completion, allow at most one success-only `send_input` notification before finishing.
- Mention the tool name `send_input` literally when describing that notification path.
- Use the exact tool shape `send_input({ target: <parent-thread-id>, message: <steering-message> })`.
Expand Down
8 changes: 5 additions & 3 deletions internal-skills/review-runtime/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ Background contract:
- return stdout only
- ignore stderr progress chatter such as `[cc] ...`
- do not inspect the repo or perform the review itself
- run the companion command as one blocking foreground shell-tool call, not as a background terminal/session
- do not request a shell session id, poll a shell session later, or return before the companion command exits
- if the available shell tool is `exec_command`, call it once in non-interactive mode and wait for command exit in that same call
- run the companion command in the foreground; do not add shell backgrounding such as `&`, `nohup`, or detached `spawn`
- If the shell tool returns a session id, keep polling that same session until the companion command exits.
- Exit code 0 is the only successful completion.
- Exit code 124 means the job is still running; return the companion output without claiming it finished.
- For any other non-zero exit code or shell-tool error, return the raw companion output or diagnostic without a success notification.
- use at most one `send_input` completion notification on success
- mention the tool name `send_input` literally in the child instructions
- use the exact tool shape `send_input({ target: <parent-thread-id>, message: <steering-message> })`
Expand Down
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.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cc-plugin-codex",
"version": "1.5.3",
"version": "1.5.4",
"description": "Claude Code Plugin for Codex (CBEPX fork)",
"type": "module",
"author": {
Expand Down Expand Up @@ -61,6 +61,7 @@
"test": "node --import ./tests/test-env.mjs --test tests/*.test.mjs",
"test:coverage": "c8 --all --include='scripts/**/*.mjs' --include='hooks/**/*.mjs' --reporter=text --reporter=json-summary --reporter=lcov --reports-dir=reports/coverage --check-coverage --lines=89 --statements=89 --branches=79 --functions=96 node --import ./tests/test-env.mjs --test tests/*.test.mjs tests/integration/*.test.mjs tests/e2e/*.test.mjs",
"test:cross-platform": "node --import ./tests/test-env.mjs --test tests/args.test.mjs tests/cancel-command.test.mjs tests/changelog.test.mjs tests/claude-cli.test.mjs tests/fs.test.mjs tests/install-hooks.test.mjs tests/mutation-config.test.mjs tests/plugin-install-guard.test.mjs tests/process.test.mjs tests/prompts.test.mjs tests/render.test.mjs tests/sandbox-modes.test.mjs tests/skills-contracts.test.mjs tests/structured-output.test.mjs tests/version-sync.test.mjs",
"test:lifecycle-contract": "node --import ./tests/test-env.mjs --test --test-name-pattern=\"keeps a running job while its owning worker is alive|falls back to the identity-checked Claude PID|terminates a live Claude child|bounds Windows Claude child cleanup|clears a recycled Claude child PID|clears an identity-unavailable Claude child|reports cancel_failed when a live Claude child|tracks the worker separately|logs when worker identity is unavailable|does not bypass a terminal writer|ignores progress after its job file disappears\" tests/state.test.mjs tests/tracked-jobs.test.mjs",
"test:integration": "node --import ./tests/test-env.mjs --test tests/integration/*.test.mjs",
"test:mutation": "npm run test:mutation:pr",
"test:mutation:pr": "npm run test:mutation:critical && npm run test:mutation:shard:managed && npm run test:mutation:shard:installer",
Expand Down
Loading
Loading