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.
Files changed (79) hide show
  1. package/dist/adapters/iterm/core.d.ts +18 -7
  2. package/dist/adapters/iterm/core.d.ts.map +1 -1
  3. package/dist/adapters/iterm/core.js +24 -13
  4. package/dist/adapters/iterm/core.js.map +1 -1
  5. package/dist/adapters/iterm/sessions.js +4 -4
  6. package/dist/adapters/iterm/sessions.js.map +1 -1
  7. package/dist/adapters/pailot/gateway.d.ts.map +1 -1
  8. package/dist/adapters/pailot/gateway.js +206 -18
  9. package/dist/adapters/pailot/gateway.js.map +1 -1
  10. package/dist/adapters/pailot/mqtt-broker.d.ts +5 -0
  11. package/dist/adapters/pailot/mqtt-broker.d.ts.map +1 -1
  12. package/dist/adapters/pailot/mqtt-broker.js +60 -6
  13. package/dist/adapters/pailot/mqtt-broker.js.map +1 -1
  14. package/dist/adapters/session/backend.js +1 -1
  15. package/dist/adapters/session/backend.js.map +1 -1
  16. package/dist/apns/client.d.ts +9 -0
  17. package/dist/apns/client.d.ts.map +1 -1
  18. package/dist/apns/client.js +25 -0
  19. package/dist/apns/client.js.map +1 -1
  20. package/dist/core/persistence.d.ts +7 -0
  21. package/dist/core/persistence.d.ts.map +1 -1
  22. package/dist/core/persistence.js +11 -0
  23. package/dist/core/persistence.js.map +1 -1
  24. package/dist/daemon/cli.d.ts +6 -0
  25. package/dist/daemon/cli.d.ts.map +1 -1
  26. package/dist/daemon/cli.js +13 -1
  27. package/dist/daemon/cli.js.map +1 -1
  28. package/dist/daemon/commands.d.ts.map +1 -1
  29. package/dist/daemon/commands.js +2 -1
  30. package/dist/daemon/commands.js.map +1 -1
  31. package/dist/daemon/core-handlers.d.ts.map +1 -1
  32. package/dist/daemon/core-handlers.js +79 -8
  33. package/dist/daemon/core-handlers.js.map +1 -1
  34. package/dist/daemon/index.d.ts.map +1 -1
  35. package/dist/daemon/index.js +16 -2
  36. package/dist/daemon/index.js.map +1 -1
  37. package/dist/daemon/ota.d.ts +8 -0
  38. package/dist/daemon/ota.d.ts.map +1 -0
  39. package/dist/daemon/ota.js +90 -0
  40. package/dist/daemon/ota.js.map +1 -0
  41. package/dist/daemon/pai-projects.d.ts +1 -1
  42. package/dist/daemon/pai-projects.d.ts.map +1 -1
  43. package/dist/daemon/pai-projects.js +34 -16
  44. package/dist/daemon/pai-projects.js.map +1 -1
  45. package/dist/daemon/session-content.d.ts.map +1 -1
  46. package/dist/daemon/session-content.js +2 -1
  47. package/dist/daemon/session-content.js.map +1 -1
  48. package/dist/ipc/client.d.ts.map +1 -1
  49. package/dist/ipc/client.js +4 -0
  50. package/dist/ipc/client.js.map +1 -1
  51. package/dist/ipc/server.d.ts.map +1 -1
  52. package/dist/ipc/server.js +9 -0
  53. package/dist/ipc/server.js.map +1 -1
  54. package/dist/mcp/index.d.ts +1 -1
  55. package/dist/mcp/index.js +62 -6
  56. package/dist/mcp/index.js.map +1 -1
  57. package/dist/transport/index.d.ts +18 -0
  58. package/dist/transport/index.d.ts.map +1 -0
  59. package/dist/transport/index.js +51 -0
  60. package/dist/transport/index.js.map +1 -0
  61. package/dist/transport/iterm.d.ts +21 -0
  62. package/dist/transport/iterm.d.ts.map +1 -0
  63. package/dist/transport/iterm.js +55 -0
  64. package/dist/transport/iterm.js.map +1 -0
  65. package/dist/transport/session-transport.d.ts +64 -0
  66. package/dist/transport/session-transport.d.ts.map +1 -0
  67. package/dist/transport/session-transport.js +17 -0
  68. package/dist/transport/session-transport.js.map +1 -0
  69. package/dist/transport/sync-facade.d.ts +52 -0
  70. package/dist/transport/sync-facade.d.ts.map +1 -0
  71. package/dist/transport/sync-facade.js +135 -0
  72. package/dist/transport/sync-facade.js.map +1 -0
  73. package/dist/transport/tmux.d.ts +53 -0
  74. package/dist/transport/tmux.d.ts.map +1 -0
  75. package/dist/transport/tmux.js +254 -0
  76. package/dist/transport/tmux.js.map +1 -0
  77. package/dist/types/ipc.d.ts +8 -0
  78. package/dist/types/ipc.d.ts.map +1 -1
  79. 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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"}
@@ -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
  }
@@ -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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aibroker",
3
- "version": "0.7.11",
3
+ "version": "0.7.13",
4
4
  "description": "Platform-agnostic AI message broker — routes between user channels and AI backends",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",