@monotykamary/localterm-server 2.66.8 → 2.66.10

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 (125) hide show
  1. package/dist/agent-git-status.d.ts +3 -0
  2. package/dist/agent-git-status.d.ts.map +1 -0
  3. package/dist/agent-git-status.js +46 -0
  4. package/dist/agent-git-status.js.map +1 -0
  5. package/dist/agent-log-utils.d.ts +18 -0
  6. package/dist/agent-log-utils.d.ts.map +1 -0
  7. package/dist/agent-log-utils.js +123 -0
  8. package/dist/agent-log-utils.js.map +1 -0
  9. package/dist/agent-models.d.ts +4 -0
  10. package/dist/agent-models.d.ts.map +1 -0
  11. package/dist/agent-models.js +100 -0
  12. package/dist/agent-models.js.map +1 -0
  13. package/dist/agent-runner.d.ts +3 -5
  14. package/dist/agent-runner.d.ts.map +1 -1
  15. package/dist/agent-runner.js +8 -522
  16. package/dist/agent-runner.js.map +1 -1
  17. package/dist/agent-session-reader.d.ts +3 -0
  18. package/dist/agent-session-reader.d.ts.map +1 -0
  19. package/dist/agent-session-reader.js +113 -0
  20. package/dist/agent-session-reader.js.map +1 -0
  21. package/dist/build-pty-environment.d.ts +8 -0
  22. package/dist/build-pty-environment.d.ts.map +1 -0
  23. package/dist/build-pty-environment.js +44 -0
  24. package/dist/build-pty-environment.js.map +1 -0
  25. package/dist/caffeinate-automatic-detector.d.ts +57 -0
  26. package/dist/caffeinate-automatic-detector.d.ts.map +1 -0
  27. package/dist/caffeinate-automatic-detector.js +275 -0
  28. package/dist/caffeinate-automatic-detector.js.map +1 -0
  29. package/dist/caffeinate-battery-guard.d.ts +35 -0
  30. package/dist/caffeinate-battery-guard.d.ts.map +1 -0
  31. package/dist/caffeinate-battery-guard.js +190 -0
  32. package/dist/caffeinate-battery-guard.js.map +1 -0
  33. package/dist/caffeinate-manager.d.ts +5 -31
  34. package/dist/caffeinate-manager.d.ts.map +1 -1
  35. package/dist/caffeinate-manager.js +55 -400
  36. package/dist/caffeinate-manager.js.map +1 -1
  37. package/dist/cdp/cdp-client.d.ts +4 -70
  38. package/dist/cdp/cdp-client.d.ts.map +1 -1
  39. package/dist/cdp/cdp-client.js +58 -418
  40. package/dist/cdp/cdp-client.js.map +1 -1
  41. package/dist/cdp/cdp-connection.d.ts +72 -0
  42. package/dist/cdp/cdp-connection.d.ts.map +1 -0
  43. package/dist/cdp/cdp-connection.js +272 -0
  44. package/dist/cdp/cdp-connection.js.map +1 -0
  45. package/dist/cdp/constants.d.ts +6 -0
  46. package/dist/cdp/constants.d.ts.map +1 -0
  47. package/dist/cdp/constants.js +9 -0
  48. package/dist/cdp/constants.js.map +1 -0
  49. package/dist/cdp/target-registry.d.ts +41 -0
  50. package/dist/cdp/target-registry.d.ts.map +1 -0
  51. package/dist/cdp/target-registry.js +118 -0
  52. package/dist/cdp/target-registry.js.map +1 -0
  53. package/dist/constants.d.ts +2 -0
  54. package/dist/constants.d.ts.map +1 -1
  55. package/dist/constants.js +2 -0
  56. package/dist/constants.js.map +1 -1
  57. package/dist/git-branch-metadata.d.ts +11 -0
  58. package/dist/git-branch-metadata.d.ts.map +1 -0
  59. package/dist/git-branch-metadata.js +85 -0
  60. package/dist/git-branch-metadata.js.map +1 -0
  61. package/dist/git-diff-cache.d.ts +13 -0
  62. package/dist/git-diff-cache.d.ts.map +1 -0
  63. package/dist/git-diff-cache.js +32 -0
  64. package/dist/git-diff-cache.js.map +1 -0
  65. package/dist/git-diff-parser.d.ts +15 -0
  66. package/dist/git-diff-parser.d.ts.map +1 -0
  67. package/dist/git-diff-parser.js +196 -0
  68. package/dist/git-diff-parser.js.map +1 -0
  69. package/dist/git-diff-service.d.ts +10 -0
  70. package/dist/git-diff-service.d.ts.map +1 -0
  71. package/dist/git-diff-service.js +395 -0
  72. package/dist/git-diff-service.js.map +1 -0
  73. package/dist/git-diff.d.ts +8 -41
  74. package/dist/git-diff.d.ts.map +1 -1
  75. package/dist/git-diff.js +5 -944
  76. package/dist/git-diff.js.map +1 -1
  77. package/dist/github-pr.d.ts +32 -0
  78. package/dist/github-pr.d.ts.map +1 -0
  79. package/dist/github-pr.js +266 -0
  80. package/dist/github-pr.js.map +1 -0
  81. package/dist/pi-binary-resolver.d.ts +6 -0
  82. package/dist/pi-binary-resolver.d.ts.map +1 -0
  83. package/dist/pi-binary-resolver.js +70 -0
  84. package/dist/pi-binary-resolver.js.map +1 -0
  85. package/dist/pi-rpc-client.d.ts +14 -0
  86. package/dist/pi-rpc-client.d.ts.map +1 -0
  87. package/dist/pi-rpc-client.js +87 -0
  88. package/dist/pi-rpc-client.js.map +1 -0
  89. package/dist/session-client-hub.d.ts +57 -0
  90. package/dist/session-client-hub.d.ts.map +1 -0
  91. package/dist/session-client-hub.js +435 -0
  92. package/dist/session-client-hub.js.map +1 -0
  93. package/dist/session-command-executor.d.ts +14 -0
  94. package/dist/session-command-executor.d.ts.map +1 -0
  95. package/dist/session-command-executor.js +207 -0
  96. package/dist/session-command-executor.js.map +1 -0
  97. package/dist/session-git-event-bridge.d.ts +16 -0
  98. package/dist/session-git-event-bridge.d.ts.map +1 -0
  99. package/dist/session-git-event-bridge.js +56 -0
  100. package/dist/session-git-event-bridge.js.map +1 -0
  101. package/dist/session-lifecycle-policy.d.ts +15 -0
  102. package/dist/session-lifecycle-policy.d.ts.map +1 -0
  103. package/dist/session-lifecycle-policy.js +105 -0
  104. package/dist/session-lifecycle-policy.js.map +1 -0
  105. package/dist/session-manager.d.ts +11 -42
  106. package/dist/session-manager.d.ts.map +1 -1
  107. package/dist/session-manager.js +72 -987
  108. package/dist/session-manager.js.map +1 -1
  109. package/dist/session-output-coordinator.d.ts +21 -0
  110. package/dist/session-output-coordinator.d.ts.map +1 -0
  111. package/dist/session-output-coordinator.js +134 -0
  112. package/dist/session-output-coordinator.js.map +1 -0
  113. package/dist/session-output-transport.d.ts +22 -0
  114. package/dist/session-output-transport.d.ts.map +1 -0
  115. package/dist/session-output-transport.js +160 -0
  116. package/dist/session-output-transport.js.map +1 -0
  117. package/dist/session.d.ts +0 -4
  118. package/dist/session.d.ts.map +1 -1
  119. package/dist/session.js +11 -258
  120. package/dist/session.js.map +1 -1
  121. package/dist/shell-hook-builder.d.ts +16 -0
  122. package/dist/shell-hook-builder.d.ts.map +1 -0
  123. package/dist/shell-hook-builder.js +230 -0
  124. package/dist/shell-hook-builder.js.map +1 -0
  125. package/package.json +1 -1
@@ -0,0 +1,57 @@
1
+ import { GitMetadataCoordinator } from "./git-metadata-coordinator.js";
2
+ import type { ManagedSession } from "./session-manager.js";
3
+ import { SessionOutputTransport } from "./session-output-transport.js";
4
+ import type { CompressMode } from "./schemas.js";
5
+ import type { GitBranchPr, ServerToClientMessage, SessionClientProfile } from "./types.js";
6
+ import type { SessionOwner } from "./identity/types.js";
7
+ import type { ClientSocket } from "./utils/ws-socket.js";
8
+ import type { WorkspaceEntry } from "./workspace-store.js";
9
+ interface SessionClientHubOptions {
10
+ outputTransport: SessionOutputTransport;
11
+ sendControl: (ws: ClientSocket, payload: ServerToClientMessage) => void;
12
+ pendingPromoteTimeoutMs: number;
13
+ sessionFor: (id: string, owner: SessionOwner) => ManagedSession | null;
14
+ cancelGrace: (managed: ManagedSession) => void;
15
+ startGrace: (managed: ManagedSession) => void;
16
+ onSessionActivity: () => void;
17
+ }
18
+ export declare class SessionClientHub {
19
+ private readonly wsToClient;
20
+ private readonly coordinatorsByCwd;
21
+ private readonly outputTransport;
22
+ private readonly sendControl;
23
+ private readonly pendingPromoteTimeoutMs;
24
+ private readonly sessionFor;
25
+ private readonly cancelGrace;
26
+ private readonly startGrace;
27
+ private readonly onSessionActivity;
28
+ constructor(options: SessionClientHubOptions);
29
+ clientProfilesFor(managed: ManagedSession): SessionClientProfile[];
30
+ workspaceEntries(sessions: Iterable<ManagedSession>): WorkspaceEntry[];
31
+ clientProfile(ws: ClientSocket): {
32
+ owner: SessionOwner;
33
+ windowId: string;
34
+ } | null;
35
+ attachedClientCount(sessions: Iterable<ManagedSession>, owner: SessionOwner, windowId: string): number;
36
+ attach(ws: ClientSocket, id: string, owner?: SessionOwner, windowId?: string): ManagedSession | null;
37
+ promote(ws: ClientSocket, replay: boolean, compress?: CompressMode): Promise<void>;
38
+ writeInput(ws: ClientSocket, data: string): void;
39
+ writeTerminalResponse(ws: ClientSocket, data: string): void;
40
+ private ensureTerminalResponder;
41
+ private assignTerminalResponder;
42
+ resize(ws: ClientSocket, cols: number, rows: number, pixelWidth?: number, pixelHeight?: number): void;
43
+ detach(ws: ClientSocket): void;
44
+ broadcastToOwner(managed: ManagedSession, payload: ServerToClientMessage): void;
45
+ private recomputeResize;
46
+ moveClientCoordinators(managed: ManagedSession, cwd: string): void;
47
+ private moveClientCoordinator;
48
+ tearDown(managed: ManagedSession): void;
49
+ private releaseClient;
50
+ dispose(): void;
51
+ coordinatorForCwd(cwd: string): GitMetadataCoordinator;
52
+ private releaseCoordinator;
53
+ broadcastGitBranchPr(cwd: string, pr: GitBranchPr | null): void;
54
+ hasCoordinatorFor(cwd: string): boolean;
55
+ }
56
+ export {};
57
+ //# sourceMappingURL=session-client-hub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-client-hub.d.ts","sourceRoot":"","sources":["../src/session-client-hub.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,435 @@
1
+ import path from "node:path";
2
+ import { WS_OUTPUT_BROTLI_QUALITY } from "./constants.js";
3
+ import { GitMetadataCoordinator } from "./git-metadata-coordinator.js";
4
+ import { makeBrotliEncoder, SessionOutputTransport } from "./session-output-transport.js";
5
+ export class SessionClientHub {
6
+ wsToClient = new Map();
7
+ coordinatorsByCwd = new Map();
8
+ outputTransport;
9
+ sendControl;
10
+ pendingPromoteTimeoutMs;
11
+ sessionFor;
12
+ cancelGrace;
13
+ startGrace;
14
+ onSessionActivity;
15
+ constructor(options) {
16
+ this.outputTransport = options.outputTransport;
17
+ this.sendControl = options.sendControl;
18
+ this.pendingPromoteTimeoutMs = options.pendingPromoteTimeoutMs;
19
+ this.sessionFor = options.sessionFor;
20
+ this.cancelGrace = options.cancelGrace;
21
+ this.startGrace = options.startGrace;
22
+ this.onSessionActivity = options.onSessionActivity;
23
+ }
24
+ // The attached clients grouped by their per-browser-profile handle, for the
25
+ // session picker's per-profile peer display. Each entry counts how many of
26
+ // that profile's windows are viewing this PTY; sorted by count desc then id
27
+ // for a stable order (the picker re-ranks its own profile to the front).
28
+ clientProfilesFor(managed) {
29
+ const counts = new Map();
30
+ for (const client of managed.clients) {
31
+ counts.set(client.windowId, (counts.get(client.windowId) ?? 0) + 1);
32
+ }
33
+ return [...counts.entries()]
34
+ .map(([windowId, count]) => ({ windowId, count }))
35
+ .sort((firstProfile, secondProfile) => secondProfile.count - firstProfile.count ||
36
+ firstProfile.windowId.localeCompare(secondProfile.windowId));
37
+ }
38
+ // The persisted workspace manifest: every currently-open tab, grouped by
39
+ // (owner, windowId), recording the live cwd + shell to respawn it in. A
40
+ // session with N attached clients of one windowId contributes N tabs (each
41
+ // viewer is a tab). Automation-run sessions are skipped (their tabs are
42
+ // one-shot), and sessions with no clients (dormant/orphaned) contribute
43
+ // nothing — only tabs that are actively open are restored. Computed from
44
+ // in-memory state, so the daemon snapshots it to disk before a graceful
45
+ // stop (and debounced during life for crash recovery).
46
+ workspaceEntries(sessions) {
47
+ const byKey = new Map();
48
+ const now = Date.now();
49
+ for (const managed of sessions) {
50
+ if (managed.automation)
51
+ continue;
52
+ if (managed.clients.size === 0)
53
+ continue;
54
+ const cwd = managed.session.lastEmittedCwd || managed.session.cwd;
55
+ const shell = managed.session.shell;
56
+ const tab = { cwd, shell };
57
+ for (const client of managed.clients) {
58
+ if (!client.windowId)
59
+ continue;
60
+ const key = `${managed.owner ?? ""}\u0000${client.windowId}`;
61
+ let entry = byKey.get(key);
62
+ if (!entry) {
63
+ entry = { owner: managed.owner, windowId: client.windowId, tabs: [], savedAt: now };
64
+ byKey.set(key, entry);
65
+ }
66
+ entry.tabs.push(tab);
67
+ }
68
+ }
69
+ return [...byKey.values()];
70
+ }
71
+ // The (owner, windowId) a socket's tab is viewing, for scoping a CDP
72
+ // workspace restore to the browser profile that just reconnected. Returns
73
+ // null when the socket isn't attached to a session (e.g. a transient
74
+ // mid-detach state).
75
+ clientProfile(ws) {
76
+ const entry = this.wsToClient.get(ws);
77
+ if (!entry)
78
+ return null;
79
+ return { owner: entry.session.owner, windowId: entry.client.windowId };
80
+ }
81
+ // How many of a browser profile's tabs are currently attached to a (non-
82
+ // automation) session — the "already open" count the restore reconciles
83
+ // the persisted manifest against. Surviving tabs that reattach after a
84
+ // daemon restart are counted here so the daemon only opens the deficit.
85
+ attachedClientCount(sessions, owner, windowId) {
86
+ let count = 0;
87
+ for (const managed of sessions) {
88
+ if (owner !== null && managed.owner !== owner)
89
+ continue;
90
+ if (managed.automation)
91
+ continue;
92
+ for (const client of managed.clients)
93
+ if (client.windowId === windowId)
94
+ count++;
95
+ }
96
+ return count;
97
+ }
98
+ // Attach `ws` to a live PTY by id. Returns the session to reattach to, or
99
+ // null when the id is unknown / already exited — the caller spawns fresh.
100
+ attach(ws, id, owner = null, windowId = "") {
101
+ const managed = this.sessionFor(id, owner);
102
+ if (!managed)
103
+ return null;
104
+ // Re-subscribing cancels the no-clients grace timer (if armed): the shell
105
+ // has a viewer again, so it stays alive.
106
+ this.cancelGrace(managed);
107
+ // Notify existing subscribers a peer joined (a mobile ingested this
108
+ // session's share QR) so a host can react — e.g. the desktop's QR modal
109
+ // auto-closes. Gated on existing clients so a fresh spawn's first attach
110
+ // stays silent, and fired before adding the joiner so it isn't told about
111
+ // itself. See peerAttachedMessageSchema for the frame's payload rationale.
112
+ if (managed.clients.size > 0)
113
+ this.outputTransport.broadcast(managed, { type: "peer-attached" });
114
+ const coordinator = this.coordinatorForCwd(managed.session.cwd);
115
+ const client = {
116
+ ws,
117
+ pending: true,
118
+ pendingControl: [],
119
+ pendingBytes: [],
120
+ pendingTimer: null,
121
+ cols: 0,
122
+ rows: 0,
123
+ windowId,
124
+ coordinator,
125
+ compressMode: null,
126
+ brotliEncoder: null,
127
+ terminalResponder: false,
128
+ };
129
+ coordinator.add(ws);
130
+ managed.clients.add(client);
131
+ this.wsToClient.set(ws, { client, session: managed });
132
+ this.recomputeResize(managed);
133
+ // Seed a joiner with the current effective size when it's entering an
134
+ // already-multi-viewer session whose min its own (possibly wider) report
135
+ // doesn't change — recomputeResize only broadcasts on a change, so without
136
+ // this the new viewer would never learn it's constrained and would render
137
+ // no mask. A fresh spawn (now the lone viewer) has no stored size and is
138
+ // skipped, and a joiner that changes the min is reached by the broadcast.
139
+ if (managed.clients.size > 1 && managed.ptySizeCols !== null && managed.ptySizeRows !== null) {
140
+ this.outputTransport.sendToClient(client, {
141
+ type: "pty-size",
142
+ cols: managed.ptySizeCols,
143
+ rows: managed.ptySizeRows,
144
+ });
145
+ }
146
+ // Auto-promote a client that never sends {type:"ready"} — a back-compat
147
+ // client (an older bundled terminal, or any plain WS reader) would otherwise
148
+ // stay pending and never receive output. The localterm client sends ready
149
+ // within milliseconds of the session frame; the window is sized to clear a
150
+ // mobile/tailscale RTT (often DERP-relayed) so its {ready} lands first and
151
+ // its scrollback replay still lands before live fan-out. `promote` always
152
+ // sends `replay-end`, so even a slow link that auto-promotes with
153
+ // `replay: false` can't deadlock the client in its replay window.
154
+ client.pendingTimer = setTimeout(() => void this.promote(ws, false), this.pendingPromoteTimeoutMs);
155
+ client.pendingTimer.unref?.();
156
+ this.onSessionActivity();
157
+ return managed;
158
+ }
159
+ // Promote a pending client to live fan-out. Idempotent (a no-op once the
160
+ // client is already live), so the pending timeout and an explicit {ready}
161
+ // can race safely. When `replay` is true the session's scrollback ring
162
+ // buffer is sent as one binary frame first, then the control messages and
163
+ // output bytes buffered while pending flush in order — so a tab switching
164
+ // to this PTY lands on recent output instead of a blank screen, with no
165
+ // live frame interleaving between replay and the buffered fan-out.
166
+ //
167
+ // `replay-end` is sent on EVERY promote (not just `replay: true`): the
168
+ // localterm client opens its suppressed-replay window on the {session}
169
+ // frame — before its {ready} reaches us — so a slow link whose pending
170
+ // timeout auto-promotes with `replay: false` would otherwise never send the
171
+ // marker the client is waiting on, deadlocking it on a blank screen with
172
+ // every output frame buffered client-side. The auto-promote's `replay-end`
173
+ // lets the client flush whatever it buffered (the pending bytes that raced
174
+ // ahead of the marker) and rejoin live fan-out. A client that didn't open the
175
+ // window (a silent reattach, or a back-compat reader) treats it as a no-op.
176
+ async promote(ws, replay, compress = null) {
177
+ const entry = this.wsToClient.get(ws);
178
+ if (!entry)
179
+ return;
180
+ const client = entry.client;
181
+ if (!client.pending)
182
+ return;
183
+ if (client.pendingTimer !== null) {
184
+ clearTimeout(client.pendingTimer);
185
+ client.pendingTimer = null;
186
+ }
187
+ client.compressMode = compress;
188
+ this.ensureTerminalResponder(entry.session, client);
189
+ // Reset the persistent Brotli encoder: a new promote is a fresh attach (a
190
+ // PTY switch or reconnect), so the prior screen's LZ77 context is stale.
191
+ // The first frame of the new stream has no prior context (the per-frame
192
+ // equivalent); subsequent frames compress against it.
193
+ if (client.brotliEncoder !== null) {
194
+ client.brotliEncoder.release();
195
+ client.brotliEncoder = null;
196
+ }
197
+ if (compress === "br-ctx")
198
+ client.brotliEncoder = makeBrotliEncoder(WS_OUTPUT_BROTLI_QUALITY);
199
+ // Tell the client the chosen compress mode BEFORE the scrollback replay so
200
+ // it knows how to parse the compressed replay frames. A back-compat server
201
+ // that doesn't know "br-ctx" never sends this frame, so an old-server +
202
+ // new-client pair degrades to raw (no header) instead of mis-parsing.
203
+ this.sendControl(ws, { type: "compress", mode: compress });
204
+ if (replay) {
205
+ await this.outputTransport.sendScrollback(ws, entry.session, client);
206
+ }
207
+ // Tell the client the replay bytes have all landed so it can write them as
208
+ // one suppressed block (dropping xterm's responses to the stale query
209
+ // requests in the ring buffer). Sent on every promote — even when the
210
+ // snapshot was empty or replay wasn't requested — so the client always
211
+ // exits its suppressed-replay window and never deadlocks on a slow link.
212
+ this.sendControl(ws, { type: "replay-end" });
213
+ for (const payload of client.pendingControl)
214
+ this.sendControl(ws, payload);
215
+ for (const bytes of client.pendingBytes) {
216
+ await this.outputTransport.sendOutputFrame(ws, bytes, client);
217
+ }
218
+ client.pendingControl = [];
219
+ client.pendingBytes = [];
220
+ client.pending = false;
221
+ // Re-push the ambient git-diff summary to the now-live client so a summary
222
+ // pushed while pending (and wiped by the client's cwd-driven null-reset on
223
+ // a cwd change during the pending window) is restored. See
224
+ // GitMetadataCoordinator.replayLastSummary.
225
+ client.coordinator?.replayLastSummary(ws);
226
+ }
227
+ writeInput(ws, data) {
228
+ const entry = this.wsToClient.get(ws);
229
+ if (!entry)
230
+ return;
231
+ // A client sending input is clearly live and wants output. Promote it out
232
+ // of the pending hold without a scrollback replay — a back-compat client
233
+ // that never sends {type:"ready"} still unblocks on its first keystroke.
234
+ // The localterm client sends {type:"ready"} before any input, so this is a
235
+ // no-op for it. Promote flushes any buffered output before the input echoes.
236
+ if (entry.client.pending)
237
+ void this.promote(ws, false);
238
+ // Query replies follow the viewer that most recently drove the PTY.
239
+ this.assignTerminalResponder(entry.session, entry.client);
240
+ entry.session.session.write(data);
241
+ }
242
+ writeTerminalResponse(ws, data) {
243
+ const entry = this.wsToClient.get(ws);
244
+ if (!entry?.client.terminalResponder)
245
+ return;
246
+ this.writeInput(ws, data);
247
+ }
248
+ ensureTerminalResponder(managed, preferredClient) {
249
+ for (const client of managed.clients) {
250
+ if (client.terminalResponder)
251
+ return;
252
+ }
253
+ const nextClient = preferredClient ??
254
+ Array.from(managed.clients).find((client) => !client.pending) ??
255
+ managed.clients.values().next().value;
256
+ if (nextClient)
257
+ this.assignTerminalResponder(managed, nextClient);
258
+ }
259
+ assignTerminalResponder(managed, responder) {
260
+ for (const client of managed.clients)
261
+ client.terminalResponder = client === responder;
262
+ }
263
+ resize(ws, cols, rows, pixelWidth, pixelHeight) {
264
+ const entry = this.wsToClient.get(ws);
265
+ if (!entry)
266
+ return;
267
+ entry.client.cols = cols;
268
+ entry.client.rows = rows;
269
+ entry.client.pixelWidth = pixelWidth;
270
+ entry.client.pixelHeight = pixelHeight;
271
+ this.recomputeResize(entry.session);
272
+ }
273
+ // Detach a single client. If this was the last subscriber, arm the
274
+ // no-clients grace timer: the PTY stays alive for SESSION_GRACE_MS so a
275
+ // transient drop or a switch can re-attach, then is reaped if nobody does.
276
+ detach(ws) {
277
+ const entry = this.wsToClient.get(ws);
278
+ if (!entry)
279
+ return;
280
+ this.wsToClient.delete(ws);
281
+ const managed = entry.session;
282
+ const client = entry.client;
283
+ this.releaseClient(client);
284
+ managed.clients.delete(client);
285
+ if (client.terminalResponder)
286
+ this.ensureTerminalResponder(managed);
287
+ this.recomputeResize(managed);
288
+ if (managed.clients.size === 0 && !managed.session.isExited)
289
+ this.startGrace(managed);
290
+ this.onSessionActivity();
291
+ }
292
+ // Fan a control message out to every client currently viewing any session
293
+ // owned by the same identity as `managed`, not just `managed`'s own viewers.
294
+ // Used for notifications so a user who stepped away to another session still
295
+ // gets the ping; owner-scoped so a notification never crosses an identity
296
+ // boundary (a non-operator client can only be attached to an owner-matching
297
+ // session, so matching session.owner === managed.owner is the partition).
298
+ broadcastToOwner(managed, payload) {
299
+ for (const { client, session } of this.wsToClient.values()) {
300
+ if (session.owner === managed.owner)
301
+ this.outputTransport.sendToClient(client, payload);
302
+ }
303
+ }
304
+ recomputeResize(managed) {
305
+ const session = managed.session;
306
+ if (session.isExited)
307
+ return;
308
+ let cols = Infinity;
309
+ let rows = Infinity;
310
+ let single = null;
311
+ let count = 0;
312
+ for (const client of managed.clients) {
313
+ count++;
314
+ single = client;
315
+ if (client.cols > 0 && client.cols < cols)
316
+ cols = client.cols;
317
+ if (client.rows > 0 && client.rows < rows)
318
+ rows = client.rows;
319
+ }
320
+ if (count === 0)
321
+ return;
322
+ if (!Number.isFinite(cols) || !Number.isFinite(rows))
323
+ return;
324
+ if (count === 1 && single?.pixelWidth !== undefined && single?.pixelHeight !== undefined) {
325
+ session.resize(cols, rows, single.pixelWidth, single.pixelHeight);
326
+ }
327
+ else {
328
+ session.resize(cols, rows);
329
+ }
330
+ // Keep the capture renderer's grid at the PTY's effective size so a
331
+ // capture-pane reflects the same line wrapping a viewer would see.
332
+ managed.captureRenderer?.resize(cols, rows);
333
+ // The PTY's effective size is the min across attached clients (tmux-style):
334
+ // a narrower peer constrains everyone. Broadcast it on change so each
335
+ // viewer can mask the dead area beyond its own (possibly wider) grid as
336
+ // inactive chrome. A lone viewer is never constrained (its effective size
337
+ // always equals its own), so it's left quiet except for one clear frame when
338
+ // a peer detaches and drops it back to solo — that erases the mask the
339
+ // leaving peer had imposed. A joiner entering an already-constrained
340
+ // session without changing the min is seeded in attach.
341
+ const sizeChanged = managed.ptySizeCols !== cols || managed.ptySizeRows !== rows;
342
+ managed.ptySizeCols = cols;
343
+ managed.ptySizeRows = rows;
344
+ if (count > 1) {
345
+ managed.ptySizeWasMultiViewer = true;
346
+ if (sizeChanged) {
347
+ this.outputTransport.broadcast(managed, { type: "pty-size", cols, rows });
348
+ }
349
+ }
350
+ else if (managed.ptySizeWasMultiViewer) {
351
+ managed.ptySizeWasMultiViewer = false;
352
+ this.outputTransport.broadcast(managed, { type: "pty-size", cols, rows });
353
+ }
354
+ }
355
+ moveClientCoordinators(managed, cwd) {
356
+ for (const client of managed.clients)
357
+ this.moveClientCoordinator(client, cwd);
358
+ }
359
+ moveClientCoordinator(client, cwd) {
360
+ const next = this.coordinatorForCwd(cwd);
361
+ if (client.coordinator === next)
362
+ return;
363
+ if (client.coordinator) {
364
+ client.coordinator.remove(client.ws);
365
+ this.releaseCoordinator(client.coordinator);
366
+ }
367
+ client.coordinator = next;
368
+ next.add(client.ws);
369
+ }
370
+ tearDown(managed) {
371
+ for (const client of managed.clients) {
372
+ if (client.pendingTimer !== null) {
373
+ clearTimeout(client.pendingTimer);
374
+ client.pendingTimer = null;
375
+ }
376
+ client.pendingControl = [];
377
+ client.pendingBytes = [];
378
+ if (client.coordinator) {
379
+ client.coordinator.remove(client.ws);
380
+ this.releaseCoordinator(client.coordinator);
381
+ }
382
+ this.wsToClient.delete(client.ws);
383
+ }
384
+ managed.clients.clear();
385
+ }
386
+ releaseClient(client) {
387
+ if (client.pendingTimer !== null) {
388
+ clearTimeout(client.pendingTimer);
389
+ client.pendingTimer = null;
390
+ }
391
+ if (client.brotliEncoder !== null) {
392
+ client.brotliEncoder.release();
393
+ client.brotliEncoder = null;
394
+ }
395
+ client.pendingControl = [];
396
+ client.pendingBytes = [];
397
+ if (client.coordinator) {
398
+ client.coordinator.remove(client.ws);
399
+ this.releaseCoordinator(client.coordinator);
400
+ }
401
+ }
402
+ dispose() {
403
+ this.coordinatorsByCwd.clear();
404
+ }
405
+ coordinatorForCwd(cwd) {
406
+ const key = path.resolve(cwd);
407
+ let coordinator = this.coordinatorsByCwd.get(key);
408
+ if (!coordinator) {
409
+ coordinator = new GitMetadataCoordinator(key, this.sendControl);
410
+ this.coordinatorsByCwd.set(key, coordinator);
411
+ }
412
+ return coordinator;
413
+ }
414
+ releaseCoordinator(coordinator) {
415
+ if (coordinator.isEmpty)
416
+ this.coordinatorsByCwd.delete(coordinator.cwd);
417
+ }
418
+ // Push a freshly-detected PR to every tab in `cwd` after the
419
+ // /api/git/branches/pr endpoint recomputes it, so a remote state change one
420
+ // tab observed (a merge on GitHub) reaches siblings sharing the directory.
421
+ // Non-creating: a cwd with no subscribers has no coordinator, and allocating
422
+ // one here would orphan it (it never enters the attach/detach release path).
423
+ broadcastGitBranchPr(cwd, pr) {
424
+ this.coordinatorsByCwd.get(path.resolve(cwd))?.broadcastPr(pr);
425
+ }
426
+ // Whether any tab is currently subscribed to the per-cwd coordinator — i.e.
427
+ // there is a live audience for a PR lease refresh. Used to gate the
428
+ // gh-activity refresh so a `gh` invocation in a cwd nobody is viewing never
429
+ // triggers a pointless GitHub API call (mirrors broadcastGitBranchPr's
430
+ // non-creating philosophy).
431
+ hasCoordinatorFor(cwd) {
432
+ return this.coordinatorsByCwd.has(path.resolve(cwd));
433
+ }
434
+ }
435
+ //# sourceMappingURL=session-client-hub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-client-hub.js","sourceRoot":"","sources":["../src/session-client-hub.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ExecOptions, ExecResult, ManagedSession, WaitPredicate, WaitResult } from "./session-manager.js";
2
+ export declare class SessionCommandExecutor {
3
+ capturePane(managed: ManagedSession, lines?: number): Promise<string>;
4
+ waitFor(managed: ManagedSession, predicate: WaitPredicate, timeoutMs: number, idleMs?: number): Promise<WaitResult>;
5
+ findTextInViewport(managed: ManagedSession, needle: string): Promise<{
6
+ col: number;
7
+ row: number;
8
+ } | null>;
9
+ private ensureCaptureRenderer;
10
+ execute(managed: ManagedSession, command: string, options?: ExecOptions): Promise<ExecResult>;
11
+ private buildExecResult;
12
+ private clampInt;
13
+ }
14
+ //# sourceMappingURL=session-command-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-command-executor.d.ts","sourceRoot":"","sources":["../src/session-command-executor.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,aAAa,EACb,UAAU,EACX,MAAM,sBAAsB,CAAC;AAE9B,qBAAa,sBAAsB;IAC3B,WAAW,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E;IAEK,OAAO,CACX,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,CAAC,CAwDrB;IAEK,kBAAkB,CACtB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAI9C;YAOa,qBAAqB;IAU7B,OAAO,CACX,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAmGrB;YAEa,eAAe;IAyC7B,OAAO,CAAC,QAAQ;CAGjB"}