borgmcp 2.16.1 → 3.0.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 (115) hide show
  1. package/README.md +5 -3
  2. package/dist/assimilate-cmd.js +43 -43
  3. package/dist/assimilate-cmd.js.map +1 -1
  4. package/dist/assimilate-deps.js +2 -2
  5. package/dist/assimilate-deps.js.map +1 -1
  6. package/dist/assimilate-guard.js +4 -4
  7. package/dist/assimilate-guard.js.map +1 -1
  8. package/dist/assimilate-welcome.js +2 -2
  9. package/dist/assimilate-welcome.js.map +1 -1
  10. package/dist/claude.d.ts +0 -2
  11. package/dist/claude.d.ts.map +1 -1
  12. package/dist/claude.js +2 -15
  13. package/dist/claude.js.map +1 -1
  14. package/dist/cleanup-cmd.d.ts +1 -1
  15. package/dist/cleanup-cmd.d.ts.map +1 -1
  16. package/dist/cleanup-cmd.js +3 -3
  17. package/dist/cleanup-cmd.js.map +1 -1
  18. package/dist/cli-help.d.ts +1 -2
  19. package/dist/cli-help.d.ts.map +1 -1
  20. package/dist/cli-help.js +15 -24
  21. package/dist/cli-help.js.map +1 -1
  22. package/dist/cubes.js +2 -2
  23. package/dist/cubes.js.map +1 -1
  24. package/dist/docs-sections.js +1 -1
  25. package/dist/docs-sections.js.map +1 -1
  26. package/dist/drone-lifecycle.d.ts.map +1 -1
  27. package/dist/drone-lifecycle.js +3 -3
  28. package/dist/drone-lifecycle.js.map +1 -1
  29. package/dist/drone-management.js +1 -1
  30. package/dist/drone-management.js.map +1 -1
  31. package/dist/evict-drone.js +2 -2
  32. package/dist/evict-drone.js.map +1 -1
  33. package/dist/foreign-path-reminder.js +1 -1
  34. package/dist/foreign-path-reminder.js.map +1 -1
  35. package/dist/inbox-monitor.js +2 -2
  36. package/dist/inbox-monitor.js.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/launch-all-cmd.js +12 -12
  40. package/dist/launch-all-cmd.js.map +1 -1
  41. package/dist/launch-all-discovery.js +1 -1
  42. package/dist/launch-all-discovery.js.map +1 -1
  43. package/dist/opencode-seat-identity.js +5 -5
  44. package/dist/opencode-seat-identity.js.map +1 -1
  45. package/dist/regen-format.d.ts.map +1 -1
  46. package/dist/regen-format.js +2 -1
  47. package/dist/regen-format.js.map +1 -1
  48. package/dist/remote-client.js +1 -1
  49. package/dist/remote-client.js.map +1 -1
  50. package/dist/repository-cube-init.js +1 -1
  51. package/dist/repository-cube-init.js.map +1 -1
  52. package/dist/reset-local-seat-cmd.d.ts +2 -2
  53. package/dist/reset-local-seat-cmd.d.ts.map +1 -1
  54. package/dist/reset-local-seat-cmd.js +17 -17
  55. package/dist/reset-local-seat-cmd.js.map +1 -1
  56. package/dist/seat-reattach-guard.js +1 -1
  57. package/dist/seat-reattach-guard.js.map +1 -1
  58. package/dist/seat-store.d.ts +1 -1
  59. package/dist/seat-store.js +6 -6
  60. package/dist/seat-store.js.map +1 -1
  61. package/dist/seats.js +1 -1
  62. package/dist/seats.js.map +1 -1
  63. package/dist/server-handshake.js +1 -1
  64. package/dist/server-handshake.js.map +1 -1
  65. package/dist/stream-status.js +3 -3
  66. package/dist/stream-status.js.map +1 -1
  67. package/dist/tool-manifest.js +1 -1
  68. package/dist/tool-manifest.js.map +1 -1
  69. package/dist/unknown-subcommand.d.ts +1 -1
  70. package/dist/unknown-subcommand.d.ts.map +1 -1
  71. package/dist/unknown-subcommand.js +1 -2
  72. package/dist/unknown-subcommand.js.map +1 -1
  73. package/dist/worktree-lifecycle.d.ts +0 -16
  74. package/dist/worktree-lifecycle.d.ts.map +1 -1
  75. package/dist/worktree-lifecycle.js +0 -38
  76. package/dist/worktree-lifecycle.js.map +1 -1
  77. package/docs/EXTRACTION_PROVENANCE.md +2 -2
  78. package/docs/LOCAL_SERVER.md +2 -2
  79. package/docs/SEAT_LIFECYCLE.md +19 -19
  80. package/package.json +1 -1
  81. package/src/assimilate-cmd.ts +43 -43
  82. package/src/assimilate-deps.ts +2 -2
  83. package/src/assimilate-guard.ts +4 -4
  84. package/src/assimilate-welcome.ts +2 -2
  85. package/src/claude.ts +2 -17
  86. package/src/cleanup-cmd.ts +4 -4
  87. package/src/cli-help.ts +15 -27
  88. package/src/cubes.ts +2 -2
  89. package/src/docs-sections.ts +1 -1
  90. package/src/drone-lifecycle.ts +3 -3
  91. package/src/drone-management.ts +1 -1
  92. package/src/evict-drone.ts +2 -2
  93. package/src/foreign-path-reminder.ts +1 -1
  94. package/src/inbox-monitor.ts +2 -2
  95. package/src/index.ts +1 -1
  96. package/src/launch-all-cmd.ts +12 -12
  97. package/src/launch-all-discovery.ts +1 -1
  98. package/src/opencode-seat-identity.ts +5 -5
  99. package/src/regen-format.ts +2 -1
  100. package/src/remote-client.ts +1 -1
  101. package/src/repository-cube-init.ts +1 -1
  102. package/src/reset-local-seat-cmd.ts +17 -17
  103. package/src/seat-reattach-guard.ts +1 -1
  104. package/src/seat-store.ts +6 -6
  105. package/src/seats.ts +1 -1
  106. package/src/server-handshake.ts +1 -1
  107. package/src/stream-status.ts +3 -3
  108. package/src/tool-manifest.ts +1 -1
  109. package/src/unknown-subcommand.ts +1 -2
  110. package/src/worktree-lifecycle.ts +0 -45
  111. package/dist/sync.d.ts +0 -129
  112. package/dist/sync.d.ts.map +0 -1
  113. package/dist/sync.js +0 -286
  114. package/dist/sync.js.map +0 -1
  115. package/src/sync.ts +0 -363
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "borgmcp",
3
- "version": "2.16.1",
3
+ "version": "3.0.0",
4
4
  "description": "Coordinate AI coding agents in shared cubes. Works with Claude Code, Codex, and OpenCode.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -615,7 +615,7 @@ function reportServerFailure(
615
615
  );
616
616
  return 1;
617
617
  }
618
- if (/seat store lock file .* is stale/i.test(message)) {
618
+ if (/(?:private|seat) store lock file .* is stale/i.test(message)) {
619
619
  // RULED option (b): a lock whose recorded holder is DEAD (or whose payload is
620
620
  // corrupt) is NEVER auto-removed. Surface the fail-closed guidance verbatim —
621
621
  // it already names the exact lockfile path and the delete-only-if-no-borg
@@ -626,16 +626,16 @@ function reportServerFailure(
626
626
  );
627
627
  return 1;
628
628
  }
629
- if (/(?:seat|credential) store is busy/i.test(message)) {
629
+ if (/(?:private|seat|credential) store is busy/i.test(message)) {
630
630
  deps.stderr(
631
- `Borg's local seat store is busy for ${apiUrl} because another Borg process is ` +
632
- `creating or resuming saved seat state. Wait for it to finish, then rerun ${retryCommand}.\n`,
631
+ `Borg's private store is busy for ${apiUrl} because another Borg process is ` +
632
+ `creating or resuming saved connection state. Wait for it to finish, then rerun ${retryCommand}.\n`,
633
633
  );
634
634
  return 1;
635
635
  }
636
- if (/(?:local )?seat store|(?:secure )?credential (?:store|storage)/i.test(message)) {
636
+ if (/(?:(?:local )?(?:private|seat) store|(?:secure )?credential (?:store|storage))/i.test(message)) {
637
637
  deps.stderr(
638
- `Borg could not access its local seat store for ${apiUrl}. ` +
638
+ `Borg could not access its private store for ${apiUrl}. ` +
639
639
  `Ensure its directory on this machine is readable and writable, then rerun ${retryCommand}.\n`,
640
640
  );
641
641
  return 1;
@@ -680,7 +680,7 @@ function reportServerFailure(
680
680
  }
681
681
 
682
682
  function resetLocalSeatCommand(apiUrl: string): string {
683
- return `\`borg reset-local-seat --host ${apiUrl}\``;
683
+ return `\`borg reset-local-connection --host ${apiUrl}\``;
684
684
  }
685
685
 
686
686
  // Pin-matched terminal session diagnosis. This is intentionally output-only:
@@ -699,7 +699,7 @@ function diagnoseSessionTermination(
699
699
  : `borg assimilate --host ${apiUrl} --enroll`;
700
700
  deps.stderr(
701
701
  `${message}\n` +
702
- `Next: run borg reset-local-seat, then ${recovery}.\n`,
702
+ `Next: run borg reset-local-connection, then ${recovery}.\n`,
703
703
  );
704
704
  return 1;
705
705
  }
@@ -1287,9 +1287,9 @@ export async function runAssimilate(
1287
1287
  }
1288
1288
  } else {
1289
1289
  deps.stderr(
1290
- `This worktree has saved seat metadata for ${authority.apiUrl}, but its local session ` +
1291
- 'credential could not be loaded from the local seat store. No new seat was created. Run ' +
1292
- `${resetLocalSeatCommand(authority.apiUrl)} to clear this worktree's saved seat, then ` +
1290
+ `This worktree has a saved connection to ${authority.apiUrl}, but its local session ` +
1291
+ 'credential could not be loaded from the private store. No drone was created. Run ' +
1292
+ `${resetLocalSeatCommand(authority.apiUrl)} to clear this worktree's saved connection, then ` +
1293
1293
  `ask the operator for a new invitation and rerun ${localAssimilateCommand(authority.apiUrl, true)}.\n`,
1294
1294
  );
1295
1295
  return 1;
@@ -1301,8 +1301,8 @@ export async function runAssimilate(
1301
1301
  existing.serverTrustIdentity !== auth.serverTrustIdentity)
1302
1302
  ) {
1303
1303
  deps.stderr(
1304
- `This worktree's saved seat does not match ${authority.apiUrl}. ` +
1305
- 'No new seat was created. Restore the expected server identity or use a fresh ' +
1304
+ `This worktree's saved connection does not match ${authority.apiUrl}. ` +
1305
+ 'No drone was created. Restore the expected server identity or use a fresh ' +
1306
1306
  `worktree, then rerun ${localAssimilateCommand(authority.apiUrl)}.\n`,
1307
1307
  );
1308
1308
  return 1;
@@ -1323,7 +1323,7 @@ export async function runAssimilate(
1323
1323
  );
1324
1324
  // Canonical rotated/revoked path: a pin-matched 401 on THIS worktree's
1325
1325
  // saved bearer. PURE DIAGNOSIS — attach never mutates local state on a
1326
- // rejection; it points at the offline `borg reset-local-seat` command.
1326
+ // rejection; it points at the offline `borg reset-local-connection` command.
1327
1327
  // Distinct from unreachable/404/5xx/trust-mismatch, which stay
1328
1328
  // indeterminate below.
1329
1329
  if (status === 'revoked') {
@@ -1338,7 +1338,7 @@ export async function runAssimilate(
1338
1338
  // The saved SESSION bearer was rejected WITHOUT the typed takeover code
1339
1339
  // (a bare/other 401). Non-destructive: re-enroll, never a seat reset.
1340
1340
  deps.stderr(
1341
- `The saved enrollment for ${authority.apiUrl} was rejected. No new seat was created ` +
1341
+ `The saved enrollment for ${authority.apiUrl} was rejected. No drone was created ` +
1342
1342
  `and nothing was changed. Re-enroll with ${localAssimilateCommand(authority.apiUrl, true)} ` +
1343
1343
  'from the operator’s terminal.\n',
1344
1344
  );
@@ -1349,7 +1349,7 @@ export async function runAssimilate(
1349
1349
  // fix it — verify this is the expected server / re-initialization.
1350
1350
  deps.stderr(
1351
1351
  `Borg could not verify the expected server identity for ${authority.apiUrl}. ` +
1352
- 'No new seat was created. Verify that this is the expected server; if it was ' +
1352
+ 'No drone was created. Verify that this is the expected server; if it was ' +
1353
1353
  're-initialized, restore the expected identity, then rerun ' +
1354
1354
  `${localAssimilateCommand(authority.apiUrl)}.\n`,
1355
1355
  );
@@ -1361,7 +1361,7 @@ export async function runAssimilate(
1361
1361
  // fix it; align versions. Non-destructive: no seat created, nothing reset.
1362
1362
  deps.stderr(
1363
1363
  `Borg reached ${authority.apiUrl} but it did not recognize this worktree's drone ` +
1364
- 'endpoint — the client and server versions are likely incompatible. No new seat ' +
1364
+ 'endpoint — the client and server versions are likely incompatible. No drone ' +
1365
1365
  'was created and nothing was changed. Update the Borg client and/or server so ' +
1366
1366
  `their versions match, then rerun ${localAssimilateCommand(authority.apiUrl)}.\n`,
1367
1367
  );
@@ -1372,7 +1372,7 @@ export async function runAssimilate(
1372
1372
  // check the server, then retry. Non-destructive.
1373
1373
  deps.stderr(
1374
1374
  `Borg reached ${authority.apiUrl} but it returned a server error while verifying ` +
1375
- "this worktree's saved seat. No new seat was created. Check the server (its logs / " +
1375
+ "this worktree's saved connection. No drone was created. Check the server (its logs / " +
1376
1376
  `\`borg-mcp-server start\`), then rerun ${localAssimilateCommand(authority.apiUrl)}.\n`,
1377
1377
  );
1378
1378
  return 1;
@@ -1381,16 +1381,16 @@ export async function runAssimilate(
1381
1381
  // CR5: transport failure / timeout (unreachable) or a genuinely ambiguous
1382
1382
  // failure (indeterminate) — both transient. Start or restart the server.
1383
1383
  deps.stderr(
1384
- `Borg could not verify this worktree's saved seat on ${authority.apiUrl}. ` +
1385
- 'No new seat was created. Start or restart the server with ' +
1384
+ `Borg could not verify this worktree's saved connection to ${authority.apiUrl}. ` +
1385
+ 'No drone was created. Start or restart the server with ' +
1386
1386
  `\`borg-mcp-server start\`, then rerun ${localAssimilateCommand(authority.apiUrl)}.\n`,
1387
1387
  );
1388
1388
  return 1;
1389
1389
  }
1390
1390
  if (status === 'live' && !savedLocalRole) {
1391
1391
  deps.stderr(
1392
- `Borg verified this worktree's saved seat on ${authority.apiUrl}, but its saved ` +
1393
- 'role is unavailable. No new seat was created. Ask the server operator to restore ' +
1392
+ `Borg verified this worktree's saved connection to ${authority.apiUrl}, but its saved ` +
1393
+ 'role is unavailable. No drone was created. Ask the server operator to restore ' +
1394
1394
  `the role, then rerun ${localAssimilateCommand(authority.apiUrl)}.\n`,
1395
1395
  );
1396
1396
  return 1;
@@ -1401,8 +1401,8 @@ export async function runAssimilate(
1401
1401
  } else if (existing && args.flags.here) {
1402
1402
  if (existing.serverTrustIdentity !== undefined || existing.apiUrl !== auth.apiUrl) {
1403
1403
  deps.stderr(
1404
- 'This worktree\'s saved seat belongs to a different Borg authority. ' +
1405
- 'No new seat was created; use a fresh worktree.\n',
1404
+ 'This worktree\'s saved connection belongs to a different Borg authority. ' +
1405
+ 'No drone was created; use a fresh worktree.\n',
1406
1406
  );
1407
1407
  return 1;
1408
1408
  }
@@ -1583,7 +1583,7 @@ export async function runAssimilate(
1583
1583
  // a non-reattach DroneEvictedError falls through to the generic message.
1584
1584
  if (err instanceof DroneEvictedError && reattachPriorId != null) {
1585
1585
  deps.stderr(
1586
- `This worktree's saved seat on ${authority.apiUrl} was evicted. ` +
1586
+ `This worktree's drone on ${authority.apiUrl} was evicted. ` +
1587
1587
  `Remove this worktree, or from a fresh worktree run ` +
1588
1588
  `${localAssimilateCommand(authority.apiUrl)}.\n`,
1589
1589
  );
@@ -1593,7 +1593,7 @@ export async function runAssimilate(
1593
1593
  // Reached only after a successful pinned-TLS attach, so it is pin-matched by
1594
1594
  // construction — a pin mismatch throws a distinct trust error and never
1595
1595
  // enters this branch. Attach mutates NOTHING; it recommends the offline
1596
- // `borg reset-local-seat` command.
1596
+ // `borg reset-local-connection` command.
1597
1597
  if (err instanceof BorgServerError && reattachPriorId != null) {
1598
1598
  if (err.code === 'SESSION_REVOKED') {
1599
1599
  return diagnoseSessionTermination(deps, authority.apiUrl, 'revoked');
@@ -1616,7 +1616,7 @@ export async function runAssimilate(
1616
1616
  // concurrent offline reset, or a competing enroll). No FS/network mutation
1617
1617
  // happened; never silently recreate.
1618
1618
  deps.stderr(
1619
- `This worktree's saved local seat on ${authority.apiUrl} changed before the attach ` +
1619
+ `This worktree's saved connection to ${authority.apiUrl} changed before the attach ` +
1620
1620
  '(a concurrent reset or enroll); no credential was created or sent and nothing was ' +
1621
1621
  `changed. Re-run ${localAssimilateCommand(authority.apiUrl)} to attach against the ` +
1622
1622
  'current state.\n',
@@ -1641,16 +1641,16 @@ export async function runAssimilate(
1641
1641
  const assignedRole =
1642
1642
  cubeDetail.roles.find((r) => r.id === result.role_id) ?? resolvedRole;
1643
1643
  if (result.result === 'reused') {
1644
- // The seat's existing role is authoritative on an idempotent reattach —
1644
+ // The drone's existing role is authoritative on an idempotent reattach —
1645
1645
  // a role difference is expected, not a grant fallback. The bearer is
1646
1646
  // reused, not rotated: no new drone minted.
1647
1647
  deps.stderr(
1648
- `re-attached to existing seat ${result.drone_label} (same session, no new drone minted)\n`
1648
+ `re-attached as ${result.drone_label} (same session, no new drone minted)\n`
1649
1649
  );
1650
1650
  } else if (assignedRole.id !== resolvedRole.id) {
1651
1651
  deps.stderr(
1652
1652
  `The requested role "${resolvedRole.name}" was unavailable; ` +
1653
- `attached to the "${assignedRole.name}" seat instead.\n`
1653
+ `attached under the "${assignedRole.name}" role instead.\n`
1654
1654
  );
1655
1655
  }
1656
1656
 
@@ -1814,7 +1814,7 @@ export async function runAssimilate(
1814
1814
  }
1815
1815
  deps.stderr(
1816
1816
  `spawned sibling worktree at ${candidate} on branch ${wtBranch} (${startRef}); ` +
1817
- `the original dir keeps its active drone binding — run \`borg reset-local-seat\` there if that binding is stale.\n`
1817
+ `the original dir keeps its active drone binding — run \`borg reset-local-connection\` there if that binding is stale.\n`
1818
1818
  );
1819
1819
  deps.chdir(candidate);
1820
1820
  deps.stderr(renderWorktreeSteeringNote(candidate, wtBranch, projectRoot));
@@ -1903,7 +1903,7 @@ export async function runAssimilate(
1903
1903
  // EXACT prior binding with its live-bearer digest; eviction remint = EXACT ref
1904
1904
  // only, bearer intentionally replaced; fresh/sibling = ABSENT).
1905
1905
  if (result.finalize === undefined || deps.finalizeServerSeat === undefined) {
1906
- deps.stderr('Local Borg server session metadata is incomplete; no seat was saved.\n');
1906
+ deps.stderr('Local Borg server session metadata is incomplete; no connection was saved.\n');
1907
1907
  rollbackWorktree();
1908
1908
  return 1;
1909
1909
  }
@@ -1959,12 +1959,12 @@ export async function runAssimilate(
1959
1959
  if (bindOutcome === 'bound') {
1960
1960
  // The worktree now owns a durable locator (the bound-pending record points
1961
1961
  // here). PRESERVE it. Truthful convergence copy: a rerun FROM here re-sends
1962
- // the identical bearer (no duplicate), and `reset-local-seat` from here now
1962
+ // the identical bearer (no duplicate), and `reset-local-connection` from here now
1963
1963
  // discovers + clears the bound-pending record.
1964
1964
  deps.stderr(
1965
1965
  `This worktree's secure session on ${auth.apiUrl} did not finish activating, but ` +
1966
- 'its resumable seat state was PRESERVED here. This worktree was NOT removed. From ' +
1967
- `here, re-run ${localAssimilateCommand(auth.apiUrl)} to converge (the identical seat ` +
1966
+ 'its resumable connection state was PRESERVED here. This worktree was NOT removed. From ' +
1967
+ `here, re-run ${localAssimilateCommand(auth.apiUrl)} to converge (the identical connection ` +
1968
1968
  `is reused — no duplicate is minted), or run ${resetLocalSeatCommand(auth.apiUrl)} to ` +
1969
1969
  'clear it.\n',
1970
1970
  );
@@ -1977,17 +1977,17 @@ export async function runAssimilate(
1977
1977
  // that can silently create a duplicate server seat (#35).
1978
1978
  const bindFailure =
1979
1979
  bindOutcome === 'missing'
1980
- ? 'the exact pending seat record went missing locally before it could be bound'
1980
+ ? 'the exact pending connection record went missing locally before it could be bound'
1981
1981
  : bindOutcome === 'replaced'
1982
- ? 'the exact pending seat record was replaced locally before it could be bound; the replacement was left untouched'
1982
+ ? 'the exact pending connection record was replaced locally before it could be bound; the replacement was left untouched'
1983
1983
  : bindOutcome === 'threw'
1984
- ? 'the local seat store could not be read or written while preserving the pending seat'
1985
- : 'this client did not receive a pending-seat preservation handle';
1984
+ ? 'the private store could not be read or written while preserving the pending connection'
1985
+ : 'this client did not receive a pending-connection preservation handle';
1986
1986
  deps.stderr(
1987
1987
  `This worktree's secure session on ${auth.apiUrl} did not finish activating: ` +
1988
1988
  `${bindFailure}. The spawned worktree will be removed. No client-only command can ` +
1989
- 'prove reuse or safely clear the possibly accepted server-side seat; ask the server ' +
1990
- 'operator to inspect that seat before retrying.\n',
1989
+ 'prove reuse or safely clear the possibly accepted server-side drone; ask the server ' +
1990
+ 'operator to inspect that drone before retrying.\n',
1991
1991
  );
1992
1992
  rollbackWorktree();
1993
1993
  return 1;
@@ -1997,8 +1997,8 @@ export async function runAssimilate(
1997
1997
  // reset or enroll). The composite scrubbed only our own pending record — no
1998
1998
  // orphan ACTIVE credential — so a just-spawned worktree is safe to remove.
1999
1999
  deps.stderr(
2000
- `This worktree's saved local seat on ${auth.apiUrl} changed during attach ` +
2001
- '(a concurrent reset or enroll); no seat was created and nothing was overwritten. ' +
2000
+ `This worktree's saved connection to ${auth.apiUrl} changed during attach ` +
2001
+ '(a concurrent reset or enroll); no drone was created and nothing was overwritten. ' +
2002
2002
  `Re-run ${localAssimilateCommand(auth.apiUrl)} to attach against the current state.\n`,
2003
2003
  );
2004
2004
  rollbackWorktree();
@@ -474,13 +474,13 @@ export function buildDefaultAssimilateDeps(
474
474
  if (params.remint_invalid_prior) {
475
475
  if (prepared.result !== 'created' || prepared.drone.id === params.prior_drone_id) {
476
476
  await prepared.scrubPending();
477
- throw new Error('Borg server did not remint a fresh seat after eviction');
477
+ throw new Error('Borg server did not remint a fresh drone after eviction');
478
478
  }
479
479
  } else if (prepared.result !== 'reused' || prepared.drone.id !== params.prior_drone_id) {
480
480
  await prepared.scrubPending();
481
481
  throw new BorgServerError(
482
482
  'ATTACH_CONFLICT',
483
- 'Borg server did not reattach the saved seat',
483
+ 'Borg server did not reattach the saved connection',
484
484
  );
485
485
  }
486
486
  }
@@ -48,8 +48,8 @@ export function reattachOnlyRefusal(
48
48
  ): string {
49
49
  if (decision.kind === 'no-identity') {
50
50
  return (
51
- `◼ This session has no drone seat for this worktree, and in-session borg_assimilate is ` +
52
- `re-attach-only (it never creates seats — gh#780). To create a seat for cube ` +
51
+ `◼ This session has no drone for this worktree, and in-session borg_assimilate is ` +
52
+ `re-attach-only (it never creates drones — gh#780). To create a drone for cube ` +
53
53
  `"${requestedCubeName}", run \`borg assimilate\` in a terminal — it spawns the worktree, ` +
54
54
  `persists the identity, and launches the agent in one step.`
55
55
  );
@@ -76,9 +76,9 @@ export function reattachFailureMessage(error: {
76
76
  }): string {
77
77
  const detail = error.message ?? String(error);
78
78
  return (
79
- `◼ Re-attach failed — this worktree's saved seat is unreachable (likely evicted or its ` +
79
+ `◼ Re-attach failed — this worktree's saved connection is unreachable (likely evicted or its ` +
80
80
  `session was revoked). Server said: ${detail}\n` +
81
- `Recover by running \`borg assimilate\` in a terminal to create a fresh seat; ` +
81
+ `Recover by running \`borg assimilate\` in a terminal to create a fresh drone; ` +
82
82
  `in-session borg_assimilate never re-mints (gh#780).`
83
83
  );
84
84
  }
@@ -31,8 +31,8 @@ export function renderAssimilationWelcome(
31
31
  return [
32
32
  `${check} Attached \`${droneLabel}\` to \`${roleName}\` in cube \`${cubeName}\`.`,
33
33
  ``,
34
- `In the launched agent, run \`borg_whoami\` and \`borg_roster\` to verify the seat`,
35
- `and begin coordinating.`,
34
+ `In the launched agent, run \`borg_whoami\` and \`borg_roster\``,
35
+ `to verify the connection and begin coordinating.`,
36
36
  `Launch future sessions in this repository with \`borg\`.`,
37
37
  ...teammateLines,
38
38
  ``,
package/src/claude.ts CHANGED
@@ -12,8 +12,6 @@
12
12
  * borg setup → Re-route to the setup wizard
13
13
  * borg spawn <name> → Create a sibling git worktree + launch a
14
14
  * fresh drone inside it (see spawn.ts)
15
- * borg sync → Advance the current worktree across the 5
16
- * lifecycle states (see sync.ts, gh#33)
17
15
  * borg server <cmd> → Forward a lifecycle command to borg-mcp-server
18
16
  */
19
17
 
@@ -31,7 +29,6 @@ import { handleVersionFlag, getPackageVersion } from './version.js';
31
29
  import { clientSubcommandHelpText, topLevelHelpText } from './cli-help.js';
32
30
  import { runSpawn } from './spawn.js';
33
31
  import { buildClaudeLaunchArgs } from './claude-launch-args.js';
34
- import { parseSyncArgs, runSync } from './sync.js';
35
32
  import { parseCleanupArgs, runCleanup } from './cleanup-cmd.js';
36
33
  import { parseAssimilateArgs } from './parse-assimilate-args.js';
37
34
  import { runAssimilate } from './assimilate-cmd.js';
@@ -216,11 +213,11 @@ async function main() {
216
213
  const code = await runAssimilateEntry(process.argv.slice(3));
217
214
  process.exit(code);
218
215
  }
219
- if (process.argv[2] === 'reset-local-seat') {
216
+ if (process.argv[2] === 'reset-local-connection') {
220
217
  const parsed = parseResetLocalSeatArgs(process.argv.slice(3));
221
218
  if (!parsed.ok) {
222
219
  process.stderr.write(
223
- chalk.red(`${consolePrefix()}◼ borg reset-local-seat: ${parsed.error}\n`)
220
+ chalk.red(`${consolePrefix()}◼ borg reset-local-connection: ${parsed.error}\n`)
224
221
  );
225
222
  process.stderr.write(`Run \`borg --help\` for usage.\n`);
226
223
  process.exit(1);
@@ -254,18 +251,6 @@ async function main() {
254
251
  const code = await runSpawn();
255
252
  process.exit(code);
256
253
  }
257
- if (process.argv[2] === 'sync') {
258
- const parsed = parseSyncArgs(process.argv.slice(3));
259
- if (!parsed.ok) {
260
- process.stderr.write(
261
- chalk.red(`${consolePrefix()}◼ borg sync: ${parsed.error}\n`)
262
- );
263
- process.stderr.write(`Run \`borg --help\` for usage.\n`);
264
- process.exit(1);
265
- }
266
- const code = await runSync({}, parsed.options);
267
- process.exit(code);
268
- }
269
254
  if (process.argv[2] === 'cleanup') {
270
255
  const parsed = parseCleanupArgs(process.argv.slice(3));
271
256
  if (!parsed.ok) {
@@ -74,7 +74,7 @@ export type CleanupReason =
74
74
  | 'SURVIVES-live'
75
75
  | 'SURVIVES-self'
76
76
  | 'UNKNOWN-indeterminate'
77
- | 'UNKNOWN-no-seat'
77
+ | 'UNKNOWN-no-connection'
78
78
  | 'LEGACY-manual-review';
79
79
 
80
80
  export interface CleanupRow {
@@ -350,7 +350,7 @@ async function classifyWorktree(
350
350
  case 'revoked':
351
351
  return { reason: 'SURVIVES-revoked', detail: 'session revoked — recoverable via re-enroll, never delete' };
352
352
  case 'live':
353
- return { reason: 'SURVIVES-live', detail: 'seat resolves (drone alive)' };
353
+ return { reason: 'SURVIVES-live', detail: 'connection resolves (drone alive)' };
354
354
  case 'indeterminate':
355
355
  default:
356
356
  return {
@@ -431,7 +431,7 @@ export async function buildCleanupReport(
431
431
  // sibling → REPORT for manual review, never auto-prune (S5). No seat →
432
432
  // an arbitrary user worktree we never touch or list.
433
433
  if (seat) {
434
- rows.push({ worktreePath: wt, wtBranch: null, reason: 'LEGACY-manual-review', detail: 'borg seat outside worktreesHome (pre-gh#556 sibling)' });
434
+ rows.push({ worktreePath: wt, wtBranch: null, reason: 'LEGACY-manual-review', detail: 'borg connection outside worktreesHome (pre-gh#556 sibling)' });
435
435
  }
436
436
  continue;
437
437
  }
@@ -439,7 +439,7 @@ export async function buildCleanupReport(
439
439
  // Under worktreesHome but no saved seat → not eviction-orphaned
440
440
  // (pre-assimilate or hand-made). Report, never auto-prune.
441
441
  if (!seat) {
442
- rows.push({ worktreePath: wt, wtBranch: null, reason: 'UNKNOWN-no-seat', detail: 'no saved seat — manual review' });
442
+ rows.push({ worktreePath: wt, wtBranch: null, reason: 'UNKNOWN-no-connection', detail: 'no saved connection — manual review' });
443
443
  continue;
444
444
  }
445
445
 
package/src/cli-help.ts CHANGED
@@ -16,16 +16,6 @@ export function isHelpFlag(arg: string | undefined): boolean {
16
16
  return arg === '--help' || arg === '-h';
17
17
  }
18
18
 
19
- export function syncHelpText(version: string): string {
20
- return (
21
- `borg sync (borgmcp ${version}) — update this Borg worktree from origin/main\n\n` +
22
- `Usage:\n` +
23
- ` borg sync Update safely; refuse if the worktree is dirty\n` +
24
- ` borg sync --prune Also delete a merged local feature branch\n` +
25
- ` borg sync --help Show this help\n`
26
- );
27
- }
28
-
29
19
  export function cleanupHelpText(version: string): string {
30
20
  return (
31
21
  `borg cleanup (borgmcp ${version}) — review orphaned Borg-managed worktrees\n\n` +
@@ -63,9 +53,8 @@ export function clientSubcommandHelpText(
63
53
  switch (command) {
64
54
  case 'setup': return setupHelpText(version);
65
55
  case 'assimilate': return assimilateHelpText(version);
66
- case 'reset-local-seat': return resetLocalSeatHelpText(version);
56
+ case 'reset-local-connection': return resetLocalSeatHelpText(version);
67
57
  case 'recover-enrollment': return recoverEnrollmentHelpText(version);
68
- case 'sync': return syncHelpText(version);
69
58
  case 'cleanup': return cleanupHelpText(version);
70
59
  case 'launch-all': return launchAllHelpText(version);
71
60
  default: return null;
@@ -101,9 +90,8 @@ export function topLevelHelpText(version: string): string {
101
90
  ` borg assimilate --host <host> Join or create on an explicit server\n` +
102
91
  ` borg assimilate --worktree <name> Spawn a worktree drone (in ~/.borg/worktrees/<repo>/<name>)\n` +
103
92
  ` borg server cube init Initialize this repository's cube without creating a drone\n` +
104
- ` borg reset-local-seat Clear ONLY this worktree's saved local seat (offline; after a rejection)\n` +
93
+ ` borg reset-local-connection Clear ONLY this worktree's saved connection to its cube (offline; after a rejection)\n` +
105
94
  ` borg recover-enrollment Restore or clear ONLY one failed server enrollment transaction\n` +
106
- ` borg sync [--prune] Sync this worktree's branch to origin/main\n` +
107
95
  ` borg cleanup [--prune] Report (or --prune) worktrees orphaned by evicted drones\n` +
108
96
  ` borg launch-all [cube] Launch all drone worktrees of a cube (default: active cube)\n` +
109
97
  ` borg launch-all [cube] --cli claude|codex|opencode\n` +
@@ -157,8 +145,8 @@ export function serverHelpText(): string {
157
145
  ` update Verify and activate a local server artifact.\n` +
158
146
  ` invite Create a single-use invitation in an interactive terminal.\n` +
159
147
  ` cert-reissue Widen the server certificate to cover another address without replacing the CA.\n` +
160
- ` client-list List enrolled clients, states, and cube grants while the server is stopped.\n` +
161
- ` client-grant Grant a client read, write, or manage access to a cube while the server is stopped.\n` +
148
+ ` client-list List enrolled clients, states, and cube grants while the server is live; committed changes take effect on the next request.\n` +
149
+ ` client-grant Grant a client read, write, or manage access to a cube while the server is live; committed changes take effect on the next request.\n` +
162
150
  ` dashboard View the running local server dashboard.\n` +
163
151
  ` cube init Initialize this Git repository's cube; does not create a drone.\n\n` +
164
152
  `Run borg server <command> --help for server command options.\n`
@@ -203,7 +191,7 @@ export function assimilateHelpText(version: string): string {
203
191
  `Flags:\n` +
204
192
  ` --worktree <name> Create + launch the drone in a sibling git worktree\n` +
205
193
  ` --here Stay in the current worktree (no sibling spawn)\n` +
206
- ` --force Override a live-seat guard for a wedged monitor\n` +
194
+ ` --force Reattach despite a still-live inbox monitor in this worktree\n` +
207
195
  ` --cube-name <name> Repository cube name (otherwise edit the proposed name)\n` +
208
196
  ` --host <host> Borg server host or URL (bare hosts default to HTTPS)\n` +
209
197
  ` --enroll Prompt for a hidden enrollment invitation in the operator terminal\n` +
@@ -216,7 +204,7 @@ export function assimilateHelpText(version: string): string {
216
204
  `repository association skips all prompts. One accessible exact-name legacy cube requires\n` +
217
205
  `explicit interactive adoption; ambiguous matches fail closed. An enrolled owner client may\n` +
218
206
  `create an idempotent repository cube; ordinary clients require an explicit cube grant.\n` +
219
- `Agent seats begin only after enrollment. Preview only.\n` +
207
+ `A drone is created only after enrollment. Preview only.\n` +
220
208
  `See docs/LOCAL_SERVER.md for self-hosted setup and current status.\n\n` +
221
209
  `For local or provider-specific models, configure the selected agent CLI directly.\n` +
222
210
  `OpenCode supports Ollama and other providers through its own model configuration.\n`
@@ -224,25 +212,25 @@ export function assimilateHelpText(version: string): string {
224
212
  }
225
213
 
226
214
  /**
227
- * Help text for `borg reset-local-seat --help`. The offline, network-free seat
215
+ * Help text for `borg reset-local-connection --help`. The offline, network-free seat
228
216
  * reset recommended by the pin-matched SESSION_REJECTED diagnostic (#1082).
229
217
  */
230
218
  export function resetLocalSeatHelpText(version: string): string {
231
219
  return (
232
- `borg reset-local-seat (borgmcp ${version}) — clear ONLY this worktree's saved local seat\n\n` +
220
+ `borg reset-local-connection (borgmcp ${version}) — clear ONLY this worktree's saved connection to its cube\n\n` +
233
221
  `Offline and network-free: it contacts no server and revokes nothing server-side. It clears\n` +
234
- `just this worktree's saved local seat — its credential and cube binding together — from the\n` +
235
- `local seat store on this machine. Server, trust anchor, cube, and every sibling worktree are\n` +
222
+ `just this worktree's saved connection — its credential and cube binding together — from the\n` +
223
+ `private store on this machine. Server, trust anchor, cube, and every sibling worktree are\n` +
236
224
  `left untouched.\n\n` +
237
225
  `Use it after \`borg assimilate\` reports this worktree's session was revoked or superseded\n` +
238
226
  `(a pin-matched rejection), then ask the operator for a new invitation and re-enroll.\n\n` +
239
227
  `Usage:\n` +
240
- ` borg reset-local-seat Reset this worktree's saved seat (TTY confirms [y/N])\n` +
241
- ` borg reset-local-seat --host <host> No-op unless this worktree's seat is on <host>\n` +
242
- ` borg reset-local-seat --yes Reset without a prompt (required when non-interactive)\n` +
243
- ` borg reset-local-seat --help Show this help\n\n` +
228
+ ` borg reset-local-connection Reset this worktree's saved connection (TTY confirms [y/N])\n` +
229
+ ` borg reset-local-connection --host <host> No-op unless this worktree connects to <host>\n` +
230
+ ` borg reset-local-connection --yes Reset without a prompt (required when non-interactive)\n` +
231
+ ` borg reset-local-connection --help Show this help\n\n` +
244
232
  `Flags:\n` +
245
- ` --host <host> Only act if this worktree's saved seat is on <host> (else no-op)\n` +
233
+ ` --host <host> Only act if this worktree connects to <host> (else no-op)\n` +
246
234
  ` --yes, -y Skip the confirmation prompt (required in non-TTY contexts)\n`
247
235
  );
248
236
  }
package/src/cubes.ts CHANGED
@@ -110,7 +110,7 @@ let pinnedMcpSeatIdentity: {
110
110
  export class McpSeatIdentityChangedError extends Error {
111
111
  readonly code = 'SEAT_IDENTITY_CHANGED';
112
112
  constructor() {
113
- super('The saved Borg seat changed after this MCP session pinned its identity. Exit this session and relaunch from the intended worktree.');
113
+ super('This worktree\'s saved connection changed after this MCP session pinned its identity. Exit this session and relaunch from the intended worktree.');
114
114
  this.name = 'McpSeatIdentityChangedError';
115
115
  }
116
116
  }
@@ -439,7 +439,7 @@ export async function snapshotLocalSeat(): Promise<LocalSeatSnapshot | null> {
439
439
  // CR#4: discover an ACTIVE seat OR a bound-PENDING record (a sibling whose
440
440
  // activation failed, bound to THIS worktree by the attach bind-pending step).
441
441
  // getActiveSeatForWorktree would MISS the bound-pending record (it requires
442
- // state==='active' + a drone id), so `reset-local-seat` would FALSELY report
442
+ // state==='active' + a drone id), so `reset-local-connection` would FALSELY report
443
443
  // "nothing to reset" (exit 0) while a resumable, server-digest-bound bearer
444
444
  // persists at rest — a FALSE-SUCCESS revocation failure. getSeatForWorktree sees
445
445
  // both, and the offline reset's exact re-check + delete cover the bound-pending
@@ -78,7 +78,7 @@ export const DOCS_SECTIONS: DocsSection[] = [
78
78
  url: SEAT_LIFECYCLE_URL,
79
79
  page: "docs/SEAT_LIFECYCLE.md",
80
80
  summary: "Saved-seat states, re-attach and reset recovery, duplicate-session guards, and deterministic multi-seat selection.",
81
- keywords: ["seat", "lifecycle", "reattach", "re-attach", "reset-local-seat", "evicted", "revoked", "superseded", "inbox monitor", "multiple seats", "silent deafness"],
81
+ keywords: ["seat", "lifecycle", "reattach", "re-attach", "reset-local-connection", "evicted", "revoked", "superseded", "inbox monitor", "multiple seats", "silent deafness"],
82
82
  },
83
83
  {
84
84
  slug: "self-hosting",
@@ -16,7 +16,7 @@ export const CUBE_DELETED_CODE = 'CUBE_DELETED';
16
16
 
17
17
  export class DroneEvictedError extends Error {
18
18
  constructor(
19
- message = 'This seat was removed from the cube.'
19
+ message = 'This drone was removed from the cube.'
20
20
  ) {
21
21
  super(message);
22
22
  this.name = 'DroneEvictedError';
@@ -45,8 +45,8 @@ export const CUBE_DELETED_RESULT_MARKER = '[CUBE-DELETED]';
45
45
  export function formatEvictedToolResult(cubeName?: string): string {
46
46
  const cube = cubeName ?? 'the selected cube';
47
47
  return (
48
- `${EVICTED_RESULT_MARKER} This seat was removed from cube ${cube}.\n\n` +
49
- 'Borg has stopped listening for activity for this seat. Do not retry this request or restart the loop.\n\n' +
48
+ `${EVICTED_RESULT_MARKER} This drone was removed from cube ${cube}.\n\n` +
49
+ 'Borg has stopped listening for activity for this drone. Do not retry this request or restart the loop.\n\n' +
50
50
  'Your worktree and project files are unchanged. Finish any local file safety checks, then end this agent session.\n\n' +
51
51
  'To rejoin later, start a new session and use a new invitation from the server operator. Do not re-assimilate from this evicted session.'
52
52
  );
@@ -50,7 +50,7 @@ const defaultDeps: DroneManagementDeps = {
50
50
  };
51
51
 
52
52
  export const STALE_ROLE_DISPLAY_WARNING =
53
- 'Local display warning: The server committed this change, but Borg could not refresh this worktree\'s saved seat metadata. Local role details may be stale. Do not retry the reassignment.\n\n' +
53
+ 'Local display warning: The server committed this change, but Borg could not refresh this worktree\'s saved connection metadata. Local role details may be stale. Do not retry the reassignment.\n\n' +
54
54
  'Run `borg_regen` to refresh the server-authoritative role. If this session still shows the previous role, restart this agent session once. Do not re-assimilate or repeat the management request.';
55
55
 
56
56
  function opaqueNotFound(): never {
@@ -75,8 +75,8 @@ export function formatReassignDroneSuccess(input: {
75
75
  export function formatEvictDroneSuccess(droneLabel: string, cubeName: string): string {
76
76
  return (
77
77
  `Removed ${droneLabel} from cube ${cubeName}.\n` +
78
- 'The seat credential is revoked. The session will stop after its next Borg request.\n' +
79
- 'The worktree and project files were not deleted. Activity history remains attributed to the removed seat.\n' +
78
+ 'The drone\'s credential is revoked. The session will stop after its next Borg request.\n' +
79
+ 'The worktree and project files were not deleted. Activity history remains attributed to the removed drone.\n' +
80
80
  'After its work is merged, run `borg cleanup` to review whether the worktree can be pruned.'
81
81
  );
82
82
  }
@@ -17,7 +17,7 @@ import {
17
17
  BORG_LAUNCH_WORKTREE_ENV,
18
18
  } from './launch-access.js';
19
19
 
20
- const REMINDER = 'Reminder: this seat is scoped to its own worktree and scratch root; coordinate before working on a foreign path.';
20
+ const REMINDER = 'Reminder: this drone is scoped to its own worktree and scratch root; coordinate before working on a foreign path.';
21
21
 
22
22
  const PATH_KEYS = new Set([
23
23
  'cwd',
@@ -797,8 +797,8 @@ function liveMonitorYieldLine(
797
797
  : null;
798
798
  const holder = livePid === null ? 'another monitor instance' : `a live instance (pid ${livePid})`;
799
799
  return (
800
- `borg-inbox-monitor: seat inbox ${JSON.stringify(inboxPath)} is already monitored by ${holder}; ` +
801
- 'yielding — another session likely holds this seat.'
800
+ `borg-inbox-monitor: inbox ${JSON.stringify(inboxPath)} is already monitored by ${holder}; ` +
801
+ 'yielding — another session likely holds this worktree\'s connection.'
802
802
  );
803
803
  }
804
804
 
package/src/index.ts CHANGED
@@ -561,7 +561,7 @@ export async function main() {
561
561
  `# Re-attached to cube: ${displayIdentity.cubeName}`,
562
562
  ``,
563
563
  `**Drone label:** ${displayIdentity.droneLabel}`,
564
- `**Seat:** existing identity reused — no new drone minted (gh#780)`,
564
+ `**Drone:** existing identity reused — no new drone minted (gh#780)`,
565
565
  ``,
566
566
  ``,
567
567
  ].join('\n');