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.
- package/README.md +5 -3
- package/dist/assimilate-cmd.js +43 -43
- package/dist/assimilate-cmd.js.map +1 -1
- package/dist/assimilate-deps.js +2 -2
- package/dist/assimilate-deps.js.map +1 -1
- package/dist/assimilate-guard.js +4 -4
- package/dist/assimilate-guard.js.map +1 -1
- package/dist/assimilate-welcome.js +2 -2
- package/dist/assimilate-welcome.js.map +1 -1
- package/dist/claude.d.ts +0 -2
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +2 -15
- package/dist/claude.js.map +1 -1
- package/dist/cleanup-cmd.d.ts +1 -1
- package/dist/cleanup-cmd.d.ts.map +1 -1
- package/dist/cleanup-cmd.js +3 -3
- package/dist/cleanup-cmd.js.map +1 -1
- package/dist/cli-help.d.ts +1 -2
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +15 -24
- package/dist/cli-help.js.map +1 -1
- package/dist/cubes.js +2 -2
- package/dist/cubes.js.map +1 -1
- package/dist/docs-sections.js +1 -1
- package/dist/docs-sections.js.map +1 -1
- package/dist/drone-lifecycle.d.ts.map +1 -1
- package/dist/drone-lifecycle.js +3 -3
- package/dist/drone-lifecycle.js.map +1 -1
- package/dist/drone-management.js +1 -1
- package/dist/drone-management.js.map +1 -1
- package/dist/evict-drone.js +2 -2
- package/dist/evict-drone.js.map +1 -1
- package/dist/foreign-path-reminder.js +1 -1
- package/dist/foreign-path-reminder.js.map +1 -1
- package/dist/inbox-monitor.js +2 -2
- package/dist/inbox-monitor.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/launch-all-cmd.js +12 -12
- package/dist/launch-all-cmd.js.map +1 -1
- package/dist/launch-all-discovery.js +1 -1
- package/dist/launch-all-discovery.js.map +1 -1
- package/dist/opencode-seat-identity.js +5 -5
- package/dist/opencode-seat-identity.js.map +1 -1
- package/dist/regen-format.d.ts.map +1 -1
- package/dist/regen-format.js +2 -1
- package/dist/regen-format.js.map +1 -1
- package/dist/remote-client.js +1 -1
- package/dist/remote-client.js.map +1 -1
- package/dist/repository-cube-init.js +1 -1
- package/dist/repository-cube-init.js.map +1 -1
- package/dist/reset-local-seat-cmd.d.ts +2 -2
- package/dist/reset-local-seat-cmd.d.ts.map +1 -1
- package/dist/reset-local-seat-cmd.js +17 -17
- package/dist/reset-local-seat-cmd.js.map +1 -1
- package/dist/seat-reattach-guard.js +1 -1
- package/dist/seat-reattach-guard.js.map +1 -1
- package/dist/seat-store.d.ts +1 -1
- package/dist/seat-store.js +6 -6
- package/dist/seat-store.js.map +1 -1
- package/dist/seats.js +1 -1
- package/dist/seats.js.map +1 -1
- package/dist/server-handshake.js +1 -1
- package/dist/server-handshake.js.map +1 -1
- package/dist/stream-status.js +3 -3
- package/dist/stream-status.js.map +1 -1
- package/dist/tool-manifest.js +1 -1
- package/dist/tool-manifest.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 -2
- package/dist/unknown-subcommand.js.map +1 -1
- package/dist/worktree-lifecycle.d.ts +0 -16
- package/dist/worktree-lifecycle.d.ts.map +1 -1
- package/dist/worktree-lifecycle.js +0 -38
- package/dist/worktree-lifecycle.js.map +1 -1
- package/docs/EXTRACTION_PROVENANCE.md +2 -2
- package/docs/LOCAL_SERVER.md +2 -2
- package/docs/SEAT_LIFECYCLE.md +19 -19
- package/package.json +1 -1
- package/src/assimilate-cmd.ts +43 -43
- package/src/assimilate-deps.ts +2 -2
- package/src/assimilate-guard.ts +4 -4
- package/src/assimilate-welcome.ts +2 -2
- package/src/claude.ts +2 -17
- package/src/cleanup-cmd.ts +4 -4
- package/src/cli-help.ts +15 -27
- package/src/cubes.ts +2 -2
- package/src/docs-sections.ts +1 -1
- package/src/drone-lifecycle.ts +3 -3
- package/src/drone-management.ts +1 -1
- package/src/evict-drone.ts +2 -2
- package/src/foreign-path-reminder.ts +1 -1
- package/src/inbox-monitor.ts +2 -2
- package/src/index.ts +1 -1
- package/src/launch-all-cmd.ts +12 -12
- package/src/launch-all-discovery.ts +1 -1
- package/src/opencode-seat-identity.ts +5 -5
- package/src/regen-format.ts +2 -1
- package/src/remote-client.ts +1 -1
- package/src/repository-cube-init.ts +1 -1
- package/src/reset-local-seat-cmd.ts +17 -17
- package/src/seat-reattach-guard.ts +1 -1
- package/src/seat-store.ts +6 -6
- package/src/seats.ts +1 -1
- package/src/server-handshake.ts +1 -1
- package/src/stream-status.ts +3 -3
- package/src/tool-manifest.ts +1 -1
- package/src/unknown-subcommand.ts +1 -2
- package/src/worktree-lifecycle.ts +0 -45
- package/dist/sync.d.ts +0 -129
- package/dist/sync.d.ts.map +0 -1
- package/dist/sync.js +0 -286
- package/dist/sync.js.map +0 -1
- package/src/sync.ts +0 -363
package/package.json
CHANGED
package/src/assimilate-cmd.ts
CHANGED
|
@@ -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
|
|
632
|
-
`creating or resuming saved
|
|
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
|
|
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-
|
|
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-
|
|
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
|
|
1291
|
-
'credential could not be loaded from the
|
|
1292
|
-
`${resetLocalSeatCommand(authority.apiUrl)} to clear this worktree's saved
|
|
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
|
|
1305
|
-
'No
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1385
|
-
'No
|
|
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
|
|
1393
|
-
'role is unavailable. No
|
|
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
|
|
1405
|
-
'No
|
|
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
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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
|
|
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-
|
|
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
|
|
1967
|
-
`here, re-run ${localAssimilateCommand(auth.apiUrl)} to converge (the identical
|
|
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
|
|
1980
|
+
? 'the exact pending connection record went missing locally before it could be bound'
|
|
1981
1981
|
: bindOutcome === 'replaced'
|
|
1982
|
-
? 'the exact pending
|
|
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
|
|
1985
|
-
: 'this client did not receive a pending-
|
|
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
|
|
1990
|
-
'operator to inspect that
|
|
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
|
|
2001
|
-
'(a concurrent reset or enroll); no
|
|
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();
|
package/src/assimilate-deps.ts
CHANGED
|
@@ -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
|
|
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
|
|
483
|
+
'Borg server did not reattach the saved connection',
|
|
484
484
|
);
|
|
485
485
|
}
|
|
486
486
|
}
|
package/src/assimilate-guard.ts
CHANGED
|
@@ -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
|
|
52
|
-
`re-attach-only (it never creates
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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-
|
|
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) {
|
package/src/cleanup-cmd.ts
CHANGED
|
@@ -74,7 +74,7 @@ export type CleanupReason =
|
|
|
74
74
|
| 'SURVIVES-live'
|
|
75
75
|
| 'SURVIVES-self'
|
|
76
76
|
| 'UNKNOWN-indeterminate'
|
|
77
|
-
| 'UNKNOWN-no-
|
|
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: '
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
161
|
-
` client-grant Grant a client read, write, or manage access to a cube while the server is
|
|
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
|
|
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
|
-
`
|
|
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-
|
|
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-
|
|
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
|
|
235
|
-
`
|
|
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-
|
|
241
|
-
` borg reset-local-
|
|
242
|
-
` borg reset-local-
|
|
243
|
-
` borg reset-local-
|
|
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
|
|
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('
|
|
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-
|
|
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
|
package/src/docs-sections.ts
CHANGED
|
@@ -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-
|
|
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",
|
package/src/drone-lifecycle.ts
CHANGED
|
@@ -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
|
|
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
|
|
49
|
-
'Borg has stopped listening for activity for this
|
|
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
|
);
|
package/src/drone-management.ts
CHANGED
|
@@ -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
|
|
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 {
|
package/src/evict-drone.ts
CHANGED
|
@@ -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
|
|
79
|
-
'The worktree and project files were not deleted. Activity history remains attributed to the removed
|
|
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
|
|
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',
|
package/src/inbox-monitor.ts
CHANGED
|
@@ -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:
|
|
801
|
-
'yielding — another session likely holds this
|
|
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
|
-
`**
|
|
564
|
+
`**Drone:** existing identity reused — no new drone minted (gh#780)`,
|
|
565
565
|
``,
|
|
566
566
|
``,
|
|
567
567
|
].join('\n');
|