cyberlegion 0.0.1 → 0.2.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/dist/index.d.mts CHANGED
@@ -1,3 +1,6 @@
1
+ import { Exec, Exec as Exec$1, MuxAdapter, MuxPlacement, MuxProbe, probeMultiplexer } from "cyber-mux";
2
+ import { assertDistinctFromPrimary, gitWorktreeAdapter, resolvePrimaryRoot } from "cyber-mux/worktree";
3
+
1
4
  //#region src/store/store.d.ts
2
5
  interface Message {
3
6
  id: string;
@@ -16,14 +19,18 @@ type AgentStatus = 'spawning' | 'active' | 'idle' | 'stale' | 'exited' | 'paused
16
19
  interface AgentRecord {
17
20
  id: string;
18
21
  handle: string;
19
- harness: Harness;
22
+ /** Absent for a standing record (a human/owner principal — no claude/cursor/codex harness). */
23
+ harness?: Harness;
20
24
  cwd: string;
21
25
  worktree?: {
22
26
  root: string;
23
27
  branch?: string;
24
28
  } | null;
25
- tmux?: {
26
- pane: string;
29
+ /** Where this session lives, tagged with its multiplexer so `prune` runs the right liveness check.
30
+ * `null` for a session in no pane and for a standing record. `window`/`session` are tmux-only. */
31
+ pane?: {
32
+ mux: 'tmux' | 'herdr';
33
+ id: string;
27
34
  window?: string;
28
35
  session?: string;
29
36
  } | null;
@@ -33,12 +40,21 @@ interface AgentRecord {
33
40
  lastSeen: string;
34
41
  brief?: string;
35
42
  spawnedBy?: string;
43
+ /** Absent ⇒ session (backward compat, no migration). 'standing' = a session-independent,
44
+ * prune-exempt owner inbox minted by `unit register --standing`. */
45
+ kind?: 'session' | 'standing';
46
+ /** Only meaningful on a `kind: 'standing'` record — the id of the unit currently standing in for
47
+ * it (`unit claim`), a per-record singleton pointer that moves as the principal moves between
48
+ * units (last claim wins). Resolved live, never trusted: a presence unit that has exited reads as
49
+ * no presence bound, same as if none were ever claimed — nothing self-heals a stale pointer, it
50
+ * stays inert until re-claimed. Independent of the hub's `mainPane` (the human's read-pane). */
51
+ presence?: string;
36
52
  }
37
53
  interface InboxSnapshot {
38
54
  unread: Message[];
39
55
  read: Message[];
40
56
  }
41
- /** The seam all mailbox + registry + brief/result access goes through. */
57
+ /** The seam all mailbox + registry + brief access goes through. */
42
58
  interface Store {
43
59
  /** This store's root (for path-relative concerns the Store itself doesn't cover, e.g. spawning
44
60
  * a worktree under a project-local root distinct from this hub). */
@@ -67,22 +83,19 @@ interface Store {
67
83
  removePaneIndex(pane: string): void;
68
84
  writeBrief(agentId: string, text: string): void;
69
85
  readBrief(agentId: string): string | undefined;
70
- /** Path this dispatch's result file would live at (computed only — no IO; existence not implied). */
71
- resultPath(id: string): string;
72
- /** Write a dispatch's result as JSON text. */
73
- writeResult(id: string, value: unknown): void;
74
- /** Read a dispatch's result JSON text, or undefined if not yet written. */
75
- readResult(id: string): string | undefined;
86
+ /** Set (or move) the hub's single main pane — the standing owner's live presence — or clear it
87
+ * (`null`, a no-op when already unbound). A hub-level singleton, independent of any agent record. */
88
+ setMainPane(pane: string | null): void;
89
+ /** The hub's currently bound main pane, or undefined when none is bound. */
90
+ getMainPane(): string | undefined;
76
91
  }
77
92
  //#endregion
78
93
  //#region src/identity.d.ts
79
- /** Runs a command synchronously; returns trimmed stdout, or null on any failure. */
80
- type Exec = (cmd: string, args: string[]) => string | null;
81
- declare const realExec: Exec;
94
+ declare const realExec: Exec$1;
82
95
  interface IdContext {
83
96
  store: Store;
84
97
  env?: NodeJS.ProcessEnv;
85
- exec?: Exec;
98
+ exec?: Exec$1;
86
99
  now?: () => number;
87
100
  }
88
101
  declare function loadAgent(store: Store, id: string): AgentRecord | undefined;
@@ -90,10 +103,11 @@ declare function listAgents(store: Store): AgentRecord[];
90
103
  /** Detect the harness: explicit wins, then env probes, then the tmux pane command. */
91
104
  declare function detectHarness(explicit: string | undefined, ctx: IdContext): Harness | undefined;
92
105
  /**
93
- * Recover the calling agent's own id. In tmux the pane index is authoritative — a pane with no
94
- * pane entry is simply unregistered and must NOT adopt `$CYBERLEGION_AGENT_ID` (that env fallback
95
- * applies only when there is no `$TMUX_PANE`). There is no shared bare "self" file — self-id is
96
- * always pane-keyed or explicit via the env var.
106
+ * Recover the calling agent's own id, mux-agnostically. Inside any multiplexer pane (tmux or herdr)
107
+ * the pane index is authoritative — a pane with no pane entry is simply unregistered and must NOT
108
+ * adopt `$CYBERLEGION_AGENT_ID` (that env fallback applies ONLY when the session is in no
109
+ * multiplexer pane at all). There is no shared bare "self" file — self-id is always pane-keyed or
110
+ * explicit via the env var.
97
111
  */
98
112
  declare function resolveSelfId(ctx: IdContext): string | undefined;
99
113
  interface RegisterInput {
@@ -102,7 +116,8 @@ interface RegisterInput {
102
116
  }
103
117
  /** Register (or idempotently refresh) this session's identity. */
104
118
  declare function register(ctx: IdContext, input: RegisterInput): AgentRecord;
105
- /** Resolve a recipient argument (id or handle) to an agent id. */
119
+ /** Resolve a recipient argument (id or handle) to an agent id. A handle resolves to live units
120
+ * only — mail addressed to an exited unit lands in an inbox nobody reads. */
106
121
  declare function resolveRecipient(store: Store, to: string): string;
107
122
  /**
108
123
  * Resolve a unit reference by id, handle, or its worktree branch (the unit↔CR join key: an
@@ -113,7 +128,9 @@ declare function resolveAgent(store: Store, ref: string): AgentRecord;
113
128
  declare function bumpLastSeen(ctx: IdContext, id: string): void;
114
129
  /** Refresh this session's own last-seen if it is registered — best-effort, never throws. */
115
130
  declare function touch(ctx: IdContext): void;
116
- /** Mark agents whose pane is gone or whose last-seen is stale as exited. */
131
+ /** Mark agents whose pane is gone or whose last-seen is stale as exited. Reconcile-culls against the
132
+ * current mux's live set first, then falls through to the per-record paneExists + staleness check
133
+ * (covers the other mux and sessions outside any multiplexer pane). */
117
134
  declare function prune(ctx: IdContext): AgentRecord[];
118
135
  //#endregion
119
136
  //#region src/agentdef/resolve.d.ts
@@ -164,118 +181,6 @@ interface RealizedLaunch {
164
181
  * `--model` when known, `--append-system-prompt` carrying the def's instructions body) since the
165
182
  * exact per-harness flag surface is realized later by the launching caller, not by cyberlegion. */
166
183
  declare function realizeLaunch(def: AgentDef, opts?: RealizeLaunchOptions): RealizedLaunch;
167
- interface RealizeSubagentOptions {
168
- /** File the spawned subagent reads its brief from. */
169
- briefFile: string;
170
- /** File the spawned subagent writes its result JSON to. */
171
- resultFile: string;
172
- }
173
- /** Build the instruction string a parent model uses to spawn its OWN harness Task subagent for
174
- * `def` — cyberlegion never invokes the Task tool itself. Names `subagent_type: <def.name>` for a
175
- * harness that recognizes it, but always inlines the model + full instructions too so the same
176
- * instruction string is correct even when the harness has no such named subagent type. */
177
- declare function realizeSubagentInstruction(def: AgentDef, opts: RealizeSubagentOptions): string;
178
- //#endregion
179
- //#region src/console/session.d.ts
180
- /** Generic multiplexer seam — no legion-specific concepts, so this composes with any host. */
181
- /** Where a new pane/window/session should be placed relative to the caller's current one. */
182
- type SessionPlacement = 'pane:right' | 'pane:down' | 'tab' | 'window';
183
- interface SessionOpenOptions {
184
- /** Working directory the new pane/window/session should start in. */
185
- cwd: string;
186
- /** Command line to launch inside the new pane once it is open. */
187
- launch: string;
188
- /** Placement relative to the caller; defaults to 'pane:right'. */
189
- at?: SessionPlacement;
190
- }
191
- /** Opaque handle to an open pane/window/session; backend-specific id lives in `id`. */
192
- interface SessionTarget {
193
- id: string;
194
- }
195
- interface SessionReadOptions {
196
- /** How many trailing lines of output to capture; omit for the backend's default. */
197
- lines?: number;
198
- }
199
- interface SessionAdapter {
200
- /** Backend name, e.g. "tmux" or "herdr". */
201
- readonly name: string;
202
- /** Create a new pane/window running `opts.launch` in `opts.cwd`; returns its target handle. */
203
- open(exec: Exec, opts: SessionOpenOptions): SessionTarget;
204
- /** Type text into the target session (submitted, not queued). */
205
- send(exec: Exec, target: SessionTarget, text: string): void;
206
- /** Capture the target session's current output. */
207
- read(exec: Exec, target: SessionTarget, opts?: SessionReadOptions): string;
208
- /** Move input focus to the target session; best-effort (may no-op if the backend can't). */
209
- focus(exec: Exec, target: SessionTarget): void;
210
- /** Close the target session. */
211
- teardown(exec: Exec, target: SessionTarget): void;
212
- }
213
- //#endregion
214
- //#region src/console/index.d.ts
215
- /**
216
- * Backend selection via the two-mode mux probe (`$CYBERLEGION_MUX` fast-path/override, else
217
- * ancestry discovery from `$$` falling back to the `$TMUX`/`$HERDR_ENV` hint when the walk is
218
- * inconclusive) — tmux/herdr map to their existing adapters; anything else is a clear error.
219
- */
220
- declare function selectSessionAdapter(env: NodeJS.ProcessEnv, exec?: Exec): SessionAdapter;
221
- //#endregion
222
- //#region src/console/mux-probe.d.ts
223
- type Mux = 'tmux' | 'herdr' | 'screen' | 'none';
224
- interface MuxProbe {
225
- mux: Mux;
226
- pane?: string;
227
- /** 'env' — trusted the $CYBERLEGION_MUX fast-path/override. 'ancestry' — walked the process tree. */
228
- via: 'env' | 'ancestry';
229
- }
230
- /**
231
- * Two-mode multiplexer detection.
232
- *
233
- * Fast-path: `$CYBERLEGION_MUX` (tmux | herdr | screen | none) is trusted outright — this also
234
- * serves as an OVERRIDE (`=none` forces no-mux even inside a real multiplexer). `$CYBERLEGION_MUX_PANE`
235
- * carries the pane id alongside it.
236
- *
237
- * Discovery (else): walk the process ancestry from `$$` via `ps -o ppid=,comm= -p <pid>`, since the
238
- * tool's own shell may not be the human's pane. `$TMUX`/`$HERDR_ENV` are NOT trusted alone — they
239
- * are used only as a fast-positive hint the ancestry walk falls back to when the walk itself is
240
- * inconclusive (e.g. `ps` unavailable), never as a substitute for it.
241
- */
242
- declare function probeMultiplexer(exec: Exec, env: NodeJS.ProcessEnv, opts?: {
243
- discover?: boolean;
244
- }): MuxProbe;
245
- //#endregion
246
- //#region src/console/worktree.d.ts
247
- /** Generic multiplexer/worktree seam — no legion-specific concepts. */
248
- interface WorktreeAddOptions {
249
- /** The primary checkout's root — the repo `git worktree add` runs against. */
250
- primaryRoot: string;
251
- /** Where the new worktree should be checked out. */
252
- path: string;
253
- /** Branch to create the worktree on. */
254
- branch: string;
255
- }
256
- interface Worktree {
257
- root: string;
258
- branch: string;
259
- }
260
- interface WorktreeRemoveOptions {
261
- primaryRoot: string;
262
- }
263
- interface WorktreeAdapter {
264
- add(exec: Exec, opts: WorktreeAddOptions): Worktree;
265
- remove(exec: Exec, path: string, opts: WorktreeRemoveOptions): void;
266
- }
267
- /** The only worktree backend at MVP — plain `git worktree`. */
268
- declare const gitWorktreeAdapter: WorktreeAdapter;
269
- /**
270
- * Resolve the primary checkout's root regardless of whether the caller's cwd is the primary
271
- * checkout or a linked worktree — `--git-common-dir` always points at the main repo's `.git`.
272
- */
273
- declare function resolvePrimaryRoot(exec: Exec): string;
274
- /**
275
- * Refuse the primary checkout: a spawned unit's resolved worktree root must never be the primary
276
- * checkout itself. A unit is never run in the primary checkout.
277
- */
278
- declare function assertDistinctFromPrimary(worktreeRoot: string, primaryRoot: string): void;
279
184
  //#endregion
280
185
  //#region src/decommission.d.ts
281
186
  interface DecommissionInput {
@@ -297,78 +202,6 @@ interface DecommissionResult {
297
202
  */
298
203
  declare function decommission(ctx: IdContext, input: DecommissionInput): DecommissionResult;
299
204
  //#endregion
300
- //#region src/dispatch/prep.d.ts
301
- interface DispatchContext {
302
- store: Store;
303
- }
304
- interface PrepInput {
305
- /** Resolve an agent def (`.agents/agents/<name>.md`) to build the instruction from. */
306
- agent?: string;
307
- /** Read an exact agent def file instead of resolving by name (plugin-scoped escape hatch). */
308
- agentFile?: string;
309
- /** Role label folded into the generic instruction when no agent def is given. */
310
- role?: string;
311
- /** Brief body text. */
312
- briefText?: string;
313
- /** Read the brief from a file, or `-` for stdin. */
314
- briefFile?: string;
315
- /** JSON schema file the eventual result must satisfy — carried through by callers that validate. */
316
- verdictSchema?: string;
317
- /** Thread id correlating a channel-path reply; defaults to the minted dispatch id. */
318
- thread?: string;
319
- }
320
- interface DispatchEnvelope {
321
- id: string;
322
- thread: string;
323
- briefFile: string;
324
- resultFile: string;
325
- instruction: string;
326
- }
327
- /**
328
- * Allocate a dispatch: mint an id (thread defaults to it), write the brief into the Store, compute
329
- * the result-slot path, and build the instruction from a resolved agent def (or a generic one).
330
- * Spawns nothing — the envelope is handed to whatever spawns next (a Task tool, `channel()`, a
331
- * human).
332
- */
333
- declare function prep(ctx: DispatchContext, input: PrepInput, readStdin?: () => string): DispatchEnvelope;
334
- //#endregion
335
- //#region src/dispatch/channel.d.ts
336
- interface ChannelInput extends PrepInput {
337
- /** Block for the mail-thread reply and return a validated `DispatchResult`; without it, the peer
338
- * is spawned and the envelope is returned so the caller can `mail await` later. */
339
- wait?: boolean;
340
- /** Placement relative to the caller; defaults to 'pane:right'. */
341
- at?: SessionPlacement;
342
- timeoutMs?: number;
343
- maxWaitS?: number;
344
- }
345
- interface DispatchResult {
346
- id: string;
347
- verdict?: unknown;
348
- body: string;
349
- ts: number;
350
- }
351
- /** Thrown by a `--wait` channel call when its internal poll-cycle cap is hit with no reply yet — a
352
- * clean, re-armable sentinel (mirrors `mail await`'s "waiting" outcome), never a failure. */
353
- declare class DispatchWaitingError extends Error {
354
- readonly thread: string;
355
- constructor(thread: string);
356
- }
357
- /**
358
- * `prep()` + spawn a peer session realized from the same agent def + (optionally) `awaitReply` on
359
- * the thread. Requires `--agent`/`--agent-file` (a channel peer needs a real launch to realize).
360
- */
361
- declare function channel(ctx: IdContext, input: ChannelInput, readStdin?: () => string): Promise<DispatchResult | DispatchEnvelope>;
362
- //#endregion
363
- //#region src/dispatch/collect.d.ts
364
- interface CollectContext {
365
- store: Store;
366
- now?: () => number;
367
- }
368
- /** Read + validate a dispatch's result file. Throws (fail-loud) when the file is not yet written,
369
- * or when it fails the optional verdict schema. */
370
- declare function collect(ctx: CollectContext, id: string, verdictSchema?: string): DispatchResult;
371
- //#endregion
372
205
  //#region src/runtime/inject-inbox.d.ts
373
206
  type HookEvent = 'SessionStart' | 'PostToolUse';
374
207
  interface InjectPayload {
@@ -394,7 +227,7 @@ interface InstallResult {
394
227
  status: InstallStatus;
395
228
  }
396
229
  /** Register the surfacing hook into one harness's config, idempotently. */
397
- declare function install(harness: Harness, projectDir?: string): InstallResult[];
230
+ declare function install(harness: Harness, projectDir?: string, pin?: string): InstallResult[];
398
231
  //#endregion
399
232
  //#region src/message.d.ts
400
233
  interface MsgContext {
@@ -432,6 +265,21 @@ declare function ack(ctx: MsgContext, meId: string, msgId: string): Message;
432
265
  /** Permanently remove a message (unread or already-acked) from the caller's inbox. */
433
266
  declare function deleteMessage(ctx: MsgContext, meId: string, msgId: string): void;
434
267
  //#endregion
268
+ //#region src/mux-select.d.ts
269
+ /**
270
+ * Backend selection via cyber-mux's two-mode mux probe, normalized through the transitional
271
+ * `$CYBERLEGION_MUX*` → `$CYBER_MUX*` env seam (`mux-env.ts`) — tmux/herdr map to their existing
272
+ * cyber-mux adapters.
273
+ *
274
+ * cyber-mux detects MORE backends than `unit/registry`'s `AgentRecord.pane` can carry a locator
275
+ * under (`'tmux' | 'herdr'` only). A DETECTED wezterm/zellij is refused HERE, before anything opens,
276
+ * naming the backend it found (mux.feature: "a detected backend a unit record cannot carry is
277
+ * refused before opening anything") — driving it would open a real pane no record could name,
278
+ * stranding a live session `prune` can never reap and no caller can nudge. Anything else (`none`,
279
+ * `screen`) falls through to the plain "no backend" refusal, unchanged from before the migration.
280
+ */
281
+ declare function selectSessionAdapter(env: NodeJS.ProcessEnv, exec?: Exec): MuxAdapter;
282
+ //#endregion
435
283
  //#region src/output.d.ts
436
284
  type Format = 'toon' | 'json';
437
285
  /** One TOON-encoded object: `key: value` lines, blank/undefined fields dropped. */
@@ -459,13 +307,13 @@ declare function fail(msg: string): never;
459
307
  /** Walk up from `cwd` to the nearest git repo root; fall back to `cwd`. */
460
308
  declare function projectRoot(cwd?: string): string;
461
309
  /** Runs a command synchronously in `cwd`; returns trimmed stdout, or null on any failure. */
462
- type Exec$1 = (cmd: string, args: string[]) => string | null;
310
+ type Exec$2 = (cmd: string, args: string[]) => string | null;
463
311
  interface RootOptions {
464
312
  root?: string;
465
313
  space?: string;
466
314
  cwd?: string;
467
315
  env?: NodeJS.ProcessEnv;
468
- exec?: Exec$1;
316
+ exec?: Exec$2;
469
317
  }
470
318
  /**
471
319
  * Resolve the cyberlegion hub root. Precedence: explicit --root/--space, then `$CYBERLEGION_ROOT`,
@@ -475,9 +323,10 @@ interface RootOptions {
475
323
  */
476
324
  declare function resolveRoot(opts?: RootOptions): string;
477
325
  /**
478
- * Resolve the primary checkout's project-local cyberlegion dir — where spawned unit worktrees
479
- * live (never the global hub), keyed off `git worktree`'s common-dir so it resolves the same from
480
- * the primary checkout or from any of its linked worktrees.
326
+ * Resolve the primary checkout's project-local cyberlegion dir — the tracked marker for a
327
+ * legion-enabled project (never the global hub, and never where spawned unit worktrees themselves
328
+ * are checked out — see `resolveUnitWorktreePath`), keyed off `git worktree`'s common-dir so it
329
+ * resolves the same from the primary checkout or from any of its linked worktrees.
481
330
  */
482
331
  declare function resolveProjectLocalRoot(opts?: RootOptions): string;
483
332
  /**
@@ -495,8 +344,7 @@ declare const paths: {
495
344
  inboxReadDir: (root: string, id: string) => string;
496
345
  dataDir: (root: string, id: string) => string;
497
346
  briefFile: (root: string, id: string) => string;
498
- resultFile: (root: string, id: string) => string;
499
- worktreeDir: (root: string, id: string) => string;
347
+ mainPaneFile: (root: string) => string;
500
348
  };
501
349
  //#endregion
502
350
  //#region src/session.d.ts
@@ -512,10 +360,15 @@ interface SpawnInput {
512
360
  command?: string;
513
361
  /** Branch to create the unit's worktree on; defaults to `cyberlegion/unit-<id>`. */
514
362
  branch?: string;
515
- /** Where to check out the unit's worktree; defaults under `<primary>/.agents/cyberlegion/worktrees/<id>`. */
363
+ /** Where to check out the unit's worktree; defaults to a sibling of the primary checkout
364
+ * (`<parent>/<repo>.worktrees/legion-<id6>`, `id6` the same 6-char slice `handle` defaults to)
365
+ * — never nested inside the primary's own tree. */
516
366
  worktreePath?: string;
517
- /** Placement relative to the caller; defaults to 'pane:right'. */
518
- at?: SessionPlacement;
367
+ /** Spawn into this existing directory instead — creates no worktree. Mutually exclusive with
368
+ * `branch`/`worktreePath` (those create a worktree; this reuses one). */
369
+ cwd?: string;
370
+ /** Placement relative to the caller; defaults to 'tab'. */
371
+ at?: MuxPlacement;
519
372
  }
520
373
  interface SpawnResult {
521
374
  agent: AgentRecord;
@@ -528,9 +381,10 @@ interface SpawnResult {
528
381
  * its cwd set to that worktree, pre-register the peer, and drop its brief as a file the peer's own
529
382
  * SessionStart hook reads — never typed into its prompt.
530
383
  *
531
- * Spawned unit worktrees live project-local (`<primary>/.agents/cyberlegion/worktrees/<id>`), even
532
- * though the registry/mailbox itself lives in the global hub — the hub addresses units across
533
- * project and worktree boundaries, but a unit's checkout is necessarily project-local.
384
+ * Spawned unit worktrees live sibling to the primary checkout (`<parent>/<repo>.worktrees/legion-<id6>`),
385
+ * never nested inside it, even though the registry/mailbox itself lives in the global hub — the hub
386
+ * addresses units across project and worktree boundaries, but a unit's checkout is necessarily
387
+ * scoped to this one project's git remote.
534
388
  */
535
389
  declare function spawn(ctx: IdContext, input: SpawnInput): SpawnResult;
536
390
  //#endregion
@@ -556,9 +410,8 @@ declare class FileStore implements Store {
556
410
  removePaneIndex(pane: string): void;
557
411
  writeBrief(agentId: string, text: string): void;
558
412
  readBrief(agentId: string): string | undefined;
559
- resultPath(id: string): string;
560
- writeResult(id: string, value: unknown): void;
561
- readResult(id: string): string | undefined;
413
+ setMainPane(pane: string | null): void;
414
+ getMainPane(): string | undefined;
562
415
  }
563
416
  //#endregion
564
417
  //#region src/wake/await.d.ts
@@ -595,46 +448,6 @@ type AwaitOutcome = {
595
448
  */
596
449
  declare function awaitReply(ctx: MsgContext, input: AwaitInput): Promise<AwaitOutcome>;
597
450
  //#endregion
598
- //#region src/wake/wake-path.d.ts
599
- /**
600
- * The wake-matrix path a gateway would drive a turn through. Pure decision helper — no I/O, no
601
- * polling, no session backend calls; the gateway (`legion-gateway-legate`, CR-5) composes this with
602
- * the actual `mail await` / `session nudge` primitives.
603
- *
604
- * - **A** — a single unbounded `mail await` (not returned here; superseded by A-loop everywhere the
605
- * gateway drives this decision, since a raw A risks a harness tool-timeout SIGKILL).
606
- * - **A-loop** — the portable default: a bounded `mail await` cycle, re-armed by the caller.
607
- * - **A-prime** — Claude Code with an observable background task: run `await` via
608
- * `run_in_background` and poll its result instead of blocking the turn.
609
- * - **B** — a live foreign session behind a verified multiplexer: ring the doorbell
610
- * (`session nudge`) instead of polling. Never selected without a mux.
611
- * - **C** — own-the-PTY (dropped from the shipped matrix; kept as a type for completeness).
612
- * - **D** — `/loop`-style external re-invocation (dropped from the shipped matrix).
613
- * - **E** — hook surfacing at a turn boundary (selected by the caller directly, not by this
614
- * function — it has no wait/poll shape to decide between).
615
- */
616
- type WakePath = 'A' | 'A-loop' | 'A-prime' | 'B' | 'C' | 'D' | 'E';
617
- interface WakePathInput {
618
- /** The calling harness, e.g. 'claude' | 'cursor' | 'codex'. */
619
- harness: string;
620
- mux: MuxProbe;
621
- /** The harness can observe a backgrounded task's result without blocking the turn. */
622
- observable?: boolean;
623
- /** The target is a live, foreign interactive session that can be rung rather than polled. */
624
- dedicatedListener?: boolean;
625
- }
626
- interface WakePathResult {
627
- path: WakePath;
628
- why: string;
629
- }
630
- /**
631
- * Select a wake path from the shipped matrix. Rule order: a `mux.mux === 'none'` caller can never
632
- * get **B** — it always falls through to the bounded poll. Claude Code + an observable background
633
- * task prefers **A-prime**. A live foreign session behind a verified mux prefers **B**. Otherwise
634
- * the portable default is **A-loop**.
635
- */
636
- declare function selectWakePath(input: WakePathInput): WakePathResult;
637
- //#endregion
638
451
  //#region src/wake/watch.d.ts
639
452
  interface WatchInput {
640
453
  meId: string;
@@ -653,4 +466,4 @@ interface WatchOptions {
653
466
  */
654
467
  declare function watchMail(ctx: MsgContext, input: WatchInput, onMessage: (msg: InboxItem) => void, opts?: WatchOptions): Promise<void>;
655
468
  //#endregion
656
- export { type AgentDef, type AgentRecord, type AwaitInput, type AwaitOutcome, type ChannelInput, type DecommissionInput, type DecommissionResult, type DispatchEnvelope, type DispatchResult, DispatchWaitingError, type Exec, FileStore, type Format, type Harness, type HookEvent, type IdContext, type InboxItem, type InboxQuery, type InboxSnapshot, type Message, type MuxProbe, type PrepInput, type RegisterInput, type RootOptions, type SendInput, type SpawnInput, type SpawnResult, type Store, type WakePathInput, type WakePathResult, ack, assertDistinctFromPrimary, awaitReply, bumpLastSeen, channel, collect, decommission, deleteMessage, detectHarness, emit, ensureMarker, fail, gitWorktreeAdapter, inbox, injectInbox, install, listAgentDefs, listAgents, loadAgent, nextStep, paths, peek, prep, probeMultiplexer, projectRoot, prune, realExec, realizeLaunch, realizeSubagentInstruction, register, resolveAgent, resolveAgentDef, resolveBody, resolvePrimaryRoot, resolveProjectLocalRoot, resolveRecipient, resolveRoot, resolveSelfId, selectSessionAdapter, selectWakePath, send, spawn, toonList, toonObject, touch, watchMail };
469
+ export { type AgentDef, type AgentRecord, type AwaitInput, type AwaitOutcome, type DecommissionInput, type DecommissionResult, type Exec, FileStore, type Format, type Harness, type HookEvent, type IdContext, type InboxItem, type InboxQuery, type InboxSnapshot, type Message, type MuxProbe, type RegisterInput, type RootOptions, type SendInput, type SpawnInput, type SpawnResult, type Store, ack, assertDistinctFromPrimary, awaitReply, bumpLastSeen, decommission, deleteMessage, detectHarness, emit, ensureMarker, fail, gitWorktreeAdapter, inbox, injectInbox, install, listAgentDefs, listAgents, loadAgent, nextStep, paths, peek, probeMultiplexer, projectRoot, prune, realExec, realizeLaunch, register, resolveAgent, resolveAgentDef, resolveBody, resolvePrimaryRoot, resolveProjectLocalRoot, resolveRecipient, resolveRoot, resolveSelfId, selectSessionAdapter, send, spawn, toonList, toonObject, touch, watchMail };
package/dist/index.mjs CHANGED
@@ -1,28 +1,4 @@
1
- import { A as resolveProjectLocalRoot, B as loadAgent, C as resolveAgentDef, D as ensureMarker, E as spawn, F as selectSessionAdapter, G as resolveRecipient, H as realExec, I as probeMultiplexer, K as resolveSelfId, L as bumpLastSeen, M as assertDistinctFromPrimary, N as gitWorktreeAdapter, O as paths, P as resolvePrimaryRoot, R as detectHarness, S as listAgentDefs, T as realizeSubagentInstruction, U as register, V as prune, W as resolveAgent, _ as inbox, a as fail, b as send, c as toonObject, d as DispatchWaitingError, f as channel, g as deleteMessage, h as ack, i as emit, j as resolveRoot, k as projectRoot, l as install, m as awaitReply, n as FileStore, o as nextStep, p as prep, q as touch, r as injectInbox, s as toonList, t as watchMail, u as collect, v as peek, w as realizeLaunch, x as decommission, y as resolveBody, z as listAgents } from "./watch-DA8I44dv.mjs";
2
- //#region src/wake/wake-path.ts
3
- /**
4
- * Select a wake path from the shipped matrix. Rule order: a `mux.mux === 'none'` caller can never
5
- * get **B** — it always falls through to the bounded poll. Claude Code + an observable background
6
- * task prefers **A-prime**. A live foreign session behind a verified mux prefers **B**. Otherwise
7
- * the portable default is **A-loop**.
8
- */
9
- function selectWakePath(input) {
10
- if (input.mux.mux === "none") return {
11
- path: "A-loop",
12
- why: "no multiplexer detected — bounded poll only, B is never available"
13
- };
14
- if (input.harness === "claude" && input.observable) return {
15
- path: "A-prime",
16
- why: "Claude Code + an observable background task — await via run_in_background"
17
- };
18
- if (input.dedicatedListener) return {
19
- path: "B",
20
- why: `a live foreign session behind a verified ${input.mux.mux} mux — ring the doorbell`
21
- };
22
- return {
23
- path: "A-loop",
24
- why: "portable default — bounded mail await cycle"
25
- };
26
- }
27
- //#endregion
28
- export { DispatchWaitingError, FileStore, ack, assertDistinctFromPrimary, awaitReply, bumpLastSeen, channel, collect, decommission, deleteMessage, detectHarness, emit, ensureMarker, fail, gitWorktreeAdapter, inbox, injectInbox, install, listAgentDefs, listAgents, loadAgent, nextStep, paths, peek, prep, probeMultiplexer, projectRoot, prune, realExec, realizeLaunch, realizeSubagentInstruction, register, resolveAgent, resolveAgentDef, resolveBody, resolvePrimaryRoot, resolveProjectLocalRoot, resolveRecipient, resolveRoot, resolveSelfId, selectSessionAdapter, selectWakePath, send, spawn, toonList, toonObject, touch, watchMail };
1
+ import { A as loadAgent, B as resolveSelfId, C as spawn, F as register, G as projectRoot, H as touch, K as resolveProjectLocalRoot, L as resolveAgent, M as prune, N as realExec, O as detectHarness, T as bumpLastSeen, U as ensureMarker, W as paths, _ as install, a as emit, b as resolveAgentDef, c as toonList, d as deleteMessage, f as inbox, g as send, h as resolveBody, i as injectInbox, k as listAgents, l as toonObject, n as awaitReply, o as fail, p as peek, q as resolveRoot, r as FileStore, s as nextStep, t as watchMail, u as ack, v as decommission, w as selectSessionAdapter, x as realizeLaunch, y as listAgentDefs, z as resolveRecipient } from "./watch-nkm6F1_f.mjs";
2
+ import { probeMultiplexer } from "cyber-mux";
3
+ import { assertDistinctFromPrimary, gitWorktreeAdapter, resolvePrimaryRoot } from "cyber-mux/worktree";
4
+ export { FileStore, ack, assertDistinctFromPrimary, awaitReply, bumpLastSeen, decommission, deleteMessage, detectHarness, emit, ensureMarker, fail, gitWorktreeAdapter, inbox, injectInbox, install, listAgentDefs, listAgents, loadAgent, nextStep, paths, peek, probeMultiplexer, projectRoot, prune, realExec, realizeLaunch, register, resolveAgent, resolveAgentDef, resolveBody, resolvePrimaryRoot, resolveProjectLocalRoot, resolveRecipient, resolveRoot, resolveSelfId, selectSessionAdapter, send, spawn, toonList, toonObject, touch, watchMail };