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,322 @@
1
+ /**
2
+ * Command handler — processes /slash commands from users.
3
+ * Extracted from daemon.ts for modularity.
4
+ */
5
+ import { existsSync } from 'node:fs';
6
+ import { resolve } from 'node:path';
7
+ import { homedir } from 'node:os';
8
+ import { config } from '../config.js';
9
+ import * as sessionStore from '../services/session-store.js';
10
+ import * as scheduleStore from '../services/schedule-store.js';
11
+ import * as scheduler from './scheduler.js';
12
+ import { scanProjects } from '../services/project-scanner.js';
13
+ import { buildRepoSelectCard, getCliDisplayName } from '../im/lark/card-builder.js';
14
+ import { logger } from '../utils/logger.js';
15
+ import { getSessionCost, formatNumber } from './cost-calculator.js';
16
+ import { killWorker, getCurrentClaudeVersion } from './worker-pool.js';
17
+ import { expandHome, getSessionWorkingDir, getProjectScanDir } from './session-manager.js';
18
+ // ─── Exported constants ──────────────────────────────────────────────────────
19
+ export const DAEMON_COMMANDS = new Set(['/close', '/clear', '/restart', '/status', '/help', '/cd', '/repo', '/cost', '/schedule']);
20
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
21
+ function tag(ds) {
22
+ return ds.session.sessionId.substring(0, 8);
23
+ }
24
+ function formatUptime(ms) {
25
+ const s = Math.floor(ms / 1000);
26
+ if (s < 60)
27
+ return `${s}s`;
28
+ const m = Math.floor(s / 60);
29
+ if (m < 60)
30
+ return `${m}m${s % 60}s`;
31
+ const h = Math.floor(m / 60);
32
+ return `${h}h${m % 60}m`;
33
+ }
34
+ // ─── Schedule command ────────────────────────────────────────────────────────
35
+ async function handleScheduleCommand(args, rootId, chatId, deps) {
36
+ const { activeSessions, sessionReply } = deps;
37
+ const trimmed = args.trim();
38
+ // /schedule list | /schedule 列表
39
+ if (!trimmed || trimmed === 'list' || trimmed === '列表') {
40
+ const tasks = scheduleStore.listTasks();
41
+ if (tasks.length === 0) {
42
+ await sessionReply(rootId, '暂无定时任务。\n\n用法示例:\n/schedule 每日17:50 帮我看看今天AI圈有什么新闻\n/schedule 工作日每天9:00 检查服务状态\n/schedule 每周一10:00 生成周报');
43
+ return;
44
+ }
45
+ const lines = tasks.map(t => {
46
+ const status = t.enabled ? '✅' : '⏸️';
47
+ const next = t.enabled ? scheduler.getNextRun(t.id) : null;
48
+ const nextStr = next ? ` → 下次: ${next.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}` : '';
49
+ const lastStr = t.lastRunAt ? ` | 上次: ${new Date(t.lastRunAt).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}` : '';
50
+ return `${status} [${t.id}] ${t.schedule} | ${t.name}\n prompt: ${t.prompt.substring(0, 50)}${t.prompt.length > 50 ? '...' : ''}${nextStr}${lastStr}`;
51
+ });
52
+ await sessionReply(rootId, `定时任务列表 (${tasks.length}):\n\n${lines.join('\n\n')}`);
53
+ return;
54
+ }
55
+ // /schedule remove <id> | /schedule 删除 <id>
56
+ const removeMatch = trimmed.match(/^(?:remove|删除)\s+(\S+)/);
57
+ if (removeMatch) {
58
+ const id = removeMatch[1];
59
+ if (scheduler.removeTask(id)) {
60
+ await sessionReply(rootId, `已删除定时任务 ${id}`);
61
+ }
62
+ else {
63
+ await sessionReply(rootId, `未找到任务 ${id}`);
64
+ }
65
+ return;
66
+ }
67
+ // /schedule enable <id> | /schedule 启用 <id>
68
+ const enableMatch = trimmed.match(/^(?:enable|启用)\s+(\S+)/);
69
+ if (enableMatch) {
70
+ const id = enableMatch[1];
71
+ if (scheduler.enableTask(id)) {
72
+ await sessionReply(rootId, `已启用定时任务 ${id}`);
73
+ }
74
+ else {
75
+ await sessionReply(rootId, `未找到任务 ${id}`);
76
+ }
77
+ return;
78
+ }
79
+ // /schedule disable <id> | /schedule 禁用 <id>
80
+ const disableMatch = trimmed.match(/^(?:disable|禁用)\s+(\S+)/);
81
+ if (disableMatch) {
82
+ const id = disableMatch[1];
83
+ if (scheduler.disableTask(id)) {
84
+ await sessionReply(rootId, `已禁用定时任务 ${id}`);
85
+ }
86
+ else {
87
+ await sessionReply(rootId, `未找到任务 ${id}`);
88
+ }
89
+ return;
90
+ }
91
+ // /schedule run <id> | /schedule 执行 <id>
92
+ const runMatch = trimmed.match(/^(?:run|执行)\s+(\S+)/);
93
+ if (runMatch) {
94
+ const id = runMatch[1];
95
+ if (scheduler.runTaskNow(id)) {
96
+ await sessionReply(rootId, `已触发定时任务 ${id} 立即执行`);
97
+ }
98
+ else {
99
+ await sessionReply(rootId, `未找到任务 ${id}`);
100
+ }
101
+ return;
102
+ }
103
+ // Natural language: /schedule 每日17:50给我"帮我看看AI新闻"
104
+ const parsed = scheduler.parseNaturalSchedule(trimmed);
105
+ if (parsed) {
106
+ const ds = activeSessions.get(rootId);
107
+ const workingDir = ds?.workingDir ?? config.daemon.workingDir;
108
+ const task = scheduler.addTask({
109
+ name: parsed.name,
110
+ type: parsed.type,
111
+ schedule: parsed.cron,
112
+ prompt: parsed.prompt,
113
+ workingDir,
114
+ chatId,
115
+ });
116
+ const next = scheduler.getNextRun(task.id);
117
+ const nextStr = next ? next.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }) : 'N/A';
118
+ await sessionReply(rootId, `✅ 定时任务已创建!\n\nID: ${task.id}\n名称: ${task.name}\nCron: ${task.schedule}\nPrompt: ${task.prompt}\n工作目录: ${expandHome(workingDir)}\n下次执行: ${nextStr}`);
119
+ return;
120
+ }
121
+ // Unrecognized format
122
+ await sessionReply(rootId, `无法解析定时任务,请使用自然语言格式:\n\n/schedule 每日17:50 帮我看看今天AI圈有什么新闻\n/schedule 工作日每天9:00 检查服务状态\n/schedule 每周一10:00 生成周报\n/schedule 每小时 检查服务健康状态\n/schedule 每30分钟 ping一下服务\n/schedule 每月1号9:00 生成月报\n\n管理命令:\n/schedule list — 查看所有任务\n/schedule remove <id> — 删除任务\n/schedule enable <id> — 启用任务\n/schedule disable <id> — 禁用任务\n/schedule run <id> — 立即执行一次`);
123
+ }
124
+ // ─── Main command handler ────────────────────────────────────────────────────
125
+ export async function handleCommand(cmd, rootId, message, deps) {
126
+ const { activeSessions, sessionReply, getActiveCount, lastRepoScan } = deps;
127
+ const ds = activeSessions.get(rootId);
128
+ const t = ds ? tag(ds) : rootId.substring(0, 12);
129
+ logger.info(`[${t}] Command: ${cmd}`);
130
+ try {
131
+ switch (cmd) {
132
+ case '/close': {
133
+ if (ds) {
134
+ killWorker(ds);
135
+ sessionStore.closeSession(ds.session.sessionId);
136
+ activeSessions.delete(rootId);
137
+ await sessionReply(rootId, '会话已关闭,Claude 进程已终止。');
138
+ logger.info(`[${t}] Session closed by /close command`);
139
+ }
140
+ else {
141
+ await sessionReply(rootId, '当前话题没有活跃的会话。');
142
+ }
143
+ break;
144
+ }
145
+ case '/clear': {
146
+ if (ds) {
147
+ killWorker(ds);
148
+ sessionStore.closeSession(ds.session.sessionId);
149
+ const newSession = sessionStore.createSession(ds.chatId, rootId, ds.session.title, ds.chatType);
150
+ ds.session = newSession;
151
+ ds.claudeVersion = getCurrentClaudeVersion();
152
+ ds.hasHistory = false;
153
+ await sessionReply(rootId, `上下文已清除,下次发消息时将使用新会话。\nNew Session: ${newSession.sessionId}`);
154
+ logger.info(`[${t}] Context cleared by /clear command, new session: ${newSession.sessionId}`);
155
+ }
156
+ else {
157
+ await sessionReply(rootId, '当前话题没有活跃的会话。');
158
+ }
159
+ break;
160
+ }
161
+ case '/restart': {
162
+ if (ds) {
163
+ if (ds.worker && !ds.worker.killed) {
164
+ ds.worker.send({ type: 'restart' });
165
+ const cliName = getCliDisplayName(config.daemon.cliId);
166
+ await sessionReply(rootId, `🔄 正在重启 ${cliName}...`);
167
+ }
168
+ else {
169
+ killWorker(ds);
170
+ const cliName = getCliDisplayName(config.daemon.cliId);
171
+ await sessionReply(rootId, `${cliName} 进程已终止,下次发消息时将自动恢复。`);
172
+ }
173
+ logger.info(`[${t}] Restart by /restart command`);
174
+ }
175
+ else {
176
+ await sessionReply(rootId, '当前话题没有活跃的会话。');
177
+ }
178
+ break;
179
+ }
180
+ case '/cd': {
181
+ const targetPath = message.content.replace(/^\/cd\s*/, '').trim();
182
+ if (!targetPath) {
183
+ await sessionReply(rootId, '用法:/cd <path>\n例如:/cd ~/projects/my-app');
184
+ break;
185
+ }
186
+ const resolvedPath = resolve(expandHome(targetPath));
187
+ if (!existsSync(resolvedPath)) {
188
+ await sessionReply(rootId, `目录不存在:${resolvedPath}`);
189
+ break;
190
+ }
191
+ // Ensure resolved path is under home directory to prevent traversal
192
+ const homeDir = homedir();
193
+ if (!resolvedPath.startsWith(homeDir)) {
194
+ await sessionReply(rootId, `路径必须在用户主目录 (${homeDir}) 下`);
195
+ break;
196
+ }
197
+ if (ds) {
198
+ killWorker(ds);
199
+ ds.workingDir = targetPath;
200
+ ds.session.workingDir = targetPath;
201
+ sessionStore.updateSession(ds.session);
202
+ await sessionReply(rootId, `工作目录已切换到 ${resolvedPath},下次发消息时将在新目录下恢复。`);
203
+ logger.info(`[${t}] Working directory changed to ${resolvedPath} by /cd command`);
204
+ }
205
+ else {
206
+ await sessionReply(rootId, '当前话题没有活跃的会话。');
207
+ }
208
+ break;
209
+ }
210
+ case '/repo': {
211
+ // If Claude is already running, warn user — switching repo means closing the session
212
+ if (ds?.worker && !ds.worker.killed) {
213
+ await sessionReply(rootId, '⚠️ 当前会话已在运行中,切换仓库将关闭当前会话并创建新会话。\n如需切换,请在下方卡片中选择新仓库。');
214
+ }
215
+ // Show project list card (works both for pending-repo and mid-session switch)
216
+ const scanDir = getProjectScanDir(ds);
217
+ if (!existsSync(scanDir)) {
218
+ await sessionReply(rootId, `扫描目录不存在:${scanDir}\n请设置 PROJECT_SCAN_DIR 环境变量。`);
219
+ break;
220
+ }
221
+ const projects = scanProjects(scanDir);
222
+ if (projects.length === 0) {
223
+ await sessionReply(rootId, `在 ${scanDir} 下未找到 git 仓库。`);
224
+ break;
225
+ }
226
+ if (ds)
227
+ lastRepoScan.set(ds.chatId, projects);
228
+ const currentCwd = getSessionWorkingDir(ds);
229
+ const cardJson = buildRepoSelectCard(projects, currentCwd, rootId);
230
+ await sessionReply(rootId, cardJson, 'interactive');
231
+ logger.info(`[${t}] Sent repo card with ${projects.length} project(s)`);
232
+ break;
233
+ }
234
+ case '/status': {
235
+ if (ds) {
236
+ const alive = ds.worker && !ds.worker.killed;
237
+ const idle = formatUptime(Date.now() - ds.lastMessageAt);
238
+ const termUrl = ds.workerPort ? `http://${config.web.externalHost}:${ds.workerPort}` : '-';
239
+ const lines = [
240
+ `Session: ${ds.session.sessionId}`,
241
+ `Status: ${alive ? '运行中' : '等待中'}`,
242
+ `Terminal: ${termUrl}`,
243
+ `CWD: ${getSessionWorkingDir(ds)}`,
244
+ `Claude: v${ds.claudeVersion}${ds.claudeVersion !== getCurrentClaudeVersion() ? ` (latest: v${getCurrentClaudeVersion()})` : ''}`,
245
+ ...(alive ? [`Uptime: ${formatUptime(Date.now() - ds.spawnedAt)}`] : []),
246
+ `Last message: ${idle} ago`,
247
+ `Active sessions: ${getActiveCount()}`,
248
+ ];
249
+ await sessionReply(rootId, lines.join('\n'));
250
+ }
251
+ else {
252
+ await sessionReply(rootId, `当前话题没有活跃的会话。\nDaemon active sessions: ${getActiveCount()}\nClaude: v${getCurrentClaudeVersion()}`);
253
+ }
254
+ break;
255
+ }
256
+ case '/cost': {
257
+ if (ds) {
258
+ const cwd = getSessionWorkingDir(ds);
259
+ const cost = getSessionCost(ds.session.sessionId, cwd);
260
+ if (cost) {
261
+ const lines = [
262
+ `Session: ${ds.session.sessionId}`,
263
+ `Model: ${cost.model || 'unknown'}`,
264
+ `Turns: ${cost.turns}`,
265
+ `Input tokens: ${formatNumber(cost.inputTokens)}`,
266
+ `Output tokens: ${formatNumber(cost.outputTokens)}`,
267
+ `Cache read: ${formatNumber(cost.cacheReadTokens)}`,
268
+ `Cache creation: ${formatNumber(cost.cacheCreateTokens)}`,
269
+ ];
270
+ await sessionReply(rootId, lines.join('\n'));
271
+ }
272
+ else {
273
+ await sessionReply(rootId, `未找到会话 ${ds.session.sessionId} 的 token 数据。`);
274
+ }
275
+ logger.info(`[${t}] Cost queried for session ${ds.session.sessionId}`);
276
+ }
277
+ else {
278
+ await sessionReply(rootId, '当前话题没有活跃的会话。');
279
+ }
280
+ break;
281
+ }
282
+ case '/schedule': {
283
+ const scheduleArgs = message.content.replace(/^\/schedule\s*/, '');
284
+ const chatId = activeSessions.get(rootId)?.chatId;
285
+ await handleScheduleCommand(scheduleArgs, rootId, chatId, deps);
286
+ logger.info(`[${t}] Schedule command handled`);
287
+ break;
288
+ }
289
+ case '/help': {
290
+ const cliName = getCliDisplayName(config.daemon.cliId);
291
+ const help = [
292
+ '📌 会话管理:',
293
+ `/close - 关闭当前会话,终止 ${cliName} 进程`,
294
+ `/clear - 清除上下文,重启 ${cliName} 进程`,
295
+ `/restart - 重启 ${cliName} 进程(保留 session)`,
296
+ `/cd <path> - 切换工作目录并重启 ${cliName} 进程`,
297
+ '/repo - 查看项目列表(交互式下拉 + 文本列表)',
298
+ '/repo <N> - 切换到第 N 个项目',
299
+ '/cost - 查看当前会话的 token 消耗和估算费用',
300
+ '/status - 查看当前会话状态(含终端链接)',
301
+ '',
302
+ '⏰ 定时任务:',
303
+ '/schedule 每日17:50 帮我看AI新闻 - 创建定时任务(自然语言)',
304
+ '/schedule list - 查看所有定时任务',
305
+ '/schedule remove <id> - 删除任务',
306
+ '/schedule enable/disable <id> - 启用/禁用任务',
307
+ '/schedule run <id> - 立即执行一次',
308
+ '',
309
+ '支持的时间格式:每日/每天、每周X、每月X号、工作日每天、每N小时、每N分钟',
310
+ '',
311
+ '/help - 显示此帮助',
312
+ ];
313
+ await sessionReply(rootId, help.join('\n'));
314
+ break;
315
+ }
316
+ }
317
+ }
318
+ catch (err) {
319
+ logger.error(`[${t}] Command ${cmd} error: ${err.message}`);
320
+ }
321
+ }
322
+ //# sourceMappingURL=command-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-handler.js","sourceRoot":"","sources":["../../src/core/command-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface SessionCost {
2
+ inputTokens: number;
3
+ outputTokens: number;
4
+ cacheReadTokens: number;
5
+ cacheCreateTokens: number;
6
+ model: string;
7
+ turns: number;
8
+ }
9
+ export declare function getSessionJsonlPath(sessionId: string, cwd: string): string | null;
10
+ export declare function getSessionCost(sessionId: string, cwd: string): SessionCost | null;
11
+ export declare function formatNumber(n: number): string;
12
+ //# sourceMappingURL=cost-calculator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-calculator.d.ts","sourceRoot":"","sources":["../../src/core/cost-calculator.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOjF;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAmCjF;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Session cost calculator — computes token usage from JSONL logs.
3
+ */
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ import { join, resolve } from 'node:path';
6
+ import { homedir } from 'node:os';
7
+ import { logger } from '../utils/logger.js';
8
+ import { expandHome } from './session-manager.js';
9
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
10
+ export function getSessionJsonlPath(sessionId, cwd) {
11
+ const resolvedCwd = resolve(expandHome(cwd));
12
+ // Claude stores sessions at ~/.claude/projects/<project-key>/<sessionId>.jsonl
13
+ // where project-key = absolute path with / replaced by -
14
+ const projectKey = resolvedCwd.replace(/\//g, '-');
15
+ const jsonlPath = join(homedir(), '.claude', 'projects', projectKey, `${sessionId}.jsonl`);
16
+ return existsSync(jsonlPath) ? jsonlPath : null;
17
+ }
18
+ export function getSessionCost(sessionId, cwd) {
19
+ const jsonlPath = getSessionJsonlPath(sessionId, cwd);
20
+ if (!jsonlPath)
21
+ return null;
22
+ let inputTokens = 0;
23
+ let outputTokens = 0;
24
+ let cacheReadTokens = 0;
25
+ let cacheCreateTokens = 0;
26
+ let model = '';
27
+ let turns = 0;
28
+ try {
29
+ const content = readFileSync(jsonlPath, 'utf-8');
30
+ for (const line of content.split('\n')) {
31
+ if (!line.trim())
32
+ continue;
33
+ try {
34
+ const entry = JSON.parse(line);
35
+ if (entry.type !== 'assistant')
36
+ continue;
37
+ const msg = entry.message;
38
+ if (!msg?.usage)
39
+ continue;
40
+ const u = msg.usage;
41
+ inputTokens += u.input_tokens ?? 0;
42
+ outputTokens += u.output_tokens ?? 0;
43
+ cacheReadTokens += u.cache_read_input_tokens ?? 0;
44
+ cacheCreateTokens += u.cache_creation_input_tokens ?? 0;
45
+ if (msg.model && !model)
46
+ model = msg.model;
47
+ turns++;
48
+ }
49
+ catch { /* skip malformed lines */ }
50
+ }
51
+ }
52
+ catch (err) {
53
+ logger.error(`Failed to read session JSONL: ${err.message}`);
54
+ return null;
55
+ }
56
+ return { inputTokens, outputTokens, cacheReadTokens, cacheCreateTokens, model, turns };
57
+ }
58
+ export function formatNumber(n) {
59
+ return n.toLocaleString('en-US');
60
+ }
61
+ //# sourceMappingURL=cost-calculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-calculator.js","sourceRoot":"","sources":["../../src/core/cost-calculator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { ScheduledTask } from '../types.js';
2
+ export declare function setExecuteCallback(cb: (task: ScheduledTask) => Promise<void>): void;
3
+ interface ParseResult {
4
+ cron: string;
5
+ type: ScheduledTask['type'];
6
+ prompt: string;
7
+ name: string;
8
+ }
9
+ /**
10
+ * Parse natural language schedule expression into cron + prompt.
11
+ *
12
+ * Examples:
13
+ * "每日17:50给我帮我看看AI新闻" → { cron: "50 17 * * *", prompt: "帮我看看AI新闻" }
14
+ * "每天9:00 检查服务状态" → { cron: "0 9 * * *", prompt: "检查服务状态" }
15
+ * "每周一10:30 生成周报" → { cron: "30 10 * * 1", prompt: "生成周报" }
16
+ * "工作日每天9:00 检查邮件" → { cron: "0 9 * * 1-5", prompt: "检查邮件" }
17
+ * "每小时 检查服务" → { cron: "0 * * * *", prompt: "检查服务" }
18
+ * "每30分钟 ping" → { cron: "*\/30 * * * *", prompt: "ping" }
19
+ * "每月1号9:00 生成月报" → { cron: "0 9 1 * *", prompt: "生成月报" }
20
+ */
21
+ export declare function parseNaturalSchedule(input: string): ParseResult | null;
22
+ export declare function startScheduler(): void;
23
+ export declare function stopScheduler(): void;
24
+ export declare function addTask(params: {
25
+ name: string;
26
+ type: ScheduledTask['type'];
27
+ schedule: string;
28
+ prompt: string;
29
+ workingDir: string;
30
+ chatId: string;
31
+ }): ScheduledTask;
32
+ export declare function removeTask(id: string): boolean;
33
+ export declare function enableTask(id: string): boolean;
34
+ export declare function disableTask(id: string): boolean;
35
+ export declare function runTaskNow(id: string): boolean;
36
+ export declare function getNextRun(id: string): Date | null;
37
+ export {};
38
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AASjD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAEnF;AASD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CA4GtE;AA0CD,wBAAgB,cAAc,IAAI,IAAI,CAQrC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,aAAa,CAIhB;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAG9C;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAO9C;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAM/C;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAa9C;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAGlD"}