botmux 2.12.0 → 2.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/adapters/cli/claude-code.d.ts +9 -3
  2. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  3. package/dist/adapters/cli/claude-code.js +20 -12
  4. package/dist/adapters/cli/claude-code.js.map +1 -1
  5. package/dist/core/session-discovery.d.ts.map +1 -1
  6. package/dist/core/session-discovery.js +11 -1
  7. package/dist/core/session-discovery.js.map +1 -1
  8. package/dist/core/worker-pool.d.ts.map +1 -1
  9. package/dist/core/worker-pool.js +13 -9
  10. package/dist/core/worker-pool.js.map +1 -1
  11. package/dist/daemon.js +10 -9
  12. package/dist/daemon.js.map +1 -1
  13. package/dist/services/bridge-rotation-policy.d.ts +139 -0
  14. package/dist/services/bridge-rotation-policy.d.ts.map +1 -0
  15. package/dist/services/bridge-rotation-policy.js +125 -0
  16. package/dist/services/bridge-rotation-policy.js.map +1 -0
  17. package/dist/services/bridge-turn-queue.d.ts +9 -1
  18. package/dist/services/bridge-turn-queue.d.ts.map +1 -1
  19. package/dist/services/bridge-turn-queue.js +9 -2
  20. package/dist/services/bridge-turn-queue.js.map +1 -1
  21. package/dist/services/claude-transcript.d.ts +67 -0
  22. package/dist/services/claude-transcript.d.ts.map +1 -1
  23. package/dist/services/claude-transcript.js +228 -1
  24. package/dist/services/claude-transcript.js.map +1 -1
  25. package/dist/services/codex-bridge-queue.d.ts +56 -0
  26. package/dist/services/codex-bridge-queue.d.ts.map +1 -0
  27. package/dist/services/codex-bridge-queue.js +150 -0
  28. package/dist/services/codex-bridge-queue.js.map +1 -0
  29. package/dist/services/codex-transcript.d.ts +68 -0
  30. package/dist/services/codex-transcript.d.ts.map +1 -0
  31. package/dist/services/codex-transcript.js +233 -0
  32. package/dist/services/codex-transcript.js.map +1 -0
  33. package/dist/utils/idle-detector.d.ts.map +1 -1
  34. package/dist/utils/idle-detector.js +15 -4
  35. package/dist/utils/idle-detector.js.map +1 -1
  36. package/dist/worker.js +743 -114
  37. package/dist/worker.js.map +1 -1
  38. package/package.json +2 -2
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Reader for Codex's per-session rollout JSONL.
3
+ *
4
+ * Codex stores each session's full transcript at
5
+ * ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-<ts>-<cliSessionId>.jsonl
6
+ * and creates the file lazily on the first user submit. Inside, the bridge
7
+ * fallback only cares about two `response_item.payload.type === 'message'`
8
+ * shapes:
9
+ *
10
+ * - role=user → the user's prompt text (input_text content)
11
+ * - role=assistant +
12
+ * phase=final_answer → the model's final reply (output_text content)
13
+ *
14
+ * Why these and not `event_msg`:
15
+ * - `response_item` is the canonical transcript record; `event_msg` is a
16
+ * UI-event stream that can carry the same final text via two channels
17
+ * (`agent_message phase=final_answer` AND `task_complete.last_agent_message`).
18
+ * Picking `response_item` keeps the reader to a single source of truth
19
+ * and avoids any chance of double-emit if both paths are present.
20
+ * - Skipping role=developer (system instructions), phase=commentary
21
+ * (mid-turn status), reasoning, and function_call* keeps the bridge
22
+ * focused on what the user actually said and what the model finally
23
+ * answered — same scope as the Claude bridge.
24
+ *
25
+ * Pure I/O. Attribution belongs in CodexBridgeQueue.
26
+ */
27
+ import { existsSync, statSync, openSync, readSync, closeSync, readdirSync, readlinkSync } from 'node:fs';
28
+ import { homedir } from 'node:os';
29
+ import { join } from 'node:path';
30
+ const CODEX_SESSIONS_ROOT = join(homedir(), '.codex', 'sessions');
31
+ /** Extract the cliSessionId encoded in a rollout filename. Codex's session
32
+ * id is UUID-shaped (8-4-4-4-12 hex), which lets us anchor the regex on
33
+ * the UUID alone — the `<ts>` segment between "rollout-" and the sid
34
+ * contains its own dashes that would otherwise let a greedy match swallow
35
+ * parts of the sid. Returns undefined for paths that don't match. */
36
+ export function codexSessionIdFromRolloutPath(path) {
37
+ const m = /rollout-.*-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i.exec(path);
38
+ return m ? m[1] : undefined;
39
+ }
40
+ /** Find the rollout file an externally-running Codex process has open by
41
+ * walking `/proc/<pid>/fd/*`. The Codex process keeps fd open on its
42
+ * current rollout for the entire lifetime of the session, so this is the
43
+ * authoritative way to bind a Codex pid to its sessionId — far more
44
+ * reliable than scanning `~/.codex/sessions` by mtime (which would race
45
+ * with sibling Codex panes in the same project).
46
+ *
47
+ * Linux-only: relies on `/proc`. macOS/BSD callers should fall back to
48
+ * the cliSessionId path (read from `~/.codex/history.jsonl`'s last
49
+ * matching cwd entry) — but the use case for /proc-based discovery is
50
+ * /adopt, which already runs on Linux servers in practice. */
51
+ export function findCodexRolloutByPid(pid) {
52
+ if (!Number.isInteger(pid) || pid <= 0)
53
+ return undefined;
54
+ const fdDir = `/proc/${pid}/fd`;
55
+ if (!existsSync(fdDir))
56
+ return undefined;
57
+ let entries;
58
+ try {
59
+ entries = readdirSync(fdDir);
60
+ }
61
+ catch {
62
+ return undefined;
63
+ }
64
+ for (const fd of entries) {
65
+ let target;
66
+ try {
67
+ target = readlinkSync(join(fdDir, fd));
68
+ }
69
+ catch {
70
+ continue;
71
+ }
72
+ if (!target.endsWith('.jsonl'))
73
+ continue;
74
+ if (!target.includes('/.codex/sessions/'))
75
+ continue;
76
+ const sid = codexSessionIdFromRolloutPath(target);
77
+ if (sid)
78
+ return { path: target, cliSessionId: sid };
79
+ }
80
+ return undefined;
81
+ }
82
+ /** Split a drained event list into "history" (older than the live cutoff)
83
+ * and "live" (cutoff or newer). The Codex adopt bridge uses this when
84
+ * it discovers the rollout file LATE (after the user already typed in
85
+ * iTerm or sent a Lark message): drain-from-0 produces a mix of pre-
86
+ * adopt history and post-adopt live events. The worker then `absorb()`s
87
+ * the history (so it isn't replayed) and `ingest()`s the live partition
88
+ * (so the local-turn synthesis / fingerprint match still works). Pure
89
+ * function — no I/O, easy to test against fixed timestamps. */
90
+ export function splitCodexEventsByCutoff(events, liveSinceMs) {
91
+ const history = [];
92
+ const live = [];
93
+ for (const ev of events) {
94
+ if (ev.timestampMs < liveSinceMs)
95
+ history.push(ev);
96
+ else
97
+ live.push(ev);
98
+ }
99
+ return { history, live };
100
+ }
101
+ /** Locate the rollout file for a given Codex sessionId. Codex names files
102
+ * `rollout-<ts>-<sid>.jsonl`, so a suffix match is unambiguous. The
103
+ * directory tree is small (year/month/day) — a one-shot recursive scan
104
+ * is cheap enough that we don't bother caching. */
105
+ export function findCodexRolloutBySessionId(cliSessionId) {
106
+ if (!cliSessionId || !existsSync(CODEX_SESSIONS_ROOT))
107
+ return undefined;
108
+ const suffix = `-${cliSessionId}.jsonl`;
109
+ const stack = [CODEX_SESSIONS_ROOT];
110
+ while (stack.length > 0) {
111
+ const dir = stack.pop();
112
+ let entries;
113
+ try {
114
+ entries = readdirSync(dir);
115
+ }
116
+ catch {
117
+ continue;
118
+ }
119
+ for (const name of entries) {
120
+ const full = join(dir, name);
121
+ let st;
122
+ try {
123
+ st = statSync(full);
124
+ }
125
+ catch {
126
+ continue;
127
+ }
128
+ if (st.isDirectory()) {
129
+ stack.push(full);
130
+ }
131
+ else if (st.isFile() && name.endsWith(suffix)) {
132
+ return full;
133
+ }
134
+ }
135
+ }
136
+ return undefined;
137
+ }
138
+ /** Concatenate all text blocks of a content array. Codex rollout content
139
+ * is always an array of `{type, text}`; the kinds we care about are
140
+ * `input_text` (user) and `output_text` (assistant). Other block types
141
+ * (image_url, audio, etc.) are ignored — the bridge only forwards text. */
142
+ function joinTextBlocks(content, kind) {
143
+ if (!Array.isArray(content))
144
+ return '';
145
+ const parts = [];
146
+ for (const block of content) {
147
+ if (block && typeof block === 'object' && block.type === kind) {
148
+ const text = block.text;
149
+ if (typeof text === 'string')
150
+ parts.push(text);
151
+ }
152
+ }
153
+ return parts.join('');
154
+ }
155
+ /** Increment-read the rollout from `fromOffset`. Mirrors the byte-offset
156
+ * contract of claude-transcript.drainTranscript so callers can swap them
157
+ * out and reuse the existing fs.watch / poll wakeup machinery. */
158
+ export function drainCodexRollout(path, fromOffset) {
159
+ if (!existsSync(path))
160
+ return { events: [], newOffset: 0, pendingTail: '' };
161
+ let size;
162
+ try {
163
+ size = statSync(path).size;
164
+ }
165
+ catch {
166
+ return { events: [], newOffset: fromOffset, pendingTail: '' };
167
+ }
168
+ let start = fromOffset;
169
+ // Truncated/rotated jsonl — re-read from the top. Codex doesn't normally
170
+ // rewrite rollouts, but mirror Claude's defensive handling.
171
+ if (size < start)
172
+ start = 0;
173
+ if (size === start)
174
+ return { events: [], newOffset: start, pendingTail: '' };
175
+ const len = size - start;
176
+ const buf = Buffer.alloc(len);
177
+ const fd = openSync(path, 'r');
178
+ try {
179
+ readSync(fd, buf, 0, len, start);
180
+ }
181
+ finally {
182
+ closeSync(fd);
183
+ }
184
+ const text = buf.toString('utf8');
185
+ const lastNl = text.lastIndexOf('\n');
186
+ const completeText = lastNl >= 0 ? text.slice(0, lastNl + 1) : '';
187
+ const pendingTail = lastNl >= 0 ? text.slice(lastNl + 1) : text;
188
+ const newOffset = start + Buffer.byteLength(completeText, 'utf8');
189
+ const events = [];
190
+ // Track byte offset within the file as we walk lines so synthetic uuids
191
+ // are stable across re-drains.
192
+ let cursor = start;
193
+ for (const line of completeText.split('\n')) {
194
+ if (line.length === 0) {
195
+ cursor += 1; // the \n after an empty line
196
+ continue;
197
+ }
198
+ const lineByteLen = Buffer.byteLength(line, 'utf8') + 1; // include \n
199
+ const lineStart = cursor;
200
+ cursor += lineByteLen;
201
+ let obj;
202
+ try {
203
+ obj = JSON.parse(line);
204
+ }
205
+ catch {
206
+ continue;
207
+ }
208
+ if (obj?.type !== 'response_item')
209
+ continue;
210
+ const p = obj.payload;
211
+ if (!p || typeof p !== 'object' || p.type !== 'message')
212
+ continue;
213
+ const ts = typeof obj.timestamp === 'string' ? Date.parse(obj.timestamp) : NaN;
214
+ const timestampMs = Number.isFinite(ts) ? ts : Date.now();
215
+ if (p.role === 'user') {
216
+ const text = joinTextBlocks(p.content, 'input_text');
217
+ if (!text)
218
+ continue;
219
+ events.push({ uuid: `${path}:${lineStart}`, timestampMs, kind: 'user', text });
220
+ }
221
+ else if (p.role === 'assistant' && p.phase === 'final_answer') {
222
+ const text = joinTextBlocks(p.content, 'output_text');
223
+ if (!text)
224
+ continue;
225
+ events.push({ uuid: `${path}:${lineStart}`, timestampMs, kind: 'assistant_final', text });
226
+ }
227
+ // Skip role=developer (instructions), phase=commentary (mid-turn
228
+ // status), and any reasoning / function_call* events — see file
229
+ // header for rationale.
230
+ }
231
+ return { events, newOffset, pendingTail };
232
+ }
233
+ //# sourceMappingURL=codex-transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-transcript.js","sourceRoot":"","sources":["../../src/services/codex-transcript.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"idle-detector.d.ts","sourceRoot":"","sources":["../../src/utils/idle-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAY3D,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,eAAe,CAA8C;IACrE,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,SAAS,CAAS;gBAEd,GAAG,EAAE,UAAU;IAK3B,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAI5B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAwCxB,KAAK,IAAI,IAAI;IAQb,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,SAAS;CAKlB"}
1
+ {"version":3,"file":"idle-detector.d.ts","sourceRoot":"","sources":["../../src/utils/idle-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAY3D,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,eAAe,CAA8C;IACrE,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,SAAS,CAAS;gBAEd,GAAG,EAAE,UAAU;IAK3B,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAI5B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAoDxB,KAAK,IAAI,IAAI;IAQb,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,SAAS;CAKlB"}
@@ -23,8 +23,16 @@ export class IdleDetector {
23
23
  this.idleCallback = cb;
24
24
  }
25
25
  feed(data) {
26
- if (this.isIdle)
27
- return;
26
+ // A botmux-owned submit calls reset() before writing input, but adopted
27
+ // panes can also receive local terminal input while we are already idle.
28
+ // Treat any later PTY data as a fresh cycle so that local work can become
29
+ // idle and flush transcript-driven fallback output.
30
+ if (this.isIdle) {
31
+ this.isIdle = false;
32
+ this.outputTail = '';
33
+ this.readySeen = false;
34
+ this.lastSpinnerAt = Date.now();
35
+ }
28
36
  const stripped = this.stripAnsi(data);
29
37
  this.outputTail = (this.outputTail + stripped).slice(-500);
30
38
  // Track when the CLI's input prompt appears.
@@ -38,11 +46,14 @@ export class IdleDetector {
38
46
  }
39
47
  // Track spinner — but not if it's part of completion marker,
40
48
  // and not after ready pattern is seen (status bar chars like · are not real spinners)
41
- if (SPINNER_RE.test(stripped) && !(this.completionPattern?.test(this.outputTail)) && !this.readySeen) {
49
+ if (SPINNER_RE.test(stripped) && !(this.completionPattern?.test(stripped) || this.completionPattern?.test(this.outputTail)) && !this.readySeen) {
42
50
  this.lastSpinnerAt = Date.now();
43
51
  }
44
52
  // Strategy 1: CLI-specific completion marker
45
- if (this.completionPattern?.test(this.outputTail)) {
53
+ // Check the current chunk too: a single full-screen redraw can contain
54
+ // the completion line and enough trailing status text to push it out of
55
+ // the 500-char tail before this check runs.
56
+ if (this.completionPattern?.test(stripped) || this.completionPattern?.test(this.outputTail)) {
46
57
  this.clearTimer();
47
58
  this.quiescenceTimer = setTimeout(() => {
48
59
  this.quiescenceTimer = null;
@@ -1 +1 @@
1
- {"version":3,"file":"idle-detector.js","sourceRoot":"","sources":["../../src/utils/idle-detector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"idle-detector.js","sourceRoot":"","sources":["../../src/utils/idle-detector.ts"],"names":[],"mappings":"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"}