@wastedcode/claudemux 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.
Files changed (249) hide show
  1. package/CHANGELOG.md +257 -0
  2. package/LICENSE +21 -0
  3. package/README.md +493 -0
  4. package/bin/claudemux +6 -0
  5. package/dist/agents/claude.d.ts +3 -0
  6. package/dist/agents/claude.d.ts.map +1 -0
  7. package/dist/agents/claude.js +585 -0
  8. package/dist/agents/claude.js.map +1 -0
  9. package/dist/agents/index.d.ts +2 -0
  10. package/dist/agents/index.d.ts.map +1 -0
  11. package/dist/agents/index.js +2 -0
  12. package/dist/agents/index.js.map +1 -0
  13. package/dist/agents/types.d.ts +252 -0
  14. package/dist/agents/types.d.ts.map +1 -0
  15. package/dist/agents/types.js +2 -0
  16. package/dist/agents/types.js.map +1 -0
  17. package/dist/backends/tmux/capture.d.ts +25 -0
  18. package/dist/backends/tmux/capture.d.ts.map +1 -0
  19. package/dist/backends/tmux/capture.js +35 -0
  20. package/dist/backends/tmux/capture.js.map +1 -0
  21. package/dist/backends/tmux/exec.d.ts +105 -0
  22. package/dist/backends/tmux/exec.d.ts.map +1 -0
  23. package/dist/backends/tmux/exec.js +226 -0
  24. package/dist/backends/tmux/exec.js.map +1 -0
  25. package/dist/backends/tmux/index.d.ts +22 -0
  26. package/dist/backends/tmux/index.d.ts.map +1 -0
  27. package/dist/backends/tmux/index.js +108 -0
  28. package/dist/backends/tmux/index.js.map +1 -0
  29. package/dist/backends/tmux/keys.d.ts +38 -0
  30. package/dist/backends/tmux/keys.d.ts.map +1 -0
  31. package/dist/backends/tmux/keys.js +63 -0
  32. package/dist/backends/tmux/keys.js.map +1 -0
  33. package/dist/backends/tmux/options.d.ts +24 -0
  34. package/dist/backends/tmux/options.d.ts.map +1 -0
  35. package/dist/backends/tmux/options.js +84 -0
  36. package/dist/backends/tmux/options.js.map +1 -0
  37. package/dist/backends/tmux/sessions.d.ts +70 -0
  38. package/dist/backends/tmux/sessions.d.ts.map +1 -0
  39. package/dist/backends/tmux/sessions.js +156 -0
  40. package/dist/backends/tmux/sessions.js.map +1 -0
  41. package/dist/backends/tmux/socket.d.ts +26 -0
  42. package/dist/backends/tmux/socket.d.ts.map +1 -0
  43. package/dist/backends/tmux/socket.js +31 -0
  44. package/dist/backends/tmux/socket.js.map +1 -0
  45. package/dist/backends/types.d.ts +110 -0
  46. package/dist/backends/types.d.ts.map +1 -0
  47. package/dist/backends/types.js +24 -0
  48. package/dist/backends/types.js.map +1 -0
  49. package/dist/cli/ask.d.ts +11 -0
  50. package/dist/cli/ask.d.ts.map +1 -0
  51. package/dist/cli/ask.js +17 -0
  52. package/dist/cli/ask.js.map +1 -0
  53. package/dist/cli/capture.d.ts +8 -0
  54. package/dist/cli/capture.d.ts.map +1 -0
  55. package/dist/cli/capture.js +15 -0
  56. package/dist/cli/capture.js.map +1 -0
  57. package/dist/cli/context.d.ts +71 -0
  58. package/dist/cli/context.d.ts.map +1 -0
  59. package/dist/cli/context.js +82 -0
  60. package/dist/cli/context.js.map +1 -0
  61. package/dist/cli/exists.d.ts +7 -0
  62. package/dist/cli/exists.d.ts.map +1 -0
  63. package/dist/cli/exists.js +16 -0
  64. package/dist/cli/exists.js.map +1 -0
  65. package/dist/cli/interrupt.d.ts +10 -0
  66. package/dist/cli/interrupt.d.ts.map +1 -0
  67. package/dist/cli/interrupt.js +13 -0
  68. package/dist/cli/interrupt.js.map +1 -0
  69. package/dist/cli/kill.d.ts +7 -0
  70. package/dist/cli/kill.d.ts.map +1 -0
  71. package/dist/cli/kill.js +14 -0
  72. package/dist/cli/kill.js.map +1 -0
  73. package/dist/cli/list.d.ts +10 -0
  74. package/dist/cli/list.d.ts.map +1 -0
  75. package/dist/cli/list.js +19 -0
  76. package/dist/cli/list.js.map +1 -0
  77. package/dist/cli/main.d.ts +13 -0
  78. package/dist/cli/main.d.ts.map +1 -0
  79. package/dist/cli/main.js +143 -0
  80. package/dist/cli/main.js.map +1 -0
  81. package/dist/cli/messages.d.ts +9 -0
  82. package/dist/cli/messages.d.ts.map +1 -0
  83. package/dist/cli/messages.js +13 -0
  84. package/dist/cli/messages.js.map +1 -0
  85. package/dist/cli/respond.d.ts +10 -0
  86. package/dist/cli/respond.d.ts.map +1 -0
  87. package/dist/cli/respond.js +23 -0
  88. package/dist/cli/respond.js.map +1 -0
  89. package/dist/cli/resume.d.ts +12 -0
  90. package/dist/cli/resume.d.ts.map +1 -0
  91. package/dist/cli/resume.js +21 -0
  92. package/dist/cli/resume.js.map +1 -0
  93. package/dist/cli/send.d.ts +9 -0
  94. package/dist/cli/send.d.ts.map +1 -0
  95. package/dist/cli/send.js +16 -0
  96. package/dist/cli/send.js.map +1 -0
  97. package/dist/cli/spawn.d.ts +14 -0
  98. package/dist/cli/spawn.d.ts.map +1 -0
  99. package/dist/cli/spawn.js +21 -0
  100. package/dist/cli/spawn.js.map +1 -0
  101. package/dist/cli/state.d.ts +7 -0
  102. package/dist/cli/state.d.ts.map +1 -0
  103. package/dist/cli/state.js +11 -0
  104. package/dist/cli/state.js.map +1 -0
  105. package/dist/cli/turn-complete.d.ts +8 -0
  106. package/dist/cli/turn-complete.d.ts.map +1 -0
  107. package/dist/cli/turn-complete.js +14 -0
  108. package/dist/cli/turn-complete.js.map +1 -0
  109. package/dist/cli/wait.d.ts +13 -0
  110. package/dist/cli/wait.d.ts.map +1 -0
  111. package/dist/cli/wait.js +17 -0
  112. package/dist/cli/wait.js.map +1 -0
  113. package/dist/compose.d.ts +81 -0
  114. package/dist/compose.d.ts.map +1 -0
  115. package/dist/compose.js +64 -0
  116. package/dist/compose.js.map +1 -0
  117. package/dist/errors.d.ts +250 -0
  118. package/dist/errors.d.ts.map +1 -0
  119. package/dist/errors.js +300 -0
  120. package/dist/errors.js.map +1 -0
  121. package/dist/index.d.ts +22 -0
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +17 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/io/baseline.d.ts +53 -0
  126. package/dist/io/baseline.d.ts.map +1 -0
  127. package/dist/io/baseline.js +97 -0
  128. package/dist/io/baseline.js.map +1 -0
  129. package/dist/io/capture.d.ts +15 -0
  130. package/dist/io/capture.d.ts.map +1 -0
  131. package/dist/io/capture.js +13 -0
  132. package/dist/io/capture.js.map +1 -0
  133. package/dist/io/interrupt.d.ts +46 -0
  134. package/dist/io/interrupt.d.ts.map +1 -0
  135. package/dist/io/interrupt.js +60 -0
  136. package/dist/io/interrupt.js.map +1 -0
  137. package/dist/io/respond.d.ts +28 -0
  138. package/dist/io/respond.d.ts.map +1 -0
  139. package/dist/io/respond.js +33 -0
  140. package/dist/io/respond.js.map +1 -0
  141. package/dist/io/send.d.ts +44 -0
  142. package/dist/io/send.d.ts.map +1 -0
  143. package/dist/io/send.js +66 -0
  144. package/dist/io/send.js.map +1 -0
  145. package/dist/io/stabilize.d.ts +28 -0
  146. package/dist/io/stabilize.d.ts.map +1 -0
  147. package/dist/io/stabilize.js +20 -0
  148. package/dist/io/stabilize.js.map +1 -0
  149. package/dist/io/wait.d.ts +47 -0
  150. package/dist/io/wait.d.ts.map +1 -0
  151. package/dist/io/wait.js +117 -0
  152. package/dist/io/wait.js.map +1 -0
  153. package/dist/observe/incremental.d.ts +28 -0
  154. package/dist/observe/incremental.d.ts.map +1 -0
  155. package/dist/observe/incremental.js +57 -0
  156. package/dist/observe/incremental.js.map +1 -0
  157. package/dist/observe/observer.d.ts +86 -0
  158. package/dist/observe/observer.d.ts.map +1 -0
  159. package/dist/observe/observer.js +167 -0
  160. package/dist/observe/observer.js.map +1 -0
  161. package/dist/observe/session-observer.d.ts +49 -0
  162. package/dist/observe/session-observer.d.ts.map +1 -0
  163. package/dist/observe/session-observer.js +123 -0
  164. package/dist/observe/session-observer.js.map +1 -0
  165. package/dist/session/adopt.d.ts +52 -0
  166. package/dist/session/adopt.d.ts.map +1 -0
  167. package/dist/session/adopt.js +57 -0
  168. package/dist/session/adopt.js.map +1 -0
  169. package/dist/session/boot.d.ts +66 -0
  170. package/dist/session/boot.d.ts.map +1 -0
  171. package/dist/session/boot.js +216 -0
  172. package/dist/session/boot.js.map +1 -0
  173. package/dist/session/constants.d.ts +57 -0
  174. package/dist/session/constants.d.ts.map +1 -0
  175. package/dist/session/constants.js +54 -0
  176. package/dist/session/constants.js.map +1 -0
  177. package/dist/session/create.d.ts +88 -0
  178. package/dist/session/create.d.ts.map +1 -0
  179. package/dist/session/create.js +66 -0
  180. package/dist/session/create.js.map +1 -0
  181. package/dist/session/default-backend.d.ts +27 -0
  182. package/dist/session/default-backend.d.ts.map +1 -0
  183. package/dist/session/default-backend.js +58 -0
  184. package/dist/session/default-backend.js.map +1 -0
  185. package/dist/session/handle.d.ts +63 -0
  186. package/dist/session/handle.d.ts.map +1 -0
  187. package/dist/session/handle.js +284 -0
  188. package/dist/session/handle.js.map +1 -0
  189. package/dist/session/hooks.d.ts +37 -0
  190. package/dist/session/hooks.d.ts.map +1 -0
  191. package/dist/session/hooks.js +42 -0
  192. package/dist/session/hooks.js.map +1 -0
  193. package/dist/session/mutex.d.ts +15 -0
  194. package/dist/session/mutex.d.ts.map +1 -0
  195. package/dist/session/mutex.js +29 -0
  196. package/dist/session/mutex.js.map +1 -0
  197. package/dist/session/recover.d.ts +43 -0
  198. package/dist/session/recover.d.ts.map +1 -0
  199. package/dist/session/recover.js +45 -0
  200. package/dist/session/recover.js.map +1 -0
  201. package/dist/session/ref.d.ts +2 -0
  202. package/dist/session/ref.d.ts.map +1 -0
  203. package/dist/session/ref.js +5 -0
  204. package/dist/session/ref.js.map +1 -0
  205. package/dist/session/registry.d.ts +31 -0
  206. package/dist/session/registry.d.ts.map +1 -0
  207. package/dist/session/registry.js +32 -0
  208. package/dist/session/registry.js.map +1 -0
  209. package/dist/session/resolve.d.ts +30 -0
  210. package/dist/session/resolve.d.ts.map +1 -0
  211. package/dist/session/resolve.js +24 -0
  212. package/dist/session/resolve.js.map +1 -0
  213. package/dist/session/resume.d.ts +68 -0
  214. package/dist/session/resume.d.ts.map +1 -0
  215. package/dist/session/resume.js +54 -0
  216. package/dist/session/resume.js.map +1 -0
  217. package/dist/session/spawn-boot.d.ts +44 -0
  218. package/dist/session/spawn-boot.d.ts.map +1 -0
  219. package/dist/session/spawn-boot.js +87 -0
  220. package/dist/session/spawn-boot.js.map +1 -0
  221. package/dist/session/validate.d.ts +10 -0
  222. package/dist/session/validate.d.ts.map +1 -0
  223. package/dist/session/validate.js +0 -0
  224. package/dist/session/validate.js.map +1 -0
  225. package/dist/state/classifier.d.ts +29 -0
  226. package/dist/state/classifier.d.ts.map +1 -0
  227. package/dist/state/classifier.js +37 -0
  228. package/dist/state/classifier.js.map +1 -0
  229. package/dist/state/types.d.ts +32 -0
  230. package/dist/state/types.d.ts.map +1 -0
  231. package/dist/state/types.js +2 -0
  232. package/dist/state/types.js.map +1 -0
  233. package/dist/types.d.ts +401 -0
  234. package/dist/types.d.ts.map +1 -0
  235. package/dist/types.js +9 -0
  236. package/dist/types.js.map +1 -0
  237. package/dist/util/ansi.d.ts +14 -0
  238. package/dist/util/ansi.d.ts.map +1 -0
  239. package/dist/util/ansi.js +18 -0
  240. package/dist/util/ansi.js.map +1 -0
  241. package/dist/util/emitter.d.ts +17 -0
  242. package/dist/util/emitter.d.ts.map +1 -0
  243. package/dist/util/emitter.js +33 -0
  244. package/dist/util/emitter.js.map +1 -0
  245. package/dist/util/sleep.d.ts +8 -0
  246. package/dist/util/sleep.d.ts.map +1 -0
  247. package/dist/util/sleep.js +10 -0
  248. package/dist/util/sleep.js.map +1 -0
  249. package/package.json +50 -0
@@ -0,0 +1,70 @@
1
+ import { type TmuxExec } from "./exec.js";
2
+ /**
3
+ * Build the namespaced tmux session target name from `namespace` + `name`.
4
+ * The namespace prefix is what lets two consumers + manual user tmux
5
+ * sessions coexist on one private server without collision.
6
+ *
7
+ * The separator is `--` because `:` and `.` are reserved by tmux's target
8
+ * grammar (`session:window.pane`) — a colon-separated name would parse as
9
+ * "session=<namespace>, window=<name>" and trip "no such window" errors.
10
+ */
11
+ export declare function targetOf(namespace: string, name: string): string;
12
+ /**
13
+ * Create a new tmux session running `cmd` + `argv` in `cwd`, with the
14
+ * substrate's server-global options set in the same invocation so they
15
+ * land before the agent's pane is allocated.
16
+ *
17
+ * Per-session environment (including `LC_ALL=C.UTF-8` for unicode glyph
18
+ * stability — a substrate concern, not an agent one) rides on `new-session
19
+ * -e KEY=VAL` pairs. `-e` on `new-session` is tmux ≥3.2; that sets the
20
+ * substrate's supported floor (see README §Compatibility / details.md
21
+ * §Quality). `set-environment` after `new-session` is not an option — it
22
+ * doesn't affect the already-spawned pane process.
23
+ */
24
+ export declare function newSession(exec: TmuxExec, o: {
25
+ namespace: string;
26
+ name: string;
27
+ cwd: string;
28
+ env?: Record<string, string>;
29
+ cmd: string;
30
+ argv: string[];
31
+ /** User-facing label for error messages (defaults to tmux target encoding). */
32
+ label?: string;
33
+ }): Promise<void>;
34
+ /**
35
+ * Is the named session currently alive on the server?
36
+ *
37
+ * Returns `false` (never throws) for "the session isn't here":
38
+ * - exit 0 → `true`
39
+ * - `can't find session/window/pane: …` (any level of tmux's target
40
+ * grammar) → `false`, via `isSessionGoneStderr`. A name that trips the
41
+ * `session:window.pane` parser still yields a boolean, not a throw.
42
+ * - `no-server` BackendUnreachable (empty/down server) → `false`.
43
+ *
44
+ * It DOES throw `BackendUnreachable` for `spawn-failed` (backend binary
45
+ * missing) and `timeout` (wedged backend) — those are real faults; a missing
46
+ * dependency must not masquerade as "no such session." The no-server gate
47
+ * lives solely in the catch (exec.run rejects no-server before it could
48
+ * resolve), so there is no dead resolve-path branch here.
49
+ *
50
+ * `label` is the user-facing identifier used in error messages (defaults to
51
+ * `target`). Errors thrown from this function carry `label`, not the tmux
52
+ * internal target encoding.
53
+ */
54
+ export declare function hasSession(exec: TmuxExec, target: string, label?: string): Promise<boolean>;
55
+ /**
56
+ * Kill a session by target name. Idempotent — "session was already gone" or
57
+ * "no server running" is treated as success. A *missing backend binary*
58
+ * (`spawn-failed`) or a *wedged* server (`timeout`) still throws — those are
59
+ * real faults, not "the session is already gone."
60
+ */
61
+ export declare function killSession(exec: TmuxExec, target: string, label?: string): Promise<void>;
62
+ /**
63
+ * List the *short* session names within `namespace` (the piece after the
64
+ * `<namespace>--` prefix), in whatever order tmux reports. A running-but-empty
65
+ * server, or no server at all, returns `[]`. A missing backend binary or a
66
+ * wedged server throws `BackendUnreachable` — an empty list must mean "no
67
+ * sessions," never "we couldn't reach the backend."
68
+ */
69
+ export declare function listSessions(exec: TmuxExec, namespace: string): Promise<string[]>;
70
+ //# sourceMappingURL=sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../src/backends/tmux/sessions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,QAAQ,EAAwD,MAAM,WAAW,CAAC;AAGhG;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,CAAC,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAe,GACrB,OAAO,CAAC,OAAO,CAAC,CAYlB;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBvF"}
@@ -0,0 +1,156 @@
1
+ import { SessionGone } from "../../errors.js";
2
+ import { PANE_HEIGHT } from "../../session/constants.js";
3
+ import { classifyTmuxFailure, isNoServer, isSessionGoneStderr } from "./exec.js";
4
+ import { serverOptionsArgv } from "./options.js";
5
+ /**
6
+ * Build the namespaced tmux session target name from `namespace` + `name`.
7
+ * The namespace prefix is what lets two consumers + manual user tmux
8
+ * sessions coexist on one private server without collision.
9
+ *
10
+ * The separator is `--` because `:` and `.` are reserved by tmux's target
11
+ * grammar (`session:window.pane`) — a colon-separated name would parse as
12
+ * "session=<namespace>, window=<name>" and trip "no such window" errors.
13
+ */
14
+ export function targetOf(namespace, name) {
15
+ return `${namespace}--${name}`;
16
+ }
17
+ /**
18
+ * Create a new tmux session running `cmd` + `argv` in `cwd`, with the
19
+ * substrate's server-global options set in the same invocation so they
20
+ * land before the agent's pane is allocated.
21
+ *
22
+ * Per-session environment (including `LC_ALL=C.UTF-8` for unicode glyph
23
+ * stability — a substrate concern, not an agent one) rides on `new-session
24
+ * -e KEY=VAL` pairs. `-e` on `new-session` is tmux ≥3.2; that sets the
25
+ * substrate's supported floor (see README §Compatibility / details.md
26
+ * §Quality). `set-environment` after `new-session` is not an option — it
27
+ * doesn't affect the already-spawned pane process.
28
+ */
29
+ export async function newSession(exec, o) {
30
+ const target = targetOf(o.namespace, o.name);
31
+ const label = o.label ?? target;
32
+ // LC_ALL=C.UTF-8 is the substrate's default locale; `o.env` may override or
33
+ // augment it. Merging into one object dedupes the key, so the agent passing
34
+ // `env: { LC_ALL }` (claude does) doesn't produce a duplicate `-e` flag.
35
+ const env = { LC_ALL: "C.UTF-8", ...o.env };
36
+ const envFlags = Object.entries(env).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
37
+ const newSessionCmd = [
38
+ "new-session",
39
+ "-d",
40
+ "-s",
41
+ target,
42
+ "-x",
43
+ "120",
44
+ "-y",
45
+ // Pane height = the classifier's scan cap; one source so they can't drift.
46
+ String(PANE_HEIGHT),
47
+ ...envFlags,
48
+ "-c",
49
+ o.cwd,
50
+ o.cmd,
51
+ ...o.argv,
52
+ ];
53
+ // Combine server-options + new-session into ONE tmux invocation so the
54
+ // globals land in the same client connection that creates the session.
55
+ // The server only stays alive once a session exists, so `start-server`
56
+ // followed by `set-option -g` doesn't work — globals must be set in the
57
+ // same invocation that registers the first session.
58
+ const argv = [...serverOptionsArgv(), ...newSessionCmd];
59
+ const r = await exec.run(argv, { sessionName: label });
60
+ const err = classifyTmuxFailure(label, ["tmux", ...argv], r);
61
+ if (err)
62
+ throw err;
63
+ }
64
+ /**
65
+ * Is the named session currently alive on the server?
66
+ *
67
+ * Returns `false` (never throws) for "the session isn't here":
68
+ * - exit 0 → `true`
69
+ * - `can't find session/window/pane: …` (any level of tmux's target
70
+ * grammar) → `false`, via `isSessionGoneStderr`. A name that trips the
71
+ * `session:window.pane` parser still yields a boolean, not a throw.
72
+ * - `no-server` BackendUnreachable (empty/down server) → `false`.
73
+ *
74
+ * It DOES throw `BackendUnreachable` for `spawn-failed` (backend binary
75
+ * missing) and `timeout` (wedged backend) — those are real faults; a missing
76
+ * dependency must not masquerade as "no such session." The no-server gate
77
+ * lives solely in the catch (exec.run rejects no-server before it could
78
+ * resolve), so there is no dead resolve-path branch here.
79
+ *
80
+ * `label` is the user-facing identifier used in error messages (defaults to
81
+ * `target`). Errors thrown from this function carry `label`, not the tmux
82
+ * internal target encoding.
83
+ */
84
+ export async function hasSession(exec, target, label = target) {
85
+ try {
86
+ const r = await exec.run(["has-session", "-t", target], { sessionName: label });
87
+ if (r.exit === 0)
88
+ return true;
89
+ if (isSessionGoneStderr(r.stderr))
90
+ return false;
91
+ const err = classifyTmuxFailure(label, ["tmux", "has-session", "-t", target], r);
92
+ if (err)
93
+ throw err;
94
+ return false;
95
+ }
96
+ catch (err) {
97
+ if (isNoServer(err))
98
+ return false; // empty server == no such session
99
+ throw err; // spawn-failed (binary missing) / timeout (wedged) surface loudly
100
+ }
101
+ }
102
+ /**
103
+ * Kill a session by target name. Idempotent — "session was already gone" or
104
+ * "no server running" is treated as success. A *missing backend binary*
105
+ * (`spawn-failed`) or a *wedged* server (`timeout`) still throws — those are
106
+ * real faults, not "the session is already gone."
107
+ */
108
+ export async function killSession(exec, target, label = target) {
109
+ try {
110
+ const r = await exec.run(["kill-session", "-t", target], { sessionName: label });
111
+ if (r.exit === 0)
112
+ return;
113
+ const err = classifyTmuxFailure(label, ["tmux", "kill-session", "-t", target], r);
114
+ if (err instanceof SessionGone)
115
+ return;
116
+ if (err)
117
+ throw err;
118
+ }
119
+ catch (err) {
120
+ if (isNoServer(err))
121
+ return; // empty server == no session to kill
122
+ throw err;
123
+ }
124
+ }
125
+ /**
126
+ * List the *short* session names within `namespace` (the piece after the
127
+ * `<namespace>--` prefix), in whatever order tmux reports. A running-but-empty
128
+ * server, or no server at all, returns `[]`. A missing backend binary or a
129
+ * wedged server throws `BackendUnreachable` — an empty list must mean "no
130
+ * sessions," never "we couldn't reach the backend."
131
+ */
132
+ export async function listSessions(exec, namespace) {
133
+ let r;
134
+ try {
135
+ r = await exec.run(["list-sessions", "-F", "#{session_name}"], { sessionName: namespace });
136
+ }
137
+ catch (err) {
138
+ if (isNoServer(err))
139
+ return [];
140
+ throw err;
141
+ }
142
+ if (r.exit !== 0) {
143
+ if (r.stdout.trim() === "")
144
+ return [];
145
+ const err = classifyTmuxFailure(namespace, ["tmux", "list-sessions"], r);
146
+ if (err)
147
+ throw err;
148
+ }
149
+ const prefix = `${namespace}--`;
150
+ return r.stdout
151
+ .split("\n")
152
+ .map((line) => line.trim())
153
+ .filter((line) => line.startsWith(prefix))
154
+ .map((line) => line.slice(prefix.length));
155
+ }
156
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../src/backends/tmux/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAiB,mBAAmB,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChG,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CAAC,SAAiB,EAAE,IAAY;IACtD,OAAO,GAAG,SAAS,KAAK,IAAI,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAc,EACd,CASC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;IAEhC,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,GAAG,GAA2B,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IACpE,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9E,MAAM,aAAa,GAAG;QACpB,aAAa;QACb,IAAI;QACJ,IAAI;QACJ,MAAM;QACN,IAAI;QACJ,KAAK;QACL,IAAI;QACJ,2EAA2E;QAC3E,MAAM,CAAC,WAAW,CAAC;QACnB,GAAG,QAAQ;QACX,IAAI;QACJ,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,GAAG;QACL,GAAG,CAAC,CAAC,IAAI;KACV,CAAC;IAEF,uEAAuE;IACvE,uEAAuE;IACvE,uEAAuE;IACvE,wEAAwE;IACxE,oDAAoD;IACpD,MAAM,IAAI,GAAG,CAAC,GAAG,iBAAiB,EAAE,EAAE,GAAG,aAAa,CAAC,CAAC;IACxD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,mBAAmB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,IAAI,GAAG;QAAE,MAAM,GAAG,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAc,EACd,MAAc,EACd,QAAgB,MAAM;IAEtB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAChF,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;QAChD,MAAM,GAAG,GAAG,mBAAmB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QACjF,IAAI,GAAG;YAAE,MAAM,GAAG,CAAC;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,kCAAkC;QACrE,MAAM,GAAG,CAAC,CAAC,kEAAkE;IAC/E,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAc,EACd,MAAc,EACd,QAAgB,MAAM;IAEtB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QACzB,MAAM,GAAG,GAAG,mBAAmB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAClF,IAAI,GAAG,YAAY,WAAW;YAAE,OAAO;QACvC,IAAI,GAAG;YAAE,MAAM,GAAG,CAAC;IACrB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,qCAAqC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAc,EAAE,SAAiB;IAClE,IAAI,CAAuC,CAAC;IAC5C,IAAI,CAAC;QACH,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,IAAI,EAAE,iBAAiB,CAAC,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;IAC7F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QAC/B,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACjB,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,mBAAmB,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;QACzE,IAAI,GAAG;YAAE,MAAM,GAAG,CAAC;IACrB,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,SAAS,IAAI,CAAC;IAChC,OAAO,CAAC,CAAC,MAAM;SACZ,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;SACzC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The substrate's default tmux socket name — `"claudemux"`.
3
+ *
4
+ * Pure function (no env reads here). The bootstrap layer
5
+ * (`src/session/default-backend.ts`) composes the precedence:
6
+ *
7
+ * explicit `tmuxBackend({ socket })` > `--socket` flag > `CLAUDEMUX_SOCKET` env >
8
+ * `defaultSocketName()`
9
+ *
10
+ * tmux already namespaces socket files per-UID (`/tmp/tmux-$UID/claudemux`,
11
+ * mode 0700), so a fixed name is per-user-safe by construction. Two
12
+ * consumers from the same user share the same tmux server and coexist via
13
+ * the substrate's namespace prefix (`<ns>--<name>`) — that is the
14
+ * substrate's one justified isolation primitive.
15
+ *
16
+ * See `brain/decisions/0006-default-backend-rendezvous-identity.md`.
17
+ */
18
+ export declare function defaultSocketName(): string;
19
+ /**
20
+ * Mint a unique tmux socket name. Used by the test harness for per-test
21
+ * isolation (`test/harness/index.ts`). Production code should NOT mint a
22
+ * random socket — the CLI's cross-process discovery requires a stable
23
+ * rendezvous identity (see {@link defaultSocketName}).
24
+ */
25
+ export declare function mintSocket(): string;
26
+ //# sourceMappingURL=socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../../src/backends/tmux/socket.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
@@ -0,0 +1,31 @@
1
+ import { randomBytes } from "node:crypto";
2
+ /**
3
+ * The substrate's default tmux socket name — `"claudemux"`.
4
+ *
5
+ * Pure function (no env reads here). The bootstrap layer
6
+ * (`src/session/default-backend.ts`) composes the precedence:
7
+ *
8
+ * explicit `tmuxBackend({ socket })` > `--socket` flag > `CLAUDEMUX_SOCKET` env >
9
+ * `defaultSocketName()`
10
+ *
11
+ * tmux already namespaces socket files per-UID (`/tmp/tmux-$UID/claudemux`,
12
+ * mode 0700), so a fixed name is per-user-safe by construction. Two
13
+ * consumers from the same user share the same tmux server and coexist via
14
+ * the substrate's namespace prefix (`<ns>--<name>`) — that is the
15
+ * substrate's one justified isolation primitive.
16
+ *
17
+ * See `brain/decisions/0006-default-backend-rendezvous-identity.md`.
18
+ */
19
+ export function defaultSocketName() {
20
+ return "claudemux";
21
+ }
22
+ /**
23
+ * Mint a unique tmux socket name. Used by the test harness for per-test
24
+ * isolation (`test/harness/index.ts`). Production code should NOT mint a
25
+ * random socket — the CLI's cross-process discovery requires a stable
26
+ * rendezvous identity (see {@link defaultSocketName}).
27
+ */
28
+ export function mintSocket() {
29
+ return `claudemux-${randomBytes(6).toString("hex")}`;
30
+ }
31
+ //# sourceMappingURL=socket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket.js","sourceRoot":"","sources":["../../../src/backends/tmux/socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,aAAa,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AACvD,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The `Backend` seam — drives a named pane: spawn a process, send input,
3
+ * capture output, kill. Knows **nothing** about claude or any specific agent.
4
+ *
5
+ * This file is internal. The public surface (`src/index.ts`) does NOT
6
+ * re-export `Backend`, `SendPayload`, or `BackendEvent`.
7
+ *
8
+ * Two input primitives only — `paste` (multi-line safe) and `key` (named).
9
+ * There is no `sendRawText`: multi-line input that would submit per-line
10
+ * cannot leak around this seam.
11
+ */
12
+ /** A single backend-issued operation observable via `Backend.onCommand`. */
13
+ export interface BackendEvent {
14
+ /** Unix epoch milliseconds when the command was issued. */
15
+ ts: number;
16
+ /** The argv the substrate spawned. */
17
+ argv: string[];
18
+ /** Wall-clock milliseconds the command took. */
19
+ durationMs: number;
20
+ /** Process exit code. */
21
+ exit: number;
22
+ /** Captured stdout, if any. */
23
+ stdout?: string;
24
+ /** Captured stderr, if any. */
25
+ stderr?: string;
26
+ }
27
+ /**
28
+ * The shape of one backend write. Multi-line input rides as `paste`;
29
+ * submission and dialog responses ride as `key`.
30
+ */
31
+ export type SendPayload = {
32
+ kind: "paste";
33
+ text: string;
34
+ } | {
35
+ kind: "key";
36
+ key: "Enter" | "Escape" | "1" | "2" | "3" | "y" | "n";
37
+ };
38
+ /**
39
+ * Identifier for one named session. Every Backend method takes this shape
40
+ * so the backend owns its own naming convention — callers never construct
41
+ * `<namespace>--<name>` or any other concrete encoding. Future backends
42
+ * (node-pty, CustomPaneBackend) implement the same interface and may
43
+ * encode the pair differently internally.
44
+ */
45
+ export interface SessionRef {
46
+ namespace: string;
47
+ name: string;
48
+ }
49
+ /**
50
+ * Format a {@link SessionRef} as the human-readable label used in error
51
+ * messages and observability output. The substrate's public label format
52
+ * is `<namespace>/<name>` — distinct from any backend's internal encoding
53
+ * (the tmux backend, for example, uses `<namespace>--<name>` internally).
54
+ *
55
+ * One place; one format; rename here if the user-facing label ever changes
56
+ * (e.g. to `<namespace>:<name>`).
57
+ */
58
+ export declare function formatSessionLabel(ref: SessionRef): string;
59
+ /**
60
+ * The substrate's view of one named pane in a backend. Implemented by
61
+ * `src/backends/tmux/index.ts` currently; future backends (node-pty,
62
+ * `CustomPaneBackend`) implement the same interface.
63
+ */
64
+ export interface Backend {
65
+ /** The backend's short identifier (e.g. `"tmux"`). For diagnostics only. */
66
+ readonly id: string;
67
+ /** Create a named session running `cmd` + `argv` in `cwd`. */
68
+ spawn(o: SessionRef & {
69
+ cwd: string;
70
+ env?: Record<string, string>;
71
+ cmd: string;
72
+ argv: string[];
73
+ }): Promise<void>;
74
+ /** Kill the named session. Idempotent — kill of a missing session is success. */
75
+ kill(ref: SessionRef): Promise<void>;
76
+ /** Whether the named session is alive. */
77
+ exists(ref: SessionRef): Promise<boolean>;
78
+ /** List short session names owned by `namespace`. */
79
+ list(namespace: string): Promise<string[]>;
80
+ /** Send one payload to the named session. */
81
+ send(ref: SessionRef, payload: SendPayload): Promise<void>;
82
+ /**
83
+ * Return the named session's pane text.
84
+ * @param o.ansi — preserve escape sequences when `true`.
85
+ * @param o.lines — return only the bottom-N lines (default: full visible region).
86
+ */
87
+ capture(ref: SessionRef, o?: {
88
+ ansi?: boolean;
89
+ lines?: number;
90
+ }): Promise<string>;
91
+ /**
92
+ * Persist a small opaque string under a **session-scoped** key. The value
93
+ * lives and dies with the session. Used for cross-process coordination —
94
+ * specifically the post-submit pane fingerprint `send()` leaves for a later
95
+ * (possibly different-process) `wait()` to read. Backend-specific storage
96
+ * (the tmux backend uses a `@`-prefixed session user option); callers treat
97
+ * it as an opaque per-session key/value store and never depend on where it
98
+ * lives.
99
+ */
100
+ setSessionMeta(ref: SessionRef, key: string, value: string): Promise<void>;
101
+ /**
102
+ * Read a value previously written via {@link setSessionMeta}. Returns
103
+ * `undefined` when the key was never set (or the session/value is
104
+ * unreadable) — it is metadata, so absence is not an error.
105
+ */
106
+ getSessionMeta(ref: SessionRef, key: string): Promise<string | undefined>;
107
+ /** Subscribe to every backend command + result. Returns an unsubscribe fn. */
108
+ onCommand(handler: (e: BackendEvent) => void): () => void;
109
+ }
110
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/backends/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;CAAE,CAAC;AAE3E;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAE1D;AAED;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,8DAA8D;IAC9D,KAAK,CACH,CAAC,EAAE,UAAU,GAAG;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC7B,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,GACA,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,iFAAiF;IACjF,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErC,0CAA0C;IAC1C,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE1C,qDAAqD;IACrD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE3C,6CAA6C;IAC7C,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAElF;;;;;;;;OAQG;IACH,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3E;;;;OAIG;IACH,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE1E,8EAA8E;IAC9E,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC3D"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The `Backend` seam — drives a named pane: spawn a process, send input,
3
+ * capture output, kill. Knows **nothing** about claude or any specific agent.
4
+ *
5
+ * This file is internal. The public surface (`src/index.ts`) does NOT
6
+ * re-export `Backend`, `SendPayload`, or `BackendEvent`.
7
+ *
8
+ * Two input primitives only — `paste` (multi-line safe) and `key` (named).
9
+ * There is no `sendRawText`: multi-line input that would submit per-line
10
+ * cannot leak around this seam.
11
+ */
12
+ /**
13
+ * Format a {@link SessionRef} as the human-readable label used in error
14
+ * messages and observability output. The substrate's public label format
15
+ * is `<namespace>/<name>` — distinct from any backend's internal encoding
16
+ * (the tmux backend, for example, uses `<namespace>--<name>` internally).
17
+ *
18
+ * One place; one format; rename here if the user-facing label ever changes
19
+ * (e.g. to `<namespace>:<name>`).
20
+ */
21
+ export function formatSessionLabel(ref) {
22
+ return `${ref.namespace}/${ref.name}`;
23
+ }
24
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backends/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAsCH;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAe;IAChD,OAAO,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type CommonOpts, type PatienceCliOpts } from "./context.js";
2
+ export interface AskCliOpts extends CommonOpts, PatienceCliOpts {
3
+ }
4
+ /**
5
+ * `claudemux ask <name> <text>` — the Q&A round-trip face: send → wait → read.
6
+ * Prints the {@link AskResult} as JSON (`outcome`, `messages`, `cursor`). Exit
7
+ * code is 0 on `completed`, non-zero otherwise, so a shell caller can gate
8
+ * without parsing. `text` = `"-"` reads the prompt from stdin.
9
+ */
10
+ export declare function askCli(name: string, text: string, opts?: AskCliOpts): Promise<void>;
11
+ //# sourceMappingURL=ask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/cli/ask.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,eAAe,EAIrB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,UAAW,SAAQ,UAAU,EAAE,eAAe;CAAG;AAElE;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAM7F"}
@@ -0,0 +1,17 @@
1
+ import { ask } from "../compose.js";
2
+ import { handleFor, patienceOpts, readStdin, } from "./context.js";
3
+ /**
4
+ * `claudemux ask <name> <text>` — the Q&A round-trip face: send → wait → read.
5
+ * Prints the {@link AskResult} as JSON (`outcome`, `messages`, `cursor`). Exit
6
+ * code is 0 on `completed`, non-zero otherwise, so a shell caller can gate
7
+ * without parsing. `text` = `"-"` reads the prompt from stdin.
8
+ */
9
+ export async function askCli(name, text, opts = {}) {
10
+ const body = text === "-" ? await readStdin() : text;
11
+ const handle = await handleFor({ ...opts, name });
12
+ const result = await ask(handle, body, patienceOpts(opts));
13
+ process.stdout.write(`${JSON.stringify(result)}\n`);
14
+ if (result.outcome.kind !== "completed")
15
+ process.exitCode = 1;
16
+ }
17
+ //# sourceMappingURL=ask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.js","sourceRoot":"","sources":["../../src/cli/ask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAGL,SAAS,EACT,YAAY,EACZ,SAAS,GACV,MAAM,cAAc,CAAC;AAItB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAY,EAAE,IAAY,EAAE,OAAmB,EAAE;IAC5E,MAAM,IAAI,GAAG,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACrD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type CommonOpts } from "./context.js";
2
+ export interface CaptureCliOpts extends CommonOpts {
3
+ ansi?: boolean;
4
+ lines?: number;
5
+ }
6
+ /** `claudemux capture <name>` — print the pane text (optionally with ANSI). */
7
+ export declare function captureCli(name: string, opts?: CaptureCliOpts): Promise<void>;
8
+ //# sourceMappingURL=capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/cli/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAa,MAAM,cAAc,CAAC;AAE1D,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,+EAA+E;AAC/E,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvF"}
@@ -0,0 +1,15 @@
1
+ import { handleFor } from "./context.js";
2
+ /** `claudemux capture <name>` — print the pane text (optionally with ANSI). */
3
+ export async function captureCli(name, opts = {}) {
4
+ const handle = await handleFor({ ...opts, name });
5
+ const captureOpts = {};
6
+ if (opts.ansi === true)
7
+ captureOpts.ansi = true;
8
+ if (opts.lines !== undefined)
9
+ captureOpts.lines = opts.lines;
10
+ const text = await handle.capture(captureOpts);
11
+ process.stdout.write(text);
12
+ if (!text.endsWith("\n"))
13
+ process.stdout.write("\n");
14
+ }
15
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/cli/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAE,MAAM,cAAc,CAAC;AAO1D,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,OAAuB,EAAE;IACtE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,WAAW,GAAuC,EAAE,CAAC;IAC3D,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC;IAChD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,WAAW,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAC7D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { AgentDef } from "../agents/types.js";
2
+ import type { Backend } from "../backends/types.js";
3
+ import type { ReadyOpts, SessionHandle } from "../types.js";
4
+ /**
5
+ * Options to **locate** a session — every verb takes these. Mirrors the
6
+ * `common()` helper in `main.ts` (namespace + socket, no agent).
7
+ */
8
+ export interface RefOpts {
9
+ namespace?: string;
10
+ /**
11
+ * Explicit socket override. Precedence:
12
+ * `--socket <name>` flag > `CLAUDEMUX_SOCKET` env > default `"claudemux"`.
13
+ */
14
+ socket?: string;
15
+ }
16
+ /**
17
+ * {@link RefOpts} plus the agent — for verbs that build a session handle.
18
+ * Mirrors the `withAgent()` helper. Registry verbs (kill/list/exists) take only
19
+ * {@link RefOpts}, so the two types track the two helpers exactly.
20
+ */
21
+ export interface CommonOpts extends RefOpts {
22
+ agent?: string;
23
+ }
24
+ /**
25
+ * Resolve the agent by short name. Only `claude` is supported currently;
26
+ * any other value exits with a typed error message.
27
+ */
28
+ export declare function resolveAgent(name: string | undefined): AgentDef;
29
+ /** Resolve the namespace, applying the substrate's default. */
30
+ export declare function resolveNamespace(name: string | undefined): string;
31
+ /**
32
+ * Resolve the backend for this CLI invocation. If `--socket` was passed
33
+ * (and is non-empty after trimming), builds a fresh backend on the
34
+ * resolved socket; otherwise returns the process-wide shared default
35
+ * (which itself honors `CLAUDEMUX_SOCKET`). The trim → gate-and-return
36
+ * consistency lives in `resolveSocket` so a padded `--socket ' x '` lands
37
+ * on the same server as `--socket x`.
38
+ */
39
+ export declare function backend(opts?: RefOpts): Backend;
40
+ /**
41
+ * Attach a session handle for the CLI's per-invocation reattach. Delegates to
42
+ * the library {@link adopt} — the ONE owner of "re-attach to a running session"
43
+ * — so the CLI **recovers the agentSessionId** (and thus can locate the
44
+ * transcript + hook rendezvous) instead of reimplementing a weaker attach.
45
+ * Async because recovery reads session metadata.
46
+ *
47
+ * @throws `SessionGone` if the named session is not alive (adopt's contract) —
48
+ * the CLI surfaces it as a typed, no-tmux-leak error.
49
+ */
50
+ export declare function handleFor(o: CommonOpts & {
51
+ name: string;
52
+ }): Promise<SessionHandle>;
53
+ /** Wait-patience flags shared by `wait` and `ask`. */
54
+ export interface PatienceCliOpts {
55
+ /** `--timeout-ms` — wall-clock cap (maps to {@link ReadyOpts.maxMs}). */
56
+ timeoutMs?: number;
57
+ /** `--idle-ms` — no-progress cap (maps to {@link ReadyOpts.idleMs}). */
58
+ idleMs?: number;
59
+ }
60
+ /**
61
+ * Build the library's {@link ReadyOpts} from CLI patience flags. The library
62
+ * imposes **no** default patience; the CLI is a *consumer* and supplies its own
63
+ * so a shell `wait`/`ask` can't hang forever: if neither bound is given it caps
64
+ * the wall-clock at {@link CLI_DEFAULT_MAX_MS}. `--timeout-ms` and `--idle-ms`
65
+ * override; passing `--idle-ms` alone opts out of the wall-clock default (the
66
+ * caller chose a no-progress bound deliberately).
67
+ */
68
+ export declare function patienceOpts(o: PatienceCliOpts): ReadyOpts;
69
+ /** Read all of stdin as UTF-8 — the `<text>` = `"-"` piping convention. */
70
+ export declare function readStdin(): Promise<string>;
71
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/cli/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAQpD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAW,SAAQ,OAAO;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAO/D;AAED,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEjE;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,IAAI,GAAE,OAAY,GAAG,OAAO,CAKnD;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAOlF;AAED,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,eAAe,GAAG,SAAS,CAM1D;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAU3C"}