Skip to content

feat: align hook lifecycle with upstream Codex (v1.5.0) - #99

Merged
sf-jin-ku merged 4 commits into
mainfrom
feat/native-hook-lifecycle-alignment
Aug 30, 2026
Merged

feat: align hook lifecycle with upstream Codex (v1.5.0)#99
sf-jin-ku merged 4 commits into
mainfrom
feat/native-hook-lifecycle-alignment

Conversation

@sf-jin-ku

Copy link
Copy Markdown
Contributor

Summary

Upstream Codex moved on since v1.3.0; three behaviors here were still written against the old runtime.

  • Restore the SessionEnd hook. Codex 0.146+ dispatches SessionEnd for root sessions, so the teardown removed in v1.3.0 as non-dispatched now runs again: it reaps background jobs whose process died and clears this session's current-session marker instead of leaving it to age out after seven days. Teardown stays inside Codex's few-second budget (timeout: 3) — it never kills or waits on live processes, so detached jobs keep running and the UserPromptSubmit sweeper still covers them.
  • Stop requiring [features].plugin_hooks. Upstream retired that flag (Stage::Removed), and native plugin hooks now ride on [features].hooks alone. Setup requires only hooks = true and strips a leftover plugin_hooks line from ~/.codex/config.toml, the same way it already upgrades the legacy codex_hooks alias.
  • Correct the review skills' description of request_user_input. Omitting [tools] experimental_request_user_input leaves the tool enabled; only an explicit false hides it in an interactive thread. The conditional ask is unchanged — it still depends on the thread actually having a question tool.

Upgrade notes

  • Existing users' ~/.codex/config.toml gets its stale plugin_hooks = true line stripped on the next $cc:setup run.
  • A Codex restart is needed after the hooks/hooks.json change for the new SessionEnd registration to take effect.

Tests

  • tests/hooks.test.mjs: SessionEnd reaps a dead-PID job to failed, leaves a live job running, and drops the session marker; a SessionEnd from a different session leaves the active marker alone. Hook-name allowlist widened to the current 12 HOOK_EVENT_NAMES.
  • tests/codex-config.test.mjs: ensureNativePluginHooksEnabled requires only hooks and strips plugin_hooks; nativePluginHooksStatus reports from hooks alone.
  • Existing plugin_hooks = true assertions across install/installer/e2e/skills-contract tests inverted to doesNotMatch.
  • npm run check passes (lint, typecheck, unit, integration, e2e).

Note: the SessionEnd entry copies statusMessage from SessionStart; if upstream ignores it for that event it is simply inert.

🤖 Generated with Claude Code

Restore the SessionEnd hook, drop the retired [features].plugin_hooks
gate, and correct the review skills' request_user_input description.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-30T00:49:18.217131Z 17848c2 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e8da74826c

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread package.json
{
"name": "cc-plugin-codex",
"version": "1.4.2",
"version": "1.5.0",

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 Synchronize the lockfile with the release version

This release bumps package.json to 1.5.0, but package-lock.json still declares 1.4.2 in both its top-level version and packages[""] entry. As a result, a standard npm install --package-lock-only immediately rewrites the tracked lockfile, leaving release metadata inconsistent; update those lockfile entries as part of the version bump.

Useful? React with 👍 / 👎.

@upwind-code-us

upwind-code-us Bot commented Aug 30, 2026

Copy link
Copy Markdown

Upwind Upwind Code Scan - ✅ Proceed with Deployment

0 newly introduced vulnerabilities · 0 resolved · 0 total in this PR vs main

View full analysis in Upwind Console

Scan completed in 18s

Scan history (4 scans)
Commit Scanned at New Resolved Net
e8da748 2026-08-30 00:19 UTC 0 0 0
17848c2 2026-08-30 00:29 UTC 0 0 0
5068eb8 2026-08-30 01:13 UTC 0 0 0
df064f9 < 2026-08-30 01:39 UTC 0 0 0

Last scanned: df064f9 · 2026-08-30 01:39 UTC

@upwind-code-us

upwind-code-us Bot commented Aug 30, 2026

Copy link
Copy Markdown

Upwind Upwind IaC Scan - ✅ Proceed with Deployment

0 newly introduced misconfigurations · 0 resolved · 0 total in this PR vs main

View full analysis in Upwind Console →

Scan completed in 2s

Scan history (5 scans)
Commit Scanned at New Resolved Net
e8da748 2026-08-30 00:19 UTC 0 0 0
e8da748 2026-08-30 00:19 UTC
17848c2 2026-08-30 00:29 UTC 0 0 0
5068eb8 2026-08-30 01:13 UTC 0 0 0
df064f9 < 2026-08-30 01:39 UTC 0 0 0

Last scanned: df064f9 · 2026-08-30 01:39 UTC

Co-Authored-By: Claude Code <noreply@anthropic.com>
@sf-jin-ku

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 17848c2ac1

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@sf-jin-ku

Copy link
Copy Markdown
Contributor Author

Manual dispatch verification (Codex 0.149.1)

SessionEnd dispatch was verified empirically, not just from upstream source. Probe: the plugin installed into a throwaway CODEX_HOME from a local marketplace, its hooks/hooks.json commands swapped for a logger, all discovered hooks trusted via hooks/listconfig/batchWrite hooks.state (upstream's own recipe), then one real codex exec run.

discovered hooks: sessionStart=untrusted, sessionEnd=untrusted, userPromptSubmit=untrusted, stop=untrusted
=== FIRED ===
SessionStart      {"session_id":"01a05035-…","transcript_path":"…"}
UserPromptSubmit  {"session_id":"01a05035-…","turn_id":"…"}
Stop              {"session_id":"01a05035-…","turn_id":"…"}
SessionEnd        {"session_id":"01a05035-…","transcript_path":"…"}

SessionEnd fires — in codex exec, not only the TUI — and SessionEndRequest carries session_id and a non-optional cwd (codex-rs/hooks/src/events/session_end.rs:27), which is exactly what handleSessionEnd reads.

Upgrade caveat this turned up

Codex trusts hooks per hook, keyed cc@sendbird:hooks/hooks.json:<event>:<group>:<index> with a trusted_hash in [hooks.state]. The hash is computed per hook, and the index is per event, so adding SessionEnd does not invalidate the existing session_start / stop / user_prompt_submit entries. But the new session_end hook has no entry, so on upgrade it lands untrusted and silently inert until the user approves it in the TUI hooks browser. Worth calling out in release notes; I did not make setup self-trust its own hook, since that is plausibly the exact thing the trust system exists to prevent.

Test coverage, stated honestly

  • Handler logic: unit-tested with synthetic hook stdin, mutation-checked.
  • Registration: contract-tested against upstream HOOK_EVENT_NAMES.
  • Real dispatch: not covered by the repo's e2e suite. E2E runs real codex exec, but a fresh CODEX_HOME has no [hooks.state] trust entries, so no plugin hook has ever actually fired there — those tests assert config.toml contents only. The verification above was manual.

A trust-aware dispatch e2e is feasible with the recipe above; it is new scope and costs a real model call per run, so it is not in this PR.

jinku and others added 2 commits August 29, 2026 18:08
Co-Authored-By: Claude Code <noreply@anthropic.com>
Trust the installed plugin's hooks through hooks/list plus a hooks.state
config write, then assert a real codex exec run leaves the workspace state
directory behind without a session marker.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@sf-jin-ku

Copy link
Copy Markdown
Contributor Author

Follow-up to the note above: the dispatch gap is now closed in the suite, not just manually.

tests/e2e/codex-skills-e2e.test.mjs gains a native hook dispatch case that installs the plugin, trusts its hooks through hooks/listconfig/batchWrite hooks.state, runs one real codex exec against the existing mock provider, and asserts the workspace state directory survives without a current-session.json. Only setCurrentSession (SessionStart) creates that directory and only clearCurrentSession (SessionEnd) removes the marker, so both halves must have run; if hooks never dispatch, the directory is missing and the test fails. CLAUDE_COMPANION_SESSION_ID is cleared first, since a nested session id would make SessionStart skip the marker and fake a pass.

CI on codex-cli 0.151.0: 23 passed, 0 failed, 0 skipped — so this runs for real in CI rather than skipping out.

So the earlier "real dispatch is not covered by e2e" line is now stale: it is covered. No model tokens are spent — the suite's mock provider serves the turn.

@sf-jin-ku
sf-jin-ku merged commit 19e5651 into main Aug 30, 2026
7 checks passed
@sf-jin-ku
sf-jin-ku deleted the feat/native-hook-lifecycle-alignment branch August 30, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant