borgmcp 3.8.0 → 3.10.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/SECURITY.md +1 -1
- package/dist/claude.js +3 -3
- package/dist/claude.js.map +1 -1
- package/dist/cli-help.js +5 -5
- package/dist/cli-help.js.map +1 -1
- package/dist/cubes.js +2 -2
- package/dist/cubes.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/log-stream.d.ts +6 -2
- package/dist/log-stream.d.ts.map +1 -1
- package/dist/log-stream.js +36 -11
- package/dist/log-stream.js.map +1 -1
- package/dist/opencode-drone.d.ts +7 -2
- package/dist/opencode-drone.d.ts.map +1 -1
- package/dist/opencode-drone.js +291 -64
- package/dist/opencode-drone.js.map +1 -1
- package/dist/opencode-plugin.d.ts.map +1 -1
- package/dist/opencode-plugin.js +12 -2
- package/dist/opencode-plugin.js.map +1 -1
- package/dist/regen-format.d.ts.map +1 -1
- package/dist/regen-format.js +15 -1
- package/dist/regen-format.js.map +1 -1
- package/dist/remote-client.d.ts +13 -0
- package/dist/remote-client.d.ts.map +1 -1
- package/dist/remote-client.js +25 -0
- package/dist/remote-client.js.map +1 -1
- package/dist/seat-commands.js +12 -12
- package/dist/seat-commands.js.map +1 -1
- package/dist/stream-status.d.ts.map +1 -1
- package/dist/stream-status.js +1 -0
- package/dist/stream-status.js.map +1 -1
- package/dist/unknown-subcommand.d.ts +1 -1
- package/dist/unknown-subcommand.d.ts.map +1 -1
- package/dist/unknown-subcommand.js +1 -1
- package/dist/unknown-subcommand.js.map +1 -1
- package/docs/RELEASING.md +96 -25
- package/package.json +2 -2
- package/src/claude.ts +3 -3
- package/src/cli-help.ts +5 -5
- package/src/cubes.ts +2 -2
- package/src/index.ts +4 -1
- package/src/log-stream.ts +49 -12
- package/src/opencode-drone.ts +328 -65
- package/src/opencode-plugin.ts +13 -1
- package/src/regen-format.ts +15 -1
- package/src/remote-client.ts +36 -0
- package/src/seat-commands.ts +12 -12
- package/src/stream-status.ts +3 -0
- package/src/unknown-subcommand.ts +1 -1
package/src/log-stream.ts
CHANGED
|
@@ -59,6 +59,7 @@ import { formatCubeActivityWakeMessage } from './cube-activity-wake-copy.js';
|
|
|
59
59
|
import { readBoundedResponseBody } from './server-response.js';
|
|
60
60
|
import { BorgServerError } from './server-errors.js';
|
|
61
61
|
import { markSeatRejected } from './seats.js';
|
|
62
|
+
import { hasPendingWakeEntry as hasPendingDurableWakeEntry } from './remote-client.js';
|
|
62
63
|
import {
|
|
63
64
|
acquireStreamLease,
|
|
64
65
|
readOwnershipSnapshot,
|
|
@@ -124,13 +125,16 @@ function isProcessAlive(pid: number): boolean {
|
|
|
124
125
|
* Used by defaultDeps when no explicit injectOpenCode is supplied.
|
|
125
126
|
*/
|
|
126
127
|
let _moduleInjectOpenCode:
|
|
127
|
-
| ((text: string, entryId: string, allowSubmit: boolean) => Promise<boolean>)
|
|
128
|
+
| ((text: string, entryId: string, allowSubmit: boolean, sourceEntryId?: string) => Promise<boolean>)
|
|
128
129
|
| undefined;
|
|
130
|
+
let _moduleSettleOpenCodeEntry: ((sourceEntryId: string) => void) | undefined;
|
|
129
131
|
|
|
130
132
|
export function setModuleInjectOpenCode(
|
|
131
|
-
fn: (text: string, entryId: string, allowSubmit: boolean) => Promise<boolean
|
|
133
|
+
fn: (text: string, entryId: string, allowSubmit: boolean, sourceEntryId?: string) => Promise<boolean>,
|
|
134
|
+
settle: (sourceEntryId: string) => void,
|
|
132
135
|
): void {
|
|
133
136
|
_moduleInjectOpenCode = fn;
|
|
137
|
+
_moduleSettleOpenCodeEntry = settle;
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
/**
|
|
@@ -403,8 +407,13 @@ export interface StreamDeps {
|
|
|
403
407
|
injectOpenCode?: (
|
|
404
408
|
text: string,
|
|
405
409
|
entryId: string,
|
|
406
|
-
allowSubmit: boolean
|
|
410
|
+
allowSubmit: boolean,
|
|
411
|
+
sourceEntryId?: string,
|
|
407
412
|
) => Promise<boolean>;
|
|
413
|
+
/** Inspect whether one retry source remains beyond the durable unread cursor. */
|
|
414
|
+
hasPendingWakeEntry?: (active: ActiveCube, entryId: string) => Promise<boolean>;
|
|
415
|
+
/** Clear in-process retry diagnostics after the durable entry is consumed. */
|
|
416
|
+
settleOpenCodeEntry?: (sourceEntryId: string) => void;
|
|
408
417
|
}
|
|
409
418
|
|
|
410
419
|
const defaultDeps: Required<StreamDeps> = {
|
|
@@ -420,10 +429,15 @@ const defaultDeps: Required<StreamDeps> = {
|
|
|
420
429
|
abortSignal: new AbortController().signal,
|
|
421
430
|
ownerDeps: {},
|
|
422
431
|
ownerStaleMs: 70_000,
|
|
423
|
-
injectOpenCode: (text, entryId, allowSubmit) =>
|
|
432
|
+
injectOpenCode: (text, entryId, allowSubmit, sourceEntryId) =>
|
|
424
433
|
_moduleInjectOpenCode
|
|
425
|
-
? _moduleInjectOpenCode(text, entryId, allowSubmit)
|
|
434
|
+
? _moduleInjectOpenCode(text, entryId, allowSubmit, sourceEntryId)
|
|
426
435
|
: Promise.resolve(false),
|
|
436
|
+
hasPendingWakeEntry: (active, entryId) => hasPendingDurableWakeEntry(
|
|
437
|
+
active as Parameters<typeof hasPendingDurableWakeEntry>[0],
|
|
438
|
+
entryId,
|
|
439
|
+
),
|
|
440
|
+
settleOpenCodeEntry: (sourceEntryId) => _moduleSettleOpenCodeEntry?.(sourceEntryId),
|
|
427
441
|
};
|
|
428
442
|
|
|
429
443
|
// ------------------------------------------------------------------
|
|
@@ -678,6 +692,8 @@ export async function streamOnce(
|
|
|
678
692
|
hwmDivergenceGraceMs,
|
|
679
693
|
abortSignal,
|
|
680
694
|
injectOpenCode,
|
|
695
|
+
hasPendingWakeEntry,
|
|
696
|
+
settleOpenCodeEntry,
|
|
681
697
|
} = { ...defaultDeps, ...deps };
|
|
682
698
|
|
|
683
699
|
assertUuidShape(active.cubeId, 'cube_id');
|
|
@@ -819,6 +835,17 @@ export async function streamOnce(
|
|
|
819
835
|
pendingHwmDivergence = { hwm, timer };
|
|
820
836
|
};
|
|
821
837
|
|
|
838
|
+
const shouldDeliverWakeRetry = async (entryId: string): Promise<boolean> => {
|
|
839
|
+
try {
|
|
840
|
+
if (await hasPendingWakeEntry(active, entryId)) return true;
|
|
841
|
+
settleOpenCodeEntry(entryId);
|
|
842
|
+
} catch {
|
|
843
|
+
// A retry is never authoritative enough to cross the model boundary on
|
|
844
|
+
// its own. The durable inbox and a later retry remain available.
|
|
845
|
+
}
|
|
846
|
+
return false;
|
|
847
|
+
};
|
|
848
|
+
|
|
822
849
|
// Bounded recent-id set for replay-on-reconnect dedup per spec §(3).
|
|
823
850
|
// Set + FIFO array for O(1) membership + bounded memory.
|
|
824
851
|
const recentIds = new Set<string>();
|
|
@@ -844,6 +871,10 @@ export async function streamOnce(
|
|
|
844
871
|
const line = formatInboxLine(withSseEventId(ev.data, ev.id));
|
|
845
872
|
const deliveryId = ev.wake_nonce ?? ev.id;
|
|
846
873
|
const isReping = ev.wake_nonce !== undefined;
|
|
874
|
+
if (isReping && !(await shouldDeliverWakeRetry(ev.id))) {
|
|
875
|
+
markEventPersisted(ev.id, ev.data?.created_at ?? '');
|
|
876
|
+
return 'persisted-skip';
|
|
877
|
+
}
|
|
847
878
|
const eventHwm = ev.data?.created_at
|
|
848
879
|
? { id: ev.id, created_at: ev.data.created_at }
|
|
849
880
|
: null;
|
|
@@ -867,12 +898,11 @@ export async function streamOnce(
|
|
|
867
898
|
await hasInboxEntryId(active.cubeId, active.droneId, ev.id, line)
|
|
868
899
|
);
|
|
869
900
|
if (alreadyPersisted) {
|
|
870
|
-
// An ordinary entry at/before the persisted cursor
|
|
871
|
-
//
|
|
872
|
-
//
|
|
873
|
-
// underlying inbox line is already durable.
|
|
901
|
+
// An ordinary entry at/before the persisted cursor must not re-enter the
|
|
902
|
+
// OpenCode queue. A still-unread re-ping may reconcile the prior attempt;
|
|
903
|
+
// its source entry ID prevents a new nonce from resubmitting that prompt.
|
|
874
904
|
if (isReping) {
|
|
875
|
-
await injectOpenCode(formatOpenCodeWakePrompt(line), deliveryId, true);
|
|
905
|
+
await injectOpenCode(formatOpenCodeWakePrompt(line), deliveryId, true, ev.id);
|
|
876
906
|
}
|
|
877
907
|
markEventPersisted(ev.id, ev.data?.created_at ?? '');
|
|
878
908
|
return 'persisted-skip';
|
|
@@ -880,7 +910,10 @@ export async function streamOnce(
|
|
|
880
910
|
// The inbox append is the durable record. OpenCode injection is only the
|
|
881
911
|
// wake attempt and may return before the agent finishes processing.
|
|
882
912
|
await appendLine(active.cubeId, active.droneId, line);
|
|
883
|
-
|
|
913
|
+
const openCodeDelivered = isReping
|
|
914
|
+
? await injectOpenCode(formatOpenCodeWakePrompt(line), deliveryId, true, ev.id)
|
|
915
|
+
: await injectOpenCode(formatOpenCodeWakePrompt(line), deliveryId, true);
|
|
916
|
+
if (!openCodeDelivered) {
|
|
884
917
|
if (ev.wake_nonce === undefined) wakeCodex(formatCodexWakePrompt(line));
|
|
885
918
|
else wakeCodex(formatCodexWakePrompt(line), ev.wake_nonce);
|
|
886
919
|
}
|
|
@@ -1198,7 +1231,11 @@ export async function streamOnce(
|
|
|
1198
1231
|
if (isRecentWakeReplay) {
|
|
1199
1232
|
const line = formatInboxLine(withSseEventId(event.data, event.id));
|
|
1200
1233
|
const wakeNonce = event.wake_nonce;
|
|
1201
|
-
if (
|
|
1234
|
+
if (
|
|
1235
|
+
wakeNonce !== undefined &&
|
|
1236
|
+
await shouldDeliverWakeRetry(event.id) &&
|
|
1237
|
+
!(await injectOpenCode(formatOpenCodeWakePrompt(line), wakeNonce, true, event.id))
|
|
1238
|
+
) {
|
|
1202
1239
|
wakeCodex(formatCodexWakePrompt(line), wakeNonce);
|
|
1203
1240
|
}
|
|
1204
1241
|
continue;
|