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
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Worker pool — manages forking, killing, and lifecycle of worker processes.
3
+ * Extracted from daemon.ts for modularity.
4
+ */
5
+ import { fork } from 'node:child_process';
6
+ import { join, dirname } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { config } from '../config.js';
9
+ import * as sessionStore from '../services/session-store.js';
10
+ import { updateMessage } from '../im/lark/client.js';
11
+ import { buildStreamingCard, buildSessionCard } from '../im/lark/card-builder.js';
12
+ import { logger } from '../utils/logger.js';
13
+ import { createCliAdapterSync } from '../adapters/cli/registry.js';
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
16
+ let callbacks;
17
+ /**
18
+ * Initialise worker-pool callbacks. Must be called once before forkWorker().
19
+ */
20
+ export function initWorkerPool(cb) {
21
+ callbacks = cb;
22
+ }
23
+ function requireCallbacks() {
24
+ if (!callbacks)
25
+ throw new Error('WorkerPool not initialised — call initWorkerPool() first');
26
+ return callbacks;
27
+ }
28
+ // ─── Helpers ────────────────────────────────────────────────────────────────
29
+ function tag(ds) {
30
+ return ds.session.sessionId.substring(0, 8);
31
+ }
32
+ // ─── Restart rate-limiting ──────────────────────────────────────────────────
33
+ export const restartCounts = new Map();
34
+ // ─── MCP config ─────────────────────────────────────────────────────────────
35
+ /** Track whether ensureMcpConfig has run this daemon lifecycle */
36
+ let mcpConfigDone = false;
37
+ /**
38
+ * Ensure the botmux MCP server is registered globally.
39
+ * Delegates to the CLI adapter which knows the correct config file location.
40
+ */
41
+ export function ensureMcpConfig() {
42
+ const adapter = createCliAdapterSync(config.daemon.cliId, config.daemon.cliPathOverride);
43
+ // Resolve path relative to src/ (one level up from core/)
44
+ const serverScript = join(__dirname, '..', 'index.js');
45
+ adapter.ensureMcpConfig({
46
+ name: 'botmux',
47
+ command: 'node',
48
+ args: [serverScript],
49
+ env: {
50
+ LARK_APP_ID: config.lark.appId,
51
+ LARK_APP_SECRET: config.lark.appSecret,
52
+ SESSION_DATA_DIR: config.session.dataDir,
53
+ },
54
+ });
55
+ }
56
+ // ─── Kill worker ────────────────────────────────────────────────────────────
57
+ export function killWorker(ds) {
58
+ if (!ds.worker || ds.worker.killed)
59
+ return;
60
+ try {
61
+ ds.worker.send({ type: 'close' });
62
+ }
63
+ catch { /* IPC already closed */ }
64
+ // Give worker 2s to clean up, then force kill
65
+ const w = ds.worker;
66
+ setTimeout(() => { if (!w.killed)
67
+ w.kill('SIGTERM'); }, 2000);
68
+ ds.worker = null;
69
+ ds.workerPort = null;
70
+ ds.workerToken = null;
71
+ }
72
+ // ─── Fork worker ────────────────────────────────────────────────────────────
73
+ export function forkWorker(ds, prompt, resume = false) {
74
+ const cb = requireCallbacks();
75
+ // worker.js lives in the same directory as daemon.js (src/)
76
+ const workerPath = join(__dirname, '..', 'worker.js');
77
+ const cwd = cb.getSessionWorkingDir(ds);
78
+ const t = tag(ds);
79
+ // Guard against double-fork: if a worker is already running, kill it first
80
+ if (ds.worker && !ds.worker.killed) {
81
+ logger.warn(`[${t}] Worker already running (pid: ${ds.worker.pid}), killing before re-fork`);
82
+ try {
83
+ ds.worker.send({ type: 'close' });
84
+ }
85
+ catch { /* ignore */ }
86
+ try {
87
+ ds.worker.kill();
88
+ }
89
+ catch { /* ignore */ }
90
+ ds.worker = null;
91
+ ds.workerPort = null;
92
+ ds.workerToken = null;
93
+ }
94
+ if (!mcpConfigDone) {
95
+ ensureMcpConfig();
96
+ mcpConfigDone = true;
97
+ }
98
+ const worker = fork(workerPath, [], {
99
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
100
+ cwd,
101
+ env: { ...process.env, CLAUDECODE: undefined },
102
+ });
103
+ // Pipe worker stdout/stderr to daemon logger
104
+ worker.stdout?.on('data', (data) => {
105
+ for (const line of data.toString().split('\n')) {
106
+ const trimmed = line.trim();
107
+ if (trimmed)
108
+ logger.info(`[${t}:out] ${trimmed}`);
109
+ }
110
+ });
111
+ worker.stderr?.on('data', (data) => {
112
+ for (const line of data.toString().split('\n')) {
113
+ const trimmed = line.trim();
114
+ if (trimmed)
115
+ logger.error(`[${t}:worker] ${trimmed}`);
116
+ }
117
+ });
118
+ // Send init config
119
+ const initMsg = {
120
+ type: 'init',
121
+ sessionId: ds.session.sessionId,
122
+ chatId: ds.chatId,
123
+ rootMessageId: ds.session.rootMessageId,
124
+ workingDir: cwd,
125
+ cliId: config.daemon.cliId,
126
+ cliPathOverride: config.daemon.cliPathOverride,
127
+ backendType: config.daemon.backendType,
128
+ prompt,
129
+ resume,
130
+ ownerOpenId: ds.ownerOpenId,
131
+ };
132
+ worker.send(initMsg);
133
+ ds.initConfig = initMsg;
134
+ // Handle IPC messages from worker
135
+ worker.on('message', async (msg) => {
136
+ switch (msg.type) {
137
+ case 'ready': {
138
+ ds.workerPort = msg.port;
139
+ ds.workerToken = msg.token;
140
+ const readOnlyUrl = `http://${config.web.externalHost}:${msg.port}`;
141
+ const writeUrl = `${readOnlyUrl}?token=${msg.token}`;
142
+ logger.info(`[${t}] Worker ready, terminal at ${readOnlyUrl}`);
143
+ // Send streaming card to group thread (read-only link, will be PATCHed with live output)
144
+ try {
145
+ const initTitle = ds.currentTurnTitle || ds.session.title || 'Claude Code';
146
+ const streamCardJson = buildStreamingCard(ds.session.sessionId, ds.session.rootMessageId, readOnlyUrl, initTitle, '', 'starting', config.daemon.cliId);
147
+ ds.streamCardId = await cb.sessionReply(ds.session.rootMessageId, streamCardJson, 'interactive');
148
+ }
149
+ catch (err) {
150
+ logger.warn(`[${t}] Failed to send streaming card, falling back to static card: ${err}`);
151
+ // Fallback: send static session card
152
+ const cardJson = buildSessionCard(ds.session.sessionId, ds.session.rootMessageId, readOnlyUrl, ds.session.title || 'Claude Code', config.daemon.cliId);
153
+ await cb.sessionReply(ds.session.rootMessageId, cardJson, 'interactive');
154
+ }
155
+ break;
156
+ }
157
+ case 'prompt_ready': {
158
+ logger.info(`[${t}] Claude is ready for input`);
159
+ break;
160
+ }
161
+ case 'screen_update': {
162
+ if (!ds.workerPort)
163
+ break;
164
+ ds.lastScreenContent = msg.content;
165
+ const readUrl = `http://${config.web.externalHost}:${ds.workerPort}`;
166
+ const turnTitle = ds.currentTurnTitle || ds.session.title || 'Claude Code';
167
+ const cardJson = buildStreamingCard(ds.session.sessionId, ds.session.rootMessageId, readUrl, turnTitle, msg.content, msg.status, config.daemon.cliId);
168
+ if (ds.streamCardPending || !ds.streamCardId) {
169
+ // New turn — create a fresh card, old card freezes at its last state
170
+ ds.streamCardPending = false;
171
+ cb.sessionReply(ds.session.rootMessageId, cardJson, 'interactive')
172
+ .then(msgId => { ds.streamCardId = msgId; })
173
+ .catch(err => logger.debug(`[${t}] Failed to create streaming card: ${err}`));
174
+ }
175
+ else {
176
+ // Same turn — PATCH existing card
177
+ updateMessage(ds.streamCardId, cardJson).catch(err => {
178
+ logger.debug(`[${t}] Failed to update streaming card: ${err}`);
179
+ ds.streamCardId = undefined;
180
+ });
181
+ }
182
+ break;
183
+ }
184
+ case 'claude_exit': {
185
+ logger.info(`[${t}] Claude exited (code: ${msg.code}, signal: ${msg.signal})`);
186
+ ds.hasHistory = true;
187
+ // Rate-limit auto-restart to prevent crash loops
188
+ const key = ds.session.sessionId;
189
+ const rc = restartCounts.get(key) ?? { count: 0, lastAt: 0 };
190
+ const now = Date.now();
191
+ if (now - rc.lastAt > 60_000)
192
+ rc.count = 0; // reset after 1 min
193
+ rc.count++;
194
+ rc.lastAt = now;
195
+ restartCounts.set(key, rc);
196
+ if (rc.count > 3) {
197
+ logger.warn(`[${t}] Claude crashed ${rc.count} times in 1 min, not auto-restarting`);
198
+ // Kill the worker process to free resources
199
+ killWorker(ds);
200
+ await cb.sessionReply(ds.session.rootMessageId, `⚠️ Claude 在 1 分钟内崩溃 ${rc.count} 次,已停止自动重启。发消息可触发重新启动。`);
201
+ break;
202
+ }
203
+ // Auto-restart Claude within the same worker
204
+ if (ds.worker && !ds.worker.killed) {
205
+ logger.info(`[${t}] Auto-restarting Claude...`);
206
+ ds.worker.send({ type: 'restart' });
207
+ }
208
+ break;
209
+ }
210
+ case 'error': {
211
+ logger.error(`[${t}] Worker error: ${msg.message}`);
212
+ break;
213
+ }
214
+ }
215
+ });
216
+ worker.on('exit', (code) => {
217
+ logger.info(`[${t}] Worker process exited (code: ${code})`);
218
+ ds.worker = null;
219
+ ds.workerPort = null;
220
+ });
221
+ ds.worker = worker;
222
+ ds.spawnedAt = Date.now();
223
+ ds.claudeVersion = currentClaudeVersion;
224
+ sessionStore.updateSessionPid(ds.session.sessionId, worker.pid ?? null);
225
+ logger.info(`[${t}] Worker forked (pid: ${worker.pid}, active: ${cb.getActiveCount()})`);
226
+ }
227
+ // ─── Kill stale PIDs ────────────────────────────────────────────────────────
228
+ export function killStalePids(activeSessions_) {
229
+ for (const session of activeSessions_) {
230
+ if (!session.pid)
231
+ continue;
232
+ try {
233
+ // Check if process exists (signal 0 doesn't kill, just checks)
234
+ process.kill(session.pid, 0);
235
+ // Process exists — kill its process group
236
+ logger.info(`Killing stale Claude process (pid: ${session.pid}, session: ${session.sessionId})`);
237
+ try {
238
+ process.kill(-session.pid, 'SIGTERM');
239
+ }
240
+ catch {
241
+ try {
242
+ process.kill(session.pid, 'SIGTERM');
243
+ }
244
+ catch { /* already gone */ }
245
+ }
246
+ }
247
+ catch {
248
+ // Process doesn't exist, nothing to clean up
249
+ }
250
+ }
251
+ }
252
+ // ─── Claude version (shared with daemon) ────────────────────────────────────
253
+ /** Current CLI version, kept in sync by daemon via setCurrentClaudeVersion(). */
254
+ let currentClaudeVersion = 'unknown';
255
+ export function setCurrentClaudeVersion(v) {
256
+ currentClaudeVersion = v;
257
+ }
258
+ export function getCurrentClaudeVersion() {
259
+ return currentClaudeVersion;
260
+ }
261
+ //# sourceMappingURL=worker-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-pool.js","sourceRoot":"","sources":["../../src/core/worker-pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type { DaemonSession } from './core/types.js';
2
+ export declare function startDaemon(): Promise<void>;
3
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAUA,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA0UrD,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAmEjD"}
package/dist/daemon.js ADDED
@@ -0,0 +1,344 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { writeFileSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { config, validateConfig } from './config.js';
5
+ import { replyMessage, updateMessage, resolveAllowedUsers } from './im/lark/client.js';
6
+ import * as sessionStore from './services/session-store.js';
7
+ import * as messageQueue from './services/message-queue.js';
8
+ import { parseEventMessage } from './im/lark/message-parser.js';
9
+ import { logger } from './utils/logger.js';
10
+ import * as scheduler from './core/scheduler.js';
11
+ import { scanProjects } from './services/project-scanner.js';
12
+ import { buildRepoSelectCard, buildStreamingCard } from './im/lark/card-builder.js';
13
+ import { createCliAdapterSync } from './adapters/cli/registry.js';
14
+ import { initWorkerPool, forkWorker, killWorker, setCurrentClaudeVersion, getCurrentClaudeVersion, } from './core/worker-pool.js';
15
+ import { DAEMON_COMMANDS, handleCommand } from './core/command-handler.js';
16
+ import { getSessionWorkingDir, getProjectScanDir, downloadResources, formatAttachmentsHint, buildNewTopicPrompt, restoreActiveSessions, executeScheduledTask, } from './core/session-manager.js';
17
+ import { handleCardAction } from './im/lark/card-handler.js';
18
+ import { probeBotOpenId, startLarkEventDispatcher } from './im/lark/event-dispatcher.js';
19
+ // ─── State ───────────────────────────────────────────────────────────────────
20
+ const activeSessions = new Map();
21
+ // Cache last /repo scan results per chat for /repo <number> fallback
22
+ const lastRepoScan = new Map();
23
+ let lastVersionCheckAt = 0;
24
+ const VERSION_CHECK_INTERVAL = 60_000; // cache 1 min
25
+ /**
26
+ * Reply to a message, automatically using reply_in_thread for p2p sessions.
27
+ * In p2p chats, Lark needs reply_in_thread=true to create/continue a thread.
28
+ */
29
+ async function sessionReply(rootId, content, msgType = 'text') {
30
+ const ds = activeSessions.get(rootId);
31
+ const inThread = ds?.chatType === 'p2p';
32
+ return replyMessage(rootId, content, msgType, inThread);
33
+ }
34
+ // ─── PID file ────────────────────────────────────────────────────────────────
35
+ function getPidFile() {
36
+ return join(config.session.dataDir, 'daemon.pid');
37
+ }
38
+ function writePidFile() {
39
+ const dir = config.session.dataDir;
40
+ if (!existsSync(dir)) {
41
+ mkdirSync(dir, { recursive: true });
42
+ }
43
+ writeFileSync(getPidFile(), String(process.pid), 'utf-8');
44
+ logger.info(`PID file written: ${getPidFile()} (pid: ${process.pid})`);
45
+ }
46
+ function removePidFile() {
47
+ const pidFile = getPidFile();
48
+ if (existsSync(pidFile)) {
49
+ unlinkSync(pidFile);
50
+ logger.info('PID file removed');
51
+ }
52
+ }
53
+ // ─── Version tracking ────────────────────────────────────────────────────────
54
+ function refreshClaudeVersion() {
55
+ const now = Date.now();
56
+ if (now - lastVersionCheckAt < VERSION_CHECK_INTERVAL)
57
+ return false;
58
+ lastVersionCheckAt = now;
59
+ try {
60
+ const adapter = createCliAdapterSync(config.daemon.cliId, config.daemon.cliPathOverride);
61
+ const raw = execFileSync(adapter.resolvedBin, ['--version'], {
62
+ encoding: 'utf-8',
63
+ timeout: 5_000,
64
+ }).trim();
65
+ const newVersion = raw.replace(/^[^0-9]*/, '');
66
+ if (newVersion === 'unknown' || !newVersion)
67
+ return false;
68
+ const curVer = getCurrentClaudeVersion();
69
+ if (curVer !== 'unknown' && newVersion !== curVer) {
70
+ setCurrentClaudeVersion(newVersion);
71
+ logger.info(`CLI version updated: ${curVer} → ${newVersion} (${adapter.id})`);
72
+ return true;
73
+ }
74
+ setCurrentClaudeVersion(newVersion);
75
+ logger.info(`CLI version: ${getCurrentClaudeVersion()} (${adapter.id})`);
76
+ return false;
77
+ }
78
+ catch (err) {
79
+ logger.warn(`Failed to get CLI version: ${err.message}`);
80
+ return false;
81
+ }
82
+ }
83
+ // ─── Helpers (local to daemon) ───────────────────────────────────────────────
84
+ function tag(ds) {
85
+ return ds.session.sessionId.substring(0, 8);
86
+ }
87
+ function getActiveCount() {
88
+ let count = 0;
89
+ for (const [, ds] of activeSessions) {
90
+ if (ds.worker && !ds.worker.killed)
91
+ count++;
92
+ }
93
+ return count;
94
+ }
95
+ // Dependencies passed to command-handler
96
+ const commandDeps = {
97
+ activeSessions,
98
+ sessionReply,
99
+ getActiveCount,
100
+ lastRepoScan,
101
+ };
102
+ // Dependencies passed to card-handler
103
+ const cardDeps = {
104
+ activeSessions,
105
+ sessionReply,
106
+ lastRepoScan,
107
+ };
108
+ // ─── Event handling ──────────────────────────────────────────────────────────
109
+ async function handleNewTopic(data, chatId, messageId, chatType = 'group') {
110
+ const { parsed, resources } = parseEventMessage(data);
111
+ const content = parsed.content.trim();
112
+ const senderOpenId = data.sender?.sender_id?.open_id;
113
+ logger.info(`New topic: ${messageId} "${content.substring(0, 60)}" (resources: ${resources.length}, active: ${getActiveCount()})`);
114
+ // Intercept daemon commands in new topics (no session needed for some commands)
115
+ if (content.startsWith('/')) {
116
+ const cmd = content.split(/\s+/)[0].toLowerCase();
117
+ if (DAEMON_COMMANDS.has(cmd)) {
118
+ const session = sessionStore.createSession(chatId, messageId, content.substring(0, 50), chatType);
119
+ activeSessions.set(messageId, {
120
+ session,
121
+ worker: null,
122
+ workerPort: null,
123
+ workerToken: null,
124
+ chatId,
125
+ chatType,
126
+ spawnedAt: Date.now(),
127
+ claudeVersion: getCurrentClaudeVersion(),
128
+ lastMessageAt: Date.now(),
129
+ hasHistory: false,
130
+ ownerOpenId: senderOpenId,
131
+ });
132
+ await handleCommand(cmd, messageId, parsed, commandDeps);
133
+ return;
134
+ }
135
+ }
136
+ // Download attachments
137
+ const attachments = await downloadResources(messageId, resources);
138
+ if (attachments.length > 0) {
139
+ parsed.attachments = attachments;
140
+ }
141
+ refreshClaudeVersion();
142
+ // Create session in pending-repo state — don't spawn Claude yet
143
+ const session = sessionStore.createSession(chatId, messageId, parsed.content.substring(0, 50), chatType);
144
+ messageQueue.ensureQueue(messageId);
145
+ messageQueue.appendMessage(messageId, parsed);
146
+ const ds = {
147
+ session,
148
+ worker: null,
149
+ workerPort: null,
150
+ workerToken: null,
151
+ chatId,
152
+ chatType,
153
+ spawnedAt: Date.now(),
154
+ claudeVersion: getCurrentClaudeVersion(),
155
+ lastMessageAt: Date.now(),
156
+ hasHistory: false,
157
+ pendingRepo: true,
158
+ pendingPrompt: content,
159
+ pendingAttachments: attachments.length > 0 ? attachments : undefined,
160
+ ownerOpenId: senderOpenId,
161
+ currentTurnTitle: content.substring(0, 50),
162
+ };
163
+ activeSessions.set(messageId, ds);
164
+ // Show repo selection card
165
+ const scanDir = getProjectScanDir(ds);
166
+ let projects = [];
167
+ if (existsSync(scanDir)) {
168
+ projects = scanProjects(scanDir);
169
+ }
170
+ if (projects.length > 0) {
171
+ lastRepoScan.set(chatId, projects);
172
+ const currentCwd = getSessionWorkingDir(ds);
173
+ const cardJson = buildRepoSelectCard(projects, currentCwd, messageId);
174
+ await sessionReply(messageId, cardJson, 'interactive');
175
+ logger.info(`[${tag(ds)}] Waiting for repo selection (${projects.length} projects)`);
176
+ }
177
+ else {
178
+ // No projects found — skip repo selection, spawn directly
179
+ ds.pendingRepo = false;
180
+ const prompt = buildNewTopicPrompt(content, session.sessionId, attachments);
181
+ forkWorker(ds, prompt);
182
+ logger.info(`Session ${session.sessionId} ready (no projects to select), total active: ${getActiveCount()}`);
183
+ }
184
+ }
185
+ async function handleThreadReply(data, rootId) {
186
+ const { parsed, resources } = parseEventMessage(data);
187
+ const content = parsed.content.trim();
188
+ // Intercept daemon commands
189
+ if (content.startsWith('/')) {
190
+ const cmd = content.split(/\s+/)[0].toLowerCase();
191
+ if (DAEMON_COMMANDS.has(cmd)) {
192
+ handleCommand(cmd, rootId, parsed, commandDeps);
193
+ return;
194
+ }
195
+ }
196
+ logger.info(`Thread reply in ${rootId}: ${content.substring(0, 100)} (resources: ${resources.length})`);
197
+ // Download attachments
198
+ const attachments = await downloadResources(parsed.messageId, resources);
199
+ if (attachments.length > 0) {
200
+ parsed.attachments = attachments;
201
+ }
202
+ // Update last message time
203
+ const ds = activeSessions.get(rootId);
204
+ if (ds)
205
+ ds.lastMessageAt = Date.now();
206
+ // If waiting for repo selection, remind user
207
+ if (ds?.pendingRepo) {
208
+ await sessionReply(rootId, '请先在上方卡片中选择仓库,再发送消息。');
209
+ return;
210
+ }
211
+ // Route to file queue
212
+ messageQueue.ensureQueue(rootId);
213
+ messageQueue.appendMessage(rootId, parsed);
214
+ if (!ds) {
215
+ // No active session for this thread — auto-create with repo selection
216
+ const chatId = data?.message?.chat_id ?? '';
217
+ const chatType = (data?.message?.chat_type === 'p2p' ? 'p2p' : 'group');
218
+ logger.info(`No active session for thread ${rootId}, auto-creating new session...`);
219
+ refreshClaudeVersion();
220
+ const session = sessionStore.createSession(chatId, rootId, parsed.content.substring(0, 50), chatType);
221
+ const newDs = {
222
+ session,
223
+ worker: null,
224
+ workerPort: null,
225
+ workerToken: null,
226
+ chatId,
227
+ chatType,
228
+ spawnedAt: Date.now(),
229
+ claudeVersion: getCurrentClaudeVersion(),
230
+ lastMessageAt: Date.now(),
231
+ hasHistory: false,
232
+ pendingRepo: true,
233
+ pendingPrompt: parsed.content,
234
+ pendingAttachments: attachments.length > 0 ? attachments : undefined,
235
+ ownerOpenId: data.sender?.sender_id?.open_id,
236
+ currentTurnTitle: parsed.content.substring(0, 50),
237
+ };
238
+ activeSessions.set(rootId, newDs);
239
+ // Show repo selection card (same as handleNewTopic)
240
+ const scanDir = getProjectScanDir(newDs);
241
+ let projects = [];
242
+ if (existsSync(scanDir)) {
243
+ projects = scanProjects(scanDir);
244
+ }
245
+ if (projects.length > 0) {
246
+ lastRepoScan.set(chatId, projects);
247
+ const currentCwd = getSessionWorkingDir(newDs);
248
+ const cardJson = buildRepoSelectCard(projects, currentCwd, rootId);
249
+ await sessionReply(rootId, cardJson, 'interactive');
250
+ logger.info(`[${tag(newDs)}] Waiting for repo selection (${projects.length} projects)`);
251
+ }
252
+ else {
253
+ // No projects found — skip repo selection, spawn directly
254
+ newDs.pendingRepo = false;
255
+ const prompt = buildNewTopicPrompt(parsed.content, session.sessionId, attachments);
256
+ forkWorker(newDs, prompt);
257
+ }
258
+ return;
259
+ }
260
+ // Send message to worker via IPC
261
+ if (ds.worker && !ds.worker.killed) {
262
+ const msgContent = attachments.length > 0
263
+ ? `${parsed.content}${formatAttachmentsHint(attachments)}`
264
+ : parsed.content;
265
+ // Freeze the previous turn's card at "idle" before starting a new turn
266
+ if (ds.streamCardId && ds.workerPort) {
267
+ const readUrl = `http://${config.web.externalHost}:${ds.workerPort}`;
268
+ const prevTitle = ds.currentTurnTitle || ds.session.title || 'Claude Code';
269
+ const frozenCard = buildStreamingCard(ds.session.sessionId, ds.session.rootMessageId, readUrl, prevTitle, ds.lastScreenContent ?? '', 'idle', config.daemon.cliId);
270
+ updateMessage(ds.streamCardId, frozenCard).catch(() => { });
271
+ }
272
+ // Mark new turn — next screen_update will create a fresh streaming card
273
+ ds.streamCardPending = true;
274
+ ds.currentTurnTitle = parsed.content.substring(0, 50);
275
+ ds.worker.send({ type: 'message', content: msgContent });
276
+ }
277
+ else {
278
+ // Worker not running — re-fork with resume
279
+ logger.info(`[${tag(ds)}] Worker not running, re-forking...`);
280
+ ds.currentTurnTitle = parsed.content.substring(0, 50);
281
+ forkWorker(ds, parsed.content, ds.hasHistory);
282
+ }
283
+ }
284
+ // ─── Main ────────────────────────────────────────────────────────────────────
285
+ export async function startDaemon() {
286
+ validateConfig();
287
+ writePidFile();
288
+ // Initialise worker pool with daemon callbacks
289
+ initWorkerPool({
290
+ sessionReply,
291
+ getSessionWorkingDir,
292
+ getActiveCount,
293
+ });
294
+ // Get initial CLI version
295
+ refreshClaudeVersion();
296
+ if (getCurrentClaudeVersion() === 'unknown') {
297
+ logger.warn('Could not detect CLI version at startup');
298
+ }
299
+ // Resolve email prefixes in ALLOWED_USERS to open_ids
300
+ if (config.daemon.allowedUsers.length > 0) {
301
+ const hasEmails = config.daemon.allowedUsers.some(u => !u.startsWith('ou_'));
302
+ if (hasEmails) {
303
+ try {
304
+ config.daemon.allowedUsers = await resolveAllowedUsers(config.daemon.allowedUsers);
305
+ logger.info(`Resolved allowedUsers: ${config.daemon.allowedUsers.join(', ')}`);
306
+ }
307
+ catch (err) {
308
+ logger.warn(`Failed to resolve allowedUsers: ${err.message}`);
309
+ }
310
+ }
311
+ }
312
+ // Probe bot open_id at startup (non-blocking)
313
+ probeBotOpenId().catch(err => {
314
+ logger.warn(`Bot open_id probe failed (will learn from events): ${err.message}`);
315
+ });
316
+ // Restore active sessions from previous run
317
+ restoreActiveSessions(activeSessions);
318
+ // Start scheduled task scheduler
319
+ scheduler.setExecuteCallback((task) => executeScheduledTask(task, activeSessions, refreshClaudeVersion));
320
+ scheduler.startScheduler();
321
+ // Start Lark event dispatcher
322
+ startLarkEventDispatcher({
323
+ handleCardAction: (data) => handleCardAction(data, cardDeps),
324
+ handleNewTopic,
325
+ handleThreadReply,
326
+ });
327
+ // Graceful shutdown
328
+ const shutdown = () => {
329
+ logger.info(`Daemon shutting down... (active: ${getActiveCount()})`);
330
+ scheduler.stopScheduler();
331
+ for (const [, ds] of activeSessions) {
332
+ if (ds.worker && !ds.worker.killed) {
333
+ logger.info(`Shutting down worker for session ${ds.session.sessionId}`);
334
+ killWorker(ds);
335
+ }
336
+ }
337
+ removePidFile();
338
+ process.exit(0);
339
+ };
340
+ process.on('SIGTERM', shutdown);
341
+ process.on('SIGINT', shutdown);
342
+ logger.info('Daemon is running. Press Ctrl+C to stop.');
343
+ }
344
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}