feat: add codex-worktree session adapter

Adds the third session adapter (after dmux-tmux and claude-history),
normalizing Codex rollout sessions into the harness-neutral
ecc.session.v1 snapshot. Reads ~/.codex/sessions rollout JSONL,
derives objective (skipping the AGENTS.md preamble + leading message
UUID), model, originator, worktree cwd, and best-effort git branch.

This is step 1 of ECC-2.0-SESSION-ADAPTER-DISCOVERY (move the
abstraction beyond tmux + Claude-history) and supports the
wrap/adapt control-pane strategy: ECC reads sessions from any
harness rather than owning one UX.

- scripts/lib/session-adapters/codex-worktree.js: adapter + rollout parser
- canonical-session.js: normalizeCodexWorktreeSession
- registry.js: register adapter, codex/codex-worktree target types
- tests/lib/session-adapters-codex.test.js: 4 tests (unit + registry routing)
This commit is contained in:
Affaan Mustafa
2026-06-04 16:20:57 -04:00
parent bc8e12bb80
commit e391419026
4 changed files with 548 additions and 2 deletions
@@ -520,11 +520,63 @@ function normalizeClaudeHistorySession(session, sourceTarget) {
});
}
function normalizeCodexWorktreeSession(session, sourceTarget) {
const state = session.active ? 'active' : 'recorded';
const objective = typeof session.objective === 'string' ? session.objective : '';
const worker = {
id: session.sessionId,
label: session.sessionId,
state,
health: 'healthy',
branch: session.branch || null,
worktree: session.cwd || null,
runtime: {
kind: 'codex-session',
command: 'codex',
pid: null,
active: Boolean(session.active),
dead: !session.active,
},
intent: {
objective,
seedPaths: []
},
outputs: {
summary: [],
validation: [],
remainingRisks: []
},
artifacts: {
sessionFile: session.sessionPath || null,
model: session.model || null,
originator: session.originator || null,
cliVersion: session.cliVersion || null,
startedAt: session.startedAt || null,
recordCount: Number.isInteger(session.recordCount) ? session.recordCount : null
}
};
return validateCanonicalSnapshot({
schemaVersion: SESSION_SCHEMA_VERSION,
adapterId: 'codex-worktree',
session: {
id: session.sessionId,
kind: 'codex-worktree',
state,
repoRoot: session.cwd || null,
sourceTarget
},
workers: [worker],
aggregates: buildAggregates([worker])
});
}
module.exports = {
SESSION_SCHEMA_VERSION,
buildAggregates,
getFallbackSessionRecordingPath,
normalizeClaudeHistorySession,
normalizeCodexWorktreeSession,
normalizeDmuxSnapshot,
persistCanonicalSnapshot,
validateCanonicalSnapshot