ttyd-mux 0.3.0 → 0.4.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.
Files changed (196) hide show
  1. package/README.md +105 -1
  2. package/dist/caddy/client.d.ts +3 -55
  3. package/dist/caddy/client.d.ts.map +1 -1
  4. package/dist/caddy/client.js +0 -73
  5. package/dist/caddy/client.js.map +1 -1
  6. package/dist/caddy/route-builder.d.ts +49 -0
  7. package/dist/caddy/route-builder.d.ts.map +1 -0
  8. package/dist/caddy/route-builder.js +175 -0
  9. package/dist/caddy/route-builder.js.map +1 -0
  10. package/dist/caddy/types.d.ts +27 -0
  11. package/dist/caddy/types.d.ts.map +1 -0
  12. package/dist/caddy/types.js +3 -0
  13. package/dist/caddy/types.js.map +1 -0
  14. package/dist/client/api-client.d.ts +26 -0
  15. package/dist/client/api-client.d.ts.map +1 -0
  16. package/dist/client/api-client.js +62 -0
  17. package/dist/client/api-client.js.map +1 -0
  18. package/dist/client/daemon-client.d.ts +48 -0
  19. package/dist/client/daemon-client.d.ts.map +1 -0
  20. package/dist/client/daemon-client.js +205 -0
  21. package/dist/client/daemon-client.js.map +1 -0
  22. package/dist/client/index.d.ts +2 -10
  23. package/dist/client/index.d.ts.map +1 -1
  24. package/dist/client/index.js +4 -136
  25. package/dist/client/index.js.map +1 -1
  26. package/dist/commands/attach.js +3 -4
  27. package/dist/commands/attach.js.map +1 -1
  28. package/dist/commands/caddy.d.ts +2 -1
  29. package/dist/commands/caddy.d.ts.map +1 -1
  30. package/dist/commands/caddy.js +227 -75
  31. package/dist/commands/caddy.js.map +1 -1
  32. package/dist/commands/daemon.js.map +1 -1
  33. package/dist/commands/deploy.d.ts +7 -0
  34. package/dist/commands/deploy.d.ts.map +1 -0
  35. package/dist/commands/deploy.js +100 -0
  36. package/dist/commands/deploy.js.map +1 -0
  37. package/dist/commands/doctor.d.ts +8 -0
  38. package/dist/commands/doctor.d.ts.map +1 -0
  39. package/dist/commands/doctor.js +180 -0
  40. package/dist/commands/doctor.js.map +1 -0
  41. package/dist/commands/down.d.ts.map +1 -1
  42. package/dist/commands/down.js +11 -0
  43. package/dist/commands/down.js.map +1 -1
  44. package/dist/commands/reload.d.ts +14 -0
  45. package/dist/commands/reload.d.ts.map +1 -0
  46. package/dist/commands/reload.js +50 -0
  47. package/dist/commands/reload.js.map +1 -0
  48. package/dist/commands/shutdown.d.ts +2 -1
  49. package/dist/commands/shutdown.d.ts.map +1 -1
  50. package/dist/commands/shutdown.js +8 -2
  51. package/dist/commands/shutdown.js.map +1 -1
  52. package/dist/commands/start.d.ts.map +1 -1
  53. package/dist/commands/start.js +16 -3
  54. package/dist/commands/start.js.map +1 -1
  55. package/dist/commands/status.js.map +1 -1
  56. package/dist/commands/stop.js.map +1 -1
  57. package/dist/commands/up.js.map +1 -1
  58. package/dist/config/config.d.ts.map +1 -1
  59. package/dist/config/config.js +9 -2
  60. package/dist/config/config.js.map +1 -1
  61. package/dist/config/index.d.ts +3 -3
  62. package/dist/config/index.d.ts.map +1 -1
  63. package/dist/config/index.js +6 -3
  64. package/dist/config/index.js.map +1 -1
  65. package/dist/config/state-store.d.ts +27 -0
  66. package/dist/config/state-store.d.ts.map +1 -0
  67. package/dist/config/state-store.js +55 -0
  68. package/dist/config/state-store.js.map +1 -0
  69. package/dist/config/state.d.ts +6 -0
  70. package/dist/config/state.d.ts.map +1 -1
  71. package/dist/config/state.js +49 -14
  72. package/dist/config/state.js.map +1 -1
  73. package/dist/config/types.d.ts +35 -0
  74. package/dist/config/types.d.ts.map +1 -1
  75. package/dist/config/types.js +23 -1
  76. package/dist/config/types.js.map +1 -1
  77. package/dist/daemon/api-handler.d.ts +5 -0
  78. package/dist/daemon/api-handler.d.ts.map +1 -0
  79. package/dist/daemon/api-handler.js +97 -0
  80. package/dist/daemon/api-handler.js.map +1 -0
  81. package/dist/daemon/config-manager.d.ts +43 -0
  82. package/dist/daemon/config-manager.d.ts.map +1 -0
  83. package/dist/daemon/config-manager.js +154 -0
  84. package/dist/daemon/config-manager.js.map +1 -0
  85. package/dist/daemon/http-proxy.d.ts +27 -0
  86. package/dist/daemon/http-proxy.d.ts.map +1 -0
  87. package/dist/daemon/http-proxy.js +110 -0
  88. package/dist/daemon/http-proxy.js.map +1 -0
  89. package/dist/daemon/ime-helper.d.ts +1 -1
  90. package/dist/daemon/ime-helper.d.ts.map +1 -1
  91. package/dist/daemon/ime-helper.js +284 -10
  92. package/dist/daemon/ime-helper.js.map +1 -1
  93. package/dist/daemon/index.d.ts.map +1 -1
  94. package/dist/daemon/index.js +134 -29
  95. package/dist/daemon/index.js.map +1 -1
  96. package/dist/daemon/portal-utils.d.ts +20 -0
  97. package/dist/daemon/portal-utils.d.ts.map +1 -0
  98. package/dist/daemon/portal-utils.js +109 -0
  99. package/dist/daemon/portal-utils.js.map +1 -0
  100. package/dist/daemon/portal.d.ts.map +1 -1
  101. package/dist/daemon/portal.js +20 -77
  102. package/dist/daemon/portal.js.map +1 -1
  103. package/dist/daemon/pwa.d.ts +52 -0
  104. package/dist/daemon/pwa.d.ts.map +1 -0
  105. package/dist/daemon/pwa.js +229 -0
  106. package/dist/daemon/pwa.js.map +1 -0
  107. package/dist/daemon/router.d.ts +15 -0
  108. package/dist/daemon/router.d.ts.map +1 -0
  109. package/dist/daemon/router.js +164 -0
  110. package/dist/daemon/router.js.map +1 -0
  111. package/dist/daemon/server.d.ts +15 -3
  112. package/dist/daemon/server.d.ts.map +1 -1
  113. package/dist/daemon/server.js +23 -271
  114. package/dist/daemon/server.js.map +1 -1
  115. package/dist/daemon/session-manager.d.ts +44 -10
  116. package/dist/daemon/session-manager.d.ts.map +1 -1
  117. package/dist/daemon/session-manager.js +125 -49
  118. package/dist/daemon/session-manager.js.map +1 -1
  119. package/dist/daemon/session-resolver.d.ts +1 -1
  120. package/dist/daemon/session-resolver.d.ts.map +1 -1
  121. package/dist/daemon/session-resolver.js.map +1 -1
  122. package/dist/daemon/toolbar/config.d.ts +13 -0
  123. package/dist/daemon/toolbar/config.d.ts.map +1 -0
  124. package/dist/daemon/toolbar/config.js +13 -0
  125. package/dist/daemon/toolbar/config.js.map +1 -0
  126. package/dist/daemon/toolbar/index.d.ts +43 -0
  127. package/dist/daemon/toolbar/index.d.ts.map +1 -0
  128. package/dist/daemon/toolbar/index.js +835 -0
  129. package/dist/daemon/toolbar/index.js.map +1 -0
  130. package/dist/daemon/toolbar/styles.d.ts +5 -0
  131. package/dist/daemon/toolbar/styles.d.ts.map +1 -0
  132. package/dist/daemon/toolbar/styles.js +278 -0
  133. package/dist/daemon/toolbar/styles.js.map +1 -0
  134. package/dist/daemon/toolbar/template.d.ts +6 -0
  135. package/dist/daemon/toolbar/template.d.ts.map +1 -0
  136. package/dist/daemon/toolbar/template.js +45 -0
  137. package/dist/daemon/toolbar/template.js.map +1 -0
  138. package/dist/daemon/ws-proxy.d.ts +17 -0
  139. package/dist/daemon/ws-proxy.d.ts.map +1 -0
  140. package/dist/daemon/ws-proxy.js +95 -0
  141. package/dist/daemon/ws-proxy.js.map +1 -0
  142. package/dist/deploy/caddyfile.d.ts +8 -0
  143. package/dist/deploy/caddyfile.d.ts.map +1 -0
  144. package/dist/deploy/caddyfile.js +62 -0
  145. package/dist/deploy/caddyfile.js.map +1 -0
  146. package/dist/deploy/deploy-script.d.ts +8 -0
  147. package/dist/deploy/deploy-script.d.ts.map +1 -0
  148. package/dist/deploy/deploy-script.js +72 -0
  149. package/dist/deploy/deploy-script.js.map +1 -0
  150. package/dist/deploy/static-portal.d.ts +3 -0
  151. package/dist/deploy/static-portal.d.ts.map +1 -0
  152. package/dist/deploy/static-portal.js +59 -0
  153. package/dist/deploy/static-portal.js.map +1 -0
  154. package/dist/index.js +38 -9
  155. package/dist/index.js.map +1 -1
  156. package/dist/test-setup.d.ts +19 -0
  157. package/dist/test-setup.d.ts.map +1 -0
  158. package/dist/test-setup.js +33 -0
  159. package/dist/test-setup.js.map +1 -0
  160. package/dist/tmux.d.ts +28 -1
  161. package/dist/tmux.d.ts.map +1 -1
  162. package/dist/tmux.js +37 -32
  163. package/dist/tmux.js.map +1 -1
  164. package/dist/ui.d.ts +2 -1
  165. package/dist/ui.d.ts.map +1 -1
  166. package/dist/ui.js +16 -9
  167. package/dist/ui.js.map +1 -1
  168. package/dist/utils/errors.d.ts +4 -0
  169. package/dist/utils/errors.d.ts.map +1 -1
  170. package/dist/utils/errors.js +9 -1
  171. package/dist/utils/errors.js.map +1 -1
  172. package/dist/utils/logger.d.ts +14 -0
  173. package/dist/utils/logger.d.ts.map +1 -0
  174. package/dist/utils/logger.js +53 -0
  175. package/dist/utils/logger.js.map +1 -0
  176. package/dist/utils/process-runner.d.ts +50 -0
  177. package/dist/utils/process-runner.d.ts.map +1 -0
  178. package/dist/utils/process-runner.js +73 -0
  179. package/dist/utils/process-runner.js.map +1 -0
  180. package/dist/utils/socket-client.d.ts +24 -0
  181. package/dist/utils/socket-client.d.ts.map +1 -0
  182. package/dist/utils/socket-client.js +30 -0
  183. package/dist/utils/socket-client.js.map +1 -0
  184. package/dist/utils/tmux-client.d.ts +57 -0
  185. package/dist/utils/tmux-client.d.ts.map +1 -0
  186. package/dist/utils/tmux-client.js +117 -0
  187. package/dist/utils/tmux-client.js.map +1 -0
  188. package/dist/version.d.ts +3 -0
  189. package/dist/version.d.ts.map +1 -0
  190. package/dist/version.js +4 -0
  191. package/dist/version.js.map +1 -0
  192. package/package.json +6 -2
  193. package/dist/daemon/proxy.d.ts +0 -7
  194. package/dist/daemon/proxy.d.ts.map +0 -1
  195. package/dist/daemon/proxy.js +0 -17
  196. package/dist/daemon/proxy.js.map +0 -1
@@ -1,281 +1,33 @@
1
1
  import { createServer } from 'node:http';
2
- import { gzipSync } from 'node:zlib';
3
- import httpProxy from 'http-proxy';
4
- import WebSocket, { WebSocketServer } from 'ws';
5
- import { getFullPath, normalizeBasePath } from '../config/config.js';
6
- import { getDaemonState } from '../config/state.js';
7
- import { getErrorMessage } from '../utils/errors.js';
8
- import { injectImeHelper } from './ime-helper.js';
9
- import { generateJsonResponse, generatePortalHtml } from './portal.js';
10
- import { allocatePort, listSessions, sessionNameFromDir, startSession, stopSession } from './session-manager.js';
11
- // Create proxy server for HTTP only
12
- const proxy = httpProxy.createProxyServer({
13
- changeOrigin: true,
14
- xfwd: true
15
- });
16
- // Handle proxy errors
17
- proxy.on('error', (err, _req, res) => {
18
- console.error('Proxy error:', err.message);
19
- if (res && 'writeHead' in res && typeof res.writeHead === 'function') {
20
- const httpRes = res;
21
- if (!httpRes.headersSent) {
22
- httpRes.writeHead(502, { 'Content-Type': 'text/plain' });
23
- httpRes.end('Bad Gateway');
24
- }
25
- }
26
- });
27
- // Handle selfHandleResponse for HTML injection
28
- proxy.on('proxyRes', (proxyRes, req, res) => {
29
- const httpRes = res;
30
- // Check if this is a self-handled HTML response
31
- const contentType = proxyRes.headers['content-type'] ?? '';
32
- if (!contentType.includes('text/html')) {
33
- // Not HTML, just pipe through
34
- httpRes.writeHead(proxyRes.statusCode ?? 200, proxyRes.headers);
35
- proxyRes.pipe(httpRes);
36
- return;
37
- }
38
- // Check if client supports gzip (stored in custom header before deletion)
39
- const acceptEncoding = req.originalAcceptEncoding ?? '';
40
- const supportsGzip = acceptEncoding.includes('gzip');
41
- // Collect HTML body and inject IME helper
42
- const chunks = [];
43
- proxyRes.on('data', (chunk) => chunks.push(chunk));
44
- proxyRes.on('end', () => {
45
- const originalHtml = Buffer.concat(chunks).toString('utf-8');
46
- const modifiedHtml = injectImeHelper(originalHtml);
47
- // Update headers
48
- const headers = { ...proxyRes.headers };
49
- delete headers['content-encoding'];
50
- if (supportsGzip) {
51
- // Compress with gzip
52
- const compressed = gzipSync(modifiedHtml);
53
- headers['content-encoding'] = 'gzip';
54
- headers['content-length'] = String(compressed.length);
55
- httpRes.writeHead(proxyRes.statusCode ?? 200, headers);
56
- httpRes.end(compressed);
57
- }
58
- else {
59
- // Send uncompressed
60
- headers['content-length'] = String(Buffer.byteLength(modifiedHtml));
61
- httpRes.writeHead(proxyRes.statusCode ?? 200, headers);
62
- httpRes.end(modifiedHtml);
63
- }
64
- });
65
- });
66
- export function findSessionForPath(config, path) {
67
- const sessions = listSessions();
68
- const basePath = normalizeBasePath(config.base_path);
69
- for (const session of sessions) {
70
- const sessionFullPath = `${basePath}${session.path}`;
71
- if (path.startsWith(`${sessionFullPath}/`) || path === sessionFullPath) {
72
- return session;
73
- }
74
- }
75
- return null;
76
- }
77
- function sendJson(res, status, data) {
78
- const body = generateJsonResponse(data);
79
- res.writeHead(status, {
80
- 'Content-Type': 'application/json',
81
- 'Content-Length': Buffer.byteLength(body)
82
- });
83
- res.end(body);
84
- }
85
- function handleApiRequest(config, req, res) {
86
- const basePath = normalizeBasePath(config.base_path);
87
- const url = req.url ?? '/';
88
- const path = url.slice(basePath.length);
89
- const method = req.method ?? 'GET';
90
- // GET /api/status
91
- if (path === '/api/status' && method === 'GET') {
92
- const daemon = getDaemonState();
93
- const sessions = listSessions().map((s) => ({
94
- ...s,
95
- fullPath: getFullPath(config, s.path)
96
- }));
97
- sendJson(res, 200, { daemon, sessions });
98
- return;
99
- }
100
- // GET /api/sessions
101
- if (path === '/api/sessions' && method === 'GET') {
102
- const sessions = listSessions().map((s) => ({
103
- ...s,
104
- fullPath: getFullPath(config, s.path)
105
- }));
106
- sendJson(res, 200, sessions);
107
- return;
108
- }
109
- // POST /api/sessions
110
- if (path === '/api/sessions' && method === 'POST') {
111
- let body = '';
112
- req.on('data', (chunk) => {
113
- body += chunk.toString();
114
- });
115
- req.on('end', () => {
116
- try {
117
- const parsed = JSON.parse(body);
118
- const name = parsed.name ?? sessionNameFromDir(parsed.dir);
119
- const sessionPath = parsed.path ?? `/${name}`;
120
- const port = allocatePort(config);
121
- const fullPath = getFullPath(config, sessionPath);
122
- const options = {
123
- name,
124
- dir: parsed.dir,
125
- path: sessionPath,
126
- port,
127
- fullPath
128
- };
129
- const session = startSession(options);
130
- sendJson(res, 201, { ...session, fullPath });
131
- }
132
- catch (error) {
133
- sendJson(res, 400, { error: getErrorMessage(error) });
134
- }
135
- });
136
- return;
137
- }
138
- // DELETE /api/sessions/:name
139
- const deleteMatch = path.match(/^\/api\/sessions\/(.+)$/);
140
- if (deleteMatch?.[1] && method === 'DELETE') {
141
- const name = decodeURIComponent(deleteMatch[1]);
142
- try {
143
- stopSession(name);
144
- sendJson(res, 200, { success: true });
145
- }
146
- catch (error) {
147
- sendJson(res, 400, { error: getErrorMessage(error) });
148
- }
149
- return;
150
- }
151
- // POST /api/shutdown
152
- if (path === '/api/shutdown' && method === 'POST') {
153
- sendJson(res, 200, { success: true });
154
- setTimeout(() => {
155
- process.exit(0);
156
- }, 100);
157
- return;
158
- }
159
- // Not found
160
- sendJson(res, 404, { error: 'API endpoint not found' });
161
- }
162
- function handleRequest(config, req, res) {
163
- const url = req.url ?? '/';
164
- const method = req.method ?? 'GET';
165
- const basePath = normalizeBasePath(config.base_path);
166
- // API routes
167
- if (url.startsWith(`${basePath}/api/`)) {
168
- handleApiRequest(config, req, res);
169
- return;
170
- }
171
- // Portal page
172
- if (url === basePath || url === `${basePath}/`) {
173
- if (method === 'GET') {
174
- const sessions = listSessions();
175
- const html = generatePortalHtml(config, sessions);
176
- res.writeHead(200, {
177
- 'Content-Type': 'text/html; charset=utf-8',
178
- 'Content-Length': Buffer.byteLength(html)
179
- });
180
- res.end(html);
181
- return;
182
- }
183
- }
184
- // Try to proxy to a session
185
- const session = findSessionForPath(config, url);
186
- if (session) {
187
- const target = `http://localhost:${session.port}`;
188
- // Store original Accept-Encoding before deletion (for gzip re-compression)
189
- req.originalAcceptEncoding =
190
- req.headers['accept-encoding'];
191
- // Remove Accept-Encoding to get uncompressed response for HTML injection
192
- delete req.headers['accept-encoding'];
193
- // Always use selfHandleResponse to avoid conflicts with proxyRes handler
194
- proxy.web(req, res, { target, selfHandleResponse: true });
195
- return;
196
- }
197
- // Not found
198
- res.writeHead(404, { 'Content-Type': 'text/plain' });
199
- res.end('Not Found');
200
- }
201
- // Create WebSocket server (noServer mode for manual upgrade handling)
202
- const wss = new WebSocketServer({ noServer: true });
203
- function handleUpgrade(config, req, socket, head) {
204
- const url = req.url ?? '/';
205
- const session = findSessionForPath(config, url);
206
- if (!session) {
207
- socket.destroy();
208
- return;
209
- }
210
- // Connect to backend WebSocket
211
- const backendUrl = `ws://127.0.0.1:${session.port}${url}`;
212
- const protocol = req.headers['sec-websocket-protocol'];
213
- const backendWs = new WebSocket(backendUrl, protocol ? protocol.split(',').map((p) => p.trim()) : []);
214
- backendWs.on('open', () => {
215
- // Upgrade client connection once backend is ready
216
- wss.handleUpgrade(req, socket, head, (clientWs) => {
217
- let closed = false;
218
- const cleanup = (initiator, code, reason) => {
219
- if (closed)
220
- return;
221
- closed = true;
222
- // Close the other side with proper code
223
- const closeCode = code ?? 1000;
224
- const closeReason = reason?.toString() ?? '';
225
- if (initiator === 'client') {
226
- if (backendWs.readyState === WebSocket.OPEN) {
227
- backendWs.close(closeCode, closeReason);
228
- }
229
- else {
230
- backendWs.terminate();
231
- }
232
- }
233
- else {
234
- if (clientWs.readyState === WebSocket.OPEN) {
235
- clientWs.close(closeCode, closeReason);
236
- }
237
- else {
238
- clientWs.terminate();
239
- }
240
- }
241
- };
242
- // Forward messages bidirectionally
243
- clientWs.on('message', (data, isBinary) => {
244
- if (backendWs.readyState === WebSocket.OPEN) {
245
- backendWs.send(data, { binary: isBinary });
246
- }
247
- });
248
- backendWs.on('message', (data, isBinary) => {
249
- if (clientWs.readyState === WebSocket.OPEN) {
250
- clientWs.send(data, { binary: isBinary });
251
- }
252
- });
253
- // Handle close events
254
- clientWs.on('close', (code, reason) => cleanup('client', code, reason));
255
- backendWs.on('close', (code, reason) => cleanup('backend', code, reason));
256
- // Handle errors - terminate to ensure cleanup
257
- clientWs.on('error', () => {
258
- clientWs.terminate();
259
- cleanup('client', 1006);
260
- });
261
- backendWs.on('error', () => {
262
- backendWs.terminate();
263
- cleanup('backend', 1006);
264
- });
265
- });
266
- });
267
- backendWs.on('error', (err) => {
268
- console.error(`[WebSocket] Connection error: ${err.message}`);
269
- backendWs.terminate();
270
- socket.destroy();
271
- });
2
+ import { handleRequest } from './router.js';
3
+ import { handleUpgrade } from './ws-proxy.js';
4
+ // Dynamic import to avoid circular dependency and allow fallback
5
+ let getConfigFunc = null;
6
+ /**
7
+ * Set the config getter function (called by daemon on startup)
8
+ */
9
+ export function setConfigGetter(getter) {
10
+ getConfigFunc = getter;
272
11
  }
273
- export function createDaemonServer(config) {
12
+ /**
13
+ * Create the daemon HTTP server with WebSocket support
14
+ *
15
+ * Note: When ConfigManager is initialized (via setConfigGetter), the server
16
+ * uses the dynamic config for each request to support hot-reloading.
17
+ * Otherwise, it falls back to the initialConfig (for testing).
18
+ *
19
+ * @param initialConfig - Initial config (used as fallback when ConfigManager not initialized)
20
+ */
21
+ export function createDaemonServer(initialConfig) {
274
22
  const server = createServer((req, res) => {
23
+ // Use dynamic config if available, otherwise fall back to initialConfig
24
+ const config = getConfigFunc ? getConfigFunc() : initialConfig;
275
25
  handleRequest(config, req, res);
276
26
  });
277
27
  // Handle WebSocket upgrades
278
28
  server.on('upgrade', (req, socket, head) => {
29
+ // Use dynamic config if available, otherwise fall back to initialConfig
30
+ const config = getConfigFunc ? getConfigFunc() : initialConfig;
279
31
  handleUpgrade(config, req, socket, head);
280
32
  });
281
33
  return server;
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,WAAW,CAAC;AAItD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,iEAAiE;AACjE,IAAI,aAAa,GAA0B,IAAI,CAAC;AAEhD;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,aAAa,GAAG,MAAM,CAAC;AACzB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,aAAqB;IACtD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvC,wEAAwE;QACxE,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC/D,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,4BAA4B;IAC5B,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAoB,EAAE,MAAc,EAAE,IAAY,EAAE,EAAE;QAC1E,wEAAwE;QACxE,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC/D,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,37 +1,71 @@
1
1
  import { EventEmitter } from 'node:events';
2
- import type { Config, SessionState } from '../config/types.js';
2
+ import { type StateStore } from '../config/state-store.js';
3
+ import type { Config, SessionState, TmuxMode } from '../config/types.js';
4
+ import { type ProcessRunner } from '../utils/process-runner.js';
5
+ import { type TmuxClient } from '../utils/tmux-client.js';
3
6
  export interface StartSessionOptions {
4
7
  name: string;
5
8
  dir: string;
6
9
  path: string;
7
10
  port: number;
8
11
  fullPath: string;
12
+ tmuxMode?: TmuxMode;
9
13
  }
10
14
  export interface SessionEvents {
11
15
  'session:start': (session: SessionState) => void;
12
16
  'session:stop': (name: string) => void;
13
17
  'session:exit': (name: string, code: number | null) => void;
14
18
  }
19
+ /**
20
+ * Dependencies for SessionManager (for testing)
21
+ */
22
+ export interface SessionManagerDeps {
23
+ stateStore: StateStore;
24
+ processRunner: ProcessRunner;
25
+ tmuxClient: TmuxClient;
26
+ }
27
+ /**
28
+ * Default dependencies using real implementations
29
+ */
30
+ export declare const defaultSessionManagerDeps: SessionManagerDeps;
15
31
  /**
16
32
  * Session manager with EventEmitter for proactive process monitoring
17
33
  */
18
- declare class SessionManager extends EventEmitter {
34
+ export declare class SessionManager extends EventEmitter {
19
35
  private runningProcesses;
20
- startSession(options: StartSessionOptions): SessionState;
36
+ private deps;
37
+ constructor(deps?: SessionManagerDeps);
38
+ startSession(options: StartSessionOptions): Promise<SessionState>;
21
39
  stopSession(name: string): void;
22
40
  isProcessRunning(pid: number): boolean;
23
41
  listSessions(): SessionState[];
24
42
  stopAllSessions(): void;
43
+ /**
44
+ * Revalidate sessions after daemon restart.
45
+ * Checks if each session's ttyd process is still running.
46
+ * Removes dead sessions from state.
47
+ */
48
+ revalidateSessions(): {
49
+ valid: SessionState[];
50
+ removed: string[];
51
+ };
25
52
  private handleProcessExit;
26
53
  private cleanup;
27
54
  }
28
- declare const sessionManager: SessionManager;
29
- export declare function startSession(options: StartSessionOptions): SessionState;
30
- export declare function stopSession(name: string): void;
31
- export declare function isProcessRunning(pid: number): boolean;
32
- export declare function listSessions(): SessionState[];
33
- export declare function stopAllSessions(): void;
55
+ /**
56
+ * Shared session manager instance
57
+ */
58
+ export declare const sessionManager: SessionManager;
59
+ /**
60
+ * Allocate next available port for a new session
61
+ */
34
62
  export declare function allocatePort(config: Config): number;
63
+ /**
64
+ * Extract session name from directory path
65
+ */
35
66
  export declare function sessionNameFromDir(dir: string): string;
36
- export { sessionManager };
67
+ /**
68
+ * Create a SessionManager with custom dependencies (for testing)
69
+ */
70
+ export declare function createSessionManager(deps?: Partial<SessionManagerDeps>): SessionManager;
37
71
  //# sourceMappingURL=session-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/daemon/session-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQ3C,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE/D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IACjD,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC7D;AAED;;GAEG;AACH,cAAM,cAAe,SAAQ,YAAY;IACvC,OAAO,CAAC,gBAAgB,CAAmC;IAE3D,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY;IAkDxD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAkB/B,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAStC,YAAY,IAAI,YAAY,EAAE;IAgB9B,eAAe,IAAI,IAAI;IAWvB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,OAAO;CAIhB;AAGD,QAAA,MAAM,cAAc,gBAAuB,CAAC;AAG5C,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAEvE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,YAAY,IAAI,YAAY,EAAE,CAE7C;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD;AAGD,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/daemon/session-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,wBAAwB,CAAC;AAI5E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAkBD,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IACjD,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC7D;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,kBAIvC,CAAC;AAEF;;GAEG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,gBAAgB,CAAmC;IAC3D,OAAO,CAAC,IAAI,CAAqB;gBAErB,IAAI,GAAE,kBAA8C;IAK1D,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC;IA6EvE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAuB/B,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAItC,YAAY,IAAI,YAAY,EAAE;IAiB9B,eAAe,IAAI,IAAI;IAavB;;;;OAIG;IACH,kBAAkB,IAAI;QAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE;IAoBlE,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,OAAO;CAKhB;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,gBAAuB,CAAC;AAEnD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAAG,cAAc,CAK3F"}
@@ -1,28 +1,79 @@
1
- import { spawn } from 'node:child_process';
2
1
  import { EventEmitter } from 'node:events';
3
- import { addSession, getAllSessions, getNextPort, getSession, removeSession } from '../config/state.js';
2
+ import { defaultStateStore } from '../config/state-store.js';
3
+ import { createLogger } from '../utils/logger.js';
4
+ import { defaultProcessRunner } from '../utils/process-runner.js';
5
+ import { defaultTmuxClient } from '../utils/tmux-client.js';
6
+ const log = createLogger('session');
7
+ /**
8
+ * Get tmux command arguments based on mode
9
+ */
10
+ function getTmuxCommand(name, mode) {
11
+ switch (mode) {
12
+ case 'attach':
13
+ return ['tmux', 'attach-session', '-t', name];
14
+ case 'new':
15
+ return ['tmux', 'new-session', '-s', name];
16
+ default:
17
+ // For auto mode, session is pre-created by ensureSession
18
+ // Just attach to it
19
+ return ['tmux', 'attach-session', '-t', name];
20
+ }
21
+ }
22
+ /**
23
+ * Default dependencies using real implementations
24
+ */
25
+ export const defaultSessionManagerDeps = {
26
+ stateStore: defaultStateStore,
27
+ processRunner: defaultProcessRunner,
28
+ tmuxClient: defaultTmuxClient
29
+ };
4
30
  /**
5
31
  * Session manager with EventEmitter for proactive process monitoring
6
32
  */
7
- class SessionManager extends EventEmitter {
33
+ export class SessionManager extends EventEmitter {
8
34
  runningProcesses = new Map();
9
- startSession(options) {
10
- const { name, dir, path, port, fullPath } = options;
35
+ deps;
36
+ constructor(deps = defaultSessionManagerDeps) {
37
+ super();
38
+ this.deps = deps;
39
+ }
40
+ async startSession(options) {
41
+ const { name, dir, path, port, fullPath, tmuxMode = 'auto' } = options;
42
+ const { stateStore, processRunner, tmuxClient } = this.deps;
43
+ log.info(`Starting session: ${name} (port=${port}, mode=${tmuxMode})`);
11
44
  // Check if already running
12
- const existing = getSession(name);
13
- if (existing && this.isProcessRunning(existing.pid)) {
14
- throw new Error(`Session "${name}" is already running`);
45
+ const existing = stateStore.getSession(name);
46
+ if (existing && processRunner.isProcessRunning(existing.pid)) {
47
+ log.warn(`Session "${name}" is already running (pid=${existing.pid})`);
48
+ throw new Error(`Session "${name}" is already running on port ${existing.port}.\n To view running sessions: ttyd-mux status\n To stop this session: ttyd-mux down ${name}`);
49
+ }
50
+ // Check if port is available
51
+ const portAvailable = await processRunner.isPortAvailable(port);
52
+ if (!portAvailable) {
53
+ log.error(`Port ${port} is already in use`);
54
+ throw new Error(`Port ${port} is already in use by another process.\n To find the process: lsof -i :${port}\n To stop all sessions: ttyd-mux shutdown`);
15
55
  }
56
+ // For auto mode, ensure tmux session exists before starting ttyd
57
+ if (tmuxMode === 'auto') {
58
+ log.debug(`Ensuring tmux session exists: ${name}`);
59
+ tmuxClient.ensureSession(name, dir);
60
+ }
61
+ // Get tmux command based on mode
62
+ const tmuxCmd = getTmuxCommand(name, tmuxMode);
63
+ const ttydArgs = ['-W', '-p', String(port), '-b', fullPath, ...tmuxCmd];
64
+ log.debug(`ttyd command: ttyd ${ttydArgs.join(' ')}`);
16
65
  // Start ttyd process
17
- const ttydProcess = spawn('ttyd', ['-W', '-p', String(port), '-b', fullPath, 'tmux', 'new', '-A', '-s', name], {
66
+ const ttydProcess = processRunner.spawn('ttyd', ttydArgs, {
18
67
  cwd: dir,
19
68
  detached: true,
20
69
  stdio: 'ignore'
21
70
  });
22
71
  ttydProcess.unref();
23
72
  if (!ttydProcess.pid) {
24
- throw new Error(`Failed to start ttyd for session "${name}"`);
73
+ log.error(`Failed to start ttyd for session "${name}"`);
74
+ throw new Error(`Failed to start ttyd for session "${name}".\n Possible causes:\n - ttyd is not installed\n - Directory "${dir}" does not exist\n - Permission denied\n Run 'ttyd-mux doctor' to check dependencies.`);
25
75
  }
76
+ log.info(`ttyd started: pid=${ttydProcess.pid}`);
26
77
  // Track the process
27
78
  this.runningProcesses.set(name, ttydProcess);
28
79
  // Proactive cleanup: listen for process exit
@@ -38,41 +89,40 @@ class SessionManager extends EventEmitter {
38
89
  dir,
39
90
  started_at: new Date().toISOString()
40
91
  };
41
- addSession(session);
92
+ stateStore.addSession(session);
42
93
  this.emit('session:start', session);
43
94
  return session;
44
95
  }
45
96
  stopSession(name) {
46
- const session = getSession(name);
97
+ const { stateStore, processRunner } = this.deps;
98
+ log.info(`Stopping session: ${name}`);
99
+ const session = stateStore.getSession(name);
47
100
  if (!session) {
48
- throw new Error(`Session "${name}" not found`);
101
+ log.warn(`Session "${name}" not found`);
102
+ throw new Error(`Session "${name}" not found.\n To view running sessions: ttyd-mux status`);
49
103
  }
50
104
  // Try to kill the process
51
105
  try {
52
- process.kill(session.pid, 'SIGTERM');
106
+ processRunner.kill(session.pid, 'SIGTERM');
107
+ log.info(`Sent SIGTERM to pid ${session.pid}`);
53
108
  }
54
- catch {
55
- // Process might already be dead
109
+ catch (err) {
110
+ log.debug(`Process ${session.pid} might already be dead: ${err}`);
56
111
  }
57
112
  // Clean up
58
113
  this.cleanup(name);
59
114
  this.emit('session:stop', name);
60
115
  }
61
116
  isProcessRunning(pid) {
62
- try {
63
- process.kill(pid, 0);
64
- return true;
65
- }
66
- catch {
67
- return false;
68
- }
117
+ return this.deps.processRunner.isProcessRunning(pid);
69
118
  }
70
119
  listSessions() {
71
- const sessions = getAllSessions();
120
+ const { stateStore, processRunner } = this.deps;
121
+ const sessions = stateStore.getAllSessions();
72
122
  // Filter out dead sessions (lazy cleanup for sessions started before daemon)
73
123
  const activeSessions = [];
74
124
  for (const session of sessions) {
75
- if (this.isProcessRunning(session.pid)) {
125
+ if (processRunner.isProcessRunning(session.pid)) {
76
126
  activeSessions.push(session);
77
127
  }
78
128
  else {
@@ -82,50 +132,76 @@ class SessionManager extends EventEmitter {
82
132
  return activeSessions;
83
133
  }
84
134
  stopAllSessions() {
135
+ log.info('Stopping all sessions');
85
136
  const sessions = this.listSessions();
86
137
  for (const session of sessions) {
87
138
  try {
88
139
  this.stopSession(session.name);
89
140
  }
90
- catch {
91
- // Ignore errors when stopping
141
+ catch (err) {
142
+ log.warn(`Error stopping session "${session.name}": ${err}`);
143
+ }
144
+ }
145
+ log.info(`Stopped ${sessions.length} sessions`);
146
+ }
147
+ /**
148
+ * Revalidate sessions after daemon restart.
149
+ * Checks if each session's ttyd process is still running.
150
+ * Removes dead sessions from state.
151
+ */
152
+ revalidateSessions() {
153
+ const { stateStore, processRunner } = this.deps;
154
+ const sessions = stateStore.getAllSessions();
155
+ const valid = [];
156
+ const removed = [];
157
+ for (const session of sessions) {
158
+ if (processRunner.isProcessRunning(session.pid)) {
159
+ valid.push(session);
160
+ log.debug(`Session "${session.name}" (pid=${session.pid}) is still running`);
161
+ }
162
+ else {
163
+ stateStore.removeSession(session.name);
164
+ removed.push(session.name);
165
+ log.info(`Session "${session.name}" (pid=${session.pid}) is dead, removed from state`);
92
166
  }
93
167
  }
168
+ return { valid, removed };
94
169
  }
95
170
  handleProcessExit(name, code) {
171
+ log.info(`Session "${name}" exited with code ${code}`);
96
172
  this.cleanup(name);
97
173
  this.emit('session:exit', name, code);
98
174
  }
99
175
  cleanup(name) {
176
+ log.debug(`Cleaning up session: ${name}`);
100
177
  this.runningProcesses.delete(name);
101
- removeSession(name);
178
+ this.deps.stateStore.removeSession(name);
102
179
  }
103
180
  }
104
- // Singleton instance
105
- const sessionManager = new SessionManager();
106
- // Export singleton methods for backward compatibility
107
- export function startSession(options) {
108
- return sessionManager.startSession(options);
109
- }
110
- export function stopSession(name) {
111
- sessionManager.stopSession(name);
112
- }
113
- export function isProcessRunning(pid) {
114
- return sessionManager.isProcessRunning(pid);
115
- }
116
- export function listSessions() {
117
- return sessionManager.listSessions();
118
- }
119
- export function stopAllSessions() {
120
- sessionManager.stopAllSessions();
121
- }
181
+ /**
182
+ * Shared session manager instance
183
+ */
184
+ export const sessionManager = new SessionManager();
185
+ /**
186
+ * Allocate next available port for a new session
187
+ */
122
188
  export function allocatePort(config) {
123
- return getNextPort(config.base_port);
189
+ return defaultStateStore.getNextPort(config.base_port);
124
190
  }
191
+ /**
192
+ * Extract session name from directory path
193
+ */
125
194
  export function sessionNameFromDir(dir) {
126
195
  const parts = dir.split('/');
127
196
  return parts[parts.length - 1] || 'default';
128
197
  }
129
- // Export the manager instance for direct event access
130
- export { sessionManager };
198
+ /**
199
+ * Create a SessionManager with custom dependencies (for testing)
200
+ */
201
+ export function createSessionManager(deps = {}) {
202
+ return new SessionManager({
203
+ ...defaultSessionManagerDeps,
204
+ ...deps
205
+ });
206
+ }
131
207
  //# sourceMappingURL=session-manager.js.map