lit-shell.js 0.1.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.1.0] - 2025-01-09
9
+
10
+ ### Added
11
+
12
+ - **Tabbed Terminals**: New `show-tabs` attribute enables multiple terminal tabs in a single component
13
+ - Each tab has independent WebSocket connection and terminal session
14
+ - Tab bar with status indicators and add/close buttons
15
+ - Dynamic labels showing shell or container name
16
+ - `createTab()`, `switchTab()`, `closeTab()` methods
17
+ - **Join Existing Session**: Connection panel now shows "Join Existing Session" mode when sessions are available
18
+ - **Prompt Refresh on Join**: Joining a session now triggers a fresh prompt display
19
+
20
+ ### Fixed
21
+
22
+ - Fixed duplicate output when multiple tabs join the same session
23
+ - Fixed session list not updating after spawning a session
24
+ - Each client's data handler now correctly writes to its own tab's terminal
25
+
26
+ ## [1.0.0] - 2025-01-08
27
+
28
+ ### Added
29
+
30
+ - Initial release
31
+ - WebSocket-based terminal server with node-pty
32
+ - Lightweight client library with auto-reconnection
33
+ - `<lit-shell-terminal>` Lit web component with xterm.js
34
+ - Docker exec support for connecting to containers
35
+ - Docker attach mode for connecting to container's main process (PID 1)
36
+ - Session multiplexing - multiple clients sharing the same terminal
37
+ - Session persistence with configurable orphan timeout
38
+ - History replay for clients joining existing sessions
39
+ - Built-in connection panel with container/shell selector
40
+ - Settings dropdown (theme, font size)
41
+ - Status bar with connection info
42
+ - Dark/light/auto theme support
43
+ - Security features: shell, path, and container allowlists
44
+ - Python client bindings (`bindings/python/`)
45
+ - Example projects for Docker containers and multiplexing
@@ -5,6 +5,7 @@ var TerminalClient = class {
5
5
  this.state = "disconnected";
6
6
  this.sessionId = null;
7
7
  this.sessionInfo = null;
8
+ this.serverInfo = null;
8
9
  this.reconnectAttempts = 0;
9
10
  this.reconnectTimeout = null;
10
11
  // Event handlers
@@ -14,9 +15,21 @@ var TerminalClient = class {
14
15
  this.exitHandlers = [];
15
16
  this.errorHandlers = [];
16
17
  this.spawnedHandlers = [];
17
- // Promise resolvers for spawn
18
+ this.serverInfoHandlers = [];
19
+ this.containerListHandlers = [];
20
+ // Session multiplexing handlers
21
+ this.sessionListHandlers = [];
22
+ this.joinedHandlers = [];
23
+ this.leftHandlers = [];
24
+ this.clientJoinedHandlers = [];
25
+ this.clientLeftHandlers = [];
26
+ this.sessionClosedHandlers = [];
27
+ // Promise resolvers for spawn/join
18
28
  this.spawnResolve = null;
19
29
  this.spawnReject = null;
30
+ this.joinResolve = null;
31
+ this.joinReject = null;
32
+ this.listSessionsResolve = null;
20
33
  this.config = {
21
34
  url: config.url,
22
35
  reconnect: config.reconnect ?? true,
@@ -123,7 +136,8 @@ var TerminalClient = class {
123
136
  cwd: message.cwd,
124
137
  cols: message.cols,
125
138
  rows: message.rows,
126
- createdAt: /* @__PURE__ */ new Date()
139
+ createdAt: /* @__PURE__ */ new Date(),
140
+ container: message.container
127
141
  };
128
142
  this.spawnedHandlers.forEach((handler) => handler(this.sessionInfo));
129
143
  if (this.spawnResolve) {
@@ -149,6 +163,76 @@ var TerminalClient = class {
149
163
  this.spawnResolve = null;
150
164
  this.spawnReject = null;
151
165
  }
166
+ if (this.joinReject) {
167
+ this.joinReject(error);
168
+ this.joinResolve = null;
169
+ this.joinReject = null;
170
+ }
171
+ break;
172
+ case "serverInfo":
173
+ this.serverInfo = message.info;
174
+ this.serverInfoHandlers.forEach((handler) => handler(message.info));
175
+ break;
176
+ case "containerList":
177
+ this.containerListHandlers.forEach((handler) => handler(message.containers));
178
+ break;
179
+ case "sessionList":
180
+ this.sessionListHandlers.forEach(
181
+ (handler) => handler(message.sessions)
182
+ );
183
+ if (this.listSessionsResolve) {
184
+ this.listSessionsResolve(message.sessions);
185
+ this.listSessionsResolve = null;
186
+ }
187
+ break;
188
+ case "joined":
189
+ const joinedSession = message.session;
190
+ const history = message.history;
191
+ this.sessionId = message.sessionId;
192
+ this.sessionInfo = {
193
+ sessionId: joinedSession.sessionId,
194
+ shell: joinedSession.shell,
195
+ cwd: joinedSession.cwd,
196
+ cols: joinedSession.cols,
197
+ rows: joinedSession.rows,
198
+ createdAt: joinedSession.createdAt,
199
+ container: joinedSession.container
200
+ };
201
+ this.joinedHandlers.forEach((handler) => handler(joinedSession, history));
202
+ if (this.joinResolve) {
203
+ this.joinResolve(joinedSession);
204
+ this.joinResolve = null;
205
+ this.joinReject = null;
206
+ }
207
+ break;
208
+ case "left":
209
+ const leftSessionId = message.sessionId;
210
+ if (this.sessionId === leftSessionId) {
211
+ this.sessionId = null;
212
+ this.sessionInfo = null;
213
+ }
214
+ this.leftHandlers.forEach((handler) => handler(leftSessionId));
215
+ break;
216
+ case "clientJoined":
217
+ this.clientJoinedHandlers.forEach(
218
+ (handler) => handler(message.sessionId, message.clientCount)
219
+ );
220
+ break;
221
+ case "clientLeft":
222
+ this.clientLeftHandlers.forEach(
223
+ (handler) => handler(message.sessionId, message.clientCount)
224
+ );
225
+ break;
226
+ case "sessionClosed":
227
+ const closedSessionId = message.sessionId;
228
+ const reason = message.reason;
229
+ if (this.sessionId === closedSessionId) {
230
+ this.sessionId = null;
231
+ this.sessionInfo = null;
232
+ }
233
+ this.sessionClosedHandlers.forEach(
234
+ (handler) => handler(closedSessionId, reason)
235
+ );
152
236
  break;
153
237
  }
154
238
  }
@@ -162,7 +246,7 @@ var TerminalClient = class {
162
246
  return;
163
247
  }
164
248
  if (this.sessionId) {
165
- reject(new Error("Session already spawned. Call kill() first."));
249
+ reject(new Error("Session already active. Call kill() or leave() first."));
166
250
  return;
167
251
  }
168
252
  this.spawnResolve = resolve;
@@ -217,7 +301,7 @@ var TerminalClient = class {
217
301
  );
218
302
  }
219
303
  /**
220
- * Kill the terminal session
304
+ * Kill the terminal session (close and terminate)
221
305
  */
222
306
  kill() {
223
307
  if (!this.ws || this.state !== "connected") {
@@ -236,6 +320,91 @@ var TerminalClient = class {
236
320
  this.sessionInfo = null;
237
321
  }
238
322
  // ==========================================
323
+ // Session Multiplexing Methods
324
+ // ==========================================
325
+ /**
326
+ * List available sessions
327
+ */
328
+ listSessions(filter) {
329
+ return new Promise((resolve, reject) => {
330
+ if (this.state !== "connected" || !this.ws) {
331
+ reject(new Error("Not connected to server"));
332
+ return;
333
+ }
334
+ this.listSessionsResolve = resolve;
335
+ this.ws.send(
336
+ JSON.stringify({
337
+ type: "listSessions",
338
+ filter
339
+ })
340
+ );
341
+ });
342
+ }
343
+ /**
344
+ * Join an existing session
345
+ */
346
+ join(options) {
347
+ return new Promise((resolve, reject) => {
348
+ if (this.state !== "connected" || !this.ws) {
349
+ reject(new Error("Not connected to server"));
350
+ return;
351
+ }
352
+ if (this.sessionId) {
353
+ reject(new Error("Already in a session. Call leave() first."));
354
+ return;
355
+ }
356
+ this.joinResolve = resolve;
357
+ this.joinReject = reject;
358
+ this.ws.send(
359
+ JSON.stringify({
360
+ type: "join",
361
+ options
362
+ })
363
+ );
364
+ });
365
+ }
366
+ /**
367
+ * Leave the current session without killing it
368
+ */
369
+ leave(sessionId) {
370
+ if (!this.ws || this.state !== "connected") {
371
+ console.error("[lit-shell] Cannot leave: not connected");
372
+ return;
373
+ }
374
+ const targetSession = sessionId || this.sessionId;
375
+ if (!targetSession) {
376
+ console.error("[lit-shell] Cannot leave: no active session");
377
+ return;
378
+ }
379
+ this.ws.send(
380
+ JSON.stringify({
381
+ type: "leave",
382
+ sessionId: targetSession
383
+ })
384
+ );
385
+ if (targetSession === this.sessionId) {
386
+ this.sessionId = null;
387
+ this.sessionInfo = null;
388
+ }
389
+ }
390
+ /**
391
+ * Request session list and trigger onSessionList handlers
392
+ * (Fire-and-forget version of listSessions)
393
+ */
394
+ requestSessionList(filter) {
395
+ this.listSessions(filter).then((sessions) => {
396
+ this.sessionListHandlers.forEach((handler) => {
397
+ try {
398
+ handler(sessions);
399
+ } catch (e) {
400
+ console.error("[lit-shell] Error in sessionList handler:", e);
401
+ }
402
+ });
403
+ }).catch((err) => {
404
+ console.error("[lit-shell] Failed to list sessions:", err);
405
+ });
406
+ }
407
+ // ==========================================
239
408
  // Event handlers
240
409
  // ==========================================
241
410
  /**
@@ -274,6 +443,67 @@ var TerminalClient = class {
274
443
  onSpawned(handler) {
275
444
  this.spawnedHandlers.push(handler);
276
445
  }
446
+ /**
447
+ * Called when server info is received
448
+ */
449
+ onServerInfo(handler) {
450
+ this.serverInfoHandlers.push(handler);
451
+ if (this.serverInfo) {
452
+ handler(this.serverInfo);
453
+ }
454
+ }
455
+ /**
456
+ * Called when container list is received
457
+ */
458
+ onContainerList(handler) {
459
+ this.containerListHandlers.push(handler);
460
+ }
461
+ /**
462
+ * Called when session list is received
463
+ */
464
+ onSessionList(handler) {
465
+ this.sessionListHandlers.push(handler);
466
+ }
467
+ /**
468
+ * Called when successfully joined a session
469
+ */
470
+ onJoined(handler) {
471
+ this.joinedHandlers.push(handler);
472
+ }
473
+ /**
474
+ * Called when left a session
475
+ */
476
+ onLeft(handler) {
477
+ this.leftHandlers.push(handler);
478
+ }
479
+ /**
480
+ * Called when another client joins the current session
481
+ */
482
+ onClientJoined(handler) {
483
+ this.clientJoinedHandlers.push(handler);
484
+ }
485
+ /**
486
+ * Called when another client leaves the current session
487
+ */
488
+ onClientLeft(handler) {
489
+ this.clientLeftHandlers.push(handler);
490
+ }
491
+ /**
492
+ * Called when the session is closed by owner or orphan timeout
493
+ */
494
+ onSessionClosed(handler) {
495
+ this.sessionClosedHandlers.push(handler);
496
+ }
497
+ /**
498
+ * Request list of available containers
499
+ */
500
+ requestContainerList() {
501
+ if (!this.ws || this.state !== "connected") {
502
+ console.error("[lit-shell] Cannot request containers: not connected");
503
+ return;
504
+ }
505
+ this.ws.send(JSON.stringify({ type: "listContainers" }));
506
+ }
277
507
  // ==========================================
278
508
  // Getters
279
509
  // ==========================================
@@ -307,6 +537,12 @@ var TerminalClient = class {
307
537
  hasActiveSession() {
308
538
  return this.sessionId !== null;
309
539
  }
540
+ /**
541
+ * Get server info
542
+ */
543
+ getServerInfo() {
544
+ return this.serverInfo;
545
+ }
310
546
  };
311
547
  export {
312
548
  TerminalClient
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/client/terminal-client.ts"],
4
- "sourcesContent": ["/**\n * Terminal client for connecting to lit-shell server\n *\n * Example usage:\n * ```typescript\n * import { TerminalClient } from 'lit-shell.js/client';\n *\n * const client = new TerminalClient({ url: 'ws://localhost:3000/terminal' });\n * await client.connect();\n *\n * client.onData((data) => console.log(data));\n * client.onExit((code) => console.log('Exited with code:', code));\n *\n * await client.spawn({ shell: '/bin/bash', cwd: '/home/user' });\n * client.write('ls -la\\n');\n * client.resize(120, 40);\n * client.kill();\n * ```\n */\n\nimport type {\n ClientConfig,\n TerminalOptions,\n TerminalMessage,\n SessionInfo,\n} from '../shared/types.js';\n\n/**\n * Connection state\n */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected';\n\n/**\n * Terminal client class\n */\nexport class TerminalClient {\n private config: Required<ClientConfig>;\n private ws: WebSocket | null = null;\n private state: ConnectionState = 'disconnected';\n private sessionId: string | null = null;\n private sessionInfo: SessionInfo | null = null;\n private reconnectAttempts = 0;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n\n // Event handlers\n private connectHandlers: (() => void)[] = [];\n private disconnectHandlers: (() => void)[] = [];\n private dataHandlers: ((data: string) => void)[] = [];\n private exitHandlers: ((code: number) => void)[] = [];\n private errorHandlers: ((error: Error) => void)[] = [];\n private spawnedHandlers: ((info: SessionInfo) => void)[] = [];\n\n // Promise resolvers for spawn\n private spawnResolve: ((info: SessionInfo) => void) | null = null;\n private spawnReject: ((error: Error) => void) | null = null;\n\n constructor(config: ClientConfig) {\n this.config = {\n url: config.url,\n reconnect: config.reconnect ?? true,\n maxReconnectAttempts: config.maxReconnectAttempts ?? 10,\n reconnectDelay: config.reconnectDelay ?? 1000,\n };\n }\n\n /**\n * Connect to the terminal server\n */\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.state === 'connected') {\n resolve();\n return;\n }\n\n this.state = 'connecting';\n\n try {\n this.ws = new WebSocket(this.config.url);\n } catch (error) {\n this.state = 'disconnected';\n reject(error);\n return;\n }\n\n this.ws.onopen = () => {\n this.state = 'connected';\n this.reconnectAttempts = 0;\n this.connectHandlers.forEach((handler) => handler());\n resolve();\n };\n\n this.ws.onclose = () => {\n const wasConnected = this.state === 'connected';\n this.state = 'disconnected';\n this.sessionId = null;\n this.sessionInfo = null;\n\n if (wasConnected) {\n this.disconnectHandlers.forEach((handler) => handler());\n }\n\n // Attempt reconnection\n if (this.config.reconnect && this.reconnectAttempts < this.config.maxReconnectAttempts) {\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = (event) => {\n const error = new Error('WebSocket error');\n this.errorHandlers.forEach((handler) => handler(error));\n\n if (this.state === 'connecting') {\n reject(error);\n }\n };\n\n this.ws.onmessage = (event) => {\n this.handleMessage(event.data);\n };\n });\n }\n\n /**\n * Disconnect from the terminal server\n */\n disconnect(): void {\n this.config.reconnect = false; // Prevent auto-reconnect\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.state = 'disconnected';\n this.sessionId = null;\n this.sessionInfo = null;\n }\n\n /**\n * Schedule a reconnection attempt\n */\n private scheduleReconnect(): void {\n if (this.reconnectTimeout) return;\n\n const delay = this.config.reconnectDelay * Math.pow(2, this.reconnectAttempts);\n const maxDelay = 30000; // 30 seconds max\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null;\n this.reconnectAttempts++;\n this.connect().catch(() => {\n // Error handled by onclose\n });\n }, Math.min(delay, maxDelay));\n }\n\n /**\n * Handle incoming message\n */\n private handleMessage(data: string): void {\n let message: TerminalMessage;\n\n try {\n message = JSON.parse(data);\n } catch {\n console.error('[lit-shell] Invalid message:', data);\n return;\n }\n\n switch (message.type) {\n case 'spawned':\n this.sessionId = message.sessionId;\n this.sessionInfo = {\n sessionId: message.sessionId,\n shell: message.shell,\n cwd: message.cwd,\n cols: message.cols,\n rows: message.rows,\n createdAt: new Date(),\n };\n this.spawnedHandlers.forEach((handler) => handler(this.sessionInfo!));\n if (this.spawnResolve) {\n this.spawnResolve(this.sessionInfo);\n this.spawnResolve = null;\n this.spawnReject = null;\n }\n break;\n\n case 'data':\n this.dataHandlers.forEach((handler) => handler(message.data));\n break;\n\n case 'exit':\n const exitCode = message.exitCode;\n this.exitHandlers.forEach((handler) => handler(exitCode));\n this.sessionId = null;\n this.sessionInfo = null;\n break;\n\n case 'error':\n const error = new Error(message.error);\n this.errorHandlers.forEach((handler) => handler(error));\n if (this.spawnReject) {\n this.spawnReject(error);\n this.spawnResolve = null;\n this.spawnReject = null;\n }\n break;\n }\n }\n\n /**\n * Spawn a terminal session\n */\n spawn(options: TerminalOptions = {}): Promise<SessionInfo> {\n return new Promise((resolve, reject) => {\n if (this.state !== 'connected' || !this.ws) {\n reject(new Error('Not connected to server'));\n return;\n }\n\n if (this.sessionId) {\n reject(new Error('Session already spawned. Call kill() first.'));\n return;\n }\n\n this.spawnResolve = resolve;\n this.spawnReject = reject;\n\n this.ws.send(\n JSON.stringify({\n type: 'spawn',\n options,\n })\n );\n });\n }\n\n /**\n * Write data to the terminal\n */\n write(data: string): void {\n if (!this.ws || this.state !== 'connected') {\n console.error('[lit-shell] Cannot write: not connected');\n return;\n }\n\n if (!this.sessionId) {\n console.error('[lit-shell] Cannot write: no active session');\n return;\n }\n\n this.ws.send(\n JSON.stringify({\n type: 'data',\n sessionId: this.sessionId,\n data,\n })\n );\n }\n\n /**\n * Resize the terminal\n */\n resize(cols: number, rows: number): void {\n if (!this.ws || this.state !== 'connected') {\n console.error('[lit-shell] Cannot resize: not connected');\n return;\n }\n\n if (!this.sessionId) {\n console.error('[lit-shell] Cannot resize: no active session');\n return;\n }\n\n this.ws.send(\n JSON.stringify({\n type: 'resize',\n sessionId: this.sessionId,\n cols,\n rows,\n })\n );\n }\n\n /**\n * Kill the terminal session\n */\n kill(): void {\n if (!this.ws || this.state !== 'connected') {\n return;\n }\n\n if (!this.sessionId) {\n return;\n }\n\n this.ws.send(\n JSON.stringify({\n type: 'close',\n sessionId: this.sessionId,\n })\n );\n\n this.sessionId = null;\n this.sessionInfo = null;\n }\n\n // ==========================================\n // Event handlers\n // ==========================================\n\n /**\n * Called when connected to server\n */\n onConnect(handler: () => void): void {\n this.connectHandlers.push(handler);\n }\n\n /**\n * Called when disconnected from server\n */\n onDisconnect(handler: () => void): void {\n this.disconnectHandlers.push(handler);\n }\n\n /**\n * Called when data is received from the terminal\n */\n onData(handler: (data: string) => void): void {\n this.dataHandlers.push(handler);\n }\n\n /**\n * Called when the terminal session exits\n */\n onExit(handler: (code: number) => void): void {\n this.exitHandlers.push(handler);\n }\n\n /**\n * Called when an error occurs\n */\n onError(handler: (error: Error) => void): void {\n this.errorHandlers.push(handler);\n }\n\n /**\n * Called when a session is spawned\n */\n onSpawned(handler: (info: SessionInfo) => void): void {\n this.spawnedHandlers.push(handler);\n }\n\n // ==========================================\n // Getters\n // ==========================================\n\n /**\n * Get current connection state\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.state === 'connected';\n }\n\n /**\n * Get current session ID\n */\n getSessionId(): string | null {\n return this.sessionId;\n }\n\n /**\n * Get current session info\n */\n getSessionInfo(): SessionInfo | null {\n return this.sessionInfo;\n }\n\n /**\n * Check if a session is active\n */\n hasActiveSession(): boolean {\n return this.sessionId !== null;\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Terminal client for connecting to lit-shell server\n *\n * Example usage:\n * ```typescript\n * import { TerminalClient } from 'lit-shell.js/client';\n *\n * const client = new TerminalClient({ url: 'ws://localhost:3000/terminal' });\n * await client.connect();\n *\n * client.onData((data) => console.log(data));\n * client.onExit((code) => console.log('Exited with code:', code));\n *\n * await client.spawn({ shell: '/bin/bash', cwd: '/home/user' });\n * client.write('ls -la\\n');\n * client.resize(120, 40);\n * client.kill();\n *\n * // Session multiplexing example\n * const sessions = await client.listSessions();\n * if (sessions.length > 0) {\n * await client.join({ sessionId: sessions[0].sessionId, requestHistory: true });\n * }\n * ```\n */\n\nimport type {\n ClientConfig,\n TerminalOptions,\n TerminalMessage,\n SessionInfo,\n ContainerInfo,\n ServerInfo,\n SharedSessionInfo,\n SessionListFilter,\n JoinSessionOptions,\n} from '../shared/types.js';\n\n/**\n * Connection state\n */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected';\n\n/**\n * Terminal client class with session multiplexing support\n */\nexport class TerminalClient {\n private config: Required<ClientConfig>;\n private ws: WebSocket | null = null;\n private state: ConnectionState = 'disconnected';\n private sessionId: string | null = null;\n private sessionInfo: SessionInfo | null = null;\n private serverInfo: ServerInfo | null = null;\n private reconnectAttempts = 0;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n\n // Event handlers\n private connectHandlers: (() => void)[] = [];\n private disconnectHandlers: (() => void)[] = [];\n private dataHandlers: ((data: string) => void)[] = [];\n private exitHandlers: ((code: number) => void)[] = [];\n private errorHandlers: ((error: Error) => void)[] = [];\n private spawnedHandlers: ((info: SessionInfo) => void)[] = [];\n private serverInfoHandlers: ((info: ServerInfo) => void)[] = [];\n private containerListHandlers: ((containers: ContainerInfo[]) => void)[] = [];\n // Session multiplexing handlers\n private sessionListHandlers: ((sessions: SharedSessionInfo[]) => void)[] = [];\n private joinedHandlers: ((session: SharedSessionInfo, history?: string) => void)[] = [];\n private leftHandlers: ((sessionId: string) => void)[] = [];\n private clientJoinedHandlers: ((sessionId: string, clientCount: number) => void)[] = [];\n private clientLeftHandlers: ((sessionId: string, clientCount: number) => void)[] = [];\n private sessionClosedHandlers: ((sessionId: string, reason: string) => void)[] = [];\n\n // Promise resolvers for spawn/join\n private spawnResolve: ((info: SessionInfo) => void) | null = null;\n private spawnReject: ((error: Error) => void) | null = null;\n private joinResolve: ((info: SharedSessionInfo) => void) | null = null;\n private joinReject: ((error: Error) => void) | null = null;\n private listSessionsResolve: ((sessions: SharedSessionInfo[]) => void) | null = null;\n\n constructor(config: ClientConfig) {\n this.config = {\n url: config.url,\n reconnect: config.reconnect ?? true,\n maxReconnectAttempts: config.maxReconnectAttempts ?? 10,\n reconnectDelay: config.reconnectDelay ?? 1000,\n };\n }\n\n /**\n * Connect to the terminal server\n */\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.state === 'connected') {\n resolve();\n return;\n }\n\n this.state = 'connecting';\n\n try {\n this.ws = new WebSocket(this.config.url);\n } catch (error) {\n this.state = 'disconnected';\n reject(error);\n return;\n }\n\n this.ws.onopen = () => {\n this.state = 'connected';\n this.reconnectAttempts = 0;\n this.connectHandlers.forEach((handler) => handler());\n resolve();\n };\n\n this.ws.onclose = () => {\n const wasConnected = this.state === 'connected';\n this.state = 'disconnected';\n this.sessionId = null;\n this.sessionInfo = null;\n\n if (wasConnected) {\n this.disconnectHandlers.forEach((handler) => handler());\n }\n\n // Attempt reconnection\n if (this.config.reconnect && this.reconnectAttempts < this.config.maxReconnectAttempts) {\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = (event) => {\n const error = new Error('WebSocket error');\n this.errorHandlers.forEach((handler) => handler(error));\n\n if (this.state === 'connecting') {\n reject(error);\n }\n };\n\n this.ws.onmessage = (event) => {\n this.handleMessage(event.data);\n };\n });\n }\n\n /**\n * Disconnect from the terminal server\n */\n disconnect(): void {\n this.config.reconnect = false; // Prevent auto-reconnect\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.state = 'disconnected';\n this.sessionId = null;\n this.sessionInfo = null;\n }\n\n /**\n * Schedule a reconnection attempt\n */\n private scheduleReconnect(): void {\n if (this.reconnectTimeout) return;\n\n const delay = this.config.reconnectDelay * Math.pow(2, this.reconnectAttempts);\n const maxDelay = 30000; // 30 seconds max\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null;\n this.reconnectAttempts++;\n this.connect().catch(() => {\n // Error handled by onclose\n });\n }, Math.min(delay, maxDelay));\n }\n\n /**\n * Handle incoming message\n */\n private handleMessage(data: string): void {\n let message: TerminalMessage;\n\n try {\n message = JSON.parse(data);\n } catch {\n console.error('[lit-shell] Invalid message:', data);\n return;\n }\n\n switch (message.type) {\n case 'spawned':\n this.sessionId = message.sessionId;\n this.sessionInfo = {\n sessionId: message.sessionId,\n shell: message.shell,\n cwd: message.cwd,\n cols: message.cols,\n rows: message.rows,\n createdAt: new Date(),\n container: message.container,\n };\n this.spawnedHandlers.forEach((handler) => handler(this.sessionInfo!));\n if (this.spawnResolve) {\n this.spawnResolve(this.sessionInfo);\n this.spawnResolve = null;\n this.spawnReject = null;\n }\n break;\n\n case 'data':\n this.dataHandlers.forEach((handler) => handler(message.data));\n break;\n\n case 'exit':\n const exitCode = message.exitCode;\n this.exitHandlers.forEach((handler) => handler(exitCode));\n this.sessionId = null;\n this.sessionInfo = null;\n break;\n\n case 'error':\n const error = new Error(message.error);\n this.errorHandlers.forEach((handler) => handler(error));\n if (this.spawnReject) {\n this.spawnReject(error);\n this.spawnResolve = null;\n this.spawnReject = null;\n }\n if (this.joinReject) {\n this.joinReject(error);\n this.joinResolve = null;\n this.joinReject = null;\n }\n break;\n\n case 'serverInfo':\n this.serverInfo = message.info;\n this.serverInfoHandlers.forEach((handler) => handler(message.info));\n break;\n\n case 'containerList':\n this.containerListHandlers.forEach((handler) => handler(message.containers));\n break;\n\n // Session multiplexing messages\n case 'sessionList':\n this.sessionListHandlers.forEach((handler) =>\n handler((message as any).sessions)\n );\n if (this.listSessionsResolve) {\n this.listSessionsResolve((message as any).sessions);\n this.listSessionsResolve = null;\n }\n break;\n\n case 'joined':\n const joinedSession = (message as any).session as SharedSessionInfo;\n const history = (message as any).history as string | undefined;\n this.sessionId = message.sessionId!;\n this.sessionInfo = {\n sessionId: joinedSession.sessionId,\n shell: joinedSession.shell,\n cwd: joinedSession.cwd,\n cols: joinedSession.cols,\n rows: joinedSession.rows,\n createdAt: joinedSession.createdAt,\n container: joinedSession.container,\n };\n this.joinedHandlers.forEach((handler) => handler(joinedSession, history));\n if (this.joinResolve) {\n this.joinResolve(joinedSession);\n this.joinResolve = null;\n this.joinReject = null;\n }\n break;\n\n case 'left':\n const leftSessionId = message.sessionId!;\n if (this.sessionId === leftSessionId) {\n this.sessionId = null;\n this.sessionInfo = null;\n }\n this.leftHandlers.forEach((handler) => handler(leftSessionId));\n break;\n\n case 'clientJoined':\n this.clientJoinedHandlers.forEach((handler) =>\n handler(message.sessionId!, (message as any).clientCount)\n );\n break;\n\n case 'clientLeft':\n this.clientLeftHandlers.forEach((handler) =>\n handler(message.sessionId!, (message as any).clientCount)\n );\n break;\n\n case 'sessionClosed':\n const closedSessionId = message.sessionId!;\n const reason = (message as any).reason as string;\n if (this.sessionId === closedSessionId) {\n this.sessionId = null;\n this.sessionInfo = null;\n }\n this.sessionClosedHandlers.forEach((handler) =>\n handler(closedSessionId, reason)\n );\n break;\n }\n }\n\n /**\n * Spawn a terminal session\n */\n spawn(options: TerminalOptions = {}): Promise<SessionInfo> {\n return new Promise((resolve, reject) => {\n if (this.state !== 'connected' || !this.ws) {\n reject(new Error('Not connected to server'));\n return;\n }\n\n if (this.sessionId) {\n reject(new Error('Session already active. Call kill() or leave() first.'));\n return;\n }\n\n this.spawnResolve = resolve;\n this.spawnReject = reject;\n\n this.ws.send(\n JSON.stringify({\n type: 'spawn',\n options,\n })\n );\n });\n }\n\n /**\n * Write data to the terminal\n */\n write(data: string): void {\n if (!this.ws || this.state !== 'connected') {\n console.error('[lit-shell] Cannot write: not connected');\n return;\n }\n\n if (!this.sessionId) {\n console.error('[lit-shell] Cannot write: no active session');\n return;\n }\n\n this.ws.send(\n JSON.stringify({\n type: 'data',\n sessionId: this.sessionId,\n data,\n })\n );\n }\n\n /**\n * Resize the terminal\n */\n resize(cols: number, rows: number): void {\n if (!this.ws || this.state !== 'connected') {\n console.error('[lit-shell] Cannot resize: not connected');\n return;\n }\n\n if (!this.sessionId) {\n console.error('[lit-shell] Cannot resize: no active session');\n return;\n }\n\n this.ws.send(\n JSON.stringify({\n type: 'resize',\n sessionId: this.sessionId,\n cols,\n rows,\n })\n );\n }\n\n /**\n * Kill the terminal session (close and terminate)\n */\n kill(): void {\n if (!this.ws || this.state !== 'connected') {\n return;\n }\n\n if (!this.sessionId) {\n return;\n }\n\n this.ws.send(\n JSON.stringify({\n type: 'close',\n sessionId: this.sessionId,\n })\n );\n\n this.sessionId = null;\n this.sessionInfo = null;\n }\n\n // ==========================================\n // Session Multiplexing Methods\n // ==========================================\n\n /**\n * List available sessions\n */\n listSessions(filter?: SessionListFilter): Promise<SharedSessionInfo[]> {\n return new Promise((resolve, reject) => {\n if (this.state !== 'connected' || !this.ws) {\n reject(new Error('Not connected to server'));\n return;\n }\n\n this.listSessionsResolve = resolve;\n\n this.ws.send(\n JSON.stringify({\n type: 'listSessions',\n filter,\n })\n );\n });\n }\n\n /**\n * Join an existing session\n */\n join(options: JoinSessionOptions): Promise<SharedSessionInfo> {\n return new Promise((resolve, reject) => {\n if (this.state !== 'connected' || !this.ws) {\n reject(new Error('Not connected to server'));\n return;\n }\n\n if (this.sessionId) {\n reject(new Error('Already in a session. Call leave() first.'));\n return;\n }\n\n this.joinResolve = resolve;\n this.joinReject = reject;\n\n this.ws.send(\n JSON.stringify({\n type: 'join',\n options,\n })\n );\n });\n }\n\n /**\n * Leave the current session without killing it\n */\n leave(sessionId?: string): void {\n if (!this.ws || this.state !== 'connected') {\n console.error('[lit-shell] Cannot leave: not connected');\n return;\n }\n\n const targetSession = sessionId || this.sessionId;\n if (!targetSession) {\n console.error('[lit-shell] Cannot leave: no active session');\n return;\n }\n\n this.ws.send(\n JSON.stringify({\n type: 'leave',\n sessionId: targetSession,\n })\n );\n\n if (targetSession === this.sessionId) {\n this.sessionId = null;\n this.sessionInfo = null;\n }\n }\n\n /**\n * Request session list and trigger onSessionList handlers\n * (Fire-and-forget version of listSessions)\n */\n requestSessionList(filter?: SessionListFilter): void {\n this.listSessions(filter)\n .then((sessions) => {\n this.sessionListHandlers.forEach((handler) => {\n try {\n handler(sessions);\n } catch (e) {\n console.error('[lit-shell] Error in sessionList handler:', e);\n }\n });\n })\n .catch((err) => {\n console.error('[lit-shell] Failed to list sessions:', err);\n });\n }\n\n // ==========================================\n // Event handlers\n // ==========================================\n\n /**\n * Called when connected to server\n */\n onConnect(handler: () => void): void {\n this.connectHandlers.push(handler);\n }\n\n /**\n * Called when disconnected from server\n */\n onDisconnect(handler: () => void): void {\n this.disconnectHandlers.push(handler);\n }\n\n /**\n * Called when data is received from the terminal\n */\n onData(handler: (data: string) => void): void {\n this.dataHandlers.push(handler);\n }\n\n /**\n * Called when the terminal session exits\n */\n onExit(handler: (code: number) => void): void {\n this.exitHandlers.push(handler);\n }\n\n /**\n * Called when an error occurs\n */\n onError(handler: (error: Error) => void): void {\n this.errorHandlers.push(handler);\n }\n\n /**\n * Called when a session is spawned\n */\n onSpawned(handler: (info: SessionInfo) => void): void {\n this.spawnedHandlers.push(handler);\n }\n\n /**\n * Called when server info is received\n */\n onServerInfo(handler: (info: ServerInfo) => void): void {\n this.serverInfoHandlers.push(handler);\n // If we already have server info, call immediately\n if (this.serverInfo) {\n handler(this.serverInfo);\n }\n }\n\n /**\n * Called when container list is received\n */\n onContainerList(handler: (containers: ContainerInfo[]) => void): void {\n this.containerListHandlers.push(handler);\n }\n\n /**\n * Called when session list is received\n */\n onSessionList(handler: (sessions: SharedSessionInfo[]) => void): void {\n this.sessionListHandlers.push(handler);\n }\n\n /**\n * Called when successfully joined a session\n */\n onJoined(handler: (session: SharedSessionInfo, history?: string) => void): void {\n this.joinedHandlers.push(handler);\n }\n\n /**\n * Called when left a session\n */\n onLeft(handler: (sessionId: string) => void): void {\n this.leftHandlers.push(handler);\n }\n\n /**\n * Called when another client joins the current session\n */\n onClientJoined(handler: (sessionId: string, clientCount: number) => void): void {\n this.clientJoinedHandlers.push(handler);\n }\n\n /**\n * Called when another client leaves the current session\n */\n onClientLeft(handler: (sessionId: string, clientCount: number) => void): void {\n this.clientLeftHandlers.push(handler);\n }\n\n /**\n * Called when the session is closed by owner or orphan timeout\n */\n onSessionClosed(handler: (sessionId: string, reason: string) => void): void {\n this.sessionClosedHandlers.push(handler);\n }\n\n /**\n * Request list of available containers\n */\n requestContainerList(): void {\n if (!this.ws || this.state !== 'connected') {\n console.error('[lit-shell] Cannot request containers: not connected');\n return;\n }\n\n this.ws.send(JSON.stringify({ type: 'listContainers' }));\n }\n\n // ==========================================\n // Getters\n // ==========================================\n\n /**\n * Get current connection state\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.state === 'connected';\n }\n\n /**\n * Get current session ID\n */\n getSessionId(): string | null {\n return this.sessionId;\n }\n\n /**\n * Get current session info\n */\n getSessionInfo(): SessionInfo | null {\n return this.sessionInfo;\n }\n\n /**\n * Check if a session is active\n */\n hasActiveSession(): boolean {\n return this.sessionId !== null;\n }\n\n /**\n * Get server info\n */\n getServerInfo(): ServerInfo | null {\n return this.serverInfo;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,5 +3,5 @@
3
3
  */
4
4
  export { TerminalClient } from './terminal-client.js';
5
5
  export type { ConnectionState } from './terminal-client.js';
6
- export type { ClientConfig, TerminalOptions, SessionInfo, } from '../shared/types.js';
6
+ export type { ClientConfig, TerminalOptions, SessionInfo, SharedSessionInfo, SessionType, SessionListFilter, JoinSessionOptions, } from '../shared/types.js';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EACV,YAAY,EACZ,eAAe,EACf,WAAW,GACZ,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EACV,YAAY,EACZ,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC"}
@@ -15,15 +15,21 @@
15
15
  * client.write('ls -la\n');
16
16
  * client.resize(120, 40);
17
17
  * client.kill();
18
+ *
19
+ * // Session multiplexing example
20
+ * const sessions = await client.listSessions();
21
+ * if (sessions.length > 0) {
22
+ * await client.join({ sessionId: sessions[0].sessionId, requestHistory: true });
23
+ * }
18
24
  * ```
19
25
  */
20
- import type { ClientConfig, TerminalOptions, SessionInfo } from '../shared/types.js';
26
+ import type { ClientConfig, TerminalOptions, SessionInfo, ContainerInfo, ServerInfo, SharedSessionInfo, SessionListFilter, JoinSessionOptions } from '../shared/types.js';
21
27
  /**
22
28
  * Connection state
23
29
  */
24
30
  export type ConnectionState = 'disconnected' | 'connecting' | 'connected';
25
31
  /**
26
- * Terminal client class
32
+ * Terminal client class with session multiplexing support
27
33
  */
28
34
  export declare class TerminalClient {
29
35
  private config;
@@ -31,6 +37,7 @@ export declare class TerminalClient {
31
37
  private state;
32
38
  private sessionId;
33
39
  private sessionInfo;
40
+ private serverInfo;
34
41
  private reconnectAttempts;
35
42
  private reconnectTimeout;
36
43
  private connectHandlers;
@@ -39,8 +46,19 @@ export declare class TerminalClient {
39
46
  private exitHandlers;
40
47
  private errorHandlers;
41
48
  private spawnedHandlers;
49
+ private serverInfoHandlers;
50
+ private containerListHandlers;
51
+ private sessionListHandlers;
52
+ private joinedHandlers;
53
+ private leftHandlers;
54
+ private clientJoinedHandlers;
55
+ private clientLeftHandlers;
56
+ private sessionClosedHandlers;
42
57
  private spawnResolve;
43
58
  private spawnReject;
59
+ private joinResolve;
60
+ private joinReject;
61
+ private listSessionsResolve;
44
62
  constructor(config: ClientConfig);
45
63
  /**
46
64
  * Connect to the terminal server
@@ -71,9 +89,26 @@ export declare class TerminalClient {
71
89
  */
72
90
  resize(cols: number, rows: number): void;
73
91
  /**
74
- * Kill the terminal session
92
+ * Kill the terminal session (close and terminate)
75
93
  */
76
94
  kill(): void;
95
+ /**
96
+ * List available sessions
97
+ */
98
+ listSessions(filter?: SessionListFilter): Promise<SharedSessionInfo[]>;
99
+ /**
100
+ * Join an existing session
101
+ */
102
+ join(options: JoinSessionOptions): Promise<SharedSessionInfo>;
103
+ /**
104
+ * Leave the current session without killing it
105
+ */
106
+ leave(sessionId?: string): void;
107
+ /**
108
+ * Request session list and trigger onSessionList handlers
109
+ * (Fire-and-forget version of listSessions)
110
+ */
111
+ requestSessionList(filter?: SessionListFilter): void;
77
112
  /**
78
113
  * Called when connected to server
79
114
  */
@@ -98,6 +133,42 @@ export declare class TerminalClient {
98
133
  * Called when a session is spawned
99
134
  */
100
135
  onSpawned(handler: (info: SessionInfo) => void): void;
136
+ /**
137
+ * Called when server info is received
138
+ */
139
+ onServerInfo(handler: (info: ServerInfo) => void): void;
140
+ /**
141
+ * Called when container list is received
142
+ */
143
+ onContainerList(handler: (containers: ContainerInfo[]) => void): void;
144
+ /**
145
+ * Called when session list is received
146
+ */
147
+ onSessionList(handler: (sessions: SharedSessionInfo[]) => void): void;
148
+ /**
149
+ * Called when successfully joined a session
150
+ */
151
+ onJoined(handler: (session: SharedSessionInfo, history?: string) => void): void;
152
+ /**
153
+ * Called when left a session
154
+ */
155
+ onLeft(handler: (sessionId: string) => void): void;
156
+ /**
157
+ * Called when another client joins the current session
158
+ */
159
+ onClientJoined(handler: (sessionId: string, clientCount: number) => void): void;
160
+ /**
161
+ * Called when another client leaves the current session
162
+ */
163
+ onClientLeft(handler: (sessionId: string, clientCount: number) => void): void;
164
+ /**
165
+ * Called when the session is closed by owner or orphan timeout
166
+ */
167
+ onSessionClosed(handler: (sessionId: string, reason: string) => void): void;
168
+ /**
169
+ * Request list of available containers
170
+ */
171
+ requestContainerList(): void;
101
172
  /**
102
173
  * Get current connection state
103
174
  */
@@ -118,5 +189,9 @@ export declare class TerminalClient {
118
189
  * Check if a session is active
119
190
  */
120
191
  hasActiveSession(): boolean;
192
+ /**
193
+ * Get server info
194
+ */
195
+ getServerInfo(): ServerInfo | null;
121
196
  }
122
197
  //# sourceMappingURL=terminal-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-client.d.ts","sourceRoot":"","sources":["../../src/client/terminal-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EAEf,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,CAAC;AAE1E;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAA8C;IAGtE,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,eAAe,CAAuC;IAG9D,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,WAAW,CAAyC;gBAEhD,MAAM,EAAE,YAAY;IAShC;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAuDxB;;OAEG;IACH,UAAU,IAAI,IAAI;IAkBlB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAezB;;OAEG;IACH,OAAO,CAAC,aAAa;IAoDrB;;OAEG;IACH,KAAK,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;IAwB1D;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAoBzB;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAqBxC;;OAEG;IACH,IAAI,IAAI,IAAI;IAwBZ;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIpC;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIvC;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI7C;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI7C;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAI9C;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IAQrD;;OAEG;IACH,QAAQ,IAAI,eAAe;IAI3B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B;;OAEG;IACH,cAAc,IAAI,WAAW,GAAG,IAAI;IAIpC;;OAEG;IACH,gBAAgB,IAAI,OAAO;CAG5B"}
1
+ {"version":3,"file":"terminal-client.d.ts","sourceRoot":"","sources":["../../src/client/terminal-client.ts"],"names":[],"mappings":"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"}