cli-claw-kit 0.0.1

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 (295) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +245 -0
  3. package/config/default-groups.json +1 -0
  4. package/config/global-agents-md.template.md +37 -0
  5. package/config/mount-allowlist.json +11 -0
  6. package/container/Dockerfile +160 -0
  7. package/container/agent-runner/dist/.tsbuildinfo +1 -0
  8. package/container/agent-runner/dist/agent-definitions.js +22 -0
  9. package/container/agent-runner/dist/channel-prefixes.js +16 -0
  10. package/container/agent-runner/dist/codex-config.js +29 -0
  11. package/container/agent-runner/dist/image-detector.js +96 -0
  12. package/container/agent-runner/dist/index.js +2587 -0
  13. package/container/agent-runner/dist/mcp-tools.js +1076 -0
  14. package/container/agent-runner/dist/stream-event.types.js +5 -0
  15. package/container/agent-runner/dist/stream-processor.js +867 -0
  16. package/container/agent-runner/dist/types.js +6 -0
  17. package/container/agent-runner/dist/utils.js +115 -0
  18. package/container/agent-runner/package.json +36 -0
  19. package/container/agent-runner/prompts/security-rules.md +31 -0
  20. package/container/agent-runner/src/agent-definitions.ts +27 -0
  21. package/container/agent-runner/src/channel-prefixes.ts +16 -0
  22. package/container/agent-runner/src/codex-config.ts +40 -0
  23. package/container/agent-runner/src/image-detector.ts +116 -0
  24. package/container/agent-runner/src/index.ts +3107 -0
  25. package/container/agent-runner/src/mcp-tools.ts +1295 -0
  26. package/container/agent-runner/src/stream-event.types.ts +10 -0
  27. package/container/agent-runner/src/stream-processor.ts +932 -0
  28. package/container/agent-runner/src/types.ts +75 -0
  29. package/container/agent-runner/src/utils.ts +114 -0
  30. package/container/agent-runner/tsconfig.json +17 -0
  31. package/container/build.sh +28 -0
  32. package/container/entrypoint.sh +64 -0
  33. package/container/skills/agent-browser/SKILL.md +159 -0
  34. package/container/skills/install-skill/SKILL.md +64 -0
  35. package/container/skills/post-test-cleanup/SKILL.md +121 -0
  36. package/dist/.tsbuildinfo +1 -0
  37. package/dist/agent-output-parser.js +459 -0
  38. package/dist/app-root.js +52 -0
  39. package/dist/assistant-meta-footer.js +1 -0
  40. package/dist/auth.js +91 -0
  41. package/dist/billing.js +694 -0
  42. package/dist/channel-prefixes.js +16 -0
  43. package/dist/cli.js +86 -0
  44. package/dist/commands.js +79 -0
  45. package/dist/config.js +120 -0
  46. package/dist/container-runner.js +981 -0
  47. package/dist/daily-summary.js +210 -0
  48. package/dist/db.js +3683 -0
  49. package/dist/dingtalk.js +1347 -0
  50. package/dist/feishu-markdown-style.js +97 -0
  51. package/dist/feishu-streaming-card.js +1875 -0
  52. package/dist/feishu.js +1628 -0
  53. package/dist/file-manager.js +270 -0
  54. package/dist/group-queue.js +1070 -0
  55. package/dist/group-runtime.js +35 -0
  56. package/dist/host-workspace-cwd.js +85 -0
  57. package/dist/im-channel.js +384 -0
  58. package/dist/im-command-utils.js +142 -0
  59. package/dist/im-downloader.js +45 -0
  60. package/dist/im-manager.js +527 -0
  61. package/dist/im-utils.js +53 -0
  62. package/dist/image-detector.js +96 -0
  63. package/dist/index.js +5828 -0
  64. package/dist/logger.js +22 -0
  65. package/dist/mcp-utils.js +66 -0
  66. package/dist/message-attachments.js +69 -0
  67. package/dist/message-notifier.js +36 -0
  68. package/dist/middleware/auth.js +85 -0
  69. package/dist/mount-security.js +315 -0
  70. package/dist/permissions.js +67 -0
  71. package/dist/project-memory.js +6 -0
  72. package/dist/provider-pool.js +189 -0
  73. package/dist/qq.js +826 -0
  74. package/dist/reset-admin.js +42 -0
  75. package/dist/routes/admin.js +543 -0
  76. package/dist/routes/agent-definitions.js +241 -0
  77. package/dist/routes/agents.js +533 -0
  78. package/dist/routes/auth.js +675 -0
  79. package/dist/routes/billing.js +490 -0
  80. package/dist/routes/browse.js +210 -0
  81. package/dist/routes/bug-report.js +387 -0
  82. package/dist/routes/config.js +1868 -0
  83. package/dist/routes/files.js +671 -0
  84. package/dist/routes/groups.js +1367 -0
  85. package/dist/routes/mcp-servers.js +320 -0
  86. package/dist/routes/memory.js +523 -0
  87. package/dist/routes/monitor.js +307 -0
  88. package/dist/routes/skills.js +777 -0
  89. package/dist/routes/tasks.js +509 -0
  90. package/dist/routes/usage.js +64 -0
  91. package/dist/routes/workspace-config.js +458 -0
  92. package/dist/runtime-build.js +112 -0
  93. package/dist/runtime-command-handler.js +189 -0
  94. package/dist/runtime-command-registry.js +1 -0
  95. package/dist/runtime-config.js +1777 -0
  96. package/dist/runtime-identity.js +52 -0
  97. package/dist/schemas.js +590 -0
  98. package/dist/script-runner.js +64 -0
  99. package/dist/sdk-query.js +82 -0
  100. package/dist/skill-utils.js +145 -0
  101. package/dist/sqlite-compat.js +19 -0
  102. package/dist/stream-event.types.js +5 -0
  103. package/dist/streaming-runtime-meta.js +29 -0
  104. package/dist/task-scheduler.js +695 -0
  105. package/dist/task-utils.js +13 -0
  106. package/dist/telegram-pairing.js +59 -0
  107. package/dist/telegram.js +897 -0
  108. package/dist/terminal-manager.js +307 -0
  109. package/dist/tool-step-display.js +1 -0
  110. package/dist/types.js +1 -0
  111. package/dist/utils.js +85 -0
  112. package/dist/web-context.js +161 -0
  113. package/dist/web.js +1377 -0
  114. package/dist/wechat-crypto.js +182 -0
  115. package/dist/wechat.js +589 -0
  116. package/dist/workspace-runtime-reset.js +35 -0
  117. package/package.json +107 -0
  118. package/shared/assistant-meta-footer.ts +127 -0
  119. package/shared/channel-prefixes.ts +16 -0
  120. package/shared/dist/assistant-meta-footer.d.ts +29 -0
  121. package/shared/dist/assistant-meta-footer.js +85 -0
  122. package/shared/dist/channel-prefixes.d.ts +4 -0
  123. package/shared/dist/channel-prefixes.js +16 -0
  124. package/shared/dist/image-detector.d.ts +20 -0
  125. package/shared/dist/image-detector.js +96 -0
  126. package/shared/dist/runtime-command-registry.d.ts +38 -0
  127. package/shared/dist/runtime-command-registry.js +185 -0
  128. package/shared/dist/stream-event.d.ts +65 -0
  129. package/shared/dist/stream-event.js +8 -0
  130. package/shared/dist/tool-step-display.d.ts +4 -0
  131. package/shared/dist/tool-step-display.js +11 -0
  132. package/shared/image-detector.ts +116 -0
  133. package/shared/runtime-command-registry.ts +252 -0
  134. package/shared/stream-event.ts +67 -0
  135. package/shared/tool-step-display.ts +21 -0
  136. package/shared/tsconfig.json +24 -0
  137. package/web/dist/assets/BillingPage-B1wBR_o-.js +52 -0
  138. package/web/dist/assets/ChatPage-6GBZ9nXN.css +32 -0
  139. package/web/dist/assets/ChatPage-BOJcXtaj.js +161 -0
  140. package/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  141. package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  142. package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  143. package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  144. package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  145. package/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  146. package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  147. package/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  148. package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  149. package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  150. package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  151. package/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  152. package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  153. package/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  154. package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  155. package/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  156. package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  157. package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  158. package/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  159. package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  160. package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  161. package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  162. package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  163. package/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  164. package/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  165. package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  166. package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  167. package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  168. package/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  169. package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  170. package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  171. package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  172. package/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  173. package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  174. package/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  175. package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  176. package/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  177. package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  178. package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  179. package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  180. package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  181. package/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  182. package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  183. package/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  184. package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  185. package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  186. package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  187. package/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  188. package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  189. package/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  190. package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  191. package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  192. package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  193. package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  194. package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  195. package/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  196. package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  197. package/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  198. package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  199. package/web/dist/assets/SettingsPage-DoY7FoZ_.js +153 -0
  200. package/web/dist/assets/ShareImageDialog-C1ga8b7l.js +22 -0
  201. package/web/dist/assets/TasksPage-CRivnNsx.js +14 -0
  202. package/web/dist/assets/_basePickBy-Bf-bSoS9.js +1 -0
  203. package/web/dist/assets/_baseUniq-zAOaCuKw.js +1 -0
  204. package/web/dist/assets/arc-Dm9mVQ9U.js +1 -0
  205. package/web/dist/assets/architectureDiagram-2XIMDMQ5-BLmzX1wr.js +36 -0
  206. package/web/dist/assets/band-CquvqAHh.js +1 -0
  207. package/web/dist/assets/blockDiagram-WCTKOSBZ-B9pcqm3j.js +132 -0
  208. package/web/dist/assets/c4Diagram-IC4MRINW-Cytx1q3b.js +10 -0
  209. package/web/dist/assets/channel-BOVj73LR.js +1 -0
  210. package/web/dist/assets/channel-meta-CQD0Pei-.js +41 -0
  211. package/web/dist/assets/chunk-4BX2VUAB-0ToDr6RE.js +1 -0
  212. package/web/dist/assets/chunk-55IACEB6-DQDjnXfS.js +1 -0
  213. package/web/dist/assets/chunk-FMBD7UC4-Di8ABm6c.js +15 -0
  214. package/web/dist/assets/chunk-JSJVCQXG-BZQN6rnX.js +1 -0
  215. package/web/dist/assets/chunk-KX2RTZJC-zBbcpaN_.js +1 -0
  216. package/web/dist/assets/chunk-NQ4KR5QH-BCrLoU88.js +220 -0
  217. package/web/dist/assets/chunk-QZHKN3VN-Bqk8juan.js +1 -0
  218. package/web/dist/assets/chunk-WL4C6EOR-D2YX-MHY.js +189 -0
  219. package/web/dist/assets/classDiagram-VBA2DB6C-DUUoMyaK.js +1 -0
  220. package/web/dist/assets/classDiagram-v2-RAHNMMFH-DUUoMyaK.js +1 -0
  221. package/web/dist/assets/clone-BmaCesfa.js +1 -0
  222. package/web/dist/assets/cose-bilkent-S5V4N54A-CTsv6qQA.js +1 -0
  223. package/web/dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  224. package/web/dist/assets/dagre-KLK3FWXG-Ci4Jh9nu.js +4 -0
  225. package/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  226. package/web/dist/assets/diagram-E7M64L7V-BFRnfTI2.js +24 -0
  227. package/web/dist/assets/diagram-IFDJBPK2-B7Zhnp0b.js +43 -0
  228. package/web/dist/assets/diagram-P4PSJMXO-BVyP7nwq.js +24 -0
  229. package/web/dist/assets/erDiagram-INFDFZHY-NorKdTOF.js +70 -0
  230. package/web/dist/assets/error-CGD5mp5f.js +1 -0
  231. package/web/dist/assets/flowDiagram-PKNHOUZH-Ch97nABF.js +162 -0
  232. package/web/dist/assets/ganttDiagram-A5KZAMGK-BQ2pLWsy.js +292 -0
  233. package/web/dist/assets/gitGraphDiagram-K3NZZRJ6-bcvnBsD2.js +65 -0
  234. package/web/dist/assets/graph-CeAEckur.js +1 -0
  235. package/web/dist/assets/index-CPnL1_qC.js +768 -0
  236. package/web/dist/assets/index-DVevCbcO.css +10 -0
  237. package/web/dist/assets/infoDiagram-LFFYTUFH-CcsrFdj-.js +2 -0
  238. package/web/dist/assets/init-Dmth1JHB.js +1 -0
  239. package/web/dist/assets/ishikawaDiagram-PHBUUO56-1upyMfHN.js +70 -0
  240. package/web/dist/assets/journeyDiagram-4ABVD52K-CKUi-V0c.js +139 -0
  241. package/web/dist/assets/kanban-definition-K7BYSVSG-DOnQwXfL.js +89 -0
  242. package/web/dist/assets/layout-BmMMqTnJ.js +1 -0
  243. package/web/dist/assets/linear-DiaJloY5.js +1 -0
  244. package/web/dist/assets/mermaid.core-BWLV1B2v.js +254 -0
  245. package/web/dist/assets/mindmap-definition-YRQLILUH-BeAKHVWP.js +68 -0
  246. package/web/dist/assets/ordinal-DILIJJjt.js +1 -0
  247. package/web/dist/assets/pieDiagram-SKSYHLDU-DfiMSfWo.js +30 -0
  248. package/web/dist/assets/quadrantDiagram-337W2JSQ-wZxZOJxd.js +7 -0
  249. package/web/dist/assets/requirementDiagram-Z7DCOOCP-BK4HHm17.js +73 -0
  250. package/web/dist/assets/sankeyDiagram-WA2Y5GQK-BX6t2avX.js +10 -0
  251. package/web/dist/assets/sequenceDiagram-2WXFIKYE-BPQlkbAa.js +145 -0
  252. package/web/dist/assets/sheet-rI0FfB1g.js +6 -0
  253. package/web/dist/assets/sliders-horizontal-CuijWFNK.js +6 -0
  254. package/web/dist/assets/sparkles-BsMYXJoT.js +11 -0
  255. package/web/dist/assets/square-0CqMX1Q3.js +11 -0
  256. package/web/dist/assets/stateDiagram-RAJIS63D-DxkV0Vwd.js +1 -0
  257. package/web/dist/assets/stateDiagram-v2-FVOUBMTO-qLYoiOPe.js +1 -0
  258. package/web/dist/assets/step-D51IIHGA.js +1 -0
  259. package/web/dist/assets/tasks-D8JjBTwx.js +1 -0
  260. package/web/dist/assets/time-O8zIGux3.js +1 -0
  261. package/web/dist/assets/timeline-definition-YZTLITO2-kNp1DyFc.js +61 -0
  262. package/web/dist/assets/treemap-KZPCXAKY-CkrClVhk.js +162 -0
  263. package/web/dist/assets/utils-KGAn0XTg.js +11 -0
  264. package/web/dist/assets/vennDiagram-LZ73GAT5-CgdzEZz4.js +34 -0
  265. package/web/dist/assets/xychartDiagram-JWTSCODW-DfYGPfNB.js +7 -0
  266. package/web/dist/assets/zap-_hKJYy7J.js +6 -0
  267. package/web/dist/favicon.svg +332 -0
  268. package/web/dist/fonts/AlibabaPuHuiTi-3-55-Regular.woff2 +0 -0
  269. package/web/dist/fonts/AlibabaPuHuiTi-3-65-Medium.woff2 +0 -0
  270. package/web/dist/fonts/AlibabaPuHuiTi-3-75-SemiBold.woff2 +0 -0
  271. package/web/dist/fonts/DMSans-latin-ext.woff2 +0 -0
  272. package/web/dist/fonts/DMSans-latin.woff2 +0 -0
  273. package/web/dist/icons/README.md +20 -0
  274. package/web/dist/icons/apple-touch-icon-180.png +0 -0
  275. package/web/dist/icons/icon-128.png +0 -0
  276. package/web/dist/icons/icon-144.png +0 -0
  277. package/web/dist/icons/icon-152.png +0 -0
  278. package/web/dist/icons/icon-192.png +0 -0
  279. package/web/dist/icons/icon-192.svg +332 -0
  280. package/web/dist/icons/icon-384.png +0 -0
  281. package/web/dist/icons/icon-48.png +0 -0
  282. package/web/dist/icons/icon-512-maskable.png +0 -0
  283. package/web/dist/icons/icon-512.png +0 -0
  284. package/web/dist/icons/icon-512.svg +332 -0
  285. package/web/dist/icons/icon-72.png +0 -0
  286. package/web/dist/icons/icon-96.png +0 -0
  287. package/web/dist/icons/loading-logo.svg +332 -0
  288. package/web/dist/icons/logo-1024.png +0 -0
  289. package/web/dist/icons/logo-icon.svg +332 -0
  290. package/web/dist/icons/logo-text.svg +332 -0
  291. package/web/dist/index.html +30 -0
  292. package/web/dist/manifest.webmanifest +1 -0
  293. package/web/dist/registerSW.js +1 -0
  294. package/web/dist/sw.js +1 -0
  295. package/web/dist/workbox-08d6266a.js +1 -0
@@ -0,0 +1,307 @@
1
+ import { execFile, spawn } from 'child_process';
2
+ import readline from 'readline';
3
+ import { promisify } from 'util';
4
+ import { Hono } from 'hono';
5
+ import { resolveAppPath, resolvePackageDependency } from '../app-root.js';
6
+ import { authMiddleware, systemConfigMiddleware } from '../middleware/auth.js';
7
+ import { isHostExecutionGroup, hasHostExecutionPermission, canAccessGroup, getWebDeps, } from '../web-context.js';
8
+ import { getRegisteredGroup, getRouterState, hasContainerModeGroups, } from '../db.js';
9
+ import { CONTAINER_IMAGE } from '../config.js';
10
+ import { getSystemSettings } from '../runtime-config.js';
11
+ import { logger } from '../logger.js';
12
+ const execFileAsync = promisify(execFile);
13
+ let cachedVersions = null;
14
+ const VERSION_CACHE_TTL = 60 * 60 * 1000;
15
+ // Latest version cache (separate TTL, queried from npm registry)
16
+ let cachedLatestVersion = null;
17
+ const LATEST_VERSION_CACHE_TTL = 30 * 60 * 1000; // 30min
18
+ /** Query latest Claude Code version from npm registry */
19
+ async function getLatestClaudeCodeVersion() {
20
+ const now = Date.now();
21
+ if (cachedLatestVersion &&
22
+ now - cachedLatestVersion.fetchedAt < LATEST_VERSION_CACHE_TTL) {
23
+ return cachedLatestVersion.version;
24
+ }
25
+ try {
26
+ const { stdout } = await execFileAsync('npm', ['view', '@anthropic-ai/claude-code', 'version'], { timeout: 15000 });
27
+ const version = stdout.trim() || null;
28
+ cachedLatestVersion = { version, fetchedAt: now };
29
+ return version;
30
+ }
31
+ catch {
32
+ // Fallback: keep stale cache if available
33
+ if (cachedLatestVersion)
34
+ return cachedLatestVersion.version;
35
+ cachedLatestVersion = { version: null, fetchedAt: now };
36
+ return null;
37
+ }
38
+ }
39
+ /** Get host Claude Code version by running SDK's built-in cli.js --version */
40
+ async function getHostClaudeCodeVersion() {
41
+ try {
42
+ const cliPath = resolvePackageDependency('@anthropic-ai/claude-agent-sdk/cli.js');
43
+ const { stdout } = await execFileAsync('node', [
44
+ '-e',
45
+ `process.argv = ['node', 'claude', '--version']; require('${cliPath}')`,
46
+ ], { timeout: 10000 });
47
+ return stdout.trim() || null;
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ async function getDockerImageId() {
54
+ try {
55
+ const { stdout } = await execFileAsync('docker', ['images', CONTAINER_IMAGE, '--format', '{{.ID}}'], { timeout: 5000 });
56
+ return stdout.trim() || null;
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }
62
+ /** Get container Claude Code version from SDK's cli.js inside Docker image */
63
+ async function getContainerClaudeCodeVersion() {
64
+ try {
65
+ const { stdout } = await execFileAsync('docker', [
66
+ 'run',
67
+ '--rm',
68
+ '--entrypoint',
69
+ 'node',
70
+ CONTAINER_IMAGE,
71
+ '-e',
72
+ `process.argv = ['node', 'claude', '--version']; require('/app/node_modules/@anthropic-ai/claude-agent-sdk/cli.js')`,
73
+ ], { timeout: 30000 });
74
+ return stdout.trim() || null;
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
80
+ async function getClaudeCodeVersions() {
81
+ const now = Date.now();
82
+ const imageId = await getDockerImageId();
83
+ // Return cached if same image and within TTL
84
+ if (cachedVersions &&
85
+ cachedVersions.imageId === imageId &&
86
+ now - cachedVersions.fetchedAt < VERSION_CACHE_TTL) {
87
+ return cachedVersions.info;
88
+ }
89
+ // Fetch all versions concurrently
90
+ const [host, container, latest] = await Promise.all([
91
+ getHostClaudeCodeVersion(),
92
+ imageId ? getContainerClaudeCodeVersion() : Promise.resolve(null),
93
+ getLatestClaudeCodeVersion(),
94
+ ]);
95
+ const info = { host, container, latest };
96
+ cachedVersions = { info, fetchedAt: now, imageId };
97
+ return info;
98
+ }
99
+ // --- Docker build state ---
100
+ let buildState = {
101
+ building: false,
102
+ startedAt: null,
103
+ startedBy: null,
104
+ logs: [],
105
+ result: null,
106
+ };
107
+ // --- Dependency injection (avoid circular imports) ---
108
+ let broadcastLog = null;
109
+ let broadcastComplete = null;
110
+ export function injectMonitorDeps(deps) {
111
+ broadcastLog = deps.broadcastDockerBuildLog;
112
+ broadcastComplete = deps.broadcastDockerBuildComplete;
113
+ }
114
+ const monitorRoutes = new Hono();
115
+ // GET /api/health - 健康检查(无认证)
116
+ monitorRoutes.get('/health', async (c) => {
117
+ const checks = {
118
+ database: false,
119
+ queue: false,
120
+ uptime: 0,
121
+ };
122
+ let healthy = true;
123
+ // 检查数据库连通性
124
+ try {
125
+ getRouterState('last_timestamp');
126
+ checks.database = true;
127
+ }
128
+ catch (err) {
129
+ healthy = false;
130
+ logger.warn({ err }, '健康检查:数据库连接失败');
131
+ }
132
+ // 检查队列状态
133
+ try {
134
+ const deps = getWebDeps();
135
+ if (deps && deps.queue) {
136
+ checks.queue = true;
137
+ }
138
+ else {
139
+ healthy = false;
140
+ }
141
+ }
142
+ catch (err) {
143
+ healthy = false;
144
+ logger.warn({ err }, '健康检查:队列不可用');
145
+ }
146
+ // 进程运行时间
147
+ checks.uptime = Math.floor(process.uptime());
148
+ const status = healthy ? 'healthy' : 'unhealthy';
149
+ const statusCode = healthy ? 200 : 503;
150
+ return c.json({ status, checks }, statusCode);
151
+ });
152
+ async function checkDockerImageExists() {
153
+ // Skip Docker check entirely when no groups use container mode
154
+ if (!hasContainerModeGroups())
155
+ return false;
156
+ try {
157
+ const { stdout } = await execFileAsync('docker', ['images', CONTAINER_IMAGE, '--format', '{{.ID}}'], { timeout: 10000 });
158
+ return stdout.trim().length > 0;
159
+ }
160
+ catch {
161
+ return false;
162
+ }
163
+ }
164
+ // GET /api/status - 获取系统状态
165
+ monitorRoutes.get('/status', authMiddleware, async (c) => {
166
+ const deps = getWebDeps();
167
+ if (!deps)
168
+ return c.json({ error: 'Server not initialized' }, 500);
169
+ const authUser = c.get('user');
170
+ const isAdmin = hasHostExecutionPermission(authUser);
171
+ const queueStatus = deps.queue.getStatus();
172
+ // 监控页面属于系统管理功能,admin 可见所有群组状态(不受工作区隔离约束)
173
+ const filteredGroups = isAdmin
174
+ ? queueStatus.groups
175
+ : queueStatus.groups.filter((g) => {
176
+ const group = getRegisteredGroup(g.jid);
177
+ if (!group)
178
+ return false;
179
+ if (isHostExecutionGroup(group))
180
+ return false;
181
+ return canAccessGroup({ id: authUser.id, role: authUser.role }, group);
182
+ });
183
+ const dockerImageExists = await checkDockerImageExists();
184
+ // For non-admin users, derive aggregate metrics from their own filtered groups only
185
+ // to prevent leaking global system load information across users
186
+ let activeContainers;
187
+ let queueLength;
188
+ if (isAdmin) {
189
+ activeContainers = queueStatus.activeContainerCount;
190
+ queueLength = queueStatus.waitingCount;
191
+ }
192
+ else {
193
+ activeContainers = filteredGroups.filter((g) => g.active).length;
194
+ // Filter waiting groups by user ownership
195
+ queueLength = queueStatus.waitingGroupJids.filter((jid) => {
196
+ const group = getRegisteredGroup(jid);
197
+ if (!group)
198
+ return false;
199
+ if (isHostExecutionGroup(group))
200
+ return false;
201
+ return canAccessGroup({ id: authUser.id, role: authUser.role }, group);
202
+ }).length;
203
+ }
204
+ return c.json({
205
+ activeContainers,
206
+ activeHostProcesses: isAdmin
207
+ ? queueStatus.activeHostProcessCount
208
+ : undefined,
209
+ activeTotal: isAdmin ? queueStatus.activeCount : activeContainers,
210
+ maxConcurrentContainers: getSystemSettings().maxConcurrentContainers,
211
+ maxConcurrentHostProcesses: isAdmin
212
+ ? getSystemSettings().maxConcurrentHostProcesses
213
+ : undefined,
214
+ queueLength,
215
+ uptime: Math.floor(process.uptime()),
216
+ groups: filteredGroups,
217
+ dockerImageExists,
218
+ dockerBuildInProgress: buildState.building,
219
+ claudeCodeVersions: isAdmin ? await getClaudeCodeVersions() : undefined,
220
+ dockerBuildLogs: isAdmin && buildState.building ? buildState.logs.slice(-50) : undefined,
221
+ dockerBuildResult: isAdmin ? buildState.result : undefined,
222
+ });
223
+ });
224
+ // POST /api/docker/build - 构建 Docker 镜像(仅 admin,异步启动 + WS 推送进度)
225
+ monitorRoutes.post('/docker/build', authMiddleware, systemConfigMiddleware, async (c) => {
226
+ if (buildState.building) {
227
+ return c.json({
228
+ error: 'Docker image build already in progress',
229
+ startedAt: buildState.startedAt,
230
+ startedBy: buildState.startedBy,
231
+ }, 409);
232
+ }
233
+ const authUser = c.get('user');
234
+ const buildScript = resolveAppPath('container', 'build.sh');
235
+ buildState = {
236
+ building: true,
237
+ startedAt: Date.now(),
238
+ startedBy: authUser.username,
239
+ logs: [],
240
+ result: null,
241
+ };
242
+ logger.info({ startedBy: authUser.username }, 'Docker image build requested via API');
243
+ // Spawn build process asynchronously
244
+ const proc = spawn('bash', [buildScript], {
245
+ cwd: resolveAppPath('container'),
246
+ stdio: ['ignore', 'pipe', 'pipe'],
247
+ });
248
+ // 10-minute timeout
249
+ const timeout = setTimeout(() => {
250
+ proc.kill('SIGKILL');
251
+ const errMsg = 'Docker build timed out after 10 minutes';
252
+ logger.error(errMsg);
253
+ buildState.building = false;
254
+ buildState.result = { success: false, error: errMsg };
255
+ broadcastLog?.(errMsg);
256
+ broadcastComplete?.(false, errMsg);
257
+ }, 10 * 60 * 1000);
258
+ const pushLine = (line) => {
259
+ buildState.logs.push(line);
260
+ // Keep last 200 lines in memory
261
+ if (buildState.logs.length > 200) {
262
+ buildState.logs = buildState.logs.slice(-200);
263
+ }
264
+ broadcastLog?.(line);
265
+ };
266
+ // Read stdout and stderr line by line
267
+ if (proc.stdout) {
268
+ const rl = readline.createInterface({ input: proc.stdout });
269
+ rl.on('line', pushLine);
270
+ }
271
+ if (proc.stderr) {
272
+ const rl = readline.createInterface({ input: proc.stderr });
273
+ rl.on('line', pushLine);
274
+ }
275
+ proc.on('close', (code) => {
276
+ clearTimeout(timeout);
277
+ const success = code === 0;
278
+ const error = success
279
+ ? undefined
280
+ : `Build process exited with code ${code}`;
281
+ if (success) {
282
+ logger.info('Docker image build completed');
283
+ // Invalidate version cache so next query fetches from new image
284
+ cachedVersions = null;
285
+ }
286
+ else {
287
+ logger.error({ code }, 'Docker image build failed');
288
+ }
289
+ buildState.building = false;
290
+ buildState.result = { success, error };
291
+ broadcastComplete?.(success, error);
292
+ });
293
+ proc.on('error', (err) => {
294
+ clearTimeout(timeout);
295
+ const errorMsg = err.message;
296
+ logger.error({ err }, 'Docker image build process error');
297
+ buildState.building = false;
298
+ buildState.result = { success: false, error: errorMsg };
299
+ broadcastComplete?.(false, errorMsg);
300
+ });
301
+ // Return immediately with 202 Accepted
302
+ return c.json({
303
+ accepted: true,
304
+ message: 'Docker image build started. Progress will be streamed via WebSocket.',
305
+ }, 202);
306
+ });
307
+ export default monitorRoutes;