cyber-mux 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +73 -0
  2. package/dist/agent.d.mts +76 -10
  3. package/dist/agent.d.mts.map +1 -1
  4. package/dist/agent.mjs +12 -8
  5. package/dist/agent.mjs.map +1 -1
  6. package/dist/{backend-AErdtLRB.mjs → backend-Dg5JGbd3.mjs} +2272 -313
  7. package/dist/backend-Dg5JGbd3.mjs.map +1 -0
  8. package/dist/cli-BB14CKcd.mjs +3117 -0
  9. package/dist/cli-BB14CKcd.mjs.map +1 -0
  10. package/dist/cli.d.mts +44 -8
  11. package/dist/cli.d.mts.map +1 -1
  12. package/dist/cli.mjs +2 -2595
  13. package/dist/index.d.mts +189 -10
  14. package/dist/index.d.mts.map +1 -1
  15. package/dist/index.mjs +3 -3
  16. package/dist/{mux-DBpfXsdE.d.mts → mux-CDrZQglk.d.mts} +395 -46
  17. package/dist/mux-CDrZQglk.d.mts.map +1 -0
  18. package/dist/plugin.d.mts +15 -0
  19. package/dist/plugin.d.mts.map +1 -0
  20. package/dist/plugin.mjs +23 -0
  21. package/dist/plugin.mjs.map +1 -0
  22. package/dist/template.mjs +1 -1
  23. package/dist/{worktree-hHuFZkpW.mjs → worktree-Bj6IgHv7.mjs} +204 -11
  24. package/dist/worktree-Bj6IgHv7.mjs.map +1 -0
  25. package/dist/{worktree-9QDz-iKC.d.mts → worktree-QnKzOVzL.d.mts} +75 -13
  26. package/dist/worktree-QnKzOVzL.d.mts.map +1 -0
  27. package/dist/worktree.d.mts +2 -2
  28. package/dist/worktree.mjs +2 -2
  29. package/package.json +8 -4
  30. package/src/agent-states.ts +73 -0
  31. package/src/agent.ts +25 -8
  32. package/src/backend.ts +3 -2
  33. package/src/cli-options.ts +58 -32
  34. package/src/cli.ts +1021 -850
  35. package/src/env-fallback.ts +64 -10
  36. package/src/focus-on-open.ts +95 -0
  37. package/src/index.ts +9 -3
  38. package/src/move.ts +103 -0
  39. package/src/mux-probe.ts +30 -7
  40. package/src/mux.cmux.ts +556 -139
  41. package/src/mux.herdr.ts +213 -5
  42. package/src/mux.otty.ts +446 -66
  43. package/src/mux.rmux.ts +129 -2
  44. package/src/mux.tmux.ts +222 -26
  45. package/src/mux.ts +316 -43
  46. package/src/mux.wezterm.ts +323 -75
  47. package/src/mux.zellij.ts +257 -25
  48. package/src/plugin.ts +20 -0
  49. package/src/worktree.ts +294 -19
  50. package/src/zoom.ts +77 -0
  51. package/dist/backend-AErdtLRB.mjs.map +0 -1
  52. package/dist/cli.mjs.map +0 -1
  53. package/dist/mux-DBpfXsdE.d.mts.map +0 -1
  54. package/dist/worktree-9QDz-iKC.d.mts.map +0 -1
  55. package/dist/worktree-hHuFZkpW.mjs.map +0 -1
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # cyber-mux
2
+
3
+ [![npm version](https://img.shields.io/npm/v/cyber-mux.svg)](https://www.npmjs.com/package/cyber-mux)
4
+ [![npm downloads](https://img.shields.io/npm/dm/cyber-mux.svg)](https://www.npmjs.com/package/cyber-mux)
5
+ [![release](https://github.com/cyberuni/cyber-mux/actions/workflows/release.yml/badge.svg)](https://github.com/cyberuni/cyber-mux/actions/workflows/release.yml)
6
+ [![docs](https://img.shields.io/badge/docs-cyberuni.github.io-blue)](https://cyberuni.github.io/cyber-mux/)
7
+ [![license](https://img.shields.io/npm/l/cyber-mux.svg)](https://www.npmjs.com/package/cyber-mux)
8
+
9
+ Cross-multiplexer pane control for AI-agent tooling. One contract over terminal multiplexers — open,
10
+ send, read, focus, and close panes without caring which multiplexer you are inside.
11
+
12
+ `cyber-mux` is the mux seam used by [`cyberlegion`](https://github.com/cyberuni/cyberplace), kept
13
+ deliberately narrow: it drives panes and nothing else.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ npx cyber-mux mode
19
+ ```
20
+
21
+ ## What it does
22
+
23
+ - **Detects** the multiplexer you are running under — env fast-path (`CYBER_MUX` / `CYBER_MUX_PANE`),
24
+ otherwise a process-ancestry walk falling back to the multiplexer's own env hints.
25
+ - **Drives panes** through one `MuxAdapter` contract: `open`, `send`, `submit`, `read`, `wait`,
26
+ `focus`, `close`, `list`, `exists`.
27
+ - **Nudges** a peer pane and verifies the turn was actually taken (recovers a submit swallowed by a
28
+ booting harness).
29
+ - **Worktrees**: create a git worktree and open it in a new workspace/session in one step.
30
+
31
+ ## Backends
32
+
33
+ Drivable: **tmux**, **rmux**, **herdr**, **wezterm**, **zellij**, **cmux**, **otty**.
34
+
35
+ GNU **screen** is recognized and reported truthfully, then rejected with a named error rather than
36
+ driven — it addresses panes positionally, so a driver-created pane has no stable identity to send to,
37
+ read from, or self-identify by.
38
+
39
+ ## Commands
40
+
41
+ | Command | Description |
42
+ | --- | --- |
43
+ | `cyber-mux doctor` | Probe the multiplexer, self pane, and backend; print fast-path pins |
44
+ | `cyber-mux mode` | Report the detected session backend |
45
+ | `cyber-mux open` | Open a new pane/tab/workspace, optionally launching a command in it |
46
+ | `cyber-mux send` | Drive a pane without taking its turn (text or keys) |
47
+ | `cyber-mux submit` | Take a pane's turn: type the text if given, then press Enter |
48
+ | `cyber-mux read` | Capture a pane's output |
49
+ | `cyber-mux wait` | Block until a pane's output matches (exit 0), or the timeout elapses (exit 1) |
50
+ | `cyber-mux focus` | Beam the attached client to a pane |
51
+ | `cyber-mux close` | Close a pane |
52
+ | `cyber-mux list` / `exists` | Enumerate live panes / probe whether one is still live |
53
+ | `cyber-mux worktree` | Git worktree helpers for spawning and tearing down a session |
54
+ | `cyber-mux template` | Manage named templates (apply one with `open`/`worktree --template`) |
55
+ | `cyber-mux agent` | Inspect and wait on a pane's agent-lifecycle state |
56
+
57
+ Full reference: <https://cyberuni.github.io/cyber-mux/>
58
+
59
+ ## Development
60
+
61
+ Node and pnpm are pinned in `mise.toml` and managed by [mise](https://mise.jdx.dev):
62
+
63
+ ```bash
64
+ mise install # node + pnpm at the pinned versions
65
+ pnpm install
66
+ pnpm verify # build + typecheck + lint + test
67
+ ```
68
+
69
+ The CLI lives in `packages/cyber-mux`; the docs site in `apps/website` (Astro + Starlight).
70
+
71
+ ## License
72
+
73
+ MIT
package/dist/agent.d.mts CHANGED
@@ -1,12 +1,70 @@
1
1
  import { t as Exec } from "./exec-B81m4yjz.mjs";
2
- import { f as MuxTarget, n as AgentStatus, o as MuxAdapter, r as AgentWaitOptions, t as AgentLifecycle } from "./mux-DBpfXsdE.mjs";
2
+ import { m as MuxTarget, n as AgentStatus, o as MuxAdapter, r as AgentWaitOptions, t as AgentLifecycle } from "./mux-CDrZQglk.mjs";
3
+ //#region src/agent-states.d.ts
4
+ /**
5
+ * The agent-wait STATE-SET refusal — what an `AgentLifecycle` backend answers when it has the native
6
+ * wait but cannot express the state set the caller asked for.
7
+ *
8
+ * Its own module rather than a member of `agent.ts` for the reason `floating.ts`/`zoom.ts`/`resize.ts`
9
+ * are their own modules: the adapters throw it, and `agent.ts` imports `backend.ts`, which imports
10
+ * every adapter — so an adapter reaching into `agent.ts` for the class would close a cycle. The class
11
+ * lives here and RIDES OUT on the `cyber-mux/agent` subpath (re-exported by `agent.ts`), because the
12
+ * capability it belongs to is that subpath's and deliberately not on the core barrel.
13
+ */
14
+ /**
15
+ * A wait asked for states the backend's native wait cannot name. Distinct from
16
+ * `AgentLifecycleUnsupportedError`, and the distinction is the whole point: that one says *this
17
+ * backend has no agent wait at all*; this one says *it has one, and its vocabulary is narrower than
18
+ * what you asked for*. Collapsing them would tell a caller on otty to "run it on herdr" when the fix
19
+ * is to drop one state from `until`.
20
+ *
21
+ * **Refused by NAME rather than silently narrowed**, which is the only honest answer available. A
22
+ * backend that waits on `idle` alone, handed `until: ['idle', 'blocked']`, has exactly three options:
23
+ * wait for `idle` only and return it (a wait that ends on a state the caller did not ask for — the
24
+ * plausible-wrong-answer shape), wait for all of them (impossible, there is no flag), or say so. It
25
+ * says so.
26
+ *
27
+ * PORTABLE and exit-code-free by design, the same shape every other seam refusal takes. `backend`
28
+ * names the backend, `requested` the set that was asked for, and `supported` the set the backend can
29
+ * actually end a wait on — so a caller composes the fix without re-deriving any of it.
30
+ */
31
+ declare class AgentWaitStatesUnsupportedError extends Error {
32
+ readonly backend: string;
33
+ readonly requested: readonly AgentStatus[];
34
+ readonly supported: readonly AgentStatus[];
35
+ constructor(backend: string, requested: readonly AgentStatus[], supported: readonly AgentStatus[]);
36
+ }
37
+ /**
38
+ * Refuse an `until` set a backend's native wait cannot express — the single spelling of the refusal,
39
+ * so a second backend with a narrow vocabulary cannot drift into a second message.
40
+ *
41
+ * Takes the backend NAME rather than the adapter, for `refuseFloatingPane`/`refusePaneZoom`'s reason:
42
+ * it is called from inside an adapter method while the adapter object is still being constructed, and
43
+ * the name is the only thing the error carries anyway.
44
+ */
45
+ declare function refuseAgentWaitStates(backend: string, requested: readonly AgentStatus[], supported: readonly AgentStatus[]): never;
46
+ /**
47
+ * Whether `until` is satisfiable by a backend whose native wait ends on exactly `supported`.
48
+ *
49
+ * An EMPTY or omitted `until` is satisfiable by construction: the seam defines it as *take the
50
+ * backend's own default*, and a backend never restates that default in the command it runs — so there
51
+ * is nothing to check. A non-empty set is satisfiable only when every state in it is one the backend
52
+ * can end on; a set that names a state the backend cannot reach would otherwise end the wait on a
53
+ * state nobody asked for.
54
+ */
55
+ declare function agentWaitStatesSatisfiable(until: readonly AgentStatus[] | undefined, supported: readonly AgentStatus[]): boolean;
56
+ //#endregion
3
57
  //#region src/agent.d.ts
4
58
  /**
5
- * An agent-lifecycle wait asked of a backend that has no native agent-state primitive (`agent wait`
6
- * on tmux, wezterm or zellij). An absent `agentLifecycle` seam member is a REFUSAL, never a guess: a
7
- * wait built from `read()` polling would silently disagree with herdr's own state derivation on the
8
- * same question, and a wait has no truthful degrade the way a snapshot does — so a backend that cannot
9
- * answer is refused rather than emulated.
59
+ * An agent-lifecycle wait asked of a backend that has no native agent-state primitive (`agent wait` on
60
+ * tmux, rmux, wezterm, zellij or cmux). An absent `agentLifecycle` seam member is a REFUSAL, never a
61
+ * guess: a wait built from `read()` polling would silently disagree with the backend's own state
62
+ * derivation on the same question, and a wait has no truthful degrade the way a snapshot does — so a
63
+ * backend that cannot answer is refused rather than emulated.
64
+ *
65
+ * Distinct from `AgentWaitStatesUnsupportedError` (`agent-states.ts`), which a backend that HAS the
66
+ * wait throws when its vocabulary is narrower than the `until` it was handed. This one says *no wait
67
+ * here*; that one says *this wait, not those states*.
10
68
  *
11
69
  * PORTABLE and exit-code-free by design, the exact mirror of `CaptureUnsupportedError`. The DECISION
12
70
  * to refuse is the library's and lives in `deriveAgentWait`, the one place that sees the adapter — how
@@ -42,14 +100,22 @@ declare function deriveAgentWait(adapter: MuxAdapter, exec: Exec, target: MuxTar
42
100
  * stays specified once and enforced once, with no second refusal path here that could drift from it.
43
101
  */
44
102
  interface AgentApi {
45
- /** Whether this backend reports agent-lifecycle state at all (herdr yes; tmux/wezterm/zellij no). */
103
+ /** Whether this backend can WAIT on agent-lifecycle state (herdr and otty yes; the rest no). */
46
104
  supported(): boolean;
47
- /** A pane's current agent state, or `undefined` when the backend has no feed (absent-not-false). */
105
+ /**
106
+ * A pane's current agent state, or `undefined` when the backend has no feed (absent-not-false).
107
+ *
108
+ * Deliberately NOT the question `supported()` answers, and otty is the backend that proves the two
109
+ * are independent: otty can BLOCK on its own agent state but exposes no documented CLI read of it,
110
+ * so `supported()` is `true` there while this stays `undefined`. Until otty they happened to agree
111
+ * on every backend.
112
+ */
48
113
  status(target: MuxTarget): AgentStatus | undefined;
49
114
  /**
50
115
  * Block until the pane's agent reaches one of `opts.until` (or the backend's default set); throws
51
116
  * `AgentLifecycleUnsupportedError` naming the backend on one without the capability, via
52
- * `deriveAgentWait`. A bare `wait(target)` takes herdr's own defaults (`opts ?? {}`).
117
+ * `deriveAgentWait`, or `AgentWaitStatesUnsupportedError` on one whose native wait cannot name every
118
+ * requested state. A bare `wait(target)` takes the backend's own defaults (`opts ?? {}`).
53
119
  */
54
120
  wait(target: MuxTarget, opts?: AgentWaitOptions | undefined): AgentStatus;
55
121
  }
@@ -62,5 +128,5 @@ declare function agentApi(env: NodeJS.ProcessEnv, deps?: {
62
128
  exec?: Exec | undefined;
63
129
  } | undefined): AgentApi;
64
130
  //#endregion
65
- export { AgentApi, type AgentLifecycle, AgentLifecycleUnsupportedError, type AgentStatus, type AgentWaitOptions, agentApi, deriveAgentWait };
131
+ export { AgentApi, type AgentLifecycle, AgentLifecycleUnsupportedError, type AgentStatus, type AgentWaitOptions, AgentWaitStatesUnsupportedError, agentApi, agentWaitStatesSatisfiable, deriveAgentWait, refuseAgentWaitStates };
66
132
  //# sourceMappingURL=agent.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.mts","names":[],"sources":["../src/agent.ts"],"mappings":";;;;;;;;;;;;;;;;cA4Ba,uCAAuC;WACvC;EAAZ,YAAY;;;;;;;;;;;;;iBAiBG,gBACf,SAAS,YACT,MAAM,MACN,QAAQ,WACR,MAAM,mBACJ;;;;;;;;;;;;UAiBc;;EAEhB;;EAEA,OAAO,QAAQ,YAAY;;;;;;EAM3B,KAAK,QAAQ,WAAW,OAAO,+BAA+B;;;;;;;iBAQ/C,SAAS,KAAK,OAAO,YAAY;EAAS,OAAO;gBAAiC"}
1
+ {"version":3,"file":"agent.d.mts","names":[],"sources":["../src/agent-states.ts","../src/agent.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8Ba,wCAAwC;WAEnD;WACA,oBAA6B;WAC7B,oBAA6B;EAH9B,YACC,iBACA,oBAA6B,eAC7B,oBAA6B;;;;;;;;;;iBAef,sBACf,iBACA,oBAAoB,eACpB,oBAAoB;;;;;;;;;;iBAcL,2BACf,gBAAgB,2BAChB,oBAAoB;;;;;;;;;;;;;;;;;;;;cC/BR,uCAAuC;WACvC;EAAZ,YAAY;;;;;;;;;;;;;iBAiBG,gBACf,SAAS,YACT,MAAM,MACN,QAAQ,WACR,MAAM,mBACJ;;;;;;;;;;;;UAiBc;;EAEhB;;;;;;;;;EASA,OAAO,QAAQ,YAAY;;;;;;;EAO3B,KAAK,QAAQ,WAAW,OAAO,+BAA+B;;;;;;;iBAQ/C,SAAS,KAAK,OAAO,YAAY;EAAS,OAAO;gBAAiC"}
package/dist/agent.mjs CHANGED
@@ -1,12 +1,16 @@
1
- import { m as nodeExec } from "./worktree-hHuFZkpW.mjs";
2
- import { r as resolveMuxAdapter } from "./backend-AErdtLRB.mjs";
1
+ import { h as nodeExec } from "./worktree-Bj6IgHv7.mjs";
2
+ import { b as agentWaitStatesSatisfiable, r as resolveMuxAdapter, x as refuseAgentWaitStates, y as AgentWaitStatesUnsupportedError } from "./backend-Dg5JGbd3.mjs";
3
3
  //#region src/agent.ts
4
4
  /**
5
- * An agent-lifecycle wait asked of a backend that has no native agent-state primitive (`agent wait`
6
- * on tmux, wezterm or zellij). An absent `agentLifecycle` seam member is a REFUSAL, never a guess: a
7
- * wait built from `read()` polling would silently disagree with herdr's own state derivation on the
8
- * same question, and a wait has no truthful degrade the way a snapshot does — so a backend that cannot
9
- * answer is refused rather than emulated.
5
+ * An agent-lifecycle wait asked of a backend that has no native agent-state primitive (`agent wait` on
6
+ * tmux, rmux, wezterm, zellij or cmux). An absent `agentLifecycle` seam member is a REFUSAL, never a
7
+ * guess: a wait built from `read()` polling would silently disagree with the backend's own state
8
+ * derivation on the same question, and a wait has no truthful degrade the way a snapshot does — so a
9
+ * backend that cannot answer is refused rather than emulated.
10
+ *
11
+ * Distinct from `AgentWaitStatesUnsupportedError` (`agent-states.ts`), which a backend that HAS the
12
+ * wait throws when its vocabulary is narrower than the `until` it was handed. This one says *no wait
13
+ * here*; that one says *this wait, not those states*.
10
14
  *
11
15
  * PORTABLE and exit-code-free by design, the exact mirror of `CaptureUnsupportedError`. The DECISION
12
16
  * to refuse is the library's and lives in `deriveAgentWait`, the one place that sees the adapter — how
@@ -53,6 +57,6 @@ function agentApi(env, deps) {
53
57
  };
54
58
  }
55
59
  //#endregion
56
- export { AgentLifecycleUnsupportedError, agentApi, deriveAgentWait };
60
+ export { AgentLifecycleUnsupportedError, AgentWaitStatesUnsupportedError, agentApi, agentWaitStatesSatisfiable, deriveAgentWait, refuseAgentWaitStates };
57
61
 
58
62
  //# sourceMappingURL=agent.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.mjs","names":[],"sources":["../src/agent.ts"],"sourcesContent":["import { resolveMuxAdapter } from './backend.ts'\nimport { type Exec, nodeExec } from './exec.ts'\nimport type { AgentStatus, AgentWaitOptions, MuxAdapter, MuxTarget } from './mux.ts'\n\n/**\n * The `cyber-mux/agent` subpath — the agent-lifecycle capability's orchestrator and its refusal.\n *\n * The `AgentStatus` type rides out on the `.` barrel (it is part of `LivePane`, and `mux.ts` is\n * re-exported there); the WAIT capability — the `AgentLifecycle` seam plus the emulate-or-refuse\n * decision below — is this subpath alone, kept off the core barrel exactly as `template`'s apply\n * engine is: a capability nobody has to import to drive a pane is not on the surface everybody gets.\n */\n\nexport type { AgentLifecycle, AgentStatus, AgentWaitOptions } from './mux.ts'\n\n/**\n * An agent-lifecycle wait asked of a backend that has no native agent-state primitive (`agent wait`\n * on tmux, wezterm or zellij). An absent `agentLifecycle` seam member is a REFUSAL, never a guess: a\n * wait built from `read()` polling would silently disagree with herdr's own state derivation on the\n * same question, and a wait has no truthful degrade the way a snapshot does — so a backend that cannot\n * answer is refused rather than emulated.\n *\n * PORTABLE and exit-code-free by design, the exact mirror of `CaptureUnsupportedError`. The DECISION\n * to refuse is the library's and lives in `deriveAgentWait`, the one place that sees the adapter — how\n * the refusal SURFACES (the exit code, the fix hint, the exact sentence) is the CLI's, which catches\n * this and re-raises its own `backend-unsupported` error. `backend` names the backend so the caller\n * composes the message without re-deriving it; the terse `message` is a factual log line.\n */\nexport class AgentLifecycleUnsupportedError extends Error {\n\tconstructor(readonly backend: string) {\n\t\tsuper(`${backend} cannot report agent-lifecycle state`)\n\t\tthis.name = 'AgentLifecycleUnsupportedError'\n\t}\n}\n\n/**\n * Wait for the target pane's agent to reach one of `opts.until` (or the backend's default set) through\n * the adapter — the surface-independent orchestrator `agent wait` drives, and the single home of the\n * agent-wait refusal. The optional `agentLifecycle` seam is where a backend says whether it has a\n * native wait at all; a backend without it is refused HERE (`AgentLifecycleUnsupportedError`), BEFORE\n * any exec, because `waitForState` never sees the adapter and so cannot make that call. A backend that\n * HAS the capability delegates to it unchanged.\n *\n * Mirrors `deriveRegionCapture` (`template-capture.ts`) exactly: the orchestrator is the one place that\n * sees the adapter, so it is the one place the emulate-or-refuse decision can be made.\n */\nexport function deriveAgentWait(\n\tadapter: MuxAdapter,\n\texec: Exec,\n\ttarget: MuxTarget,\n\topts: AgentWaitOptions,\n): AgentStatus {\n\tconst agentLifecycle = adapter.agentLifecycle\n\tif (!agentLifecycle) throw new AgentLifecycleUnsupportedError(adapter.name)\n\treturn agentLifecycle.waitForState(exec, target, opts)\n}\n\n/**\n * The `agent` subpath facade with its `Exec` and backend BOUND — the exec-bound parallel of\n * `worktreeApi`/`templateApi`. `agentApi(env, deps?)` resolves the backend adapter from `env` ONCE\n * (`resolveMuxAdapter`, defaulting `exec` to `nodeExec`) and exposes `supported`/`status`/`wait` with\n * the seams already threaded, so a caller never re-plumbs an adapter or a runner into them.\n *\n * It ADDS no logic of its own: `supported` reads the very capability presence `deriveAgentWait` gates\n * on, `status` reads the same `LivePane.agentStatus` the listing already carries (for one pane rather\n * than redefining it), and `wait` routes THROUGH `deriveAgentWait` — so the emulate-or-refuse decision\n * stays specified once and enforced once, with no second refusal path here that could drift from it.\n */\nexport interface AgentApi {\n\t/** Whether this backend reports agent-lifecycle state at all (herdr yes; tmux/wezterm/zellij no). */\n\tsupported(): boolean\n\t/** A pane's current agent state, or `undefined` when the backend has no feed (absent-not-false). */\n\tstatus(target: MuxTarget): AgentStatus | undefined\n\t/**\n\t * Block until the pane's agent reaches one of `opts.until` (or the backend's default set); throws\n\t * `AgentLifecycleUnsupportedError` naming the backend on one without the capability, via\n\t * `deriveAgentWait`. A bare `wait(target)` takes herdr's own defaults (`opts ?? {}`).\n\t */\n\twait(target: MuxTarget, opts?: AgentWaitOptions | undefined): AgentStatus\n}\n\n/**\n * Bind the agent-lifecycle capability to an environment and runner once, returning an `AgentApi` whose\n * methods no longer take an `Exec`. `deps.exec` defaults to `nodeExec`; `env` is bound like\n * `resolveMux(env)` because it is what the probe resolves the backend from.\n */\nexport function agentApi(env: NodeJS.ProcessEnv, deps?: { exec?: Exec | undefined } | undefined): AgentApi {\n\tconst exec = deps?.exec ?? nodeExec\n\tconst adapter = resolveMuxAdapter(env, exec)\n\treturn {\n\t\tsupported: () => adapter.agentLifecycle !== undefined,\n\t\tstatus: (target) => adapter.listPanes(exec).find((p) => p.id === target.id)?.agentStatus,\n\t\twait: (target, opts) => deriveAgentWait(adapter, exec, target, opts ?? {}),\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA4BA,IAAa,iCAAb,cAAoD,MAAM;CACpC;CAArB,YAAY,SAA0B;EACrC,MAAM,GAAG,QAAQ,qCAAqC;EADlC,KAAA,UAAA;EAEpB,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;AAaA,SAAgB,gBACf,SACA,MACA,QACA,MACc;CACd,MAAM,iBAAiB,QAAQ;CAC/B,IAAI,CAAC,gBAAgB,MAAM,IAAI,+BAA+B,QAAQ,IAAI;CAC1E,OAAO,eAAe,aAAa,MAAM,QAAQ,IAAI;AACtD;;;;;;AA+BA,SAAgB,SAAS,KAAwB,MAA0D;CAC1G,MAAM,OAAO,MAAM,QAAQ;CAC3B,MAAM,UAAU,kBAAkB,KAAK,IAAI;CAC3C,OAAO;EACN,iBAAiB,QAAQ,mBAAmB,KAAA;EAC5C,SAAS,WAAW,QAAQ,UAAU,IAAI,CAAC,CAAC,MAAM,MAAM,EAAE,OAAO,OAAO,EAAE,CAAC,EAAE;EAC7E,OAAO,QAAQ,SAAS,gBAAgB,SAAS,MAAM,QAAQ,QAAQ,CAAC,CAAC;CAC1E;AACD"}
1
+ {"version":3,"file":"agent.mjs","names":[],"sources":["../src/agent.ts"],"sourcesContent":["import { resolveMuxAdapter } from './backend.ts'\nimport { type Exec, nodeExec } from './exec.ts'\nimport type { AgentStatus, AgentWaitOptions, MuxAdapter, MuxTarget } from './mux.ts'\n\n/**\n * The `cyber-mux/agent` subpath — the agent-lifecycle capability's orchestrator and its refusal.\n *\n * The `AgentStatus` type rides out on the `.` barrel (it is part of `LivePane`, and `mux.ts` is\n * re-exported there); the WAIT capability — the `AgentLifecycle` seam plus the emulate-or-refuse\n * decision below — is this subpath alone, kept off the core barrel exactly as `template`'s apply\n * engine is: a capability nobody has to import to drive a pane is not on the surface everybody gets.\n */\n\nexport {\n\tAgentWaitStatesUnsupportedError,\n\tagentWaitStatesSatisfiable,\n\trefuseAgentWaitStates,\n} from './agent-states.ts'\nexport type { AgentLifecycle, AgentStatus, AgentWaitOptions } from './mux.ts'\n\n/**\n * An agent-lifecycle wait asked of a backend that has no native agent-state primitive (`agent wait` on\n * tmux, rmux, wezterm, zellij or cmux). An absent `agentLifecycle` seam member is a REFUSAL, never a\n * guess: a wait built from `read()` polling would silently disagree with the backend's own state\n * derivation on the same question, and a wait has no truthful degrade the way a snapshot does — so a\n * backend that cannot answer is refused rather than emulated.\n *\n * Distinct from `AgentWaitStatesUnsupportedError` (`agent-states.ts`), which a backend that HAS the\n * wait throws when its vocabulary is narrower than the `until` it was handed. This one says *no wait\n * here*; that one says *this wait, not those states*.\n *\n * PORTABLE and exit-code-free by design, the exact mirror of `CaptureUnsupportedError`. The DECISION\n * to refuse is the library's and lives in `deriveAgentWait`, the one place that sees the adapter — how\n * the refusal SURFACES (the exit code, the fix hint, the exact sentence) is the CLI's, which catches\n * this and re-raises its own `backend-unsupported` error. `backend` names the backend so the caller\n * composes the message without re-deriving it; the terse `message` is a factual log line.\n */\nexport class AgentLifecycleUnsupportedError extends Error {\n\tconstructor(readonly backend: string) {\n\t\tsuper(`${backend} cannot report agent-lifecycle state`)\n\t\tthis.name = 'AgentLifecycleUnsupportedError'\n\t}\n}\n\n/**\n * Wait for the target pane's agent to reach one of `opts.until` (or the backend's default set) through\n * the adapter — the surface-independent orchestrator `agent wait` drives, and the single home of the\n * agent-wait refusal. The optional `agentLifecycle` seam is where a backend says whether it has a\n * native wait at all; a backend without it is refused HERE (`AgentLifecycleUnsupportedError`), BEFORE\n * any exec, because `waitForState` never sees the adapter and so cannot make that call. A backend that\n * HAS the capability delegates to it unchanged.\n *\n * Mirrors `deriveRegionCapture` (`template-capture.ts`) exactly: the orchestrator is the one place that\n * sees the adapter, so it is the one place the emulate-or-refuse decision can be made.\n */\nexport function deriveAgentWait(\n\tadapter: MuxAdapter,\n\texec: Exec,\n\ttarget: MuxTarget,\n\topts: AgentWaitOptions,\n): AgentStatus {\n\tconst agentLifecycle = adapter.agentLifecycle\n\tif (!agentLifecycle) throw new AgentLifecycleUnsupportedError(adapter.name)\n\treturn agentLifecycle.waitForState(exec, target, opts)\n}\n\n/**\n * The `agent` subpath facade with its `Exec` and backend BOUND — the exec-bound parallel of\n * `worktreeApi`/`templateApi`. `agentApi(env, deps?)` resolves the backend adapter from `env` ONCE\n * (`resolveMuxAdapter`, defaulting `exec` to `nodeExec`) and exposes `supported`/`status`/`wait` with\n * the seams already threaded, so a caller never re-plumbs an adapter or a runner into them.\n *\n * It ADDS no logic of its own: `supported` reads the very capability presence `deriveAgentWait` gates\n * on, `status` reads the same `LivePane.agentStatus` the listing already carries (for one pane rather\n * than redefining it), and `wait` routes THROUGH `deriveAgentWait` — so the emulate-or-refuse decision\n * stays specified once and enforced once, with no second refusal path here that could drift from it.\n */\nexport interface AgentApi {\n\t/** Whether this backend can WAIT on agent-lifecycle state (herdr and otty yes; the rest no). */\n\tsupported(): boolean\n\t/**\n\t * A pane's current agent state, or `undefined` when the backend has no feed (absent-not-false).\n\t *\n\t * Deliberately NOT the question `supported()` answers, and otty is the backend that proves the two\n\t * are independent: otty can BLOCK on its own agent state but exposes no documented CLI read of it,\n\t * so `supported()` is `true` there while this stays `undefined`. Until otty they happened to agree\n\t * on every backend.\n\t */\n\tstatus(target: MuxTarget): AgentStatus | undefined\n\t/**\n\t * Block until the pane's agent reaches one of `opts.until` (or the backend's default set); throws\n\t * `AgentLifecycleUnsupportedError` naming the backend on one without the capability, via\n\t * `deriveAgentWait`, or `AgentWaitStatesUnsupportedError` on one whose native wait cannot name every\n\t * requested state. A bare `wait(target)` takes the backend's own defaults (`opts ?? {}`).\n\t */\n\twait(target: MuxTarget, opts?: AgentWaitOptions | undefined): AgentStatus\n}\n\n/**\n * Bind the agent-lifecycle capability to an environment and runner once, returning an `AgentApi` whose\n * methods no longer take an `Exec`. `deps.exec` defaults to `nodeExec`; `env` is bound like\n * `resolveMux(env)` because it is what the probe resolves the backend from.\n */\nexport function agentApi(env: NodeJS.ProcessEnv, deps?: { exec?: Exec | undefined } | undefined): AgentApi {\n\tconst exec = deps?.exec ?? nodeExec\n\tconst adapter = resolveMuxAdapter(env, exec)\n\treturn {\n\t\tsupported: () => adapter.agentLifecycle !== undefined,\n\t\tstatus: (target) => adapter.listPanes(exec).find((p) => p.id === target.id)?.agentStatus,\n\t\twait: (target, opts) => deriveAgentWait(adapter, exec, target, opts ?? {}),\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqCA,IAAa,iCAAb,cAAoD,MAAM;CACpC;CAArB,YAAY,SAA0B;EACrC,MAAM,GAAG,QAAQ,qCAAqC;EADlC,KAAA,UAAA;EAEpB,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;AAaA,SAAgB,gBACf,SACA,MACA,QACA,MACc;CACd,MAAM,iBAAiB,QAAQ;CAC/B,IAAI,CAAC,gBAAgB,MAAM,IAAI,+BAA+B,QAAQ,IAAI;CAC1E,OAAO,eAAe,aAAa,MAAM,QAAQ,IAAI;AACtD;;;;;;AAuCA,SAAgB,SAAS,KAAwB,MAA0D;CAC1G,MAAM,OAAO,MAAM,QAAQ;CAC3B,MAAM,UAAU,kBAAkB,KAAK,IAAI;CAC3C,OAAO;EACN,iBAAiB,QAAQ,mBAAmB,KAAA;EAC5C,SAAS,WAAW,QAAQ,UAAU,IAAI,CAAC,CAAC,MAAM,MAAM,EAAE,OAAO,OAAO,EAAE,CAAC,EAAE;EAC7E,OAAO,QAAQ,SAAS,gBAAgB,SAAS,MAAM,QAAQ,QAAQ,CAAC,CAAC;CAC1E;AACD"}