diff --git a/README.md b/README.md index b47ec75..0fd1d32 100644 --- a/README.md +++ b/README.md @@ -268,9 +268,9 @@ $agmsg — or /skills → agmsg Codex supports `mode monitor` as a **beta** app-server bridge, plus `mode turn` and `mode off`. -> ⚠️ **The monitor beta changes how Codex starts — opt in only if you understand it.** Codex has no Monitor tool, so `mode monitor` installs a shim at `~/.agents/bin/codex` and asks you to put `~/.agents/bin` **first on your PATH**, so `codex` then resolves to the shim instead of the real binary. In monitor-mode projects the shim routes interactive launches through a bridge that turns incoming agmsg messages into turns on the current Codex thread; `codex exec` and non-monitor projects pass straight through to the real Codex. It depends on experimental Codex app-server behavior and has known rough edges (orphans on TUI close — #149; one identity per project — #150). +> ⚠️ **The monitor beta changes how Codex starts — opt in only if you understand it.** Codex has no Monitor tool, so `mode monitor` prints a shell function that makes `codex` route through agmsg's monitor shim in your interactive shell. In monitor-mode projects the shim routes interactive launches through a bridge that turns incoming agmsg messages into turns on the current Codex thread; `codex exec` and non-monitor projects pass straight through to the real Codex. It depends on experimental Codex app-server behavior and has known rough edges (orphans on TUI close — #149; one identity per project — #150). -If the shim can't be installed, launch with `~/.agents/skills//scripts/drivers/types/codex/codex-monitor.sh`. Codex sandboxing must allow writes to the skill's `db/`, `teams/`, and `run/` dirs — `install.sh` configures those `writable_roots` when `~/.codex/config.toml` exists. Setup, PATH notes, and internals: [docs/codex-monitor-beta.md](docs/codex-monitor-beta.md). +If you prefer a global PATH shim, run `~/.agents/skills//scripts/drivers/types/codex/codex-shim-install.sh install` and put `~/.agents/bin` before the real Codex binary on PATH. You can also launch with `~/.agents/skills//scripts/drivers/types/codex/codex-monitor.sh`. Codex sandboxing must allow writes to the skill's `db/`, `teams/`, and `run/` dirs — `install.sh` configures those `writable_roots` when `~/.codex/config.toml` exists. Setup notes and internals: [docs/codex-monitor-beta.md](docs/codex-monitor-beta.md). ### GitHub Copilot CLI diff --git a/docs/codex-monitor-beta.md b/docs/codex-monitor-beta.md index 2980f6c..6eef241 100644 --- a/docs/codex-monitor-beta.md +++ b/docs/codex-monitor-beta.md @@ -4,13 +4,12 @@ Codex does not expose Claude Code's Monitor tool. agmsg's Codex monitor beta approximates the same experience by launching Codex through an app-server bridge. > ⚠️ **Experimental beta — read before enabling.** This changes how Codex starts. -> Enabling monitor mode installs a shim at `~/.agents/bin/codex` and asks you to -> put `~/.agents/bin` **first on your PATH**, so `codex` then resolves to the shim -> instead of the real binary. In monitor-mode projects the shim re-routes -> interactive launches through an app-server bridge; everywhere else it passes -> straight through. **Only enable this if you understand PATH precedence and are -> comfortable with the `codex` command being intercepted.** It also depends on -> Codex app-server behavior and may break as Codex changes. Known rough edges: +> Enabling monitor mode prints a shell function that makes `codex` route through +> agmsg's monitor shim in your interactive shell. In monitor-mode projects the +> shim re-routes interactive launches through an app-server bridge; everywhere +> else it passes straight through. **Only enable this if you are comfortable with +> the `codex` command being intercepted in that shell.** It also depends on Codex +> app-server behavior and may break as Codex changes. Known rough edges: > enabling monitor takes effect only after you **restart Codex and send your > first message** — the SessionStart hook fires on the first turn, not the > moment Codex opens, so the bridge is absent until you interact once; an @@ -30,9 +29,8 @@ Enable monitor mode in a project: The command: 1. Enables agmsg's Codex SessionStart/SessionEnd hooks for the project. -2. Installs a Codex shim at `~/.agents/bin/codex` when it is safe to do so. -3. Prints PATH instructions if `~/.agents/bin` is not before the real Codex - binary. +2. Prints a shell function that routes interactive `codex` launches through the + monitor shim. The Codex sandbox must allow writes to the installed skill's runtime state: @@ -45,11 +43,12 @@ The Codex sandbox must allow writes to the installed skill's runtime state: `install.sh` and `install.sh --update` add these writable roots to `~/.codex/config.toml` when that file exists. -If the command says `~/.agents/bin` is not on PATH, add this to your shell -profile: +Add the printed function to your shell profile. It looks like: ```bash -export PATH="$HOME/.agents/bin:$PATH" +codex() { + ~/.agents/skills/agmsg/scripts/drivers/types/codex/codex-shim.sh "$@" +} ``` Restart the shell, then launch Codex normally: @@ -58,13 +57,25 @@ Restart the shell, then launch Codex normally: codex ``` -In monitor-mode projects, the shim routes interactive Codex launches through +In monitor-mode projects, the function routes interactive Codex launches through the bridge. Outside monitor-mode projects, it passes through to the real Codex. -## Fallback +## Optional PATH Shim + +If you prefer the previous global PATH shim setup, install it explicitly: + +```bash +~/.agents/skills/agmsg/scripts/drivers/types/codex/codex-shim-install.sh install +``` + +Then put `~/.agents/bin` before the real Codex binary on PATH: + +```bash +export PATH="$HOME/.agents/bin:$PATH" +``` If `~/.agents/bin/codex` already exists and is not the agmsg shim, agmsg leaves -it untouched. You can either move that command aside and run `mode monitor` +it untouched. You can either move that command aside and run the install command again, or launch monitor sessions explicitly: ```bash @@ -79,7 +90,8 @@ For custom command names, replace `agmsg` with the installed skill name: ## What The Shim Does -The shim only wraps interactive Codex TUI launches: +The shell function and optional PATH shim only wrap interactive Codex TUI +launches: ```bash codex @@ -139,7 +151,7 @@ and the bridge stops instead of looping. ```mermaid flowchart TD - user["User runs codex"] --> shim["~/.agents/bin/codex shim"] + user["User runs codex"] --> shim["codex shell function or ~/.agents/bin/codex shim"] shim --> mode{"Project delivery mode?"} mode -- "not monitor / codex exec / --version" --> real["real codex"] mode -- "monitor (interactive)" --> monitor["codex-monitor.sh"] diff --git a/scripts/drivers/types/codex/_delivery.sh b/scripts/drivers/types/codex/_delivery.sh index 32918ed..8297c1b 100644 --- a/scripts/drivers/types/codex/_delivery.sh +++ b/scripts/drivers/types/codex/_delivery.sh @@ -2,29 +2,21 @@ # codex delivery plug. # # codex keeps the default JSON event-hooks apply (agmsg_delivery_apply); it only -# adds enable/disable side effects: install the monitor shim on enable, stop the -# bridge on disable. Sourced into delivery.sh's context, so SKILL_DIR, +# adds enable/disable side effects: print the monitor shim setup on enable, stop +# the bridge on disable. Sourced into delivery.sh's context, so SKILL_DIR, # agmsg_resolve_node, CODEX_MONITOR_DOC_URL and stop_codex_bridge are in scope. # Args (both hooks): on_enable ; on_disable . agmsg_delivery_on_enable() { - if AGMSG_CODEX_SHIM_INSTALL_QUIET=1 "$SKILL_DIR/scripts/drivers/types/codex/codex-shim-install.sh" install; then - echo "Codex monitor shim installed at ~/.agents/bin/codex." - case ":$PATH:" in - *":$HOME/.agents/bin:"*) - echo "Future Codex sessions: launch with codex. In monitor-mode projects, the agmsg shim routes interactive Codex sessions through the bridge." - ;; - *) - # Loud, unambiguous: this is the #1 reason monitor silently does nothing. - echo "WARNING: ~/.agents/bin is NOT on your PATH, so 'codex' still launches the real" - echo " binary and the monitor bridge will NOT engage. Add this line, restart your shell," - echo " then launch with codex:" - echo " export PATH=\"\$HOME/.agents/bin:\$PATH\"" - ;; - esac + echo "Codex monitor beta is enabled." + echo "Add this shell function to your interactive shell profile, then restart the shell:" + if "$SKILL_DIR/scripts/drivers/types/codex/codex-shim-install.sh" function; then + echo "Future Codex sessions: launch with codex. In monitor-mode projects, the agmsg function routes interactive Codex sessions through the bridge." + echo "Optional global PATH shim is still available with:" + echo " $SKILL_DIR/scripts/drivers/types/codex/codex-shim-install.sh install" else - echo "Codex monitor mode is enabled, but the codex shim was not installed." - echo "Future Codex sessions: launch with $SKILL_DIR/scripts/drivers/types/codex/codex-monitor.sh, or resolve the shim install issue above." + echo "Codex monitor mode is enabled, but the codex shell function could not be printed." + echo "Future Codex sessions: launch with $SKILL_DIR/scripts/drivers/types/codex/codex-monitor.sh, or resolve the setup issue above." fi # Node preflight: the bridge (codex-bridge.js) is a Node program, so without # Node it silently never starts — flag it at enable time. Resolve via the same @@ -48,8 +40,8 @@ agmsg_delivery_on_disable() { if [ "${stopped:-0}" -gt 0 ]; then echo "Stopped $stopped Codex bridge process(es) for this project and cleaned their run files." fi - echo "Note: the codex shim (~/.agents/bin/codex) is shared across projects, so it was left in place." - echo " If no other project uses monitor mode, remove it and restore your PATH:" + echo "Note: shell profile functions are not changed automatically." + echo " If you installed the optional global shim and no other project uses monitor mode, remove it:" echo " $SKILL_DIR/scripts/drivers/types/codex/codex-shim-install.sh remove" - echo " # then drop ~/.agents/bin from PATH if you added it for monitor" + echo " # then drop any agmsg Codex function or ~/.agents/bin PATH entry you added for monitor" } diff --git a/scripts/drivers/types/codex/codex-shim-install.sh b/scripts/drivers/types/codex/codex-shim-install.sh index b33ac23..9660fcf 100755 --- a/scripts/drivers/types/codex/codex-shim-install.sh +++ b/scripts/drivers/types/codex/codex-shim-install.sh @@ -7,14 +7,16 @@ TARGET="$AGENTS_BIN/codex" usage() { cat </dev/null +} + resolve_real_codex() { if [ -n "${AGMSG_REAL_CODEX:-}" ]; then printf '%s\n' "$AGMSG_REAL_CODEX" @@ -35,7 +39,9 @@ resolve_real_codex() { candidate_dir="$(cd "$(dirname "$candidate")" 2>/dev/null && pwd || true)" [ -n "$candidate_dir" ] || continue candidate_path="$candidate_dir/$(basename "$candidate")" - if [ "$candidate_path" != "$self_path" ] && [ "$candidate_path" != "$shim_target" ]; then + if [ "$candidate_path" != "$self_path" ] \ + && [ "$candidate_path" != "$shim_target" ] \ + && ! is_agmsg_wrapper "$candidate_path"; then printf '%s\n' "$candidate_path" return 0 fi diff --git a/scripts/drivers/types/codex/template.md b/scripts/drivers/types/codex/template.md index bd0f1c7..c673f27 100644 --- a/scripts/drivers/types/codex/template.md +++ b/scripts/drivers/types/codex/template.md @@ -53,9 +53,9 @@ Four possible outputs: Manual $__SKILL_NAME__ only. 3) monitor — Real-time push (BETA, advanced) - Installs a `codex` shim on PATH and routes launches through an - app-server bridge. Opt in ONLY if you understand PATH precedence - and accept experimental behavior. See docs/codex-monitor-beta.md. + Prints a `codex` shell function that routes launches through an + app-server bridge. Opt in ONLY if you accept experimental behavior. + See docs/codex-monitor-beta.md. [1]: ``` @@ -63,7 +63,7 @@ Four possible outputs: - **Wait for the user's answer before proceeding.** Empty input means `1` (turn). - Map the chosen number to a mode (`1`→`turn`, `2`→`off`, `3`→`monitor`) and run: `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set codex "$(pwd)"` - - If monitor is chosen, tell the user: "Codex monitor is a BETA that changes how `codex` starts — it installs a `codex` shim and needs `~/.agents/bin` first on PATH. If the output says `~/.agents/bin` is not on PATH, add `export PATH=\"$HOME/.agents/bin:$PATH\"` to your shell profile, restart the shell, then launch future sessions with normal `codex`. If shim installation was refused because `~/.agents/bin/codex` already exists, use `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-monitor.sh` or resolve that command conflict. The bridge starts on the **first turn** of a new Codex session (the SessionStart hook fires on your first message, not the moment Codex opens), so **restart your Codex session and send one message for monitor to take effect** — this already-running session stays unmonitored until it restarts. For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md" + - If monitor is chosen, tell the user: "Codex monitor is a BETA that changes how `codex` starts — it prints a shell function to add to your shell profile. Add the printed function, restart the shell, then launch future sessions with normal `codex`. If you prefer a global PATH shim, run `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-shim-install.sh install` and put `~/.agents/bin` first on PATH. You can also use `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-monitor.sh` for explicit monitor launches. The bridge starts on the **first turn** of a new Codex session (the SessionStart hook fires on your first message, not the moment Codex opens), so **restart your Codex session and send one message for monitor to take effect** — this already-running session stays unmonitored until it restarts. For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md" 6. Then check inbox for the newly joined team. @@ -143,7 +143,7 @@ If argument is "mode" (no further args): If argument starts with "mode" followed by a mode name (e.g. "mode monitor"): 1. Parse the mode. Codex supports `monitor` (beta bridge), `turn`, and `off` — reject `both` with: "Codex bridge beta supports `monitor`, `turn`, or `off`; `both` is not supported yet." 2. Run: `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set codex "$(pwd)"` -3. If mode is `monitor`, tell the user: "Codex monitor beta is enabled. agmsg installs an optional `codex` shim automatically. If the output says `~/.agents/bin` is not on PATH, add `export PATH=\"$HOME/.agents/bin:$PATH\"` to your shell profile, restart the shell, then launch future sessions with normal `codex`. If shim installation was refused because `~/.agents/bin/codex` already exists, use `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-monitor.sh` or resolve that command conflict. The bridge starts on the **first turn** of a new Codex session (the SessionStart hook fires on your first message, not the moment Codex opens), so **restart your Codex session and send one message for monitor to take effect** — this already-running session stays unmonitored until it restarts. For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md" +3. If mode is `monitor`, tell the user: "Codex monitor beta is enabled. Add the printed shell function to your shell profile, restart the shell, then launch future sessions with normal `codex`. If you prefer a global PATH shim, run `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-shim-install.sh install` and put `~/.agents/bin` first on PATH. You can also use `~/.agents/skills/__SKILL_NAME__/scripts/drivers/types/codex/codex-monitor.sh` for explicit monitor launches. The bridge starts on the **first turn** of a new Codex session (the SessionStart hook fires on your first message, not the moment Codex opens), so **restart your Codex session and send one message for monitor to take effect** — this already-running session stays unmonitored until it restarts. For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md" If argument is "hook on" (legacy alias): 1. Run: `~/.agents/skills/__SKILL_NAME__/scripts/delivery.sh set turn codex "$(pwd)"` diff --git a/tests/test_codex_shim.bats b/tests/test_codex_shim.bats index ec291c6..ce1eb33 100644 --- a/tests/test_codex_shim.bats +++ b/tests/test_codex_shim.bats @@ -85,10 +85,57 @@ teardown() { grep -q "monitor real=$FAKE_CODEX <--project> <$TEST_PROJECT> <--codex-command> <--> <--cd> <$TEST_PROJECT>" "$CALL_LOG" } +@test "codex shim install: default prints shell function without installing bin wrapper" { + export HOME="$TEST_PROJECT/home" + mkdir -p "$HOME" + + run bash "$TYPES/codex/codex-shim-install.sh" + + [ "$status" -eq 0 ] + [[ "$output" == *"codex() {"* ]] + [[ "$output" == *"codex-shim.sh"* ]] + [ ! -e "$HOME/.agents/bin/codex" ] +} + +@test "codex shim function: existing agmsg PATH wrapper is skipped when resolving real codex" { + export HOME="$TEST_PROJECT/home" + mkdir -p "$HOME" + bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null + bash "$TYPES/codex/codex-shim-install.sh" install >/dev/null + [ -x "$HOME/.agents/bin/codex" ] + + local real_bin="$TEST_PROJECT/real-bin" + mkdir -p "$real_bin" + cp "$FAKE_CODEX" "$real_bin/codex" + chmod +x "$real_bin/codex" + + PATH="$HOME/.agents/bin:$real_bin:$PATH" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" \ + run bash -c 'eval "$("$TYPES/codex/codex-shim-install.sh" function)"; cd "$TEST_PROJECT"; codex resume --last' + + [ "$status" -eq 0 ] + grep -Fq "monitor real=$real_bin/codex <--project> <$TEST_PROJECT> <--codex-command> <--> <--last>" "$CALL_LOG" + ! grep -Fq "monitor real=$HOME/.agents/bin/codex" "$CALL_LOG" +} + +@test "codex shim function: non-agmsg PATH codex remains eligible as real codex" { + export HOME="$TEST_PROJECT/home" + mkdir -p "$HOME/.agents/bin" + bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null + cp "$FAKE_CODEX" "$HOME/.agents/bin/codex" + chmod +x "$HOME/.agents/bin/codex" + + PATH="$HOME/.agents/bin:$PATH" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" \ + run bash -c 'eval "$("$TYPES/codex/codex-shim-install.sh" function)"; cd "$TEST_PROJECT"; codex resume --last' + + [ "$status" -eq 0 ] + grep -Fq "monitor real=$HOME/.agents/bin/codex <--project> <$TEST_PROJECT> <--codex-command> <--> <--last>" "$CALL_LOG" +} + @test "codex shim install: installed bin wrapper still finds skill scripts" { export HOME="$TEST_PROJECT/home" mkdir -p "$HOME" bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null + bash "$TYPES/codex/codex-shim-install.sh" install >/dev/null [ -x "$HOME/.agents/bin/codex" ] PATH="$HOME/.agents/bin:$PATH" run bash -c 'cd "$TEST_PROJECT" && AGMSG_REAL_CODEX="$FAKE_CODEX" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" codex resume' diff --git a/tests/test_delivery.bats b/tests/test_delivery.bats index fe0358c..c9ae9c6 100644 --- a/tests/test_delivery.bats +++ b/tests/test_delivery.bats @@ -1429,18 +1429,17 @@ EOF [ ! -f "$log" ] } -@test "delivery set monitor (codex): installs SessionStart and Codex shim" { +@test "delivery set monitor (codex): installs SessionStart and prints Codex shell function" { run bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" [ "$status" -eq 0 ] - [[ "$output" == *"Codex monitor shim installed"* ]] + [[ "$output" == *"Codex monitor beta is enabled"* ]] + [[ "$output" == *"codex() {"* ]] + [[ "$output" == *"codex-shim.sh"* ]] [[ "$output" == *"launch with codex"* ]] - # HOME is sandboxed, so ~/.agents/bin is not on PATH → the loud PATH warning fires. - [[ "$output" == *"WARNING: ~/.agents/bin is NOT on your PATH"* ]] - [[ "$output" == *"export PATH=\"\$HOME/.agents/bin:\$PATH\""* ]] + [[ "$output" == *"Optional global PATH shim is still available"* ]] [[ "$output" == *"For more info: https://github.com/fujibee/agmsg/blob/main/docs/codex-monitor-beta.md"* ]] [[ "$output" != *"Monitor tool"* ]] - [ -x "$HOME/.agents/bin/codex" ] - grep -q "Optional Codex entrypoint shim for agmsg monitor mode" "$HOME/.agents/bin/codex" + [ ! -e "$HOME/.agents/bin/codex" ] local hook_file="$TEST_PROJECT/.codex/hooks.json" [ -f "$hook_file" ] grep -q "session-start.sh" "$hook_file" @@ -1494,7 +1493,7 @@ EOF [[ "$output" == *"monitor delivery will NOT start"* ]] } -@test "delivery set off (codex): stops the bridge, cleans run files, notes the shared shim" { +@test "delivery set off (codex): stops the bridge, cleans run files, notes shell profile cleanup" { bash "$SCRIPTS/join.sh" team alice codex "$TEST_PROJECT" >/dev/null mkdir -p "$TEST_SKILL_DIR/run" # Stand in for a live bridge with a real process we can check kill -0 against.