@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.
- package/CHANGELOG.md +257 -0
- package/LICENSE +21 -0
- package/README.md +493 -0
- package/bin/claudemux +6 -0
- package/dist/agents/claude.d.ts +3 -0
- package/dist/agents/claude.d.ts.map +1 -0
- package/dist/agents/claude.js +585 -0
- package/dist/agents/claude.js.map +1 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +2 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/types.d.ts +252 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/backends/tmux/capture.d.ts +25 -0
- package/dist/backends/tmux/capture.d.ts.map +1 -0
- package/dist/backends/tmux/capture.js +35 -0
- package/dist/backends/tmux/capture.js.map +1 -0
- package/dist/backends/tmux/exec.d.ts +105 -0
- package/dist/backends/tmux/exec.d.ts.map +1 -0
- package/dist/backends/tmux/exec.js +226 -0
- package/dist/backends/tmux/exec.js.map +1 -0
- package/dist/backends/tmux/index.d.ts +22 -0
- package/dist/backends/tmux/index.d.ts.map +1 -0
- package/dist/backends/tmux/index.js +108 -0
- package/dist/backends/tmux/index.js.map +1 -0
- package/dist/backends/tmux/keys.d.ts +38 -0
- package/dist/backends/tmux/keys.d.ts.map +1 -0
- package/dist/backends/tmux/keys.js +63 -0
- package/dist/backends/tmux/keys.js.map +1 -0
- package/dist/backends/tmux/options.d.ts +24 -0
- package/dist/backends/tmux/options.d.ts.map +1 -0
- package/dist/backends/tmux/options.js +84 -0
- package/dist/backends/tmux/options.js.map +1 -0
- package/dist/backends/tmux/sessions.d.ts +70 -0
- package/dist/backends/tmux/sessions.d.ts.map +1 -0
- package/dist/backends/tmux/sessions.js +156 -0
- package/dist/backends/tmux/sessions.js.map +1 -0
- package/dist/backends/tmux/socket.d.ts +26 -0
- package/dist/backends/tmux/socket.d.ts.map +1 -0
- package/dist/backends/tmux/socket.js +31 -0
- package/dist/backends/tmux/socket.js.map +1 -0
- package/dist/backends/types.d.ts +110 -0
- package/dist/backends/types.d.ts.map +1 -0
- package/dist/backends/types.js +24 -0
- package/dist/backends/types.js.map +1 -0
- package/dist/cli/ask.d.ts +11 -0
- package/dist/cli/ask.d.ts.map +1 -0
- package/dist/cli/ask.js +17 -0
- package/dist/cli/ask.js.map +1 -0
- package/dist/cli/capture.d.ts +8 -0
- package/dist/cli/capture.d.ts.map +1 -0
- package/dist/cli/capture.js +15 -0
- package/dist/cli/capture.js.map +1 -0
- package/dist/cli/context.d.ts +71 -0
- package/dist/cli/context.d.ts.map +1 -0
- package/dist/cli/context.js +82 -0
- package/dist/cli/context.js.map +1 -0
- package/dist/cli/exists.d.ts +7 -0
- package/dist/cli/exists.d.ts.map +1 -0
- package/dist/cli/exists.js +16 -0
- package/dist/cli/exists.js.map +1 -0
- package/dist/cli/interrupt.d.ts +10 -0
- package/dist/cli/interrupt.d.ts.map +1 -0
- package/dist/cli/interrupt.js +13 -0
- package/dist/cli/interrupt.js.map +1 -0
- package/dist/cli/kill.d.ts +7 -0
- package/dist/cli/kill.d.ts.map +1 -0
- package/dist/cli/kill.js +14 -0
- package/dist/cli/kill.js.map +1 -0
- package/dist/cli/list.d.ts +10 -0
- package/dist/cli/list.d.ts.map +1 -0
- package/dist/cli/list.js +19 -0
- package/dist/cli/list.js.map +1 -0
- package/dist/cli/main.d.ts +13 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +143 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/messages.d.ts +9 -0
- package/dist/cli/messages.d.ts.map +1 -0
- package/dist/cli/messages.js +13 -0
- package/dist/cli/messages.js.map +1 -0
- package/dist/cli/respond.d.ts +10 -0
- package/dist/cli/respond.d.ts.map +1 -0
- package/dist/cli/respond.js +23 -0
- package/dist/cli/respond.js.map +1 -0
- package/dist/cli/resume.d.ts +12 -0
- package/dist/cli/resume.d.ts.map +1 -0
- package/dist/cli/resume.js +21 -0
- package/dist/cli/resume.js.map +1 -0
- package/dist/cli/send.d.ts +9 -0
- package/dist/cli/send.d.ts.map +1 -0
- package/dist/cli/send.js +16 -0
- package/dist/cli/send.js.map +1 -0
- package/dist/cli/spawn.d.ts +14 -0
- package/dist/cli/spawn.d.ts.map +1 -0
- package/dist/cli/spawn.js +21 -0
- package/dist/cli/spawn.js.map +1 -0
- package/dist/cli/state.d.ts +7 -0
- package/dist/cli/state.d.ts.map +1 -0
- package/dist/cli/state.js +11 -0
- package/dist/cli/state.js.map +1 -0
- package/dist/cli/turn-complete.d.ts +8 -0
- package/dist/cli/turn-complete.d.ts.map +1 -0
- package/dist/cli/turn-complete.js +14 -0
- package/dist/cli/turn-complete.js.map +1 -0
- package/dist/cli/wait.d.ts +13 -0
- package/dist/cli/wait.d.ts.map +1 -0
- package/dist/cli/wait.js +17 -0
- package/dist/cli/wait.js.map +1 -0
- package/dist/compose.d.ts +81 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +64 -0
- package/dist/compose.js.map +1 -0
- package/dist/errors.d.ts +250 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +300 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/io/baseline.d.ts +53 -0
- package/dist/io/baseline.d.ts.map +1 -0
- package/dist/io/baseline.js +97 -0
- package/dist/io/baseline.js.map +1 -0
- package/dist/io/capture.d.ts +15 -0
- package/dist/io/capture.d.ts.map +1 -0
- package/dist/io/capture.js +13 -0
- package/dist/io/capture.js.map +1 -0
- package/dist/io/interrupt.d.ts +46 -0
- package/dist/io/interrupt.d.ts.map +1 -0
- package/dist/io/interrupt.js +60 -0
- package/dist/io/interrupt.js.map +1 -0
- package/dist/io/respond.d.ts +28 -0
- package/dist/io/respond.d.ts.map +1 -0
- package/dist/io/respond.js +33 -0
- package/dist/io/respond.js.map +1 -0
- package/dist/io/send.d.ts +44 -0
- package/dist/io/send.d.ts.map +1 -0
- package/dist/io/send.js +66 -0
- package/dist/io/send.js.map +1 -0
- package/dist/io/stabilize.d.ts +28 -0
- package/dist/io/stabilize.d.ts.map +1 -0
- package/dist/io/stabilize.js +20 -0
- package/dist/io/stabilize.js.map +1 -0
- package/dist/io/wait.d.ts +47 -0
- package/dist/io/wait.d.ts.map +1 -0
- package/dist/io/wait.js +117 -0
- package/dist/io/wait.js.map +1 -0
- package/dist/observe/incremental.d.ts +28 -0
- package/dist/observe/incremental.d.ts.map +1 -0
- package/dist/observe/incremental.js +57 -0
- package/dist/observe/incremental.js.map +1 -0
- package/dist/observe/observer.d.ts +86 -0
- package/dist/observe/observer.d.ts.map +1 -0
- package/dist/observe/observer.js +167 -0
- package/dist/observe/observer.js.map +1 -0
- package/dist/observe/session-observer.d.ts +49 -0
- package/dist/observe/session-observer.d.ts.map +1 -0
- package/dist/observe/session-observer.js +123 -0
- package/dist/observe/session-observer.js.map +1 -0
- package/dist/session/adopt.d.ts +52 -0
- package/dist/session/adopt.d.ts.map +1 -0
- package/dist/session/adopt.js +57 -0
- package/dist/session/adopt.js.map +1 -0
- package/dist/session/boot.d.ts +66 -0
- package/dist/session/boot.d.ts.map +1 -0
- package/dist/session/boot.js +216 -0
- package/dist/session/boot.js.map +1 -0
- package/dist/session/constants.d.ts +57 -0
- package/dist/session/constants.d.ts.map +1 -0
- package/dist/session/constants.js +54 -0
- package/dist/session/constants.js.map +1 -0
- package/dist/session/create.d.ts +88 -0
- package/dist/session/create.d.ts.map +1 -0
- package/dist/session/create.js +66 -0
- package/dist/session/create.js.map +1 -0
- package/dist/session/default-backend.d.ts +27 -0
- package/dist/session/default-backend.d.ts.map +1 -0
- package/dist/session/default-backend.js +58 -0
- package/dist/session/default-backend.js.map +1 -0
- package/dist/session/handle.d.ts +63 -0
- package/dist/session/handle.d.ts.map +1 -0
- package/dist/session/handle.js +284 -0
- package/dist/session/handle.js.map +1 -0
- package/dist/session/hooks.d.ts +37 -0
- package/dist/session/hooks.d.ts.map +1 -0
- package/dist/session/hooks.js +42 -0
- package/dist/session/hooks.js.map +1 -0
- package/dist/session/mutex.d.ts +15 -0
- package/dist/session/mutex.d.ts.map +1 -0
- package/dist/session/mutex.js +29 -0
- package/dist/session/mutex.js.map +1 -0
- package/dist/session/recover.d.ts +43 -0
- package/dist/session/recover.d.ts.map +1 -0
- package/dist/session/recover.js +45 -0
- package/dist/session/recover.js.map +1 -0
- package/dist/session/ref.d.ts +2 -0
- package/dist/session/ref.d.ts.map +1 -0
- package/dist/session/ref.js +5 -0
- package/dist/session/ref.js.map +1 -0
- package/dist/session/registry.d.ts +31 -0
- package/dist/session/registry.d.ts.map +1 -0
- package/dist/session/registry.js +32 -0
- package/dist/session/registry.js.map +1 -0
- package/dist/session/resolve.d.ts +30 -0
- package/dist/session/resolve.d.ts.map +1 -0
- package/dist/session/resolve.js +24 -0
- package/dist/session/resolve.js.map +1 -0
- package/dist/session/resume.d.ts +68 -0
- package/dist/session/resume.d.ts.map +1 -0
- package/dist/session/resume.js +54 -0
- package/dist/session/resume.js.map +1 -0
- package/dist/session/spawn-boot.d.ts +44 -0
- package/dist/session/spawn-boot.d.ts.map +1 -0
- package/dist/session/spawn-boot.js +87 -0
- package/dist/session/spawn-boot.js.map +1 -0
- package/dist/session/validate.d.ts +10 -0
- package/dist/session/validate.d.ts.map +1 -0
- package/dist/session/validate.js +0 -0
- package/dist/session/validate.js.map +1 -0
- package/dist/state/classifier.d.ts +29 -0
- package/dist/state/classifier.d.ts.map +1 -0
- package/dist/state/classifier.js +37 -0
- package/dist/state/classifier.js.map +1 -0
- package/dist/state/types.d.ts +32 -0
- package/dist/state/types.d.ts.map +1 -0
- package/dist/state/types.js +2 -0
- package/dist/state/types.js.map +1 -0
- package/dist/types.d.ts +401 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/util/ansi.d.ts +14 -0
- package/dist/util/ansi.d.ts.map +1 -0
- package/dist/util/ansi.js +18 -0
- package/dist/util/ansi.js.map +1 -0
- package/dist/util/emitter.d.ts +17 -0
- package/dist/util/emitter.d.ts.map +1 -0
- package/dist/util/emitter.js +33 -0
- package/dist/util/emitter.js.map +1 -0
- package/dist/util/sleep.d.ts +8 -0
- package/dist/util/sleep.d.ts.map +1 -0
- package/dist/util/sleep.js +10 -0
- package/dist/util/sleep.js.map +1 -0
- 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":"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"}
|
|
@@ -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"}
|
package/dist/cli/ask.js
ADDED
|
@@ -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"}
|