botmux 1.0.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 (202) hide show
  1. package/.env.example +24 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +267 -0
  4. package/README.md +267 -0
  5. package/dist/adapters/backend/pty-backend.d.ts +13 -0
  6. package/dist/adapters/backend/pty-backend.d.ts.map +1 -0
  7. package/dist/adapters/backend/pty-backend.js +39 -0
  8. package/dist/adapters/backend/pty-backend.js.map +1 -0
  9. package/dist/adapters/backend/tmux-backend.d.ts +20 -0
  10. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -0
  11. package/dist/adapters/backend/tmux-backend.js +30 -0
  12. package/dist/adapters/backend/tmux-backend.js.map +1 -0
  13. package/dist/adapters/backend/types.d.ts +19 -0
  14. package/dist/adapters/backend/types.d.ts.map +1 -0
  15. package/dist/adapters/backend/types.js +2 -0
  16. package/dist/adapters/backend/types.js.map +1 -0
  17. package/dist/adapters/cli/aiden.d.ts +4 -0
  18. package/dist/adapters/cli/aiden.d.ts.map +1 -0
  19. package/dist/adapters/cli/aiden.js +63 -0
  20. package/dist/adapters/cli/aiden.js.map +1 -0
  21. package/dist/adapters/cli/claude-code.d.ts +4 -0
  22. package/dist/adapters/cli/claude-code.d.ts.map +1 -0
  23. package/dist/adapters/cli/claude-code.js +59 -0
  24. package/dist/adapters/cli/claude-code.js.map +1 -0
  25. package/dist/adapters/cli/coco.d.ts +4 -0
  26. package/dist/adapters/cli/coco.d.ts.map +1 -0
  27. package/dist/adapters/cli/coco.js +46 -0
  28. package/dist/adapters/cli/coco.js.map +1 -0
  29. package/dist/adapters/cli/codex.d.ts +4 -0
  30. package/dist/adapters/cli/codex.d.ts.map +1 -0
  31. package/dist/adapters/cli/codex.js +47 -0
  32. package/dist/adapters/cli/codex.js.map +1 -0
  33. package/dist/adapters/cli/registry.d.ts +13 -0
  34. package/dist/adapters/cli/registry.d.ts.map +1 -0
  35. package/dist/adapters/cli/registry.js +42 -0
  36. package/dist/adapters/cli/registry.js.map +1 -0
  37. package/dist/adapters/cli/types.d.ts +39 -0
  38. package/dist/adapters/cli/types.d.ts.map +1 -0
  39. package/dist/adapters/cli/types.js +2 -0
  40. package/dist/adapters/cli/types.js.map +1 -0
  41. package/dist/cli.d.ts +3 -0
  42. package/dist/cli.d.ts.map +1 -0
  43. package/dist/cli.js +245 -0
  44. package/dist/cli.js.map +1 -0
  45. package/dist/config.d.ts +24 -0
  46. package/dist/config.d.ts.map +1 -0
  47. package/dist/config.js +39 -0
  48. package/dist/config.js.map +1 -0
  49. package/dist/core/command-handler.d.ts +11 -0
  50. package/dist/core/command-handler.d.ts.map +1 -0
  51. package/dist/core/command-handler.js +322 -0
  52. package/dist/core/command-handler.js.map +1 -0
  53. package/dist/core/cost-calculator.d.ts +12 -0
  54. package/dist/core/cost-calculator.d.ts.map +1 -0
  55. package/dist/core/cost-calculator.js +61 -0
  56. package/dist/core/cost-calculator.js.map +1 -0
  57. package/dist/core/scheduler.d.ts +38 -0
  58. package/dist/core/scheduler.d.ts.map +1 -0
  59. package/dist/core/scheduler.js +221 -0
  60. package/dist/core/scheduler.js.map +1 -0
  61. package/dist/core/session-manager.d.ts +13 -0
  62. package/dist/core/session-manager.d.ts.map +1 -0
  63. package/dist/core/session-manager.js +125 -0
  64. package/dist/core/session-manager.js.map +1 -0
  65. package/dist/core/types.d.ts +29 -0
  66. package/dist/core/types.d.ts.map +1 -0
  67. package/dist/core/types.js +2 -0
  68. package/dist/core/types.js.map +1 -0
  69. package/dist/core/worker-pool.d.ts +26 -0
  70. package/dist/core/worker-pool.d.ts.map +1 -0
  71. package/dist/core/worker-pool.js +261 -0
  72. package/dist/core/worker-pool.js.map +1 -0
  73. package/dist/daemon.d.ts +3 -0
  74. package/dist/daemon.d.ts.map +1 -0
  75. package/dist/daemon.js +344 -0
  76. package/dist/daemon.js.map +1 -0
  77. package/dist/im/lark/card-builder.d.ts +18 -0
  78. package/dist/im/lark/card-builder.d.ts.map +1 -0
  79. package/dist/im/lark/card-builder.js +194 -0
  80. package/dist/im/lark/card-builder.js.map +1 -0
  81. package/dist/im/lark/card-handler.d.ts +9 -0
  82. package/dist/im/lark/card-handler.d.ts.map +1 -0
  83. package/dist/im/lark/card-handler.js +131 -0
  84. package/dist/im/lark/card-handler.js.map +1 -0
  85. package/dist/im/lark/client.d.ts +23 -0
  86. package/dist/im/lark/client.d.ts.map +1 -0
  87. package/dist/im/lark/client.js +259 -0
  88. package/dist/im/lark/client.js.map +1 -0
  89. package/dist/im/lark/event-dispatcher.d.ts +34 -0
  90. package/dist/im/lark/event-dispatcher.d.ts.map +1 -0
  91. package/dist/im/lark/event-dispatcher.js +195 -0
  92. package/dist/im/lark/event-dispatcher.js.map +1 -0
  93. package/dist/im/lark/message-parser.d.ts +45 -0
  94. package/dist/im/lark/message-parser.d.ts.map +1 -0
  95. package/dist/im/lark/message-parser.js +132 -0
  96. package/dist/im/lark/message-parser.js.map +1 -0
  97. package/dist/im/types.d.ts +78 -0
  98. package/dist/im/types.d.ts.map +1 -0
  99. package/dist/im/types.js +2 -0
  100. package/dist/im/types.js.map +1 -0
  101. package/dist/index-daemon.d.ts +3 -0
  102. package/dist/index-daemon.d.ts.map +1 -0
  103. package/dist/index-daemon.js +21 -0
  104. package/dist/index-daemon.js.map +1 -0
  105. package/dist/index.d.ts +3 -0
  106. package/dist/index.d.ts.map +1 -0
  107. package/dist/index.js +16 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/scheduler.d.ts +38 -0
  110. package/dist/scheduler.d.ts.map +1 -0
  111. package/dist/scheduler.js +221 -0
  112. package/dist/scheduler.js.map +1 -0
  113. package/dist/server.d.ts +3 -0
  114. package/dist/server.d.ts.map +1 -0
  115. package/dist/server.js +23 -0
  116. package/dist/server.js.map +1 -0
  117. package/dist/services/lark-client.d.ts +22 -0
  118. package/dist/services/lark-client.d.ts.map +1 -0
  119. package/dist/services/lark-client.js +238 -0
  120. package/dist/services/lark-client.js.map +1 -0
  121. package/dist/services/lark-ws.d.ts +5 -0
  122. package/dist/services/lark-ws.d.ts.map +1 -0
  123. package/dist/services/lark-ws.js +79 -0
  124. package/dist/services/lark-ws.js.map +1 -0
  125. package/dist/services/message-queue.d.ts +9 -0
  126. package/dist/services/message-queue.d.ts.map +1 -0
  127. package/dist/services/message-queue.js +77 -0
  128. package/dist/services/message-queue.js.map +1 -0
  129. package/dist/services/message-router.d.ts +8 -0
  130. package/dist/services/message-router.d.ts.map +1 -0
  131. package/dist/services/message-router.js +73 -0
  132. package/dist/services/message-router.js.map +1 -0
  133. package/dist/services/project-scanner.d.ts +12 -0
  134. package/dist/services/project-scanner.d.ts.map +1 -0
  135. package/dist/services/project-scanner.js +109 -0
  136. package/dist/services/project-scanner.js.map +1 -0
  137. package/dist/services/schedule-store.d.ts +14 -0
  138. package/dist/services/schedule-store.d.ts.map +1 -0
  139. package/dist/services/schedule-store.js +89 -0
  140. package/dist/services/schedule-store.js.map +1 -0
  141. package/dist/services/session-store.d.ts +8 -0
  142. package/dist/services/session-store.d.ts.map +1 -0
  143. package/dist/services/session-store.js +93 -0
  144. package/dist/services/session-store.js.map +1 -0
  145. package/dist/tools/close-session.d.ts +22 -0
  146. package/dist/tools/close-session.d.ts.map +1 -0
  147. package/dist/tools/close-session.js +38 -0
  148. package/dist/tools/close-session.js.map +1 -0
  149. package/dist/tools/create-session.d.ts +28 -0
  150. package/dist/tools/create-session.d.ts.map +1 -0
  151. package/dist/tools/create-session.js +40 -0
  152. package/dist/tools/create-session.js.map +1 -0
  153. package/dist/tools/get-thread-messages.d.ts +26 -0
  154. package/dist/tools/get-thread-messages.d.ts.map +1 -0
  155. package/dist/tools/get-thread-messages.js +33 -0
  156. package/dist/tools/get-thread-messages.js.map +1 -0
  157. package/dist/tools/index.d.ts +9 -0
  158. package/dist/tools/index.d.ts.map +1 -0
  159. package/dist/tools/index.js +10 -0
  160. package/dist/tools/index.js.map +1 -0
  161. package/dist/tools/react-to-message.d.ts +41 -0
  162. package/dist/tools/react-to-message.d.ts.map +1 -0
  163. package/dist/tools/react-to-message.js +30 -0
  164. package/dist/tools/react-to-message.js.map +1 -0
  165. package/dist/tools/send-to-thread.d.ts +24 -0
  166. package/dist/tools/send-to-thread.d.ts.map +1 -0
  167. package/dist/tools/send-to-thread.js +83 -0
  168. package/dist/tools/send-to-thread.js.map +1 -0
  169. package/dist/tools/wait-for-reply.d.ts +17 -0
  170. package/dist/tools/wait-for-reply.d.ts.map +1 -0
  171. package/dist/tools/wait-for-reply.js +65 -0
  172. package/dist/tools/wait-for-reply.js.map +1 -0
  173. package/dist/types.d.ts +85 -0
  174. package/dist/types.d.ts.map +1 -0
  175. package/dist/types.js +6 -0
  176. package/dist/types.js.map +1 -0
  177. package/dist/utils/card-builder.d.ts +16 -0
  178. package/dist/utils/card-builder.d.ts.map +1 -0
  179. package/dist/utils/card-builder.js +183 -0
  180. package/dist/utils/card-builder.js.map +1 -0
  181. package/dist/utils/idle-detector.d.ts +21 -0
  182. package/dist/utils/idle-detector.d.ts.map +1 -0
  183. package/dist/utils/idle-detector.js +95 -0
  184. package/dist/utils/idle-detector.js.map +1 -0
  185. package/dist/utils/logger.d.ts +7 -0
  186. package/dist/utils/logger.d.ts.map +1 -0
  187. package/dist/utils/logger.js +22 -0
  188. package/dist/utils/logger.js.map +1 -0
  189. package/dist/utils/message-parser.d.ts +45 -0
  190. package/dist/utils/message-parser.d.ts.map +1 -0
  191. package/dist/utils/message-parser.js +132 -0
  192. package/dist/utils/message-parser.js.map +1 -0
  193. package/dist/utils/terminal-renderer.d.ts +39 -0
  194. package/dist/utils/terminal-renderer.d.ts.map +1 -0
  195. package/dist/utils/terminal-renderer.js +186 -0
  196. package/dist/utils/terminal-renderer.js.map +1 -0
  197. package/dist/worker.d.ts +3 -0
  198. package/dist/worker.d.ts.map +1 -0
  199. package/dist/worker.js +411 -0
  200. package/dist/worker.js.map +1 -0
  201. package/ecosystem.config.cjs +15 -0
  202. package/package.json +60 -0
package/dist/worker.js ADDED
@@ -0,0 +1,411 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Worker process: manages a single Claude Code PTY session + web terminal.
4
+ * Forked by the daemon, communicates via Node.js IPC.
5
+ *
6
+ * Lifecycle:
7
+ * 1. Daemon forks this process
8
+ * 2. Receives 'init' message with session config
9
+ * 3. Spawns CLI via CliAdapter + PtyBackend (interactive mode)
10
+ * 4. Starts HTTP + WebSocket server for xterm.js
11
+ * 5. Receives 'message' events from daemon, writes to PTY stdin
12
+ * 6. On 'close', kills Claude and exits
13
+ * 7. On 'restart', kills Claude and re-spawns with --resume
14
+ */
15
+ import { randomBytes } from 'node:crypto';
16
+ import { createServer as createHttpServer } from 'node:http';
17
+ import { WebSocketServer, WebSocket } from 'ws';
18
+ import { TerminalRenderer } from './utils/terminal-renderer.js';
19
+ import { createCliAdapterSync } from './adapters/cli/registry.js';
20
+ import { PtyBackend } from './adapters/backend/pty-backend.js';
21
+ import { IdleDetector } from './utils/idle-detector.js';
22
+ // ─── State ───────────────────────────────────────────────────────────────────
23
+ let cliAdapter = null;
24
+ let backend = null;
25
+ let idleDetector = null;
26
+ let httpServer = null;
27
+ let wss = null;
28
+ const wsClients = new Set();
29
+ const authedClients = new WeakSet();
30
+ const writeToken = randomBytes(16).toString('hex');
31
+ let sessionId = '';
32
+ let lastInitConfig = null;
33
+ let isPromptReady = false;
34
+ const pendingMessages = [];
35
+ /** Suppress screen updates until first prompt detected (avoids history replay in card on --resume) */
36
+ let awaitingFirstPrompt = true;
37
+ // ─── PTY Dimensions ──────────────────────────────────────────────────────────
38
+ // Wide PTY so Claude Code positions right-aligned TUI overlays (timer, timeout)
39
+ // far to the right. The snapshot reader only reads the first 160 columns,
40
+ // cleanly excluding overlays without any regex hacking.
41
+ const PTY_COLS = 300;
42
+ const PTY_ROWS = 50;
43
+ // ─── Headless Terminal for Screen Capture ────────────────────────────────────
44
+ let renderer = null;
45
+ let screenUpdateTimer = null;
46
+ const SCREEN_UPDATE_INTERVAL_MS = 2_000;
47
+ // ─── Scrollback Buffer (replay to late-connecting WS clients) ───────────────
48
+ const MAX_SCROLLBACK = 100_000; // chars
49
+ let scrollback = '';
50
+ // ─── Trust Dialog Detection ──────────────────────────────────────────────────
51
+ // Claude Code: "Yes, I trust this folder"
52
+ // Codex: "› 1. Yes, continue 2. No, quit" (ANSI cursor codes strip spaces from
53
+ // longer phrases like "Do you trust…", but "Yes, continue" survives intact
54
+ // in a single PTY chunk)
55
+ const TRUST_DIALOG_PATTERN = /Yes, I trust this folder|Yes, continue/;
56
+ let trustHandled = false;
57
+ // ─── Prompt Detection ────────────────────────────────────────────────────────
58
+ function onPtyData(data) {
59
+ renderer?.write(data);
60
+ scrollback += data;
61
+ if (scrollback.length > MAX_SCROLLBACK) {
62
+ scrollback = scrollback.slice(-MAX_SCROLLBACK);
63
+ }
64
+ for (const ws of wsClients) {
65
+ if (ws.readyState === WebSocket.OPEN)
66
+ ws.send(data);
67
+ }
68
+ // Trust dialog auto-accept
69
+ if (!trustHandled) {
70
+ const stripped = data.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
71
+ if (TRUST_DIALOG_PATTERN.test(stripped)) {
72
+ trustHandled = true;
73
+ log('Trust dialog detected, auto-accepting...');
74
+ backend?.write('\r');
75
+ return;
76
+ }
77
+ }
78
+ // Delegate idle detection to IdleDetector
79
+ idleDetector?.feed(data);
80
+ }
81
+ function markPromptReady() {
82
+ if (isPromptReady)
83
+ return; // guard against duplicate calls
84
+ isPromptReady = true;
85
+ if (awaitingFirstPrompt) {
86
+ awaitingFirstPrompt = false;
87
+ renderer?.markNewTurn(); // exclude history replay from streaming card
88
+ }
89
+ send({ type: 'prompt_ready' });
90
+ // Send immediate idle snapshot so Lark card reflects idle status
91
+ if (renderer) {
92
+ const { content } = renderer.snapshot();
93
+ send({ type: 'screen_update', content, status: 'idle' });
94
+ }
95
+ flushPending();
96
+ }
97
+ function flushPending() {
98
+ log(`flushPending: ${pendingMessages.length} pending, promptReady=${isPromptReady}, hasPty=${!!backend}`);
99
+ while (pendingMessages.length > 0 && isPromptReady && backend && cliAdapter) {
100
+ const msg = pendingMessages.shift();
101
+ isPromptReady = false;
102
+ idleDetector?.reset();
103
+ log(`Writing to PTY (flush): "${msg.substring(0, 80)}"`);
104
+ // Fire-and-forget: Aiden's delayed writes are internal to the adapter.
105
+ // Idle detector re-arms on next PTY output, not on write completion.
106
+ cliAdapter.writeInput(backend, msg);
107
+ }
108
+ }
109
+ function sendToPty(content) {
110
+ if (!backend || !cliAdapter)
111
+ return;
112
+ if (isPromptReady) {
113
+ isPromptReady = false;
114
+ idleDetector?.reset();
115
+ log(`Writing to PTY: "${content.substring(0, 80)}"`);
116
+ cliAdapter.writeInput(backend, content);
117
+ }
118
+ else {
119
+ pendingMessages.push(content);
120
+ log(`Queued message (${pendingMessages.length} pending): "${content.substring(0, 80)}" — Claude is busy`);
121
+ }
122
+ }
123
+ // ─── Screen Update Timer ─────────────────────────────────────────────────────
124
+ function startScreenUpdates() {
125
+ renderer = new TerminalRenderer(PTY_COLS, PTY_ROWS);
126
+ screenUpdateTimer = setInterval(() => {
127
+ if (!renderer || awaitingFirstPrompt)
128
+ return;
129
+ const { content, changed } = renderer.snapshot();
130
+ if (changed) {
131
+ send({ type: 'screen_update', content, status: isPromptReady ? 'idle' : 'working' });
132
+ }
133
+ }, SCREEN_UPDATE_INTERVAL_MS);
134
+ }
135
+ function stopScreenUpdates() {
136
+ if (screenUpdateTimer) {
137
+ clearInterval(screenUpdateTimer);
138
+ screenUpdateTimer = null;
139
+ }
140
+ if (renderer) {
141
+ renderer.dispose();
142
+ renderer = null;
143
+ }
144
+ }
145
+ // ─── PTY Management ──────────────────────────────────────────────────────────
146
+ function spawnClaude(cfg) {
147
+ cliAdapter = createCliAdapterSync(cfg.cliId, cfg.cliPathOverride);
148
+ backend = new PtyBackend();
149
+ const args = cliAdapter.buildArgs({
150
+ sessionId: cfg.sessionId,
151
+ resume: cfg.resume ?? false,
152
+ });
153
+ // Extra args from env (CLI_DISABLE_DEFAULT_ARGS is removed — adapters own their defaults)
154
+ const extra = (process.env.CLI_EXTRA_ARGS ?? '').trim();
155
+ if (extra)
156
+ args.push(...extra.split(/\s+/).filter(Boolean));
157
+ log(`Spawning: ${cliAdapter.resolvedBin} ${args.join(' ')} (cwd: ${cfg.workingDir})`);
158
+ backend.spawn(cliAdapter.resolvedBin, args, {
159
+ cwd: cfg.workingDir,
160
+ cols: PTY_COLS,
161
+ rows: PTY_ROWS,
162
+ env: { ...process.env, CLAUDECODE: undefined },
163
+ });
164
+ // Set up idle detection
165
+ idleDetector = new IdleDetector(cliAdapter);
166
+ idleDetector.onIdle(() => {
167
+ log('Prompt detected (idle)');
168
+ markPromptReady();
169
+ });
170
+ backend.onData(onPtyData);
171
+ backend.onExit((code, signal) => {
172
+ log(`Claude exited (code: ${code}, signal: ${signal})`);
173
+ backend = null;
174
+ isPromptReady = false;
175
+ send({ type: 'claude_exit', code, signal });
176
+ });
177
+ }
178
+ function killClaude() {
179
+ idleDetector?.dispose();
180
+ idleDetector = null;
181
+ stopScreenUpdates();
182
+ backend?.kill();
183
+ backend = null;
184
+ isPromptReady = false;
185
+ pendingMessages.length = 0;
186
+ scrollback = '';
187
+ trustHandled = false;
188
+ }
189
+ // ─── HTTP + WebSocket Server ─────────────────────────────────────────────────
190
+ function startWebServer(host) {
191
+ return new Promise((resolve, reject) => {
192
+ httpServer = createHttpServer((_req, res) => {
193
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
194
+ res.end(getTerminalHtml());
195
+ });
196
+ wss = new WebSocketServer({ server: httpServer });
197
+ wss.on('connection', (ws, req) => {
198
+ wsClients.add(ws);
199
+ // Check token from query string for write access
200
+ const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
201
+ const hasWrite = url.searchParams.get('token') === writeToken;
202
+ if (hasWrite)
203
+ authedClients.add(ws);
204
+ log(`WS client connected (total: ${wsClients.size}, write: ${hasWrite})`);
205
+ // Replay scrollback buffer so late-connecting clients see existing output
206
+ if (scrollback.length > 0) {
207
+ ws.send(scrollback);
208
+ }
209
+ ws.on('message', (raw) => {
210
+ try {
211
+ const msg = JSON.parse(String(raw));
212
+ if (msg.type === 'resize' && msg.cols > 0 && msg.rows > 0) {
213
+ backend?.resize(msg.cols, msg.rows);
214
+ }
215
+ else if (msg.type === 'input' && typeof msg.data === 'string') {
216
+ if (!authedClients.has(ws))
217
+ return; // read-only
218
+ backend?.write(msg.data);
219
+ }
220
+ }
221
+ catch { /* ignore non-JSON or bad messages */ }
222
+ });
223
+ ws.on('close', () => {
224
+ wsClients.delete(ws);
225
+ });
226
+ });
227
+ httpServer.listen(0, host, () => {
228
+ const addr = httpServer.address();
229
+ const port = typeof addr === 'object' && addr ? addr.port : 0;
230
+ log(`HTTP listening on ${host}:${port}`);
231
+ resolve(port);
232
+ });
233
+ httpServer.on('error', reject);
234
+ });
235
+ }
236
+ function getTerminalHtml() {
237
+ const label = sessionId.substring(0, 8);
238
+ return `<!DOCTYPE html>
239
+ <html>
240
+ <head>
241
+ <meta charset="utf-8">
242
+ <meta id="vp" name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
243
+ <title>Claude Code - ${label}</title>
244
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5/css/xterm.min.css">
245
+ <style>
246
+ *{margin:0;padding:0;box-sizing:border-box}
247
+ html,body{height:100%;background:#1a1b26;overflow:hidden}
248
+ body{display:flex;flex-direction:column}
249
+ #input-bar{display:none;padding:3px 6px;background:#15161e;border-bottom:1px solid #33467c;
250
+ gap:6px;align-items:flex-end}
251
+ #input-bar.show{display:flex}
252
+ #input-bar textarea{flex:1;background:#24283b;color:#a9b1d6;border:1px solid #33467c;
253
+ border-radius:4px;padding:4px 8px;font-size:14px;outline:none;resize:none;
254
+ font-family:-apple-system,sans-serif;line-height:1.3;max-height:72px;overflow-y:auto}
255
+ #input-bar textarea:focus{border-color:#7aa2f7}
256
+ #input-bar button{background:#7aa2f7;color:#1a1b26;border:none;border-radius:4px;
257
+ padding:5px 12px;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap}
258
+ #input-bar button:active{opacity:0.7}
259
+ #terminal{flex:1;min-height:0}
260
+ #terminal .xterm{height:100%}
261
+ #status{position:fixed;top:8px;right:12px;z-index:10;font:12px monospace;
262
+ color:#565f89;background:#1a1b26cc;padding:2px 8px;border-radius:4px}
263
+ #status.ok{color:#9ece6a}
264
+ #status.err{color:#f7768e}
265
+ </style>
266
+ </head>
267
+ <body>
268
+ <div id="input-bar">
269
+ <textarea id="mi" rows="1" placeholder="输入消息..." autocomplete="off" autocorrect="off"></textarea>
270
+ <button id="ms">发送</button>
271
+ </div>
272
+ <div id="terminal"></div>
273
+ <div id="status" class="err">connecting...</div>
274
+ <script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5/lib/xterm.min.js"></script>
275
+ <script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0/lib/addon-fit.min.js"></script>
276
+ <script src="https://cdn.jsdelivr.net/npm/@xterm/addon-web-links@0/lib/addon-web-links.min.js"></script>
277
+ <script src="https://cdn.jsdelivr.net/npm/@xterm/addon-unicode11@0/lib/addon-unicode11.min.js"></script>
278
+ <script>
279
+ var isTouch='ontouchstart'in window||navigator.maxTouchPoints>0;
280
+ if(isTouch)document.getElementById('vp').content='width=1100,viewport-fit=cover';
281
+
282
+ var term=new Terminal({
283
+ theme:{background:'#1a1b26',foreground:'#a9b1d6',cursor:'#c0caf5',
284
+ selectionBackground:'#33467c',black:'#15161e',red:'#f7768e',
285
+ green:'#9ece6a',yellow:'#e0af68',blue:'#7aa2f7',magenta:'#bb9af7',
286
+ cyan:'#7dcfff',white:'#a9b1d6'},
287
+ fontSize:14,fontFamily:"'JetBrains Mono','Fira Code',monospace",
288
+ cursorBlink:!isTouch,disableStdin:isTouch,scrollback:50000,allowProposedApi:true
289
+ });
290
+ var fit=new FitAddon.FitAddon();
291
+ term.loadAddon(fit);
292
+ term.loadAddon(new WebLinksAddon.WebLinksAddon());
293
+ term.loadAddon(new Unicode11Addon.Unicode11Addon());
294
+ term.unicode.activeVersion='11';
295
+ term.open(document.getElementById('terminal'));
296
+ fit.fit();
297
+
298
+ // ── WebSocket ──
299
+ var ws_=null,el=document.getElementById('status');
300
+ term.onData(function(d){if(ws_&&ws_.readyState===1)ws_.send(JSON.stringify({type:'input',data:d}))});
301
+ function sendResize(){if(ws_&&ws_.readyState===1)ws_.send(JSON.stringify({type:'resize',cols:term.cols,rows:term.rows}))}
302
+ window.addEventListener('resize',function(){fit.fit();sendResize()});
303
+ (function connect(){
304
+ var t=new URLSearchParams(location.search).get('token')||'';
305
+ var ws=new WebSocket('ws://'+location.host+'/?token='+t);
306
+ ws_=ws;ws.binaryType='arraybuffer';
307
+ ws.onopen=function(){el.textContent='connected';el.className='ok';sendResize()};
308
+ ws.onmessage=function(e){term.write(typeof e.data==='string'?e.data:new TextDecoder().decode(e.data))};
309
+ ws.onclose=function(){ws_=null;el.textContent='disconnected';el.className='err';setTimeout(connect,2000)};
310
+ ws.onerror=function(){ws.close()};
311
+ })();
312
+
313
+ // ── Mobile input bar (top) ──
314
+ if(isTouch){
315
+ var bar=document.getElementById('input-bar'),mi=document.getElementById('mi'),ms=document.getElementById('ms');
316
+ bar.classList.add('show');
317
+ function send(){
318
+ var v=mi.value;if(!v||!ws_||ws_.readyState!==1)return;
319
+ ws_.send(JSON.stringify({type:'input',data:v+String.fromCharCode(13)}));
320
+ mi.value='';mi.style.height='auto';
321
+ fit.fit();sendResize();
322
+ }
323
+ mi.addEventListener('input',function(){this.style.height='auto';this.style.height=Math.min(this.scrollHeight,72)+'px';fit.fit()});
324
+ ms.addEventListener('click',send);
325
+ }
326
+ </script>
327
+ </body>
328
+ </html>`;
329
+ }
330
+ // ─── IPC Communication ───────────────────────────────────────────────────────
331
+ function send(msg) {
332
+ process.send?.(msg);
333
+ }
334
+ function log(msg) {
335
+ const ts = new Date().toISOString();
336
+ process.stdout.write(`[${ts}] [worker:${sessionId.substring(0, 8) || '??'}] ${msg}\n`);
337
+ }
338
+ // ─── IPC Message Handler ─────────────────────────────────────────────────────
339
+ process.on('message', async (raw) => {
340
+ const msg = raw;
341
+ switch (msg.type) {
342
+ case 'init': {
343
+ if (lastInitConfig)
344
+ return; // already initialized
345
+ lastInitConfig = msg;
346
+ sessionId = msg.sessionId;
347
+ if (msg.ownerOpenId)
348
+ process.env.__OWNER_OPEN_ID = msg.ownerOpenId;
349
+ log(`Init: session=${sessionId}, cwd=${msg.workingDir}`);
350
+ try {
351
+ const port = await startWebServer('0.0.0.0');
352
+ startScreenUpdates();
353
+ spawnClaude(msg);
354
+ // Queue the initial prompt — flushed when Claude shows ❯
355
+ if (msg.prompt) {
356
+ pendingMessages.push(msg.prompt);
357
+ }
358
+ send({ type: 'ready', port, token: writeToken });
359
+ }
360
+ catch (err) {
361
+ send({ type: 'error', message: `init failed: ${err.message}` });
362
+ process.exit(1);
363
+ }
364
+ break;
365
+ }
366
+ case 'message': {
367
+ // Mark new turn baseline so the streaming card only shows this turn's content
368
+ renderer?.markNewTurn();
369
+ sendToPty(msg.content);
370
+ break;
371
+ }
372
+ case 'restart': {
373
+ log('Restart requested');
374
+ killClaude();
375
+ awaitingFirstPrompt = true;
376
+ setTimeout(() => {
377
+ if (lastInitConfig) {
378
+ startScreenUpdates();
379
+ spawnClaude({ ...lastInitConfig, resume: true, prompt: '' });
380
+ }
381
+ }, 500);
382
+ break;
383
+ }
384
+ case 'close': {
385
+ log('Close requested');
386
+ killClaude();
387
+ cleanup();
388
+ process.exit(0);
389
+ }
390
+ }
391
+ });
392
+ // ─── Cleanup ─────────────────────────────────────────────────────────────────
393
+ function cleanup() {
394
+ for (const ws of wsClients)
395
+ ws.close();
396
+ wsClients.clear();
397
+ if (wss) {
398
+ wss.close();
399
+ wss = null;
400
+ }
401
+ if (httpServer) {
402
+ httpServer.close();
403
+ httpServer = null;
404
+ }
405
+ }
406
+ process.on('SIGTERM', () => { killClaude(); cleanup(); process.exit(0); });
407
+ process.on('SIGINT', () => { killClaude(); cleanup(); process.exit(0); });
408
+ // If parent daemon dies, IPC channel closes — clean up
409
+ process.on('disconnect', () => { log('Daemon disconnected'); killClaude(); cleanup(); process.exit(0); });
410
+ log('Worker started, waiting for init...');
411
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ module.exports = {
2
+ apps: [
3
+ {
4
+ name: 'botmux',
5
+ script: 'dist/index-daemon.js',
6
+ cwd: __dirname,
7
+ autorestart: true,
8
+ max_restarts: 10,
9
+ restart_delay: 3000,
10
+ error_file: 'data/logs/daemon.log',
11
+ out_file: '/dev/null',
12
+ merge_logs: true,
13
+ },
14
+ ],
15
+ };
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "botmux",
3
+ "version": "1.0.0",
4
+ "description": "Bridge between IM platforms and AI coding CLIs — one topic, one CLI session with live streaming",
5
+ "type": "module",
6
+ "main": "dist/index-daemon.js",
7
+ "bin": {
8
+ "botmux": "dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "ecosystem.config.cjs",
13
+ ".env.example",
14
+ "README.md",
15
+ "README.en.md",
16
+ "LICENSE"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "daemon": "tsx src/index-daemon.ts",
21
+ "daemon:start": "pm2 start ecosystem.config.cjs",
22
+ "daemon:stop": "pm2 stop botmux",
23
+ "daemon:restart": "pm2 restart botmux",
24
+ "daemon:logs": "pm2 logs botmux",
25
+ "daemon:status": "pm2 status botmux",
26
+ "test": "vitest run",
27
+ "test:codex": "vitest run test/codex-input.e2e.ts",
28
+ "test:mcp": "vitest run test/codex-mcp.e2e.ts",
29
+ "test:claude-mcp": "vitest run test/claude-code-mcp.e2e.ts",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "dependencies": {
33
+ "@larksuiteoapi/node-sdk": "^1.59.0",
34
+ "@modelcontextprotocol/sdk": "^1.18.1",
35
+ "@xterm/addon-unicode11": "^0.9.0",
36
+ "@xterm/headless": "^6.0.0",
37
+ "croner": "^10.0.1",
38
+ "dotenv": "^17.3.1",
39
+ "node-pty": "^1.1.0",
40
+ "pm2": "^6.0.0",
41
+ "ws": "^8.19.0",
42
+ "zod": "^3.23.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^20.0.0",
46
+ "@types/ws": "^8.18.1",
47
+ "tsx": "^4.20.5",
48
+ "typescript": "^5.3.0",
49
+ "vitest": "^4.0.18"
50
+ },
51
+ "pnpm": {
52
+ "onlyBuiltDependencies": [
53
+ "node-pty"
54
+ ]
55
+ },
56
+ "engines": {
57
+ "node": ">=20"
58
+ },
59
+ "license": "MIT"
60
+ }