diff --git a/docs/codex-monitor-beta.md b/docs/codex-monitor-beta.md index 4fa3ba1ef..9562e0efd 100644 --- a/docs/codex-monitor-beta.md +++ b/docs/codex-monitor-beta.md @@ -105,6 +105,7 @@ codex exec ... codex app-server ... codex login codex logout +codex plugin ... ``` The shim also passes through when the current project is not in Codex monitor diff --git a/scripts/drivers/types/codex/codex-shim.sh b/scripts/drivers/types/codex/codex-shim.sh index c88695795..de3275731 100755 --- a/scripts/drivers/types/codex/codex-shim.sh +++ b/scripts/drivers/types/codex/codex-shim.sh @@ -185,7 +185,12 @@ case "$command_name" in AGMSG_REAL_CODEX="$real_codex" exec "$monitor_cmd" --project "$project" --codex-command resume -- fi ;; - app-server|exec|login|logout|mcp|completion|debug|apply|review|sandbox|help|--help|-h|version|--version|-V) + # Keep known non-remote subcommands out of the monitor bridge. The catch-all + # below is intentional: prompt strings and remote-aware session commands + # (fork/archive/delete/unarchive) must still reach the shared app-server. + # Add newly introduced non-remote Codex subcommands to this list. + app-server|exec|e|login|logout|mcp|mcp-server|plugin|remote-control|completion|update|doctor|\ + cloud|exec-server|features|debug|apply|a|review|sandbox|help|--help|-h|version|--version|-V) exec "$real_codex" "$@" ;; *) diff --git a/tests/test_codex_shim.bats b/tests/test_codex_shim.bats index 09ebbce02..dbae3b827 100644 --- a/tests/test_codex_shim.bats +++ b/tests/test_codex_shim.bats @@ -76,14 +76,56 @@ teardown() { @test "codex shim: noninteractive codex subcommands pass through even in monitor mode" { bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null - AGMSG_REAL_CODEX="$FAKE_CODEX" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" \ - run bash "$TYPES/codex/codex-shim.sh" exec echo hi + run bash -c 'cd "$TEST_PROJECT" && AGMSG_REAL_CODEX="$FAKE_CODEX" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" bash "$TYPES/codex/codex-shim.sh" exec echo hi' [ "$status" -eq 0 ] grep -q "real-codex " "$CALL_LOG" ! grep -q "^monitor" "$CALL_LOG" } +@test "codex shim: plugin marketplace commands pass through even in monitor mode" { + bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null + + run bash -c 'cd "$TEST_PROJECT" && AGMSG_REAL_CODEX="$FAKE_CODEX" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" bash "$TYPES/codex/codex-shim.sh" plugin marketplace add owner/repository' + + [ "$status" -eq 0 ] + grep -Fq "real-codex " "$CALL_LOG" + ! grep -q "^monitor" "$CALL_LOG" +} + +@test "codex shim: known non-remote subcommands and aliases bypass the monitor bridge" { + bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null + + local subcommand + for subcommand in mcp-server remote-control update doctor cloud exec-server features e a; do + : > "$CALL_LOG" + + run bash -c 'cd "$TEST_PROJECT" && AGMSG_REAL_CODEX="$FAKE_CODEX" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" bash "$TYPES/codex/codex-shim.sh" "$1" test-arg' _ "$subcommand" + + [ "$status" -eq 0 ] + grep -Fq "real-codex <$subcommand> " "$CALL_LOG" + ! grep -q "^monitor" "$CALL_LOG" + done +} + +@test "codex shim: remote-aware session commands continue through the monitor bridge" { + bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null + + local subcommand + for subcommand in fork archive delete unarchive; do + : > "$CALL_LOG" + + run bash -c 'cd "$TEST_PROJECT" && AGMSG_REAL_CODEX="$FAKE_CODEX" AGMSG_CODEX_MONITOR_CMD="$FAKE_MONITOR" bash "$TYPES/codex/codex-shim.sh" "$1" test-session' _ "$subcommand" + + [ "$status" -eq 0 ] + grep -Fq "monitor real=$FAKE_CODEX <--project> <$TEST_PROJECT> <--codex-command> <--> <$subcommand> " "$CALL_LOG" || { + echo "unexpected routing for $subcommand: $(cat "$CALL_LOG")" >&3 + false + } + ! grep -q "^real-codex" "$CALL_LOG" + done +} + @test "codex shim: --cd project is used for monitor detection" { bash "$SCRIPTS/delivery.sh" set monitor codex "$TEST_PROJECT" >/dev/null