feat(agent): add full codex agent support (v4.2.0)

- Implement CodexAdapter in lib_py/agents/adapters/codex.py with safe flags and TUI readiness
- Extend create_session, resume_session, stop_session, and reconcile for codex CLI
- Support codex agent delegation and loop integration across all multi-agent skills
- Add unit, component, and contract test suites for codex integration
- Verify all 462 tests passing cleanly
This commit is contained in:
Godopu committed 2026-09-05 23:02:29 +09:00
1 parent de0a9c2e81
commit 76f10b2096
45 files changed
+2045 -276

No files matched your search

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# create_session.sh — multi-agent-mux-create 의 부속 스크립트
# Usage:
# bash create_session.sh --workspace <path> --agent <claude|agy|hermes|grok|opencode> --role <role> [--session <name>] [--herdr-session <name>] [--wrapper]
# bash create_session.sh --workspace <path> --agent <claude|agy|hermes|grok|opencode|codex> --role <role> [--session <name>] [--herdr-session <name>] [--wrapper]
#
# 동작:
# 1) preflight: herdr/claude/agy 가용성, workspace 존재
@@ -26,11 +26,11 @@ source "$_lib_sh"
usage() {
cat <<EOF
Usage: $0 --workspace <path> --agent <claude|agy|hermes|grok|opencode> --role <role> [options]
Usage: $0 --workspace <path> --agent <claude|agy|hermes|grok|opencode|codex> --role <role> [options]
Options:
--workspace PATH project directory (required)
--agent AGENT claude | agy | hermes | grok | opencode (required)
--agent AGENT claude | agy | hermes | grok | opencode | codex (required)
--role ROLE assigned role (required)
--session NAME herdr session name (default: derived from workspace)
--wrapper force use of ~/.local/bin/<session> wrapper even if not present
@@ -90,8 +90,8 @@ fi
[ -n "$WORKSPACE" ] || { echo "ERROR: --workspace required" >&2; usage; exit 2; }
[ -n "$AGENT" ] || { echo "ERROR: --agent required" >&2; usage; exit 2; }
case "$AGENT" in
claude|agy|hermes|grok|opencode) ;;
*) echo "ERROR: --agent must be claude, agy, hermes, grok, or opencode, got: $AGENT" >&2; exit 2 ;;
claude|agy|hermes|grok|opencode|codex) ;;
*) echo "ERROR: --agent must be claude, agy, hermes, grok, opencode, or codex, got: $AGENT" >&2; exit 2 ;;
esac
[ -n "$ROLE" ] || { echo "ERROR: --role required" >&2; usage; exit 2; }
[ -d "$WORKSPACE" ] || { echo "ERROR: workspace $WORKSPACE not a directory" >&2; exit 1; }
@@ -133,6 +133,14 @@ elif [ "$AGENT" = "opencode" ]; then
echo "ERROR: opencode is not functional or configured." >&2
exit 1
fi
elif [ "$AGENT" = "codex" ]; then
codex_home="${CODEX_HOME:-$HOME/.codex}"
if [ -f "$codex_home/auth.json" ] || [ -n "${OPENAI_API_KEY:-}" ]; then
true
elif ! codex --version >/dev/null 2>&1; then
echo "ERROR: codex is not functional or configured." >&2
exit 1
fi
fi
# 세션 이름 — lib.sh::derive_session_name 이 단일 소스 (P0-A)
@@ -190,6 +198,7 @@ if [ -z "$CMD_FULL" ]; then
hermes) CMD_FULL="${RESOLVED_BIN} --yolo --accept-hooks" ;;
grok) CMD_FULL="${RESOLVED_BIN} --permission-mode bypassPermissions" ;;
opencode) CMD_FULL="${RESOLVED_BIN} --auto --agent build" ;;
codex) CMD_FULL="${RESOLVED_BIN} --dangerously-bypass-approvals-and-sandbox" ;;
esac
fi
@@ -210,7 +219,7 @@ spawn() {
HERDR_SESSION_NAME="$HERDR_SESSION_NAME" _herdr new-session -d -s "$SESSION_NAME" -x 140 -y 40 -c "$WORKSPACE" "$CMD_FULL"
fi
;;
agy|hermes|grok)
agy|hermes|grok|codex)
HERDR_SESSION_NAME="$HERDR_SESSION_NAME" _herdr new-session -d -s "$SESSION_NAME" -x 140 -y 40 -c "$WORKSPACE" "$CMD_FULL"
;;
opencode)
@@ -219,7 +228,7 @@ spawn() {
fi
HERDR_SESSION_NAME="$HERDR_SESSION_NAME" _herdr new-session -d -s "$SESSION_NAME" -x 140 -y 40 -c "$WORKSPACE" "$CMD_FULL"
;;
*) echo "ERROR: --agent must be claude, agy, hermes, grok, or opencode, got: $AGENT" >&2; exit 2 ;;
*) echo "ERROR: --agent must be claude, agy, hermes, grok, opencode, or codex, got: $AGENT" >&2; exit 2 ;;
esac
}
@@ -328,6 +337,7 @@ if [ -n "$SUBMIT_JOB_PROMPT" ]; then
agy) delegate_agent="antigravity-cli" ;;
grok) delegate_agent="grok-build" ;;
opencode) delegate_agent="opencode-cli" ;;
codex) delegate_agent="codex-cli" ;;
*) echo "ERROR: cannot resolve delegate agent key for '$AGENT'" >&2; exit 2 ;;
esac
fi
@@ -442,6 +452,13 @@ elif agent == 'opencode':
entry['session_id_source'] = 'pending-discovery'
entry['session_id_verified'] = False
entry['last_visible_status'] = "unverified"
elif agent == 'codex':
cp = os.environ.get('CHILD_PID', '0')
entry['child_pid'] = int(cp) if cp.isdigit() else 0
entry['codex_session_id_own'] = None
entry['session_id_source'] = 'pending-discovery'
entry['session_id_verified'] = False
entry['last_visible_status'] = "unverified"
last_vis_override = os.environ.get('LAST_VISIBLE_STATUS_OVERRIDE', '')
if last_vis_override: