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

@@ -53,12 +53,12 @@ def resume_on_disk(s):
name = s.get('name', '')
cwd = (s.get('pane') or {}).get('cwd', '')
agent = None
for a in ('claude', 'agy', 'hermes', 'grok', 'opencode'):
for a in ('claude', 'agy', 'hermes', 'grok', 'opencode', 'codex'):
if any(name.endswith(f'-{r}-{a}') for r in ('creator', 'planner', 'reviewer')) or name.endswith(f'-{a}'):
agent = a
break
if not agent:
for a in ('claude', 'agy', 'hermes', 'grok', 'opencode'):
for a in ('claude', 'agy', 'hermes', 'grok', 'opencode', 'codex'):
if f"-{a}" in name or f"_{a}" in name:
agent = a
break
@@ -125,6 +125,29 @@ def resume_on_disk(s):
except Exception:
return 'MISSING'
return 'no'
if agent == 'codex':
u = s.get('codex_session_id_own')
if u:
codex_home = os.environ.get('CODEX_HOME', f"{home}/.codex")
db_matches = glob.glob(f"{codex_home}/state_*.sqlite")
if db_matches:
db = max(db_matches, key=os.path.getmtime)
try:
import sqlite3
conn = sqlite3.connect(db)
r = conn.execute("SELECT rollout_path FROM threads WHERE id=?", (u,)).fetchone()
conn.close()
if r and r[0] and os.path.exists(r[0]):
return 'yes'
if r:
return 'yes'
except Exception:
pass
m = glob.glob(f"{codex_home}/sessions/*/*/*/rollout-*-{u}.jsonl")
if m and os.path.exists(m[0]):
return 'yes'
return 'MISSING'
return 'no'
return '?'
@@ -231,12 +254,12 @@ def resume_on_disk(s):
name = s.get('name', '')
cwd = (s.get('pane') or {}).get('cwd', '')
agent = None
for a in ('claude', 'agy', 'hermes', 'grok', 'opencode'):
for a in ('claude', 'agy', 'hermes', 'grok', 'opencode', 'codex'):
if any(name.endswith(f'-{r}-{a}') for r in ('creator', 'planner', 'reviewer')) or name.endswith(f'-{a}'):
agent = a
break
if not agent:
for a in ('claude', 'agy', 'hermes', 'grok', 'opencode'):
for a in ('claude', 'agy', 'hermes', 'grok', 'opencode', 'codex'):
if f"-{a}" in name or f"_{a}" in name:
agent = a
break
@@ -303,6 +326,29 @@ def resume_on_disk(s):
except Exception:
return 'MISSING'
return 'no'
if agent == 'codex':
u = s.get('codex_session_id_own')
if u:
codex_home = os.environ.get('CODEX_HOME', f"{home}/.codex")
db_matches = glob.glob(f"{codex_home}/state_*.sqlite")
if db_matches:
db = max(db_matches, key=os.path.getmtime)
try:
import sqlite3
conn = sqlite3.connect(db)
r = conn.execute("SELECT rollout_path FROM threads WHERE id=?", (u,)).fetchone()
conn.close()
if r and r[0] and os.path.exists(r[0]):
return 'yes'
if r:
return 'yes'
except Exception:
pass
m = glob.glob(f"{codex_home}/sessions/*/*/*/rollout-*-{u}.jsonl")
if m and os.path.exists(m[0]):
return 'yes'
return 'MISSING'
return 'no'
return '?'