botmux 2.60.0 → 2.61.0
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.
- package/README.en.md +3 -3
- package/README.md +4 -4
- package/dist/bot-registry.d.ts +9 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +16 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/core/command-discovery.d.ts +24 -0
- package/dist/core/command-discovery.d.ts.map +1 -0
- package/dist/core/command-discovery.js +201 -0
- package/dist/core/command-discovery.js.map +1 -0
- package/dist/core/command-handler.d.ts +9 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +50 -3
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +8 -1
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.js +3 -3
- package/dist/daemon.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +12 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +12 -0
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +17 -0
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +84 -0
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/services/codex-bridge-queue.d.ts +4 -0
- package/dist/services/codex-bridge-queue.d.ts.map +1 -1
- package/dist/services/codex-bridge-queue.js +117 -84
- package/dist/services/codex-bridge-queue.js.map +1 -1
- package/dist/services/cursor-transcript.d.ts +47 -0
- package/dist/services/cursor-transcript.d.ts.map +1 -0
- package/dist/services/cursor-transcript.js +324 -0
- package/dist/services/cursor-transcript.js.map +1 -0
- package/dist/worker.js +146 -5
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -39,11 +39,14 @@
|
|
|
39
39
|
* has finalText.
|
|
40
40
|
*/
|
|
41
41
|
import { makeFingerprint, normaliseForFingerprint } from './bridge-turn-queue.js';
|
|
42
|
+
const UNMATCHED_REPLAY_WINDOW_MS = 5_000;
|
|
43
|
+
const MAX_BUFFERED_UNMATCHED_EVENTS = 20;
|
|
42
44
|
export class CodexBridgeQueue {
|
|
43
45
|
seen = new Set();
|
|
44
46
|
queue = [];
|
|
45
47
|
collecting = null;
|
|
46
48
|
localTurnsEnabled = false;
|
|
49
|
+
bufferedUnmatched = [];
|
|
47
50
|
/** Lower bound (ms) for synthesising local turns — protects against a
|
|
48
51
|
* fresh-empty attach replaying historical iTerm conversation as
|
|
49
52
|
* "live" local input. Typically set to the moment adopt was wired up. */
|
|
@@ -61,6 +64,8 @@ export class CodexBridgeQueue {
|
|
|
61
64
|
setLocalTurns(enabled, lowerBoundMs = Date.now()) {
|
|
62
65
|
this.localTurnsEnabled = enabled;
|
|
63
66
|
this.localLowerBoundMs = lowerBoundMs;
|
|
67
|
+
if (enabled)
|
|
68
|
+
this.bufferedUnmatched = [];
|
|
64
69
|
}
|
|
65
70
|
/** Push a pending Lark turn anchored to the message text. The fingerprint
|
|
66
71
|
* derived from `message` is what the upcoming `user` event must contain
|
|
@@ -74,6 +79,7 @@ export class CodexBridgeQueue {
|
|
|
74
79
|
contentFingerprint: makeFingerprint(message),
|
|
75
80
|
markTimeMs,
|
|
76
81
|
});
|
|
82
|
+
this.replayBufferedUnmatched(markTimeMs);
|
|
77
83
|
}
|
|
78
84
|
/** Drop all pending turns. Used when the worker decides it can't reliably
|
|
79
85
|
* attribute future events (e.g. a teardown). */
|
|
@@ -81,6 +87,7 @@ export class CodexBridgeQueue {
|
|
|
81
87
|
const dropped = this.queue.splice(0);
|
|
82
88
|
if (this.collecting && dropped.includes(this.collecting))
|
|
83
89
|
this.collecting = null;
|
|
90
|
+
this.bufferedUnmatched = [];
|
|
84
91
|
return dropped;
|
|
85
92
|
}
|
|
86
93
|
/** Process newly-appended events. Idempotent on uuid: events with seen
|
|
@@ -90,91 +97,117 @@ export class CodexBridgeQueue {
|
|
|
90
97
|
if (!ev.uuid || this.seen.has(ev.uuid))
|
|
91
98
|
continue;
|
|
92
99
|
this.seen.add(ev.uuid);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
100
|
+
this.ingestOne(ev, true);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
replayBufferedUnmatched(markTimeMs) {
|
|
104
|
+
if (this.bufferedUnmatched.length === 0)
|
|
105
|
+
return;
|
|
106
|
+
const replay = this.bufferedUnmatched.filter(ev => ev.timestampMs >= markTimeMs - UNMATCHED_REPLAY_WINDOW_MS);
|
|
107
|
+
this.bufferedUnmatched = [];
|
|
108
|
+
for (const ev of replay)
|
|
109
|
+
this.ingestOne(ev, false);
|
|
110
|
+
}
|
|
111
|
+
rememberUnmatched(ev) {
|
|
112
|
+
this.bufferedUnmatched.push(ev);
|
|
113
|
+
if (this.bufferedUnmatched.length > MAX_BUFFERED_UNMATCHED_EVENTS) {
|
|
114
|
+
this.bufferedUnmatched.splice(0, this.bufferedUnmatched.length - MAX_BUFFERED_UNMATCHED_EVENTS);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
ingestOne(ev, bufferUnmatched) {
|
|
118
|
+
if (ev.kind === 'user') {
|
|
119
|
+
// First decide whether this user event is a REAL turn-start: either it
|
|
120
|
+
// matches the head pending Lark turn's fingerprint (and isn't tooOld),
|
|
121
|
+
// or — in adopt mode — it synthesises a local turn. Both the HOL-drop
|
|
122
|
+
// and the actual start key off this decision.
|
|
123
|
+
const next = this.queue.find(t => !t.started);
|
|
124
|
+
const tooOld = !!next && next.markTimeMs !== undefined && ev.timestampMs < next.markTimeMs - UNMATCHED_REPLAY_WINDOW_MS;
|
|
125
|
+
let fingerprintOk = true;
|
|
126
|
+
if (next?.contentFingerprint) {
|
|
127
|
+
fingerprintOk = normaliseForFingerprint(ev.text).includes(next.contentFingerprint);
|
|
128
|
+
}
|
|
129
|
+
const willStartNext = !!next && !tooOld && fingerprintOk;
|
|
130
|
+
const willSynthLocal = !willStartNext && this.localTurnsEnabled && ev.timestampMs >= this.localLowerBoundMs - UNMATCHED_REPLAY_WINDOW_MS;
|
|
131
|
+
// HOL-block drop (codex 0.134.0 active-turn steer): when a real new
|
|
132
|
+
// turn-start arrives while a turn is still collecting with no finalText,
|
|
133
|
+
// codex steered/merged this input into the active turn — it processes
|
|
134
|
+
// both as ONE turn and emits a single combined assistant_final, so the
|
|
135
|
+
// collecting turn will NEVER get its own final. Drop it now, otherwise
|
|
136
|
+
// it sits at the queue head forever and `drainEmittable()` wedges
|
|
137
|
+
// (started, no finalText → breaks the FIFO scan). Gating on "is a real
|
|
138
|
+
// turn-start" reuses the tooOld/fingerprint freshness already proven for
|
|
139
|
+
// turn-start, so the same 5s-skew invariant applies to both: a replayed
|
|
140
|
+
// historical user event is tooOld → won't start a turn → won't evict a
|
|
141
|
+
// live collecting turn; and a non-matching stray user event (non-adopt)
|
|
142
|
+
// is ignored rather than treated as a turn boundary. Mirrors Claude's
|
|
143
|
+
// BridgeTurnQueue.handleTurnStart HOL drop (which keys off "no assistant
|
|
144
|
+
// text yet" — the streaming-transcript equivalent of "no finalText").
|
|
145
|
+
if ((willStartNext || willSynthLocal) && this.collecting && this.collecting.finalText === undefined) {
|
|
146
|
+
const idx = this.queue.indexOf(this.collecting);
|
|
147
|
+
if (idx >= 0)
|
|
148
|
+
this.queue.splice(idx, 1);
|
|
149
|
+
this.collecting = null;
|
|
150
|
+
}
|
|
151
|
+
if (willStartNext) {
|
|
152
|
+
next.started = true;
|
|
153
|
+
next.sourceSessionId = ev.sourceSessionId;
|
|
154
|
+
// Anchor the bridge-fallback suppression window to when the turn
|
|
155
|
+
// ACTUALLY started processing (the transcript user event's
|
|
156
|
+
// timestamp), not when the worker marked it. With type-ahead the
|
|
157
|
+
// worker marks turn N+1 immediately after turn N (both at flush
|
|
158
|
+
// time), but CoCo only writes turn N+1's user event when it
|
|
159
|
+
// dequeues it — i.e. after turn N's assistant_final. Without this
|
|
160
|
+
// override the [markTimeMs, nextTurn.markTimeMs) windows are all
|
|
161
|
+
// bunched at flush time, so turn N's own `botmux send` (which
|
|
162
|
+
// lands seconds later, after the model replies) falls OUTSIDE its
|
|
163
|
+
// own window and the fallback isn't suppressed → duplicate emit.
|
|
164
|
+
// `max` (not bare assignment) keeps the lower bound from ever
|
|
165
|
+
// moving backwards: a dequeue event can only be at or after the
|
|
166
|
+
// mark, and the -5s tooOld tolerance must not be able to widen the
|
|
167
|
+
// window into a previous turn's sends. Mirrors what Claude's
|
|
168
|
+
// BridgeTurnQueue.handleTurnStart does with eventTimeMs.
|
|
169
|
+
if (next.markTimeMs === undefined)
|
|
170
|
+
next.markTimeMs = ev.timestampMs;
|
|
171
|
+
else
|
|
172
|
+
next.markTimeMs = Math.max(next.markTimeMs, ev.timestampMs);
|
|
173
|
+
this.collecting = next;
|
|
174
|
+
}
|
|
175
|
+
else if (willSynthLocal) {
|
|
176
|
+
// Adopt mode local input: user typed in iTerm, no Lark
|
|
177
|
+
// fingerprint match. Synthesise a local turn so the assistant
|
|
178
|
+
// reply still reaches Lark. Insert AHEAD of any unstarted Lark
|
|
179
|
+
// turn so emit order matches when the event hit the transcript.
|
|
180
|
+
const localTurn = {
|
|
181
|
+
turnId: `codex-local-${ev.uuid}`,
|
|
182
|
+
started: true,
|
|
183
|
+
isLocal: true,
|
|
184
|
+
userText: ev.text,
|
|
185
|
+
markTimeMs: ev.timestampMs,
|
|
186
|
+
sourceSessionId: ev.sourceSessionId,
|
|
187
|
+
};
|
|
188
|
+
const insertAt = this.queue.findIndex(t => !t.started);
|
|
189
|
+
if (insertAt === -1)
|
|
190
|
+
this.queue.push(localTurn);
|
|
191
|
+
else
|
|
192
|
+
this.queue.splice(insertAt, 0, localTurn);
|
|
193
|
+
this.collecting = localTurn;
|
|
194
|
+
}
|
|
195
|
+
else if (bufferUnmatched && !this.localTurnsEnabled) {
|
|
196
|
+
// Cursor can write the Lark/user line to JSONL before the daemon IPC
|
|
197
|
+
// that marks the turn reaches this worker. Keep a tiny recent buffer
|
|
198
|
+
// so mark() can replay it instead of losing the line to `seen`.
|
|
199
|
+
this.rememberUnmatched(ev);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else if (ev.kind === 'assistant_final') {
|
|
203
|
+
if (this.collecting) {
|
|
204
|
+
if (this.collecting.sourceSessionId && ev.sourceSessionId && this.collecting.sourceSessionId !== ev.sourceSessionId)
|
|
205
|
+
return;
|
|
206
|
+
this.collecting.finalText = ev.text;
|
|
207
|
+
this.collecting = null;
|
|
170
208
|
}
|
|
171
|
-
else if (
|
|
172
|
-
|
|
173
|
-
if (this.collecting.sourceSessionId && ev.sourceSessionId && this.collecting.sourceSessionId !== ev.sourceSessionId)
|
|
174
|
-
continue;
|
|
175
|
-
this.collecting.finalText = ev.text;
|
|
176
|
-
this.collecting = null;
|
|
177
|
-
}
|
|
209
|
+
else if (bufferUnmatched && !this.localTurnsEnabled) {
|
|
210
|
+
this.rememberUnmatched(ev);
|
|
178
211
|
}
|
|
179
212
|
}
|
|
180
213
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-bridge-queue.js","sourceRoot":"","sources":["../../src/services/codex-bridge-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"codex-bridge-queue.js","sourceRoot":"","sources":["../../src/services/codex-bridge-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CodexBridgeEvent } from './codex-transcript.js';
|
|
2
|
+
/** Default `~/.cursor/projects` root. Overridable by callers (tests) so the
|
|
3
|
+
* scan doesn't depend on a real home directory. */
|
|
4
|
+
export declare function cursorProjectsRoot(): string;
|
|
5
|
+
/** Extract the chatId encoded in a Cursor store.db path of the shape
|
|
6
|
+
* `.../.cursor/chats/<projectHash>/<chatId>/store.db` (also matches the
|
|
7
|
+
* `-wal` / `-shm` sidecar files SQLite keeps open). The chatId is the same
|
|
8
|
+
* UUID used to name the agent-transcript JSONL, so it's the bridge between
|
|
9
|
+
* the open fd and the transcript file. Returns undefined for non-matching
|
|
10
|
+
* paths. */
|
|
11
|
+
export declare function cursorChatIdFromStoreDbPath(path: string): string | undefined;
|
|
12
|
+
/** Find the chatId of an externally-running cursor-agent process by reading
|
|
13
|
+
* the store.db file it keeps open. cursor-agent holds an fd on its current
|
|
14
|
+
* chat's SQLite store for the whole session lifetime, which makes this the
|
|
15
|
+
* authoritative pid→chatId binding — far more reliable than scanning chat
|
|
16
|
+
* dirs by mtime (which would race with sibling cursor-agent panes).
|
|
17
|
+
*
|
|
18
|
+
* Linux: `/proc/<pid>/fd/*` fast path. macOS / BSD: `lsof -p <pid> -Fn`
|
|
19
|
+
* fallback (same shape as codex-transcript.findCodexRolloutByPid). */
|
|
20
|
+
export declare function findCursorChatIdByPid(pid: number): string | undefined;
|
|
21
|
+
/** Locate the agent-transcript JSONL for a given chatId. The chatId is a
|
|
22
|
+
* globally-unique UUID, so a one-shot scan of the (small) projects root for
|
|
23
|
+
* `<slug>/agent-transcripts/<chatId>/<chatId>.jsonl` is unambiguous and
|
|
24
|
+
* avoids having to reproduce Cursor's opaque cwd→slug hashing. */
|
|
25
|
+
export declare function findCursorTranscriptByChatId(chatId: string, projectsRoot?: string): string | undefined;
|
|
26
|
+
/** Resolve the transcript path for an externally-running cursor-agent pid:
|
|
27
|
+
* pid → open store.db → chatId → agent-transcript JSONL. Returns both the
|
|
28
|
+
* path and the chatId so the caller can remember the chatId for a later
|
|
29
|
+
* retry if the JSONL isn't on disk yet. */
|
|
30
|
+
export declare function findCursorTranscriptByPid(pid: number, projectsRoot?: string): {
|
|
31
|
+
path: string;
|
|
32
|
+
chatId: string;
|
|
33
|
+
} | undefined;
|
|
34
|
+
export interface CursorDrainResult {
|
|
35
|
+
events: CodexBridgeEvent[];
|
|
36
|
+
/** Byte offset of the last fully-parsed line + its trailing \n. The next
|
|
37
|
+
* drain should pass this back as fromOffset. */
|
|
38
|
+
newOffset: number;
|
|
39
|
+
/** A line written without its terminating \n yet — informational; only
|
|
40
|
+
* complete lines produce events. */
|
|
41
|
+
pendingTail: string;
|
|
42
|
+
}
|
|
43
|
+
/** Increment-read the transcript from `fromOffset`. Mirrors the byte-offset
|
|
44
|
+
* contract of codex-transcript.drainCodexRollout so the worker can reuse the
|
|
45
|
+
* same fs.watch / poll wakeup machinery and the shared CodexBridgeQueue. */
|
|
46
|
+
export declare function drainCursorTranscript(path: string, fromOffset: number): CursorDrainResult;
|
|
47
|
+
//# sourceMappingURL=cursor-transcript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-transcript.d.ts","sourceRoot":"","sources":["../../src/services/cursor-transcript.ts"],"names":[],"mappings":"AAwDA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAM9D;oDACoD;AACpD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;;;aAKa;AACb,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI5E;AAED;;;;;;;uEAOuE;AACvE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgCrE;AAED;;;mEAGmE;AACnE,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,YAAY,GAAE,MAA6B,GAC1C,MAAM,GAAG,SAAS,CASpB;AAED;;;4CAG4C;AAC5C,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,EACX,YAAY,GAAE,MAA6B,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAK9C;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B;qDACiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB;yCACqC;IACrC,WAAW,EAAE,MAAM,CAAC;CACrB;AA8ED;;6EAE6E;AAC7E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,iBAAiB,CA4DzF"}
|