mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
82 lines
3.4 KiB
TypeScript
82 lines
3.4 KiB
TypeScript
/**
|
|||
|
|
* @fileoverview A resumed codex session must keep its thread-id alias across
|
||
|
|
* `start()`, not just at construction.
|
||
|
|
*
|
||
|
|
* `claudeSessionId` doubles as the generic "external transcript id" the unified
|
||
|
|
* list folds a Past-Sessions row into its owning session by. For codex that id
|
||
|
|
* is the rollout's thread id, and losing it is not cosmetic: the stale row stays
|
||
|
|
* in PAST and still resumes, so clicking it starts a SECOND `codex resume` on a
|
||
|
|
* thread already open in the live pane.
|
||
|
|
*
|
||
|
|
* The bug this pins: the alias was wired into the constructor only. `start()`
|
||
|
|
* recomputes `claudeSessionId` at two further points — the mux branch and the
|
||
|
|
* unconditional "third reset point" that runs after both the mux and direct-PTY
|
||
|
|
* paths — and both listed only Claude's `resumeSessionId` and omp's. For codex
|
||
|
|
* both are undefined, so every mux reattach and every boot recovery reset the
|
||
|
|
* alias back to the Codeman id and the duplicate came back. The existing comment
|
||
|
|
* at the third reset point already warned that omitting omp's fallback there
|
||
|
|
* "stomps the mux branch's correctly-resolved OMP alias"; codex needed the same.
|
||
|
|
*
|
||
|
|
* Mirrors `test/omp-fresh-run-no-resume.test.ts`, which drives a real `Session`
|
||
|
|
* against the in-memory tmux layer that vitest substitutes.
|
||
|
|
*/
|
||
|
|
import { mkdirSync, rmSync } from 'node:fs';
|
||
|
|
import { homedir } from 'node:os';
|
||
|
|
import { join } from 'node:path';
|
||
|
|
import { afterEach, describe, expect, it } from 'vitest';
|
||
|
|
|
||
|
|
import { Session } from '../src/session.js';
|
||
|
|
import { TmuxManager } from '../src/tmux-manager.js';
|
||
|
|
|
||
|
|
describe('codex: a resumed thread id survives start()', () => {
|
||
|
|
const workingDir = join(homedir(), 'codeman-cases', 'codex-resume-alias');
|
||
|
|
const THREAD_ID = '01a060f0-0361-7f91-abde-b283020db0d7';
|
||
|
|
const sessions: Session[] = [];
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
for (const s of sessions.splice(0)) s.stop();
|
||
|
|
rmSync(workingDir, { recursive: true, force: true });
|
||
|
|
});
|
||
|
|
|
||
|
|
function makeSession(useMux: boolean): Session {
|
||
|
|
mkdirSync(workingDir, { recursive: true });
|
||
|
|
const session = new Session({
|
||
|
|
workingDir,
|
||
|
|
mode: 'codex',
|
||
|
|
codexConfig: { resumeSessionId: THREAD_ID },
|
||
|
|
mux: new TmuxManager(),
|
||
|
|
useMux,
|
||
|
|
});
|
||
|
|
sessions.push(session);
|
||
|
|
return session;
|
||
|
|
}
|
||
|
|
|
||
|
|
it('carries the thread id from construction', () => {
|
||
|
|
expect(makeSession(true).claudeSessionId).toBe(THREAD_ID);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('still carries it after starting under mux', async () => {
|
||
|
|
const session = makeSession(true);
|
||
|
|
await session.startInteractive();
|
||
|
|
expect(session.claudeSessionId).toBe(THREAD_ID);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('refuses to start without mux at all, so the mux path is the only one to cover', async () => {
|
||
|
|
// codex declares `requiresMux`, so there is no direct-PTY codex session for
|
||
|
|
// the third reset point to run against on its own — the assertion above is
|
||
|
|
// the whole surface.
|
||
|
|
await expect(makeSession(false).startInteractive()).rejects.toThrow(/require tmux/i);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('a fresh codex session keeps the Codeman id, having no thread of its own', async () => {
|
||
|
|
mkdirSync(workingDir, { recursive: true });
|
||
|
|
const session = new Session({ workingDir, mode: 'codex', mux: new TmuxManager(), useMux: true });
|
||
|
|
sessions.push(session);
|
||
|
|
|
||
|
|
await session.startInteractive();
|
||
|
|
|
||
|
|
// Nothing to alias to yet — codex has not written the rollout. Such a
|
||
|
|
// session is folded from the other side, by originator (codexThreadBySessionId).
|
||
|
|
expect(session.claudeSessionId).toBe(session.id);
|
||
|
|
});
|
||
|
|
});
|