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.
- package/.env.example +24 -0
- package/LICENSE +21 -0
- package/README.en.md +267 -0
- package/README.md +267 -0
- package/dist/adapters/backend/pty-backend.d.ts +13 -0
- package/dist/adapters/backend/pty-backend.d.ts.map +1 -0
- package/dist/adapters/backend/pty-backend.js +39 -0
- package/dist/adapters/backend/pty-backend.js.map +1 -0
- package/dist/adapters/backend/tmux-backend.d.ts +20 -0
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -0
- package/dist/adapters/backend/tmux-backend.js +30 -0
- package/dist/adapters/backend/tmux-backend.js.map +1 -0
- package/dist/adapters/backend/types.d.ts +19 -0
- package/dist/adapters/backend/types.d.ts.map +1 -0
- package/dist/adapters/backend/types.js +2 -0
- package/dist/adapters/backend/types.js.map +1 -0
- package/dist/adapters/cli/aiden.d.ts +4 -0
- package/dist/adapters/cli/aiden.d.ts.map +1 -0
- package/dist/adapters/cli/aiden.js +63 -0
- package/dist/adapters/cli/aiden.js.map +1 -0
- package/dist/adapters/cli/claude-code.d.ts +4 -0
- package/dist/adapters/cli/claude-code.d.ts.map +1 -0
- package/dist/adapters/cli/claude-code.js +59 -0
- package/dist/adapters/cli/claude-code.js.map +1 -0
- package/dist/adapters/cli/coco.d.ts +4 -0
- package/dist/adapters/cli/coco.d.ts.map +1 -0
- package/dist/adapters/cli/coco.js +46 -0
- package/dist/adapters/cli/coco.js.map +1 -0
- package/dist/adapters/cli/codex.d.ts +4 -0
- package/dist/adapters/cli/codex.d.ts.map +1 -0
- package/dist/adapters/cli/codex.js +47 -0
- package/dist/adapters/cli/codex.js.map +1 -0
- package/dist/adapters/cli/registry.d.ts +13 -0
- package/dist/adapters/cli/registry.d.ts.map +1 -0
- package/dist/adapters/cli/registry.js +42 -0
- package/dist/adapters/cli/registry.js.map +1 -0
- package/dist/adapters/cli/types.d.ts +39 -0
- package/dist/adapters/cli/types.d.ts.map +1 -0
- package/dist/adapters/cli/types.js +2 -0
- package/dist/adapters/cli/types.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +245 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/core/command-handler.d.ts +11 -0
- package/dist/core/command-handler.d.ts.map +1 -0
- package/dist/core/command-handler.js +322 -0
- package/dist/core/command-handler.js.map +1 -0
- package/dist/core/cost-calculator.d.ts +12 -0
- package/dist/core/cost-calculator.d.ts.map +1 -0
- package/dist/core/cost-calculator.js +61 -0
- package/dist/core/cost-calculator.js.map +1 -0
- package/dist/core/scheduler.d.ts +38 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +221 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/session-manager.d.ts +13 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +125 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/types.d.ts +29 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/worker-pool.d.ts +26 -0
- package/dist/core/worker-pool.d.ts.map +1 -0
- package/dist/core/worker-pool.js +261 -0
- package/dist/core/worker-pool.js.map +1 -0
- package/dist/daemon.d.ts +3 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +344 -0
- package/dist/daemon.js.map +1 -0
- package/dist/im/lark/card-builder.d.ts +18 -0
- package/dist/im/lark/card-builder.d.ts.map +1 -0
- package/dist/im/lark/card-builder.js +194 -0
- package/dist/im/lark/card-builder.js.map +1 -0
- package/dist/im/lark/card-handler.d.ts +9 -0
- package/dist/im/lark/card-handler.d.ts.map +1 -0
- package/dist/im/lark/card-handler.js +131 -0
- package/dist/im/lark/card-handler.js.map +1 -0
- package/dist/im/lark/client.d.ts +23 -0
- package/dist/im/lark/client.d.ts.map +1 -0
- package/dist/im/lark/client.js +259 -0
- package/dist/im/lark/client.js.map +1 -0
- package/dist/im/lark/event-dispatcher.d.ts +34 -0
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -0
- package/dist/im/lark/event-dispatcher.js +195 -0
- package/dist/im/lark/event-dispatcher.js.map +1 -0
- package/dist/im/lark/message-parser.d.ts +45 -0
- package/dist/im/lark/message-parser.d.ts.map +1 -0
- package/dist/im/lark/message-parser.js +132 -0
- package/dist/im/lark/message-parser.js.map +1 -0
- package/dist/im/types.d.ts +78 -0
- package/dist/im/types.d.ts.map +1 -0
- package/dist/im/types.js +2 -0
- package/dist/im/types.js.map +1 -0
- package/dist/index-daemon.d.ts +3 -0
- package/dist/index-daemon.d.ts.map +1 -0
- package/dist/index-daemon.js +21 -0
- package/dist/index-daemon.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/scheduler.d.ts +38 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +221 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +23 -0
- package/dist/server.js.map +1 -0
- package/dist/services/lark-client.d.ts +22 -0
- package/dist/services/lark-client.d.ts.map +1 -0
- package/dist/services/lark-client.js +238 -0
- package/dist/services/lark-client.js.map +1 -0
- package/dist/services/lark-ws.d.ts +5 -0
- package/dist/services/lark-ws.d.ts.map +1 -0
- package/dist/services/lark-ws.js +79 -0
- package/dist/services/lark-ws.js.map +1 -0
- package/dist/services/message-queue.d.ts +9 -0
- package/dist/services/message-queue.d.ts.map +1 -0
- package/dist/services/message-queue.js +77 -0
- package/dist/services/message-queue.js.map +1 -0
- package/dist/services/message-router.d.ts +8 -0
- package/dist/services/message-router.d.ts.map +1 -0
- package/dist/services/message-router.js +73 -0
- package/dist/services/message-router.js.map +1 -0
- package/dist/services/project-scanner.d.ts +12 -0
- package/dist/services/project-scanner.d.ts.map +1 -0
- package/dist/services/project-scanner.js +109 -0
- package/dist/services/project-scanner.js.map +1 -0
- package/dist/services/schedule-store.d.ts +14 -0
- package/dist/services/schedule-store.d.ts.map +1 -0
- package/dist/services/schedule-store.js +89 -0
- package/dist/services/schedule-store.js.map +1 -0
- package/dist/services/session-store.d.ts +8 -0
- package/dist/services/session-store.d.ts.map +1 -0
- package/dist/services/session-store.js +93 -0
- package/dist/services/session-store.js.map +1 -0
- package/dist/tools/close-session.d.ts +22 -0
- package/dist/tools/close-session.d.ts.map +1 -0
- package/dist/tools/close-session.js +38 -0
- package/dist/tools/close-session.js.map +1 -0
- package/dist/tools/create-session.d.ts +28 -0
- package/dist/tools/create-session.d.ts.map +1 -0
- package/dist/tools/create-session.js +40 -0
- package/dist/tools/create-session.js.map +1 -0
- package/dist/tools/get-thread-messages.d.ts +26 -0
- package/dist/tools/get-thread-messages.d.ts.map +1 -0
- package/dist/tools/get-thread-messages.js +33 -0
- package/dist/tools/get-thread-messages.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +10 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/react-to-message.d.ts +41 -0
- package/dist/tools/react-to-message.d.ts.map +1 -0
- package/dist/tools/react-to-message.js +30 -0
- package/dist/tools/react-to-message.js.map +1 -0
- package/dist/tools/send-to-thread.d.ts +24 -0
- package/dist/tools/send-to-thread.d.ts.map +1 -0
- package/dist/tools/send-to-thread.js +83 -0
- package/dist/tools/send-to-thread.js.map +1 -0
- package/dist/tools/wait-for-reply.d.ts +17 -0
- package/dist/tools/wait-for-reply.d.ts.map +1 -0
- package/dist/tools/wait-for-reply.js +65 -0
- package/dist/tools/wait-for-reply.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/card-builder.d.ts +16 -0
- package/dist/utils/card-builder.d.ts.map +1 -0
- package/dist/utils/card-builder.js +183 -0
- package/dist/utils/card-builder.js.map +1 -0
- package/dist/utils/idle-detector.d.ts +21 -0
- package/dist/utils/idle-detector.d.ts.map +1 -0
- package/dist/utils/idle-detector.js +95 -0
- package/dist/utils/idle-detector.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +22 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/message-parser.d.ts +45 -0
- package/dist/utils/message-parser.d.ts.map +1 -0
- package/dist/utils/message-parser.js +132 -0
- package/dist/utils/message-parser.js.map +1 -0
- package/dist/utils/terminal-renderer.d.ts +39 -0
- package/dist/utils/terminal-renderer.d.ts.map +1 -0
- package/dist/utils/terminal-renderer.js +186 -0
- package/dist/utils/terminal-renderer.js.map +1 -0
- package/dist/worker.d.ts +3 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +411 -0
- package/dist/worker.js.map +1 -0
- package/ecosystem.config.cjs +15 -0
- 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
|
+
}
|