aibroker 0.7.11 → 0.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/iterm/core.d.ts +18 -7
- package/dist/adapters/iterm/core.d.ts.map +1 -1
- package/dist/adapters/iterm/core.js +24 -13
- package/dist/adapters/iterm/core.js.map +1 -1
- package/dist/adapters/iterm/sessions.js +4 -4
- package/dist/adapters/iterm/sessions.js.map +1 -1
- package/dist/adapters/pailot/gateway.d.ts.map +1 -1
- package/dist/adapters/pailot/gateway.js +206 -18
- package/dist/adapters/pailot/gateway.js.map +1 -1
- package/dist/adapters/pailot/mqtt-broker.d.ts +5 -0
- package/dist/adapters/pailot/mqtt-broker.d.ts.map +1 -1
- package/dist/adapters/pailot/mqtt-broker.js +60 -6
- package/dist/adapters/pailot/mqtt-broker.js.map +1 -1
- package/dist/adapters/session/backend.js +1 -1
- package/dist/adapters/session/backend.js.map +1 -1
- package/dist/apns/client.d.ts +9 -0
- package/dist/apns/client.d.ts.map +1 -1
- package/dist/apns/client.js +25 -0
- package/dist/apns/client.js.map +1 -1
- package/dist/core/persistence.d.ts +7 -0
- package/dist/core/persistence.d.ts.map +1 -1
- package/dist/core/persistence.js +11 -0
- package/dist/core/persistence.js.map +1 -1
- package/dist/daemon/cli.d.ts +6 -0
- package/dist/daemon/cli.d.ts.map +1 -1
- package/dist/daemon/cli.js +13 -1
- package/dist/daemon/cli.js.map +1 -1
- package/dist/daemon/commands.d.ts.map +1 -1
- package/dist/daemon/commands.js +2 -1
- package/dist/daemon/commands.js.map +1 -1
- package/dist/daemon/core-handlers.d.ts.map +1 -1
- package/dist/daemon/core-handlers.js +79 -8
- package/dist/daemon/core-handlers.js.map +1 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +16 -2
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/ota.d.ts +8 -0
- package/dist/daemon/ota.d.ts.map +1 -0
- package/dist/daemon/ota.js +90 -0
- package/dist/daemon/ota.js.map +1 -0
- package/dist/daemon/pai-projects.d.ts +1 -1
- package/dist/daemon/pai-projects.d.ts.map +1 -1
- package/dist/daemon/pai-projects.js +34 -16
- package/dist/daemon/pai-projects.js.map +1 -1
- package/dist/daemon/session-content.d.ts.map +1 -1
- package/dist/daemon/session-content.js +2 -1
- package/dist/daemon/session-content.js.map +1 -1
- package/dist/ipc/client.d.ts.map +1 -1
- package/dist/ipc/client.js +4 -0
- package/dist/ipc/client.js.map +1 -1
- package/dist/ipc/server.d.ts.map +1 -1
- package/dist/ipc/server.js +9 -0
- package/dist/ipc/server.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +62 -6
- package/dist/mcp/index.js.map +1 -1
- package/dist/transport/index.d.ts +18 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +51 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/iterm.d.ts +21 -0
- package/dist/transport/iterm.d.ts.map +1 -0
- package/dist/transport/iterm.js +55 -0
- package/dist/transport/iterm.js.map +1 -0
- package/dist/transport/session-transport.d.ts +64 -0
- package/dist/transport/session-transport.d.ts.map +1 -0
- package/dist/transport/session-transport.js +17 -0
- package/dist/transport/session-transport.js.map +1 -0
- package/dist/transport/sync-facade.d.ts +52 -0
- package/dist/transport/sync-facade.d.ts.map +1 -0
- package/dist/transport/sync-facade.js +135 -0
- package/dist/transport/sync-facade.js.map +1 -0
- package/dist/transport/tmux.d.ts +53 -0
- package/dist/transport/tmux.d.ts.map +1 -0
- package/dist/transport/tmux.js +254 -0
- package/dist/transport/tmux.js.map +1 -0
- package/dist/types/ipc.d.ts +8 -0
- package/dist/types/ipc.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transport/session-transport.ts — Terminal-host abstraction.
|
|
3
|
+
*
|
|
4
|
+
* AIBroker controls Claude Code sessions through five primitives that were
|
|
5
|
+
* historically hardcoded to iTerm2 + AppleScript. This interface lets the same
|
|
6
|
+
* hub logic drive tmux (headless / Linux / SSH) or, later, a pty-owned process,
|
|
7
|
+
* without the rest of the daemon knowing which host it's talking to.
|
|
8
|
+
*
|
|
9
|
+
* Methods are SYNCHRONOUS on purpose: the daemon's existing iTerm path already
|
|
10
|
+
* blocks on `spawnSync` osascript, and the call sites (snapshot enumeration,
|
|
11
|
+
* message delivery) are written synchronously across the codebase. Keeping the
|
|
12
|
+
* same shape makes the iTerm→transport swap a drop-in with no async refactor.
|
|
13
|
+
*
|
|
14
|
+
* Zero transport-specific imports here — implementations live in sibling files.
|
|
15
|
+
*/
|
|
16
|
+
export type TransportKind = "iterm" | "tmux" | "pty";
|
|
17
|
+
export interface ManagedSession {
|
|
18
|
+
/** Transport-stable id usable as a target for every method, e.g. "%3" (tmux) or an iTerm GUID. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Best human display name (already resolved: title over raw process name). */
|
|
21
|
+
name: string;
|
|
22
|
+
/** Explicit tab/pane title if one was set, else null. */
|
|
23
|
+
tabTitle: string | null;
|
|
24
|
+
/** Controlling tty path if known. */
|
|
25
|
+
tty: string | null;
|
|
26
|
+
/** True when a foreground program is running (NOT sitting at a shell prompt). */
|
|
27
|
+
busy: boolean;
|
|
28
|
+
/** Which transport this session belongs to. */
|
|
29
|
+
transport: TransportKind;
|
|
30
|
+
/**
|
|
31
|
+
* Durable, transport-agnostic id that survives a host restart (scheme B).
|
|
32
|
+
* tmux: a `@aibroker_id` pane user-option we assign. iTerm: the GUID (already stable).
|
|
33
|
+
* This is the key the persistent paiName store should use across transports.
|
|
34
|
+
*/
|
|
35
|
+
aibrokerId: string | null;
|
|
36
|
+
}
|
|
37
|
+
export interface SendOptions {
|
|
38
|
+
/** Press Enter after the text (default true). */
|
|
39
|
+
enter?: boolean;
|
|
40
|
+
/** Confirm the text landed before pressing Enter, retrying the literal send if not (default true). */
|
|
41
|
+
verify?: boolean;
|
|
42
|
+
/** Max literal-send attempts when verify is on (default 3). */
|
|
43
|
+
maxRetries?: number;
|
|
44
|
+
}
|
|
45
|
+
export interface SessionTransport {
|
|
46
|
+
readonly kind: TransportKind;
|
|
47
|
+
/** Cheap probe: is this host present/usable right now? */
|
|
48
|
+
isAvailable(): boolean;
|
|
49
|
+
/** Enumerate all sessions this transport can see. */
|
|
50
|
+
listSessions(): ManagedSession[];
|
|
51
|
+
/**
|
|
52
|
+
* Inject text into a session. On tmux this is `send-keys -l` then a SEPARATE `Enter`
|
|
53
|
+
* (the one-command-text / one-command-enter rule), with verify+retry because bare
|
|
54
|
+
* combined sends are unreliable for Claude Code.
|
|
55
|
+
*/
|
|
56
|
+
sendText(id: string, text: string, opts?: SendOptions): boolean;
|
|
57
|
+
/** Read what the session is currently showing. `lines` includes scrollback when >visible. */
|
|
58
|
+
capture(id: string, lines?: number): string | null;
|
|
59
|
+
/** True when a foreground program is running (coarse: shell vs program). */
|
|
60
|
+
isBusy(id: string): boolean;
|
|
61
|
+
/** Set the session's title (used for the sticky paiName display). */
|
|
62
|
+
setTitle(id: string, title: string): boolean;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=session-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-transport.d.ts","sourceRoot":"","sources":["../../src/transport/session-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,kGAAkG;IAClG,EAAE,EAAE,MAAM,CAAC;IACX,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,qCAAqC;IACrC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,iFAAiF;IACjF,IAAI,EAAE,OAAO,CAAC;IACd,+CAA+C;IAC/C,SAAS,EAAE,aAAa,CAAC;IACzB;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sGAAsG;IACtG,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,0DAA0D;IAC1D,WAAW,IAAI,OAAO,CAAC;IACvB,qDAAqD;IACrD,YAAY,IAAI,cAAc,EAAE,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IAChE,6FAA6F;IAC7F,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACnD,4EAA4E;IAC5E,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transport/session-transport.ts — Terminal-host abstraction.
|
|
3
|
+
*
|
|
4
|
+
* AIBroker controls Claude Code sessions through five primitives that were
|
|
5
|
+
* historically hardcoded to iTerm2 + AppleScript. This interface lets the same
|
|
6
|
+
* hub logic drive tmux (headless / Linux / SSH) or, later, a pty-owned process,
|
|
7
|
+
* without the rest of the daemon knowing which host it's talking to.
|
|
8
|
+
*
|
|
9
|
+
* Methods are SYNCHRONOUS on purpose: the daemon's existing iTerm path already
|
|
10
|
+
* blocks on `spawnSync` osascript, and the call sites (snapshot enumeration,
|
|
11
|
+
* message delivery) are written synchronously across the codebase. Keeping the
|
|
12
|
+
* same shape makes the iTerm→transport swap a drop-in with no async refactor.
|
|
13
|
+
*
|
|
14
|
+
* Zero transport-specific imports here — implementations live in sibling files.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=session-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-transport.js","sourceRoot":"","sources":["../../src/transport/session-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transport/sync-facade.ts — Drop-in replacements for the iTerm primitives,
|
|
3
|
+
* with MULTI-TRANSPORT enumeration.
|
|
4
|
+
*
|
|
5
|
+
* The daemon historically imported `snapshotAllSessions`, `typeIntoSession`,
|
|
6
|
+
* `pasteTextIntoSession`, and `isClaudeRunningInSession` directly from
|
|
7
|
+
* adapters/iterm/core.ts. Those imports are repointed here. Every function keeps
|
|
8
|
+
* the EXACT same signature.
|
|
9
|
+
*
|
|
10
|
+
* Transport selection (decided once at module load):
|
|
11
|
+
* AIBROKER_TRANSPORT=iterm → iTerm only
|
|
12
|
+
* AIBROKER_TRANSPORT=tmux → tmux only
|
|
13
|
+
* AIBROKER_TRANSPORT=multi → both (subject to availability)
|
|
14
|
+
* unset / anything else → AUTO: enumerate whatever is available right now
|
|
15
|
+
*
|
|
16
|
+
* AUTO is the default and is safe: on a Mac with no tmux server it resolves to
|
|
17
|
+
* iTerm-only (byte-identical to the pre-transport behaviour — verified). The
|
|
18
|
+
* instant a tmux server exists, its panes merge into the same session list, so
|
|
19
|
+
* iTerm and tmux sessions show up together. This is what makes the iTerm→tmux
|
|
20
|
+
* migration seamless and unblocks PAILot seeing both worlds at once.
|
|
21
|
+
*
|
|
22
|
+
* The iTerm path calls core.ts VERBATIM (raw SessionSnapshot: name=process name,
|
|
23
|
+
* tabTitle separate, paiName=null) so every downstream consumer — gateway
|
|
24
|
+
* displayName resolution, atPrompt heuristics, name matching — is unchanged.
|
|
25
|
+
*
|
|
26
|
+
* Per-id ops (send / busy) route by id shape: tmux pane ids start with "%",
|
|
27
|
+
* iTerm uses GUIDs. With one transport active, everything routes to it.
|
|
28
|
+
*/
|
|
29
|
+
import type { SessionSnapshot } from "../adapters/iterm/core.js";
|
|
30
|
+
/** Enumerate sessions across all permitted transports, availability checked live. */
|
|
31
|
+
export declare function snapshotAllSessions(): SessionSnapshot[];
|
|
32
|
+
/** Translate a caller's $TMUX_PANE into the durable @aibroker_id identity. */
|
|
33
|
+
export declare function aibrokerIdForPane(paneId: string): string | null;
|
|
34
|
+
/** Inject text + Enter into a session. */
|
|
35
|
+
export declare function typeIntoSession(id: string, text: string): boolean;
|
|
36
|
+
/** Inject text WITHOUT Enter (chunked / partial sends). */
|
|
37
|
+
export declare function pasteTextIntoSession(id: string, text: string): boolean;
|
|
38
|
+
/** True when a foreground program (Claude) is running, not at a shell prompt. */
|
|
39
|
+
export declare function isClaudeRunningInSession(id: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Set a tmux pane's title. Returns false for non-tmux ids — iTerm visuals are
|
|
42
|
+
* set separately by the caller via the iTerm sessions adapter.
|
|
43
|
+
*/
|
|
44
|
+
export declare function setSessionTitle(id: string, title: string): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* For a tmux pane id, return the iTerm2 session id of the tab currently viewing
|
|
47
|
+
* it (via the tmux client tty → iTerm tty match), or null if detached / not on
|
|
48
|
+
* iTerm. Uses the RAW iTerm enumeration (not the de-duped facade list, which
|
|
49
|
+
* suppresses viewer tabs) so the host tab can still receive iTerm visuals.
|
|
50
|
+
*/
|
|
51
|
+
export declare function itermViewerSessionId(tmuxPaneId: string): string | null;
|
|
52
|
+
//# sourceMappingURL=sync-facade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-facade.d.ts","sourceRoot":"","sources":["../../src/transport/sync-facade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAgCjE,qFAAqF;AACrF,wBAAgB,mBAAmB,IAAI,eAAe,EAAE,CAgBvD;AAeD,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG/D;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGjE;AAED,2DAA2D;AAC3D,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGtE;AAED,iFAAiF;AACjF,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAGlE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKtE"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transport/sync-facade.ts — Drop-in replacements for the iTerm primitives,
|
|
3
|
+
* with MULTI-TRANSPORT enumeration.
|
|
4
|
+
*
|
|
5
|
+
* The daemon historically imported `snapshotAllSessions`, `typeIntoSession`,
|
|
6
|
+
* `pasteTextIntoSession`, and `isClaudeRunningInSession` directly from
|
|
7
|
+
* adapters/iterm/core.ts. Those imports are repointed here. Every function keeps
|
|
8
|
+
* the EXACT same signature.
|
|
9
|
+
*
|
|
10
|
+
* Transport selection (decided once at module load):
|
|
11
|
+
* AIBROKER_TRANSPORT=iterm → iTerm only
|
|
12
|
+
* AIBROKER_TRANSPORT=tmux → tmux only
|
|
13
|
+
* AIBROKER_TRANSPORT=multi → both (subject to availability)
|
|
14
|
+
* unset / anything else → AUTO: enumerate whatever is available right now
|
|
15
|
+
*
|
|
16
|
+
* AUTO is the default and is safe: on a Mac with no tmux server it resolves to
|
|
17
|
+
* iTerm-only (byte-identical to the pre-transport behaviour — verified). The
|
|
18
|
+
* instant a tmux server exists, its panes merge into the same session list, so
|
|
19
|
+
* iTerm and tmux sessions show up together. This is what makes the iTerm→tmux
|
|
20
|
+
* migration seamless and unblocks PAILot seeing both worlds at once.
|
|
21
|
+
*
|
|
22
|
+
* The iTerm path calls core.ts VERBATIM (raw SessionSnapshot: name=process name,
|
|
23
|
+
* tabTitle separate, paiName=null) so every downstream consumer — gateway
|
|
24
|
+
* displayName resolution, atPrompt heuristics, name matching — is unchanged.
|
|
25
|
+
*
|
|
26
|
+
* Per-id ops (send / busy) route by id shape: tmux pane ids start with "%",
|
|
27
|
+
* iTerm uses GUIDs. With one transport active, everything routes to it.
|
|
28
|
+
*/
|
|
29
|
+
import * as iterm from "../adapters/iterm/core.js";
|
|
30
|
+
import { TmuxTransport } from "./tmux.js";
|
|
31
|
+
import { log } from "../core/log.js";
|
|
32
|
+
const override = (process.env.AIBROKER_TRANSPORT ?? "").trim().toLowerCase();
|
|
33
|
+
const tmuxTransport = new TmuxTransport();
|
|
34
|
+
// Override GATES which transports are permitted; availability is then checked
|
|
35
|
+
// LIVE on every enumeration (NOT frozen at boot), so a tmux server started after
|
|
36
|
+
// the daemon launched is picked up immediately — no restart required. Likewise,
|
|
37
|
+
// iTerm yields nothing on a headless box (osascript absent), so AUTO degrades
|
|
38
|
+
// cleanly to tmux-only there.
|
|
39
|
+
const allowIterm = override !== "tmux";
|
|
40
|
+
const allowTmux = override !== "iterm";
|
|
41
|
+
function tmuxToSnapshot(s) {
|
|
42
|
+
return {
|
|
43
|
+
id: s.id,
|
|
44
|
+
name: s.name,
|
|
45
|
+
profileName: "Default",
|
|
46
|
+
tabTitle: s.tabTitle,
|
|
47
|
+
tty: s.tty ?? "",
|
|
48
|
+
atPrompt: !s.busy,
|
|
49
|
+
// paiName merged from the persistent store by callers, exactly as for iTerm.
|
|
50
|
+
paiName: null,
|
|
51
|
+
// Durable id so persistent-name lookups survive %N churn across tmux restarts.
|
|
52
|
+
aibrokerId: s.aibrokerId,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Enumerate sessions across all permitted transports, availability checked live. */
|
|
56
|
+
export function snapshotAllSessions() {
|
|
57
|
+
// Query tmux first (returns [] if no server is running). This is the LIVE
|
|
58
|
+
// availability check — a server that appears post-boot is seen immediately.
|
|
59
|
+
const tmuxSessions = allowTmux ? tmuxTransport.listSessions() : [];
|
|
60
|
+
let itermSessions = allowIterm ? iterm.snapshotAllSessions() : [];
|
|
61
|
+
if (allowIterm && tmuxSessions.length) {
|
|
62
|
+
// De-dup nesting: an iTerm/Terminal tab running `tmux attach` is just a
|
|
63
|
+
// VIEWER of tmux panes we already enumerate directly. Suppress those rows
|
|
64
|
+
// so a tmux-hosted session appears once (as the tmux pane), not twice.
|
|
65
|
+
// The link is the tty: a tmux client's tty IS the hosting tab's tty.
|
|
66
|
+
const viewerTtys = tmuxTransport.attachedClientTtys();
|
|
67
|
+
if (viewerTtys.size)
|
|
68
|
+
itermSessions = itermSessions.filter((s) => !s.tty || !viewerTtys.has(s.tty));
|
|
69
|
+
}
|
|
70
|
+
return [...itermSessions, ...tmuxSessions.map(tmuxToSnapshot)];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Decide whether an id belongs to tmux. tmux session ids are now durable
|
|
74
|
+
* @aibroker_ids (a raw "%N" pane id may also appear during inbound translation).
|
|
75
|
+
* A "%N" is unambiguously tmux; otherwise check whether a live tmux pane carries
|
|
76
|
+
* that @aibroker_id (iTerm GUIDs won't match → routed to iTerm).
|
|
77
|
+
*/
|
|
78
|
+
function routeToTmux(id) {
|
|
79
|
+
if (!allowTmux)
|
|
80
|
+
return false;
|
|
81
|
+
if (!allowIterm)
|
|
82
|
+
return true; // tmux is the only permitted transport
|
|
83
|
+
if (id.startsWith("%"))
|
|
84
|
+
return true;
|
|
85
|
+
return tmuxTransport.paneFor(id) != null;
|
|
86
|
+
}
|
|
87
|
+
/** Translate a caller's $TMUX_PANE into the durable @aibroker_id identity. */
|
|
88
|
+
export function aibrokerIdForPane(paneId) {
|
|
89
|
+
if (!allowTmux)
|
|
90
|
+
return null;
|
|
91
|
+
return tmuxTransport.aibrokerIdForPane(paneId);
|
|
92
|
+
}
|
|
93
|
+
/** Inject text + Enter into a session. */
|
|
94
|
+
export function typeIntoSession(id, text) {
|
|
95
|
+
if (routeToTmux(id))
|
|
96
|
+
return tmuxTransport.sendText(id, text, { enter: true });
|
|
97
|
+
return iterm.typeIntoSession(id, text);
|
|
98
|
+
}
|
|
99
|
+
/** Inject text WITHOUT Enter (chunked / partial sends). */
|
|
100
|
+
export function pasteTextIntoSession(id, text) {
|
|
101
|
+
if (routeToTmux(id))
|
|
102
|
+
return tmuxTransport.sendText(id, text, { enter: false });
|
|
103
|
+
return iterm.pasteTextIntoSession(id, text);
|
|
104
|
+
}
|
|
105
|
+
/** True when a foreground program (Claude) is running, not at a shell prompt. */
|
|
106
|
+
export function isClaudeRunningInSession(id) {
|
|
107
|
+
if (routeToTmux(id))
|
|
108
|
+
return tmuxTransport.isBusy(id);
|
|
109
|
+
return iterm.isClaudeRunningInSession(id);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Set a tmux pane's title. Returns false for non-tmux ids — iTerm visuals are
|
|
113
|
+
* set separately by the caller via the iTerm sessions adapter.
|
|
114
|
+
*/
|
|
115
|
+
export function setSessionTitle(id, title) {
|
|
116
|
+
if (routeToTmux(id))
|
|
117
|
+
return tmuxTransport.setTitle(id, title);
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* For a tmux pane id, return the iTerm2 session id of the tab currently viewing
|
|
122
|
+
* it (via the tmux client tty → iTerm tty match), or null if detached / not on
|
|
123
|
+
* iTerm. Uses the RAW iTerm enumeration (not the de-duped facade list, which
|
|
124
|
+
* suppresses viewer tabs) so the host tab can still receive iTerm visuals.
|
|
125
|
+
*/
|
|
126
|
+
export function itermViewerSessionId(tmuxPaneId) {
|
|
127
|
+
if (!allowTmux || !allowIterm)
|
|
128
|
+
return null;
|
|
129
|
+
const tty = tmuxTransport.clientTtyForPane(tmuxPaneId);
|
|
130
|
+
if (!tty)
|
|
131
|
+
return null;
|
|
132
|
+
return iterm.snapshotAllSessions().find((s) => s.tty === tty)?.id ?? null;
|
|
133
|
+
}
|
|
134
|
+
log(`sync-facade: transports permitted = [${[allowIterm ? "iterm" : null, allowTmux ? "tmux" : null].filter(Boolean).join(", ")}] (availability checked live per enumeration)`);
|
|
135
|
+
//# sourceMappingURL=sync-facade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-facade.js","sourceRoot":"","sources":["../../src/transport/sync-facade.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transport/tmux.ts — tmux implementation of SessionTransport (synchronous).
|
|
3
|
+
*
|
|
4
|
+
* Why tmux: cross-platform, scriptable, SSH/headless-friendly, and `send-keys -l`
|
|
5
|
+
* sidesteps the AppleScript multi-line escaping bugs. Two hard-won lessons from
|
|
6
|
+
* prior art (claude-code-tools' tmux-cli) are baked in:
|
|
7
|
+
*
|
|
8
|
+
* 1. Sending text and pressing Enter as ONE combined send is unreliable for
|
|
9
|
+
* Claude Code. We send the literal text, confirm it landed, THEN send Enter
|
|
10
|
+
* as a separate keystroke, retrying the literal send if it didn't appear.
|
|
11
|
+
* 2. Pane ids (%0, %3 …) are ephemeral — they reset when the tmux server
|
|
12
|
+
* restarts. So each pane gets a durable `@aibroker_id` user-option (scheme B)
|
|
13
|
+
* that the persistent paiName store can key on across transports.
|
|
14
|
+
*
|
|
15
|
+
* Synchronous (spawnSync) to match core.ts and the daemon's existing call sites.
|
|
16
|
+
*/
|
|
17
|
+
import type { ManagedSession, SendOptions, SessionTransport, TransportKind } from "./session-transport.js";
|
|
18
|
+
export declare class TmuxTransport implements SessionTransport {
|
|
19
|
+
readonly kind: TransportKind;
|
|
20
|
+
isAvailable(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a session's CURRENT pane id from a stable id. Accepts either a pane
|
|
23
|
+
* id ("%3" — returned as-is) or an @aibroker_id (looked up live). Pane ids are
|
|
24
|
+
* ephemeral and reused (every first pane is %0), so the public ops take the
|
|
25
|
+
* durable @aibroker_id as identity and resolve the live pane here. Returns null
|
|
26
|
+
* if no live pane carries that id.
|
|
27
|
+
*/
|
|
28
|
+
paneFor(stableId: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Durable @aibroker_id for a pane id (assigning one if the pane lacks it).
|
|
31
|
+
* Used to translate an inbound caller's $TMUX_PANE into the stable identity.
|
|
32
|
+
*/
|
|
33
|
+
aibrokerIdForPane(paneId: string): string | null;
|
|
34
|
+
listSessions(): ManagedSession[];
|
|
35
|
+
sendText(id: string, text: string, opts?: SendOptions): boolean;
|
|
36
|
+
capture(id: string, lines?: number): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* ttys of terminals currently attached as tmux clients (e.g. an iTerm tab
|
|
39
|
+
* running `tmux attach`). Used to de-dup: such a tab is a VIEWER of panes we
|
|
40
|
+
* already enumerate directly, not a session of its own.
|
|
41
|
+
*/
|
|
42
|
+
attachedClientTtys(): Set<string>;
|
|
43
|
+
/**
|
|
44
|
+
* tty of the terminal (e.g. iTerm tab) currently viewing the given pane's
|
|
45
|
+
* session, or null if the session is detached. Lets callers map a tmux pane
|
|
46
|
+
* back to its host iTerm tab so iTerm visuals (badge/tab title) can be set on
|
|
47
|
+
* the tab the user is actually looking at.
|
|
48
|
+
*/
|
|
49
|
+
clientTtyForPane(id: string): string | null;
|
|
50
|
+
isBusy(id: string): boolean;
|
|
51
|
+
setTitle(id: string, title: string): boolean;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=tmux.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.d.ts","sourceRoot":"","sources":["../../src/transport/tmux.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA0D3G,qBAAa,aAAc,YAAW,gBAAgB;IACpD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAU;IAEtC,WAAW,IAAI,OAAO;IAMtB;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAWxC;;;OAGG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAUhD,YAAY,IAAI,cAAc,EAAE;IAiChC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO;IA8CnE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAQlD;;;;OAIG;IACH,kBAAkB,IAAI,GAAG,CAAC,MAAM,CAAC;IAMjC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAa3C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAa3B,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;CAK7C"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transport/tmux.ts — tmux implementation of SessionTransport (synchronous).
|
|
3
|
+
*
|
|
4
|
+
* Why tmux: cross-platform, scriptable, SSH/headless-friendly, and `send-keys -l`
|
|
5
|
+
* sidesteps the AppleScript multi-line escaping bugs. Two hard-won lessons from
|
|
6
|
+
* prior art (claude-code-tools' tmux-cli) are baked in:
|
|
7
|
+
*
|
|
8
|
+
* 1. Sending text and pressing Enter as ONE combined send is unreliable for
|
|
9
|
+
* Claude Code. We send the literal text, confirm it landed, THEN send Enter
|
|
10
|
+
* as a separate keystroke, retrying the literal send if it didn't appear.
|
|
11
|
+
* 2. Pane ids (%0, %3 …) are ephemeral — they reset when the tmux server
|
|
12
|
+
* restarts. So each pane gets a durable `@aibroker_id` user-option (scheme B)
|
|
13
|
+
* that the persistent paiName store can key on across transports.
|
|
14
|
+
*
|
|
15
|
+
* Synchronous (spawnSync) to match core.ts and the daemon's existing call sites.
|
|
16
|
+
*/
|
|
17
|
+
import { spawnSync } from "node:child_process";
|
|
18
|
+
import { existsSync } from "node:fs";
|
|
19
|
+
import { randomUUID } from "node:crypto";
|
|
20
|
+
import { log } from "../core/log.js";
|
|
21
|
+
/** Foreground process names that mean "at a shell prompt" (idle), not running a program. */
|
|
22
|
+
const SHELL_COMMANDS = new Set(["zsh", "-zsh", "bash", "-bash", "sh", "-sh", "fish", "-fish"]);
|
|
23
|
+
/** Field separator for list-panes -F output; unlikely to appear in titles. */
|
|
24
|
+
const FIELD_SEP = "";
|
|
25
|
+
/**
|
|
26
|
+
* Resolve an absolute tmux path. A launchd-managed daemon has a minimal PATH
|
|
27
|
+
* (e.g. /usr/local/bin:/usr/bin:/bin) that excludes Homebrew's /opt/homebrew/bin,
|
|
28
|
+
* so a bare "tmux" would ENOENT. Probe common locations, fall back to PATH.
|
|
29
|
+
*/
|
|
30
|
+
function resolveTmuxBin() {
|
|
31
|
+
const candidates = ["/opt/homebrew/bin/tmux", "/usr/local/bin/tmux", "/usr/bin/tmux"];
|
|
32
|
+
for (const c of candidates)
|
|
33
|
+
if (existsSync(c))
|
|
34
|
+
return c;
|
|
35
|
+
return "tmux";
|
|
36
|
+
}
|
|
37
|
+
const TMUX_BIN = resolveTmuxBin();
|
|
38
|
+
/**
|
|
39
|
+
* tmux transliterates non-ASCII output to "_" under a C/POSIX locale — which is
|
|
40
|
+
* exactly what launchd hands the daemon (no LANG/LC_*). That mangles BOTH the
|
|
41
|
+
* \x01 FIELD_SEP (→ "_", so list-panes rows no longer split and every field
|
|
42
|
+
* collapses into the "pane id") AND unicode pane titles. Forcing a UTF-8 locale
|
|
43
|
+
* keeps the separator and titles intact. ANTHROPIC_API_KEY is stripped from the
|
|
44
|
+
* spawned env per policy (never leak it to child processes).
|
|
45
|
+
*/
|
|
46
|
+
const TMUX_ENV = (() => {
|
|
47
|
+
const e = { ...process.env };
|
|
48
|
+
e.LC_ALL = "en_US.UTF-8";
|
|
49
|
+
e.LANG = "en_US.UTF-8";
|
|
50
|
+
delete e.ANTHROPIC_API_KEY;
|
|
51
|
+
return e;
|
|
52
|
+
})();
|
|
53
|
+
function runTmux(args, timeoutMs = 4_000) {
|
|
54
|
+
const result = spawnSync(TMUX_BIN, args, {
|
|
55
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
56
|
+
timeout: timeoutMs,
|
|
57
|
+
encoding: "utf8",
|
|
58
|
+
env: TMUX_ENV,
|
|
59
|
+
});
|
|
60
|
+
if (result.status !== 0) {
|
|
61
|
+
const stderr = (result.stderr ?? "").toString().trim();
|
|
62
|
+
// "no server running" is the normal state when no tmux is up — don't spam logs.
|
|
63
|
+
if (stderr && !stderr.includes("no server running"))
|
|
64
|
+
log(`tmux ${args[0]} failed: ${stderr}`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return result.stdout ?? "";
|
|
68
|
+
}
|
|
69
|
+
/** Blocking sleep — used only for the short send-verify poll. */
|
|
70
|
+
function syncSleep(ms) {
|
|
71
|
+
const shared = new Int32Array(new SharedArrayBuffer(4));
|
|
72
|
+
Atomics.wait(shared, 0, 0, ms);
|
|
73
|
+
}
|
|
74
|
+
export class TmuxTransport {
|
|
75
|
+
kind = "tmux";
|
|
76
|
+
isAvailable() {
|
|
77
|
+
// `list-panes -a` exits non-zero ("no server running") when no server exists,
|
|
78
|
+
// zero otherwise — a cheap, reliable probe.
|
|
79
|
+
return runTmux(["list-panes", "-a"], 2_000) != null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a session's CURRENT pane id from a stable id. Accepts either a pane
|
|
83
|
+
* id ("%3" — returned as-is) or an @aibroker_id (looked up live). Pane ids are
|
|
84
|
+
* ephemeral and reused (every first pane is %0), so the public ops take the
|
|
85
|
+
* durable @aibroker_id as identity and resolve the live pane here. Returns null
|
|
86
|
+
* if no live pane carries that id.
|
|
87
|
+
*/
|
|
88
|
+
paneFor(stableId) {
|
|
89
|
+
if (stableId.startsWith("%"))
|
|
90
|
+
return stableId;
|
|
91
|
+
const out = runTmux(["list-panes", "-a", "-F", `#{@aibroker_id}${FIELD_SEP}#{pane_id}`]);
|
|
92
|
+
if (out == null)
|
|
93
|
+
return null;
|
|
94
|
+
for (const line of out.split("\n").filter(Boolean)) {
|
|
95
|
+
const [aid, pane] = line.split(FIELD_SEP);
|
|
96
|
+
if (aid && aid === stableId)
|
|
97
|
+
return pane ?? null;
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Durable @aibroker_id for a pane id (assigning one if the pane lacks it).
|
|
103
|
+
* Used to translate an inbound caller's $TMUX_PANE into the stable identity.
|
|
104
|
+
*/
|
|
105
|
+
aibrokerIdForPane(paneId) {
|
|
106
|
+
const existing = runTmux(["display-message", "-p", "-t", paneId, "#{@aibroker_id}"]);
|
|
107
|
+
if (existing == null)
|
|
108
|
+
return null;
|
|
109
|
+
const id = existing.trim();
|
|
110
|
+
if (id)
|
|
111
|
+
return id;
|
|
112
|
+
const fresh = randomUUID();
|
|
113
|
+
runTmux(["set-option", "-p", "-t", paneId, "@aibroker_id", fresh]);
|
|
114
|
+
return fresh;
|
|
115
|
+
}
|
|
116
|
+
listSessions() {
|
|
117
|
+
const fmt = ["#{pane_id}", "#{pane_current_command}", "#{pane_title}", "#{pane_tty}", "#{@aibroker_id}"].join(FIELD_SEP);
|
|
118
|
+
const out = runTmux(["list-panes", "-a", "-F", fmt]);
|
|
119
|
+
if (out == null)
|
|
120
|
+
return [];
|
|
121
|
+
const sessions = [];
|
|
122
|
+
for (const line of out.split("\n").filter(Boolean)) {
|
|
123
|
+
const [paneId, cmd, title, tty, existingId] = line.split(FIELD_SEP);
|
|
124
|
+
if (!paneId)
|
|
125
|
+
continue;
|
|
126
|
+
// Scheme B: ensure a durable id exists for this pane.
|
|
127
|
+
let aibrokerId = existingId && existingId.length > 0 ? existingId : null;
|
|
128
|
+
if (!aibrokerId) {
|
|
129
|
+
aibrokerId = randomUUID();
|
|
130
|
+
runTmux(["set-option", "-p", "-t", paneId, "@aibroker_id", aibrokerId]);
|
|
131
|
+
}
|
|
132
|
+
const cleanTitle = title && title.trim().length > 0 ? title.trim() : null;
|
|
133
|
+
sessions.push({
|
|
134
|
+
// Identity is the durable @aibroker_id, NOT the volatile pane id — so a
|
|
135
|
+
// new session reusing pane %0 is a distinct session everywhere upstream.
|
|
136
|
+
id: aibrokerId,
|
|
137
|
+
name: cleanTitle ?? cmd ?? paneId,
|
|
138
|
+
tabTitle: cleanTitle,
|
|
139
|
+
tty: tty || null,
|
|
140
|
+
busy: !SHELL_COMMANDS.has(cmd ?? ""),
|
|
141
|
+
transport: this.kind,
|
|
142
|
+
aibrokerId,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return sessions;
|
|
146
|
+
}
|
|
147
|
+
sendText(id, text, opts = {}) {
|
|
148
|
+
const { enter = true, verify = true, maxRetries = 3 } = opts;
|
|
149
|
+
const pane = this.paneFor(id);
|
|
150
|
+
if (pane == null)
|
|
151
|
+
return false;
|
|
152
|
+
let landed = false;
|
|
153
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
154
|
+
// Literal send: `--` guards against text starting with '-'; `-l` = no key-name interpretation.
|
|
155
|
+
const sent = runTmux(["send-keys", "-t", pane, "-l", "--", text]);
|
|
156
|
+
if (sent == null)
|
|
157
|
+
return false;
|
|
158
|
+
if (!verify) {
|
|
159
|
+
landed = true;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
// Poll the pane until the tail of what we typed shows on screen — then it landed.
|
|
163
|
+
const probe = text.trim().slice(-40);
|
|
164
|
+
if (probe.length === 0) {
|
|
165
|
+
landed = true;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
for (let poll = 0; poll < 10; poll++) {
|
|
169
|
+
syncSleep(60);
|
|
170
|
+
const shown = this.capture(pane);
|
|
171
|
+
if (shown && shown.includes(probe)) {
|
|
172
|
+
landed = true;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (landed)
|
|
177
|
+
break;
|
|
178
|
+
log(`tmux sendText: text did not appear on attempt ${attempt + 1} for ${pane}, retrying`);
|
|
179
|
+
}
|
|
180
|
+
if (!landed) {
|
|
181
|
+
log(`tmux sendText: gave up after ${maxRetries} attempts for ${pane}`);
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
if (enter) {
|
|
185
|
+
// Separate keystroke — combining text+Enter in one send is the unreliable path.
|
|
186
|
+
if (runTmux(["send-keys", "-t", pane, "Enter"]) == null)
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
capture(id, lines) {
|
|
192
|
+
const pane = this.paneFor(id);
|
|
193
|
+
if (pane == null)
|
|
194
|
+
return null;
|
|
195
|
+
const args = ["capture-pane", "-t", pane, "-p"];
|
|
196
|
+
if (lines && lines > 0)
|
|
197
|
+
args.push("-S", `-${lines}`);
|
|
198
|
+
return runTmux(args);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* ttys of terminals currently attached as tmux clients (e.g. an iTerm tab
|
|
202
|
+
* running `tmux attach`). Used to de-dup: such a tab is a VIEWER of panes we
|
|
203
|
+
* already enumerate directly, not a session of its own.
|
|
204
|
+
*/
|
|
205
|
+
attachedClientTtys() {
|
|
206
|
+
const out = runTmux(["list-clients", "-F", "#{client_tty}"]);
|
|
207
|
+
if (out == null)
|
|
208
|
+
return new Set();
|
|
209
|
+
return new Set(out.split("\n").map((s) => s.trim()).filter(Boolean));
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* tty of the terminal (e.g. iTerm tab) currently viewing the given pane's
|
|
213
|
+
* session, or null if the session is detached. Lets callers map a tmux pane
|
|
214
|
+
* back to its host iTerm tab so iTerm visuals (badge/tab title) can be set on
|
|
215
|
+
* the tab the user is actually looking at.
|
|
216
|
+
*/
|
|
217
|
+
clientTtyForPane(id) {
|
|
218
|
+
const pane = this.paneFor(id);
|
|
219
|
+
if (pane == null)
|
|
220
|
+
return null;
|
|
221
|
+
const session = runTmux(["display-message", "-p", "-t", pane, "#{session_name}"]);
|
|
222
|
+
if (session == null)
|
|
223
|
+
return null;
|
|
224
|
+
const name = session.trim();
|
|
225
|
+
if (!name)
|
|
226
|
+
return null;
|
|
227
|
+
const out = runTmux(["list-clients", "-t", name, "-F", "#{client_tty}"]);
|
|
228
|
+
if (out == null)
|
|
229
|
+
return null;
|
|
230
|
+
const tty = out.split("\n").map((s) => s.trim()).filter(Boolean)[0];
|
|
231
|
+
return tty ?? null;
|
|
232
|
+
}
|
|
233
|
+
isBusy(id) {
|
|
234
|
+
const pane = this.paneFor(id);
|
|
235
|
+
if (pane == null)
|
|
236
|
+
return false;
|
|
237
|
+
const out = runTmux(["display-message", "-p", "-t", pane, "#{pane_current_command}"]);
|
|
238
|
+
if (out == null)
|
|
239
|
+
return false;
|
|
240
|
+
const cmd = out.trim();
|
|
241
|
+
// Coarse layer: shell command => idle. A program (node/claude/ssh/…) => busy.
|
|
242
|
+
// NOTE: while Claude runs, this always reads "node" — it cannot distinguish
|
|
243
|
+
// "thinking" from "awaiting input". Fine-grained readiness needs output-diff
|
|
244
|
+
// silence detection (a future waitIdle helper), tracked separately.
|
|
245
|
+
return cmd.length > 0 && !SHELL_COMMANDS.has(cmd);
|
|
246
|
+
}
|
|
247
|
+
setTitle(id, title) {
|
|
248
|
+
const pane = this.paneFor(id);
|
|
249
|
+
if (pane == null)
|
|
250
|
+
return false;
|
|
251
|
+
return runTmux(["select-pane", "-t", pane, "-T", title]) != null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=tmux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../src/transport/tmux.ts"],"names":[],"mappings":"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"}
|
package/dist/types/ipc.d.ts
CHANGED
|
@@ -6,6 +6,14 @@ export interface IpcRequest {
|
|
|
6
6
|
id: string;
|
|
7
7
|
sessionId: string;
|
|
8
8
|
itermSessionId?: string;
|
|
9
|
+
/**
|
|
10
|
+
* tmux pane id of the caller (e.g. "%3"), from $TMUX_PANE. Set when the caller
|
|
11
|
+
* runs inside tmux. Unlike ITERM_SESSION_ID — which a tmux-hosted process
|
|
12
|
+
* inherits from whatever iTerm tab first started the tmux server (a DIFFERENT
|
|
13
|
+
* session) — TMUX_PANE is correct per pane, so it's the authoritative caller
|
|
14
|
+
* identity for tmux sessions.
|
|
15
|
+
*/
|
|
16
|
+
tmuxPane?: string;
|
|
9
17
|
method: string;
|
|
10
18
|
params: Record<string, unknown>;
|
|
11
19
|
}
|
package/dist/types/ipc.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ipc.d.ts","sourceRoot":"","sources":["../../src/types/ipc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|
|
1
|
+
{"version":3,"file":"ipc.d.ts","sourceRoot":"","sources":["../../src/types/ipc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|