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.
Files changed (51) hide show
  1. package/SECURITY.md +1 -1
  2. package/dist/claude.js +3 -3
  3. package/dist/claude.js.map +1 -1
  4. package/dist/cli-help.js +5 -5
  5. package/dist/cli-help.js.map +1 -1
  6. package/dist/cubes.js +2 -2
  7. package/dist/cubes.js.map +1 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +4 -3
  10. package/dist/index.js.map +1 -1
  11. package/dist/log-stream.d.ts +6 -2
  12. package/dist/log-stream.d.ts.map +1 -1
  13. package/dist/log-stream.js +36 -11
  14. package/dist/log-stream.js.map +1 -1
  15. package/dist/opencode-drone.d.ts +7 -2
  16. package/dist/opencode-drone.d.ts.map +1 -1
  17. package/dist/opencode-drone.js +291 -64
  18. package/dist/opencode-drone.js.map +1 -1
  19. package/dist/opencode-plugin.d.ts.map +1 -1
  20. package/dist/opencode-plugin.js +12 -2
  21. package/dist/opencode-plugin.js.map +1 -1
  22. package/dist/regen-format.d.ts.map +1 -1
  23. package/dist/regen-format.js +15 -1
  24. package/dist/regen-format.js.map +1 -1
  25. package/dist/remote-client.d.ts +13 -0
  26. package/dist/remote-client.d.ts.map +1 -1
  27. package/dist/remote-client.js +25 -0
  28. package/dist/remote-client.js.map +1 -1
  29. package/dist/seat-commands.js +12 -12
  30. package/dist/seat-commands.js.map +1 -1
  31. package/dist/stream-status.d.ts.map +1 -1
  32. package/dist/stream-status.js +1 -0
  33. package/dist/stream-status.js.map +1 -1
  34. package/dist/unknown-subcommand.d.ts +1 -1
  35. package/dist/unknown-subcommand.d.ts.map +1 -1
  36. package/dist/unknown-subcommand.js +1 -1
  37. package/dist/unknown-subcommand.js.map +1 -1
  38. package/docs/RELEASING.md +96 -25
  39. package/package.json +2 -2
  40. package/src/claude.ts +3 -3
  41. package/src/cli-help.ts +5 -5
  42. package/src/cubes.ts +2 -2
  43. package/src/index.ts +4 -1
  44. package/src/log-stream.ts +49 -12
  45. package/src/opencode-drone.ts +328 -65
  46. package/src/opencode-plugin.ts +13 -1
  47. package/src/regen-format.ts +15 -1
  48. package/src/remote-client.ts +36 -0
  49. package/src/seat-commands.ts +12 -12
  50. package/src/stream-status.ts +3 -0
  51. package/src/unknown-subcommand.ts +1 -1
@@ -564,6 +564,7 @@ async function localReadLogPage(
564
564
 
565
565
  interface PendingWakePage {
566
566
  entries: Array<{
567
+ id?: unknown;
567
568
  drone_id?: unknown;
568
569
  message?: unknown;
569
570
  visibility?: unknown;
@@ -622,6 +623,41 @@ export async function hasPendingWakeActivity(
622
623
  }
623
624
  }
624
625
 
626
+ /**
627
+ * Inspect the durable unread window for one specific SSE entry without
628
+ * advancing the agent-owned cursor. Wake nonces are retries of that entry, so
629
+ * the entry itself remains the authority for whether another wake is owed.
630
+ */
631
+ export async function hasPendingWakeEntry(
632
+ active: ActiveCube,
633
+ entryId: string,
634
+ deps: {
635
+ getCursor?: typeof getLocalServerCursor;
636
+ readPage?: (active: ActiveCube, opts: { cursor: LocalServerCursor | null; limit: number }) => Promise<PendingWakePage>;
637
+ } = {},
638
+ ): Promise<boolean> {
639
+ if (!active.serverTrustIdentity) {
640
+ throw new Error('Selected Borg server authority state is missing or unreadable');
641
+ }
642
+
643
+ const getCursor = deps.getCursor ?? getLocalServerCursor;
644
+ const readPage = deps.readPage ?? localReadLogPage;
645
+ let cursor = await getCursor(localCursorBinding(active));
646
+
647
+ for (;;) {
648
+ const page: PendingWakePage = await readPage(active, { cursor, limit: 500 });
649
+ if (page.entries.some((entry) =>
650
+ entry.id === entryId && isPendingWakeEntry(entry, active.droneId)
651
+ )) return true;
652
+ if (!page.has_more) return false;
653
+ if (!page.cursor ||
654
+ (cursor && page.cursor.id === cursor.id && page.cursor.created_at === cursor.created_at)) {
655
+ throw new Error('Local Borg server returned a non-advancing log cursor');
656
+ }
657
+ cursor = page.cursor;
658
+ }
659
+ }
660
+
625
661
  async function resolveLocalLogCursor(
626
662
  active: ActiveCube,
627
663
  since: string,
@@ -143,7 +143,7 @@ function oneLine(value: string): string {
143
143
 
144
144
  export function formatLocalSeatRows(rows: readonly LocalSeatRow[]): string {
145
145
  if (rows.length === 0) {
146
- return 'No drone seats are registered on this machine. Run `borg assimilate` in a project repository to create one.\n';
146
+ return 'No drones are registered on this machine. Run `borg assimilate` in a project repository to create one.\n';
147
147
  }
148
148
  const headings = ['DRONE', 'CUBE', 'STATE', 'CLI', 'WORKTREE'];
149
149
  const values = rows.map((row) => [
@@ -176,7 +176,7 @@ export async function runSeats(deps: SeatCommandDeps): Promise<number> {
176
176
  deps.stdout(formatLocalSeatRows(await readLocalSeatRows(deps)));
177
177
  return 0;
178
178
  } catch (error) {
179
- deps.stderr(`borg seats: could not read the local registry: ${error instanceof Error ? error.message : String(error)}\n`);
179
+ deps.stderr(`borg drones: could not read the local registry: ${error instanceof Error ? error.message : String(error)}\n`);
180
180
  return 1;
181
181
  }
182
182
  }
@@ -198,7 +198,7 @@ export async function runLaunchSeat(
198
198
  if (cubeIds.size === 0) {
199
199
  deps.stderr(
200
200
  `borg launch: no cube named '${args.cube}' is registered on this machine. ` +
201
- `Run \`borg seats\` to list this machine's cubes and drones.\n`,
201
+ `Run \`borg drones\` to list this machine's cubes and drones.\n`,
202
202
  );
203
203
  return 1;
204
204
  }
@@ -212,19 +212,19 @@ export async function runLaunchSeat(
212
212
  if (matches.length === 0) {
213
213
  if (rows.length === 0) {
214
214
  deps.stderr(
215
- `borg launch: drone '${args.target}' is not in this machine's seat registry. ` +
215
+ `borg launch: drone '${args.target}' is not in this machine's registry. ` +
216
216
  `The registry is local to each machine and lists only drones assimilated here. ` +
217
- `Run \`borg seats\` on the machine where the drone was created.\n`,
217
+ `Run \`borg drones\` on the machine where the drone was created.\n`,
218
218
  );
219
219
  } else if (args.cube) {
220
220
  deps.stderr(
221
221
  `borg launch: no drone matches '${args.target}' in cube '${args.cube}'. ` +
222
- `Run \`borg seats\` to list the drones you can launch.\n`,
222
+ `Run \`borg drones\` to list the drones you can launch.\n`,
223
223
  );
224
224
  } else {
225
225
  deps.stderr(
226
226
  `borg launch: no drone matches '${args.target}' on this machine. ` +
227
- `Run \`borg seats\` to list the drones you can launch.\n`,
227
+ `Run \`borg drones\` to list the drones you can launch.\n`,
228
228
  );
229
229
  }
230
230
  return 1;
@@ -248,9 +248,9 @@ export async function runLaunchSeat(
248
248
  }
249
249
  if (selected.state !== 'active') {
250
250
  deps.stderr(
251
- `borg launch: drone '${selected.droneLabel}' has a pending seat (shown as \`pending\` in \`borg seats\`) — ` +
251
+ `borg launch: drone '${selected.droneLabel}' is not fully assimilated (shown as \`pending\` in \`borg drones\`) — ` +
252
252
  `its assimilation did not complete, so launching now would start an unattached session. ` +
253
- `To complete the seat, run \`borg assimilate\` in ${selected.worktree}, then run ` +
253
+ `To finish it, run \`borg assimilate\` in ${selected.worktree}, then run ` +
254
254
  `\`borg launch ${selected.droneLabel}\` again.\n`,
255
255
  );
256
256
  return 1;
@@ -264,8 +264,8 @@ export async function runLaunchSeat(
264
264
  }
265
265
  if (!preferred) {
266
266
  deps.stderr(
267
- `borg launch: did not launch '${selected.droneLabel}' — its seat registration changed before the launch could start. ` +
268
- `Run \`borg seats\` to see the current state, then try again.\n`,
267
+ `borg launch: did not launch '${selected.droneLabel}' — its registration changed before the launch could start. ` +
268
+ `Run \`borg drones\` to see the current state, then try again.\n`,
269
269
  );
270
270
  return 1;
271
271
  }
@@ -277,7 +277,7 @@ export async function runLaunchSeat(
277
277
  deps.stderr(
278
278
  `borg launch: did not launch '${selected.droneLabel}' — the worktree at ${selected.worktree} would resume ` +
279
279
  `'${preferred.droneLabel}' (cube '${preferred.name}') instead. To resume '${preferred.droneLabel}', run \`borg\` ` +
280
- `in that worktree. To review this machine's seats, run \`borg seats\`.\n`,
280
+ `in that worktree. To review this machine's drones, run \`borg drones\`.\n`,
281
281
  );
282
282
  return 1;
283
283
  }
@@ -272,6 +272,9 @@ export function renderStreamStatus(inputs: RenderInputs): string {
272
272
  );
273
273
  lines.push(`- **OpenCode retried**: ${delivery.retried}`);
274
274
  lines.push(`- **OpenCode failed**: ${delivery.failed}`);
275
+ lines.push(
276
+ '- **OpenCode delivery-state meaning**: delivered-unconfirmed counts entries that may have been submitted but are not visible in session history; failed counts entries that could not be submitted or were rejected, until the durable source entry is observed consumed.'
277
+ );
275
278
  }
276
279
 
277
280
  // Runtime-specific wake-path warning. The wire-down case takes
@@ -21,7 +21,7 @@ export const KNOWN_SUBCOMMANDS = [
21
21
  'recover-enrollment',
22
22
  'spawn',
23
23
  'cleanup',
24
- 'seats',
24
+ 'drones',
25
25
  'launch',
26
26
  'launch-all',
27
27
  'server',