fix(codex): refresh encoded hook commands - #90
xuhaonan013 wants to merge 2 commits into
Conversation
| def _is_evo_hook_drain_command(command: str) -> bool: | ||
| """Recognize source and already-materialized evo drain commands.""" | ||
| if "${CLAUDE_PLUGIN_ROOT}/bin/evo-hook-drain" in command: | ||
| return True | ||
|
|
||
| prefix = "node -e \"eval(Buffer.from('" | ||
| suffix = "','base64').toString())\"" | ||
| if not command.startswith(prefix) or not command.endswith(suffix): | ||
| return False | ||
|
|
||
| encoded = command[len(prefix):-len(suffix)] | ||
| try: | ||
| script = base64.b64decode(encoded, validate=True).decode("utf-8") | ||
| except (binascii.Error, UnicodeDecodeError): | ||
| return False | ||
| return "evo-hook-drain" in script |
There was a problem hiding this comment.
🟡 Legacy plain-path hook command never refreshed
When a Codex hooks.json still carries the v0.6.1 form — a bare absolute path to evo-hook-drain — _is_evo_hook_drain_command returns false, so reinstall leaves it unchanged where the old "evo-hook-drain" in cmd check rewrote it. That command lacks the timeout guard added later, so those hooks can hang indefinitely and no reinstall repairs them.
Prompt for agents
The new _is_evo_hook_drain_command in plugins/evo/src/evo/host_install/codex.py is strictly narrower than the old substring check "evo-hook-drain" in cmd that it replaces at the call site (line 110). Version 0.6.1 (commit 33d87a4) materialized Codex hooks.json commands as a bare shell-quoted absolute path to the stable binary (e.g. /home/user/.evo/bin/evo-hook-drain via _command_quote(stable_binary_path())). The old code recognized this and rewrote it to the current node-wrapper command; the new function does not, so upgrading users stuck on that form keep a hook command lacking the timeout/killSignal guard added in c1e6c2c, which can hang Codex sessions. Consider also recognizing a bare command whose token resolves to a path ending in evo-hook-drain (i.e. matching the stable binary path or a path ending in /bin/evo-hook-drain) in addition to the CLAUDE_PLUGIN_ROOT source form and the base64 node wrapper, so legacy plain-path materializations are still refreshed.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Addressed in 946b14d. Legacy v0.6.1 commands are now parsed as shell tokens and accepted only when there is exactly one token whose path is absolute, whose parent directory is �in, and whose filename is �vo-hook-drain or �vo-hook-drain.exe. The ${CLAUDE_PLUGIN_ROOT} source form remains an exact match. Added a cross-platform regression built with the historical shlex.quote / subprocess.list2cmdline behavior, plus negative cases for relative and argument-bearing commands. Focused tests: 22 passed on Python 3.10, 3.12, and 3.14. Full unit suite: 803 passed, 48 skipped, 5 subtests passed.
|
The PR-focused Codex migration test file passes locally: 22 tests plus 5 subtests. The plugin sdist/wheel build and the 10-source version-consistency check also pass. The repository-wide session fixture additionally requires Cargo; GitHub CI installs Rust, but the current workflow run is still |
Summary
Teach the Codex hook materializer to recognize Evo drain commands inside the existing base64-encoded Node wrapper, so repeat installs can refresh stale commands.
Fixes #84
What changed
${CLAUDE_PLUGIN_ROOT}/bin/evo-hook-drainsource command.node -e "eval(Buffer.from(...,'base64').toString())"wrapper emitted by Evo, validate and decode its payload, then look for the drain marker in the decoded script.Why
After a hook has already been materialized, the literal
evo-hook-drainmarker exists only in the decoded payload. Matching the outer command therefore treated repeat installs as a no-op and prevented future wrapper updates (such as timeout changes) from propagating without--force.Test plan
pytest tests/unit/test_codex_install_migration.py -q- 22 passed, 5 subtests passedpython tests/unit/test_codex_install_migration.py -von Python 3.10 and 3.14 - 22 passed on eachpytest tests/unit/ -qin a Linux-native CI-equivalent copy - 803 passed, 48 skipped, 5 subtests passedruff check ... --select E4,E7,E9,F63,F7,F82python -m compileall -qon both changed files