cyberlegion 2.0.0 → 2.0.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberlegion",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Agent session spawning, messaging, and dispatch — the Legion and its Legate.",
5
5
  "author": {
6
6
  "name": "unional"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberlegion",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Agent session spawning, messaging, and dispatch — the Legion and its Legate.",
5
5
  "author": {
6
6
  "name": "unional"
package/.plugin/pins.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "cyberlegion": "2.0.0"
2
+ "cyberlegion": "2.0.1"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # cyberlegion
2
2
 
3
+ ## 2.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 7625b31: `unit prune` keeps an exited unit that only shares a worktree while it is the last record pointing at that worktree, the worktree is still on disk, and its work has not landed. Before, prune deleted it and left the work with nothing pointing at it. "Landed" is the worktree library's judgment (clean, and its branch landed on the default branch), exported as `landedWorktrees` for library callers to pass to `prune`; without it, `prune` keeps every such record.
8
+
3
9
  ## 2.0.0
4
10
 
5
11
  ### Major Changes
package/dist/cli.mjs CHANGED
@@ -11163,10 +11163,13 @@ function terminalGone(ctx, rec, terminal, cache) {
11163
11163
  * work from. Reconcile-culls against the current mux's live set first, then judges each remaining
11164
11164
  * record (covers the other mux and sessions outside any multiplexer pane): a pane-bound record by its
11165
11165
  * pane alone — a live or unprobeable pane keeps it whatever its last-seen — and a pane-less record by
11166
- * the staleness timer, its only signal. An exited unit whose worktree is still on disk is kept, since
11167
- * `unit close` owns removing that worktree; every other exited unit is deleted with `deleteExited`.
11166
+ * the staleness timer, its only signal. An exited unit whose own linked worktree is still on disk is
11167
+ * kept, since `unit close` owns removing that worktree. So is an exited unit that is the last record
11168
+ * pointing at a linked worktree it shares, while that worktree is on disk and its work has not landed
11169
+ * (`options.landed`): deleting it would leave that work with nothing pointing at it. Every other
11170
+ * exited unit is deleted with `deleteExited`.
11168
11171
  */
11169
- function prune(ctx) {
11172
+ function prune(ctx, options = {}) {
11170
11173
  const exec = ctx.exec ?? realExec;
11171
11174
  const now = ctx.now?.() ?? Date.now();
11172
11175
  const marked = reconcile(ctx);
@@ -11180,7 +11183,7 @@ function prune(ctx) {
11180
11183
  marked.push(rec);
11181
11184
  }
11182
11185
  }
11183
- const deleted = deleteExited(ctx);
11186
+ const deleted = deleteExited(ctx, options.landed ?? (() => false));
11184
11187
  const gone = new Set(deleted.map((r) => r.id));
11185
11188
  return [...marked.filter((r) => !gone.has(r.id)).map((r) => ({
11186
11189
  ...r,
@@ -11190,11 +11193,26 @@ function prune(ctx) {
11190
11193
  pruned: "deleted"
11191
11194
  }))];
11192
11195
  }
11193
- /** Whether an exited record still has a worktree on disk — the one thing it leaves behind that
11194
- * `unit close` must deal with. A record that never had a worktree has nothing on disk. */
11195
- function worktreeOnDisk(rec) {
11196
- if (rec.worktree?.root == null || !existsSync(rec.worktree.root)) return false;
11197
- return !isPrimaryCheckout(rec.worktree.root, rec.worktree.primaryRoot);
11196
+ /** Whether `checkout` is a linked worktree still on disk — something a record can point at. The
11197
+ * primary checkout always exists, but nothing removes it, so no record has to stay to point at it. */
11198
+ function linkedOnDisk(checkout) {
11199
+ return checkout?.root != null && existsSync(checkout.root) && !isPrimaryCheckout(checkout.root, checkout.primaryRoot);
11200
+ }
11201
+ /** Whether another record in the store still points at the worktree at `root`, owned or shared. */
11202
+ function pointedAtByOther(store, root, self) {
11203
+ const at = resolve(root);
11204
+ return listAgents(store).some((a) => a.id !== self && (a.worktree?.root != null && resolve(a.worktree.root) === at || a.sharedWorktree?.root != null && resolve(a.sharedWorktree.root) === at));
11205
+ }
11206
+ /**
11207
+ * Whether deleting this exited record would orphan a worktree on disk. Its own linked worktree is kept
11208
+ * for `unit close` to remove. A worktree it only shares is kept while this record is the last one
11209
+ * pointing at it and its work has not landed — the owner's record is gone, so nothing else would
11210
+ * lead to that work.
11211
+ */
11212
+ function keepsWorktree(store, rec, landed) {
11213
+ if (linkedOnDisk(rec.worktree)) return true;
11214
+ const shared = rec.sharedWorktree;
11215
+ return linkedOnDisk(shared) && !pointedAtByOther(store, shared.root, rec.id) && !landed(shared.root);
11198
11216
  }
11199
11217
  /** Whether a worktree root is its repository's primary checkout — the one test `unit close` and
11200
11218
  * `unit prune` share for "a seat on the main checkout, which nothing removes". */
@@ -11202,7 +11220,7 @@ function isPrimaryCheckout(worktreeRoot, primaryRoot) {
11202
11220
  return worktreeRoot != null && primaryRoot != null && resolve(worktreeRoot) === resolve(primaryRoot);
11203
11221
  }
11204
11222
  /**
11205
- * Delete every exited unit with no worktree left to close (none on disk, or only the primary checkout): its record, brief, mailbox, and the pane
11223
+ * Delete every exited unit that leaves no work on disk (`keepsWorktree`): its record, brief, mailbox, and the pane
11206
11224
  * pointer that still names it. Nothing revives an exited unit (`unit restart` takes only a running or
11207
11225
  * stopped one), so these records are read by nobody. A pane pointer is dropped only when it still
11208
11226
  * resolves to the deleted unit, since a multiplexer may have handed the pane id to another unit
@@ -11211,11 +11229,11 @@ function isPrimaryCheckout(worktreeRoot, primaryRoot) {
11211
11229
  * `unit close` does. No pane is torn down: an exited unit's pane is already gone or belongs to
11212
11230
  * someone else.
11213
11231
  */
11214
- function deleteExited(ctx) {
11232
+ function deleteExited(ctx, landed) {
11215
11233
  const exec = ctx.exec ?? realExec;
11216
11234
  const deleted = [];
11217
11235
  for (const rec of listAgents(ctx.store)) {
11218
- if (rec.status !== "exited" || isSessionIndependent(rec) || worktreeOnDisk(rec)) continue;
11236
+ if (rec.status !== "exited" || isSessionIndependent(rec) || keepsWorktree(ctx.store, rec, landed)) continue;
11219
11237
  const primaryRoot = rec.worktree?.primaryRoot;
11220
11238
  if (primaryRoot && existsSync(primaryRoot)) exec("git", [
11221
11239
  "-C",
@@ -13201,6 +13219,42 @@ function removeCursor(settings, event, canonical) {
13201
13219
  else delete hooks[event];
13202
13220
  return true;
13203
13221
  }
13222
+ // src/landed.ts
13223
+ /**
13224
+ * Which worktrees a unit shares hold work that has landed, as the `landed` judgment `prune` takes.
13225
+ * It is the worktree library's own judgment, the one its `acquire` recycles a worktree by: the
13226
+ * checkout is clean and its branch has landed on the default branch. Asked once per repository
13227
+ * before prune's synchronous pass, for every shared worktree still on disk. A worktree git cannot
13228
+ * judge (detached, no default branch, a repository git does not know) does not count as landed, so
13229
+ * prune keeps the record that points at it.
13230
+ */
13231
+ async function landedWorktrees(ctx) {
13232
+ const exec = asyncExec(ctx.exec ?? realExec);
13233
+ const roots = /* @__PURE__ */ new Map();
13234
+ for (const rec of listAgents(ctx.store)) {
13235
+ const shared = rec.sharedWorktree;
13236
+ if (shared?.root && existsSync(shared.root)) roots.set(shared.root, shared.primaryRoot);
13237
+ }
13238
+ const landed = /* @__PURE__ */ new Set();
13239
+ const asked = /* @__PURE__ */ new Set();
13240
+ for (const [root, recorded] of roots) {
13241
+ const primary = await primaryRoot({
13242
+ from: root,
13243
+ exec
13244
+ }).catch(() => recorded);
13245
+ if (!primary || asked.has(primary)) continue;
13246
+ asked.add(primary);
13247
+ const entries = await listWorktrees({
13248
+ primaryRoot: primary,
13249
+ exec,
13250
+ ignore: LEASE_IGNORE
13251
+ }).catch(() => []);
13252
+ for (const e of entries) if (e.linked && e.merged === true && e.dirty === false) landed.add(e.root);
13253
+ }
13254
+ const normalized = /* @__PURE__ */ new Map();
13255
+ for (const root of roots.keys()) normalized.set(root, landed.has(await normalizeWorktreePath(root)));
13256
+ return (root) => normalized.get(root) ?? false;
13257
+ }
13204
13258
  // src/output.ts
13205
13259
  function stringifyCell(v) {
13206
13260
  if (v == null) return "";
@@ -15016,10 +15070,10 @@ function runWho(opts) {
15016
15070
  if (agents.length === 0) nextStep("cyberlegion unit register to join");
15017
15071
  }
15018
15072
  syncsUnits(withGlobals(unit.command("who"))).description("list the addressable units").option("--all", "include exited units").option("--reconcile", "live-probe the current mux: cull dead-pane records and adopt unbound harness-bearing panes before listing").action(runWho);
15019
- syncsUnits(withGlobals(unit.command("prune"))).description("mark dead units exited and delete exited units with no worktree on disk").action((opts) => {
15073
+ syncsUnits(withGlobals(unit.command("prune"))).description("mark dead units exited and delete exited units that leave no work on disk").action(async (opts) => {
15020
15074
  const ctx = ctxOf(opts);
15021
15075
  touch(ctx);
15022
- const changed = prune(ctx);
15076
+ const changed = prune(ctx, { landed: await landedWorktrees(ctx) });
15023
15077
  emit(formatOf(opts), {
15024
15078
  toon: toonList("pruned", changed, [
15025
15079
  {
package/dist/index.d.mts CHANGED
@@ -285,10 +285,22 @@ type PrunedRecord = AgentRecord & {
285
285
  * work from. Reconcile-culls against the current mux's live set first, then judges each remaining
286
286
  * record (covers the other mux and sessions outside any multiplexer pane): a pane-bound record by its
287
287
  * pane alone — a live or unprobeable pane keeps it whatever its last-seen — and a pane-less record by
288
- * the staleness timer, its only signal. An exited unit whose worktree is still on disk is kept, since
289
- * `unit close` owns removing that worktree; every other exited unit is deleted with `deleteExited`.
288
+ * the staleness timer, its only signal. An exited unit whose own linked worktree is still on disk is
289
+ * kept, since `unit close` owns removing that worktree. So is an exited unit that is the last record
290
+ * pointing at a linked worktree it shares, while that worktree is on disk and its work has not landed
291
+ * (`options.landed`): deleting it would leave that work with nothing pointing at it. Every other
292
+ * exited unit is deleted with `deleteExited`.
290
293
  */
291
- export declare function prune(ctx: IdContext): PrunedRecord[];
294
+ export declare function prune(ctx: IdContext, options?: PruneOptions): PrunedRecord[];
295
+ /** What `prune` is told from outside its synchronous pass. */
296
+ interface PruneOptions {
297
+ /**
298
+ * Whether the work in the linked worktree at `root` has landed. Absent, no worktree counts as
299
+ * landed, so prune keeps every record it would otherwise orphan work by deleting. `unit prune`
300
+ * passes `landedWorktrees`, the worktree library's judgment, asked before the pass.
301
+ */
302
+ landed?: (root: string) => boolean;
303
+ }
292
304
  interface AgentDef {
293
305
  name: string;
294
306
  description?: string;
@@ -431,6 +443,15 @@ interface InstallResult {
431
443
  * plugin ships it (removing an earlier project copy), otherwise register the PATH-first project hook.
432
444
  */
433
445
  export declare function install(harness: Harness, projectDir?: string, pin?: string): InstallResult[];
446
+ /**
447
+ * Which worktrees a unit shares hold work that has landed, as the `landed` judgment `prune` takes.
448
+ * It is the worktree library's own judgment, the one its `acquire` recycles a worktree by: the
449
+ * checkout is clean and its branch has landed on the default branch. Asked once per repository
450
+ * before prune's synchronous pass, for every shared worktree still on disk. A worktree git cannot
451
+ * judge (detached, no default branch, a repository git does not know) does not count as landed, so
452
+ * prune keeps the record that points at it.
453
+ */
454
+ export declare function landedWorktrees(ctx: Pick<IdContext, 'store' | 'exec'>): Promise<(root: string) => boolean>;
434
455
  interface MsgContext {
435
456
  store: Store;
436
457
  now?: () => number;
@@ -934,4 +955,4 @@ interface WatchOptions {
934
955
  * `watch` prints stays unread and still surfaces later in `mail inbox`/`mail await`.
935
956
  */
936
957
  export declare function watchMail(ctx: MsgContext, input: WatchInput, onMessage: (msg: InboxItem) => void, opts?: WatchOptions): Promise<void>;
937
- export { type AcquireInput, type AcquireResult, type AgentDef, type AgentRecord, type AwaitInput, type AwaitOutcome, type DecommissionInput, type DecommissionResult, type Exec, type Format, type Harness, type HookEvent, type IdContext, type InboxItem, type InboxQuery, type InboxSnapshot, type Message, type MuxProbe, type OwnershipErrorCode, type ProjectContext, type ProjectRecord, type RegisterInput, type RootOptions, type SendInput, type ServiceContext, type ServiceHealth, type ServiceLease, type ServiceView, type SpawnInput, type SpawnResult, type StartInput, type StartResult, type Store, assertDistinctFromPrimary, gitWorktreeAdapter, probeMultiplexer, resolvePrimaryRoot };
958
+ export { type AcquireInput, type AcquireResult, type AgentDef, type AgentRecord, type AwaitInput, type AwaitOutcome, type DecommissionInput, type DecommissionResult, type Exec, type Format, type Harness, type HookEvent, type IdContext, type InboxItem, type InboxQuery, type InboxSnapshot, type Message, type MuxProbe, type OwnershipErrorCode, type ProjectContext, type ProjectRecord, type PruneOptions, type RegisterInput, type RootOptions, type SendInput, type ServiceContext, type ServiceHealth, type ServiceLease, type ServiceView, type SpawnInput, type SpawnResult, type StartInput, type StartResult, type Store, assertDistinctFromPrimary, gitWorktreeAdapter, probeMultiplexer, resolvePrimaryRoot };
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { callerPane, currentPane, herdrMuxAdapter, isStaged, nodeExec, probeMult
2
2
  import { assertDistinctFromPrimary, assertDistinctFromPrimary as assertDistinctFromPrimary$1, gitWorktreeAdapter, gitWorktreeAdapter as gitWorktreeAdapter$1, resolvePrimaryRoot, resolvePrimaryRoot as resolvePrimaryRoot$1 } from "cyber-mux/worktree";
3
3
  import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
4
4
  import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
5
- import { acquire, gitWorktreeCreator, primaryRoot, release } from "cyber-agentkit/worktrees";
5
+ import { acquire, gitWorktreeCreator, listWorktrees, normalizeWorktreePath, primaryRoot, release } from "cyber-agentkit/worktrees";
6
6
  import { createHash, randomBytes } from "node:crypto";
7
7
  import { execFileSync } from "node:child_process";
8
8
  import { homedir } from "node:os";
@@ -738,10 +738,13 @@ function terminalGone(ctx, rec, terminal, cache) {
738
738
  * work from. Reconcile-culls against the current mux's live set first, then judges each remaining
739
739
  * record (covers the other mux and sessions outside any multiplexer pane): a pane-bound record by its
740
740
  * pane alone — a live or unprobeable pane keeps it whatever its last-seen — and a pane-less record by
741
- * the staleness timer, its only signal. An exited unit whose worktree is still on disk is kept, since
742
- * `unit close` owns removing that worktree; every other exited unit is deleted with `deleteExited`.
741
+ * the staleness timer, its only signal. An exited unit whose own linked worktree is still on disk is
742
+ * kept, since `unit close` owns removing that worktree. So is an exited unit that is the last record
743
+ * pointing at a linked worktree it shares, while that worktree is on disk and its work has not landed
744
+ * (`options.landed`): deleting it would leave that work with nothing pointing at it. Every other
745
+ * exited unit is deleted with `deleteExited`.
743
746
  */
744
- function prune(ctx) {
747
+ function prune(ctx, options = {}) {
745
748
  const exec = ctx.exec ?? realExec;
746
749
  const now = ctx.now?.() ?? Date.now();
747
750
  const marked = reconcile(ctx);
@@ -755,7 +758,7 @@ function prune(ctx) {
755
758
  marked.push(rec);
756
759
  }
757
760
  }
758
- const deleted = deleteExited(ctx);
761
+ const deleted = deleteExited(ctx, options.landed ?? (() => false));
759
762
  const gone = new Set(deleted.map((r) => r.id));
760
763
  return [...marked.filter((r) => !gone.has(r.id)).map((r) => ({
761
764
  ...r,
@@ -765,11 +768,26 @@ function prune(ctx) {
765
768
  pruned: "deleted"
766
769
  }))];
767
770
  }
768
- /** Whether an exited record still has a worktree on disk — the one thing it leaves behind that
769
- * `unit close` must deal with. A record that never had a worktree has nothing on disk. */
770
- function worktreeOnDisk(rec) {
771
- if (rec.worktree?.root == null || !existsSync(rec.worktree.root)) return false;
772
- return !isPrimaryCheckout(rec.worktree.root, rec.worktree.primaryRoot);
771
+ /** Whether `checkout` is a linked worktree still on disk — something a record can point at. The
772
+ * primary checkout always exists, but nothing removes it, so no record has to stay to point at it. */
773
+ function linkedOnDisk(checkout) {
774
+ return checkout?.root != null && existsSync(checkout.root) && !isPrimaryCheckout(checkout.root, checkout.primaryRoot);
775
+ }
776
+ /** Whether another record in the store still points at the worktree at `root`, owned or shared. */
777
+ function pointedAtByOther(store, root, self) {
778
+ const at = resolve(root);
779
+ return listAgents(store).some((a) => a.id !== self && (a.worktree?.root != null && resolve(a.worktree.root) === at || a.sharedWorktree?.root != null && resolve(a.sharedWorktree.root) === at));
780
+ }
781
+ /**
782
+ * Whether deleting this exited record would orphan a worktree on disk. Its own linked worktree is kept
783
+ * for `unit close` to remove. A worktree it only shares is kept while this record is the last one
784
+ * pointing at it and its work has not landed — the owner's record is gone, so nothing else would
785
+ * lead to that work.
786
+ */
787
+ function keepsWorktree(store, rec, landed) {
788
+ if (linkedOnDisk(rec.worktree)) return true;
789
+ const shared = rec.sharedWorktree;
790
+ return linkedOnDisk(shared) && !pointedAtByOther(store, shared.root, rec.id) && !landed(shared.root);
773
791
  }
774
792
  /** Whether a worktree root is its repository's primary checkout — the one test `unit close` and
775
793
  * `unit prune` share for "a seat on the main checkout, which nothing removes". */
@@ -777,7 +795,7 @@ function isPrimaryCheckout(worktreeRoot, primaryRoot) {
777
795
  return worktreeRoot != null && primaryRoot != null && resolve(worktreeRoot) === resolve(primaryRoot);
778
796
  }
779
797
  /**
780
- * Delete every exited unit with no worktree left to close (none on disk, or only the primary checkout): its record, brief, mailbox, and the pane
798
+ * Delete every exited unit that leaves no work on disk (`keepsWorktree`): its record, brief, mailbox, and the pane
781
799
  * pointer that still names it. Nothing revives an exited unit (`unit restart` takes only a running or
782
800
  * stopped one), so these records are read by nobody. A pane pointer is dropped only when it still
783
801
  * resolves to the deleted unit, since a multiplexer may have handed the pane id to another unit
@@ -786,11 +804,11 @@ function isPrimaryCheckout(worktreeRoot, primaryRoot) {
786
804
  * `unit close` does. No pane is torn down: an exited unit's pane is already gone or belongs to
787
805
  * someone else.
788
806
  */
789
- function deleteExited(ctx) {
807
+ function deleteExited(ctx, landed) {
790
808
  const exec = ctx.exec ?? realExec;
791
809
  const deleted = [];
792
810
  for (const rec of listAgents(ctx.store)) {
793
- if (rec.status !== "exited" || isSessionIndependent(rec) || worktreeOnDisk(rec)) continue;
811
+ if (rec.status !== "exited" || isSessionIndependent(rec) || keepsWorktree(ctx.store, rec, landed)) continue;
794
812
  const primaryRoot = rec.worktree?.primaryRoot;
795
813
  if (primaryRoot && existsSync(primaryRoot)) exec("git", [
796
814
  "-C",
@@ -2371,6 +2389,42 @@ function removeCursor(settings, event, canonical) {
2371
2389
  else delete hooks[event];
2372
2390
  return true;
2373
2391
  }
2392
+ // src/landed.ts
2393
+ /**
2394
+ * Which worktrees a unit shares hold work that has landed, as the `landed` judgment `prune` takes.
2395
+ * It is the worktree library's own judgment, the one its `acquire` recycles a worktree by: the
2396
+ * checkout is clean and its branch has landed on the default branch. Asked once per repository
2397
+ * before prune's synchronous pass, for every shared worktree still on disk. A worktree git cannot
2398
+ * judge (detached, no default branch, a repository git does not know) does not count as landed, so
2399
+ * prune keeps the record that points at it.
2400
+ */
2401
+ async function landedWorktrees(ctx) {
2402
+ const exec = asyncExec(ctx.exec ?? realExec);
2403
+ const roots = /* @__PURE__ */ new Map();
2404
+ for (const rec of listAgents(ctx.store)) {
2405
+ const shared = rec.sharedWorktree;
2406
+ if (shared?.root && existsSync(shared.root)) roots.set(shared.root, shared.primaryRoot);
2407
+ }
2408
+ const landed = /* @__PURE__ */ new Set();
2409
+ const asked = /* @__PURE__ */ new Set();
2410
+ for (const [root, recorded] of roots) {
2411
+ const primary = await primaryRoot({
2412
+ from: root,
2413
+ exec
2414
+ }).catch(() => recorded);
2415
+ if (!primary || asked.has(primary)) continue;
2416
+ asked.add(primary);
2417
+ const entries = await listWorktrees({
2418
+ primaryRoot: primary,
2419
+ exec,
2420
+ ignore: LEASE_IGNORE
2421
+ }).catch(() => []);
2422
+ for (const e of entries) if (e.linked && e.merged === true && e.dirty === false) landed.add(e.root);
2423
+ }
2424
+ const normalized = /* @__PURE__ */ new Map();
2425
+ for (const root of roots.keys()) normalized.set(root, landed.has(await normalizeWorktreePath(root)));
2426
+ return (root) => normalized.get(root) ?? false;
2427
+ }
2374
2428
  // src/output.ts
2375
2429
  function stringifyCell(v) {
2376
2430
  if (v == null) return "";
@@ -3352,4 +3406,4 @@ async function watchMail(ctx, input, onMessage, opts = {}) {
3352
3406
  await sleep(POLL_MS);
3353
3407
  }
3354
3408
  }
3355
- export { DEFAULT_RESERVATION_TTL_MS, FileStore, ServiceOwnershipError, ack, acquireService, assertDistinctFromPrimary, awaitReply, bindService, bumpLastSeen, decommission, deleteMessage, detectHarness, emit, ensureMarker, fail, gitWorktreeAdapter, handoffService, inbox, injectInbox, install, listAgentDefs, listAgents, listProjects, loadAgent, nextStep, paths, peek, probeMultiplexer, projectRoot, prune, realExec, realizeLaunch, register, registerProject, releaseService, resolveAgent, resolveAgentDef, resolveBody, resolvePrimaryRoot, resolveProject, resolveProjectLocalRoot, resolveRecipient, resolveRoot, resolveSelfId, resolveService, selectSessionAdapter, send, serviceEndpointId, spawn, spawnAndWake, startService, toonList, toonObject, touch, verifyOwnership, watchMail, withOwnership };
3409
+ export { DEFAULT_RESERVATION_TTL_MS, FileStore, ServiceOwnershipError, ack, acquireService, assertDistinctFromPrimary, awaitReply, bindService, bumpLastSeen, decommission, deleteMessage, detectHarness, emit, ensureMarker, fail, gitWorktreeAdapter, handoffService, inbox, injectInbox, install, landedWorktrees, listAgentDefs, listAgents, listProjects, loadAgent, nextStep, paths, peek, probeMultiplexer, projectRoot, prune, realExec, realizeLaunch, register, registerProject, releaseService, resolveAgent, resolveAgentDef, resolveBody, resolvePrimaryRoot, resolveProject, resolveProjectLocalRoot, resolveRecipient, resolveRoot, resolveSelfId, resolveService, selectSessionAdapter, send, serviceEndpointId, spawn, spawnAndWake, startService, toonList, toonObject, touch, verifyOwnership, watchMail, withOwnership };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberlegion",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Harness-agnostic agent session spawning and messaging over the filesystem",
5
5
  "keywords": [
6
6
  "agent",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "cyberlegion",
4
- "version": "2.0.0",
4
+ "version": "2.0.1",
5
5
  "description": "Agent session spawning, messaging, and dispatch — the Legion and its Legate.",
6
6
  "author": {
7
7
  "name": "unional"
package/readme.md CHANGED
@@ -30,7 +30,7 @@ npx cyberlegion unit register --handle scout # register/refresh this sess
30
30
  npx cyberlegion unit register --standing --handle homa # mint a standing, session-independent owner inbox
31
31
  npx cyberlegion unit whoami # print your own identity
32
32
  npx cyberlegion unit who # list addressable peers / live peer sessions
33
- npx cyberlegion unit prune # mark dead agents exited; delete exited ones with no worktree
33
+ npx cyberlegion unit prune # mark dead agents exited; delete exited ones that leave no work on disk
34
34
  npx cyberlegion unit spawn --agent reviewer # launch a peer in its own git worktree (tmux/herdr)
35
35
  npx cyberlegion unit focus <ref> # move input focus to a peer's session
36
36
  npx cyberlegion unit nudge <ref> # ring a peer's session (doorbell)
@@ -18,7 +18,7 @@ caller supplies `P`, it is the definition to use; the by-name lookup is skipped.
18
18
  > **Running the CLI.** Every `node scripts/cyberlegion.mjs …` command below runs the `cyberlegion` CLI
19
19
  > this plugin ships. The path is relative to this skill's own directory, not the working directory.
20
20
  > If you cannot resolve it, run the published CLI of the version that shipped this skill instead,
21
- > with the same arguments: `npx -y cyberlegion@2.0.0`.
21
+ > with the same arguments: `npx -y cyberlegion@2.0.1`.
22
22
 
23
23
  ## 1. Resolve the agent definition
24
24