clawmini 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 (469) hide show
  1. package/.gemini/settings.json +46 -0
  2. package/.prettierrc +7 -0
  3. package/GEMINI.md +11 -0
  4. package/README.md +137 -0
  5. package/dist/adapter-discord/index.d.mts +5 -0
  6. package/dist/adapter-discord/index.d.mts.map +1 -0
  7. package/dist/adapter-discord/index.mjs +456 -0
  8. package/dist/adapter-discord/index.mjs.map +1 -0
  9. package/dist/chats-DKgTeU7i.mjs +91 -0
  10. package/dist/chats-DKgTeU7i.mjs.map +1 -0
  11. package/dist/chats-Zd_HXDHx.mjs +29 -0
  12. package/dist/chats-Zd_HXDHx.mjs.map +1 -0
  13. package/dist/cli/index.d.mts +1 -0
  14. package/dist/cli/index.mjs +850 -0
  15. package/dist/cli/index.mjs.map +1 -0
  16. package/dist/cli/lite.d.mts +1 -0
  17. package/dist/cli/lite.mjs +4434 -0
  18. package/dist/cli/lite.mjs.map +1 -0
  19. package/dist/daemon/index.d.mts +5 -0
  20. package/dist/daemon/index.d.mts.map +1 -0
  21. package/dist/daemon/index.mjs +1222 -0
  22. package/dist/daemon/index.mjs.map +1 -0
  23. package/dist/fetch-BjZVyU3Z.mjs +37 -0
  24. package/dist/fetch-BjZVyU3Z.mjs.map +1 -0
  25. package/dist/fs-B5wW0oaH.mjs +14 -0
  26. package/dist/fs-B5wW0oaH.mjs.map +1 -0
  27. package/dist/lite-Dl7WXyaH.mjs +80 -0
  28. package/dist/lite-Dl7WXyaH.mjs.map +1 -0
  29. package/dist/rolldown-runtime-95iHPtFO.mjs +18 -0
  30. package/dist/web/_app/env.js +1 -0
  31. package/dist/web/_app/immutable/assets/0.GI4C4dpV.css +1 -0
  32. package/dist/web/_app/immutable/chunks/B5abRDXp.js +1 -0
  33. package/dist/web/_app/immutable/chunks/B8yYFADm.js +1 -0
  34. package/dist/web/_app/immutable/chunks/BPy8HLo7.js +5 -0
  35. package/dist/web/_app/immutable/chunks/Bi0jeV7Q.js +1 -0
  36. package/dist/web/_app/immutable/chunks/BmUXQ3wy.js +2 -0
  37. package/dist/web/_app/immutable/chunks/C3k55nDF.js +1 -0
  38. package/dist/web/_app/immutable/chunks/COekwvP2.js +1 -0
  39. package/dist/web/_app/immutable/chunks/CSvS_NwK.js +1 -0
  40. package/dist/web/_app/immutable/chunks/CpaGRn9L.js +1 -0
  41. package/dist/web/_app/immutable/chunks/CyNaE55B.js +1 -0
  42. package/dist/web/_app/immutable/chunks/DG5RZBw-.js +2 -0
  43. package/dist/web/_app/immutable/chunks/Dc-UOHw9.js +1 -0
  44. package/dist/web/_app/immutable/chunks/DcrmIfTj.js +1 -0
  45. package/dist/web/_app/immutable/chunks/ZkLyk0mE.js +1 -0
  46. package/dist/web/_app/immutable/entry/app.B-vZe7PN.js +2 -0
  47. package/dist/web/_app/immutable/entry/start.oP1AgKhs.js +1 -0
  48. package/dist/web/_app/immutable/nodes/0.B5WFN0zw.js +1 -0
  49. package/dist/web/_app/immutable/nodes/1.D1wtJb2k.js +1 -0
  50. package/dist/web/_app/immutable/nodes/2.CK3CLC0f.js +1 -0
  51. package/dist/web/_app/immutable/nodes/3.BB5wCoBf.js +4 -0
  52. package/dist/web/_app/immutable/nodes/4.Dr2jvAXK.js +1 -0
  53. package/dist/web/_app/immutable/nodes/5.BJl7oM3b.js +1 -0
  54. package/dist/web/_app/version.json +1 -0
  55. package/dist/web/index.html +37 -0
  56. package/dist/web/robots.txt +3 -0
  57. package/dist/workspace-CSgfo_2J.mjs +383 -0
  58. package/dist/workspace-CSgfo_2J.mjs.map +1 -0
  59. package/docs/01_chats/development_log.md +36 -0
  60. package/docs/01_chats/notes.md +27 -0
  61. package/docs/01_chats/prd.md +47 -0
  62. package/docs/01_chats/questions.md +19 -0
  63. package/docs/01_chats/tickets.md +67 -0
  64. package/docs/02_sessions/development_log.md +79 -0
  65. package/docs/02_sessions/notes.md +40 -0
  66. package/docs/02_sessions/prd.md +75 -0
  67. package/docs/02_sessions/questions.md +7 -0
  68. package/docs/02_sessions/tickets.md +68 -0
  69. package/docs/03_web_interface/development_log.md +60 -0
  70. package/docs/03_web_interface/notes.md +29 -0
  71. package/docs/03_web_interface/prd.md +42 -0
  72. package/docs/03_web_interface/questions.md +8 -0
  73. package/docs/03_web_interface/tickets.md +59 -0
  74. package/docs/04_agents/development_log.md +54 -0
  75. package/docs/04_agents/notes.md +45 -0
  76. package/docs/04_agents/prd.md +47 -0
  77. package/docs/04_agents/questions.md +13 -0
  78. package/docs/04_agents/tickets.md +107 -0
  79. package/docs/05_routers/development_log.md +13 -0
  80. package/docs/05_routers/notes.md +40 -0
  81. package/docs/05_routers/prd.md +55 -0
  82. package/docs/05_routers/questions.md +21 -0
  83. package/docs/05_routers/tickets.md +109 -0
  84. package/docs/06_agent_templates/development_log.md +38 -0
  85. package/docs/06_agent_templates/notes.md +25 -0
  86. package/docs/06_agent_templates/prd.md +34 -0
  87. package/docs/06_agent_templates/questions.md +11 -0
  88. package/docs/06_agent_templates/tickets.md +49 -0
  89. package/docs/06_cron/development_log.md +51 -0
  90. package/docs/06_cron/notes.md +14 -0
  91. package/docs/06_cron/prd.md +92 -0
  92. package/docs/06_cron/questions.md +15 -0
  93. package/docs/06_cron/tickets.md +75 -0
  94. package/docs/07_web_chat_ux/development_log.md +30 -0
  95. package/docs/07_web_chat_ux/notes.md +25 -0
  96. package/docs/07_web_chat_ux/prd.md +46 -0
  97. package/docs/07_web_chat_ux/questions.md +7 -0
  98. package/docs/07_web_chat_ux/tickets.md +48 -0
  99. package/docs/08_agent_api/development_log.md +52 -0
  100. package/docs/08_agent_api/notes.md +31 -0
  101. package/docs/08_agent_api/prd.md +56 -0
  102. package/docs/08_agent_api/questions.md +14 -0
  103. package/docs/08_agent_api/tickets.md +104 -0
  104. package/docs/09_agent_fallbacks/development_log.md +52 -0
  105. package/docs/09_agent_fallbacks/notes.md +40 -0
  106. package/docs/09_agent_fallbacks/prd.md +55 -0
  107. package/docs/09_agent_fallbacks/questions.md +10 -0
  108. package/docs/09_agent_fallbacks/tickets.md +88 -0
  109. package/docs/09_discord_adapter/development_log.md +95 -0
  110. package/docs/09_discord_adapter/notes.md +18 -0
  111. package/docs/09_discord_adapter/prd.md +57 -0
  112. package/docs/09_discord_adapter/questions.md +16 -0
  113. package/docs/09_discord_adapter/tickets.md +116 -0
  114. package/docs/10_file_attachments/development_log.md +55 -0
  115. package/docs/10_file_attachments/notes.md +59 -0
  116. package/docs/10_file_attachments/prd.md +73 -0
  117. package/docs/10_file_attachments/questions.md +15 -0
  118. package/docs/10_file_attachments/tickets.md +88 -0
  119. package/docs/11_message_verbosity/development_log.md +43 -0
  120. package/docs/11_message_verbosity/notes.md +26 -0
  121. package/docs/11_message_verbosity/prd.md +44 -0
  122. package/docs/11_message_verbosity/questions.md +8 -0
  123. package/docs/11_message_verbosity/tickets.md +33 -0
  124. package/docs/12_environments/development_log.md +43 -0
  125. package/docs/12_environments/notes.md +45 -0
  126. package/docs/12_environments/prd.md +113 -0
  127. package/docs/12_environments/questions.md +17 -0
  128. package/docs/12_environments/tickets.md +87 -0
  129. package/docs/12_setup_flow_improvements/development_log.md +40 -0
  130. package/docs/12_setup_flow_improvements/notes.md +34 -0
  131. package/docs/12_setup_flow_improvements/prd.md +35 -0
  132. package/docs/12_setup_flow_improvements/questions.md +8 -0
  133. package/docs/12_setup_flow_improvements/tickets.md +122 -0
  134. package/docs/13_discord_typing_indicators/development_log.md +38 -0
  135. package/docs/13_discord_typing_indicators/notes.md +18 -0
  136. package/docs/13_discord_typing_indicators/prd.md +41 -0
  137. package/docs/13_discord_typing_indicators/questions.md +6 -0
  138. package/docs/13_discord_typing_indicators/tickets.md +60 -0
  139. package/docs/14_interruptions/development_log.md +50 -0
  140. package/docs/14_interruptions/notes.md +38 -0
  141. package/docs/14_interruptions/prd.md +46 -0
  142. package/docs/14_interruptions/questions.md +12 -0
  143. package/docs/14_interruptions/tickets.md +69 -0
  144. package/docs/15_sandbox_policies/development_log.md +95 -0
  145. package/docs/15_sandbox_policies/notes.md +33 -0
  146. package/docs/15_sandbox_policies/prd.md +163 -0
  147. package/docs/15_sandbox_policies/questions.md +10 -0
  148. package/docs/15_sandbox_policies/tickets.md +196 -0
  149. package/docs/CHECKS.md +9 -0
  150. package/docs/guides/discord_adapter_setup.md +69 -0
  151. package/docs/guides/sandbox_policies.md +76 -0
  152. package/eslint.config.js +47 -0
  153. package/napkin.md +21 -0
  154. package/package.json +50 -0
  155. package/scripts/create_worktree.sh +49 -0
  156. package/scripts/get_pr_comments.sh +36 -0
  157. package/src/adapter-discord/client.test.ts +65 -0
  158. package/src/adapter-discord/client.ts +41 -0
  159. package/src/adapter-discord/config.test.ts +156 -0
  160. package/src/adapter-discord/config.ts +61 -0
  161. package/src/adapter-discord/forwarder.test.ts +493 -0
  162. package/src/adapter-discord/forwarder.ts +246 -0
  163. package/src/adapter-discord/index.test.ts +399 -0
  164. package/src/adapter-discord/index.ts +147 -0
  165. package/src/adapter-discord/state.test.ts +65 -0
  166. package/src/adapter-discord/state.ts +44 -0
  167. package/src/cli/client.ts +46 -0
  168. package/src/cli/commands/agents.ts +138 -0
  169. package/src/cli/commands/chats.ts +79 -0
  170. package/src/cli/commands/down.ts +32 -0
  171. package/src/cli/commands/environments.ts +39 -0
  172. package/src/cli/commands/export-lite.ts +62 -0
  173. package/src/cli/commands/init.ts +79 -0
  174. package/src/cli/commands/jobs.ts +141 -0
  175. package/src/cli/commands/messages.ts +103 -0
  176. package/src/cli/commands/up.ts +26 -0
  177. package/src/cli/commands/web-api/agents.ts +138 -0
  178. package/src/cli/commands/web-api/chats.ts +213 -0
  179. package/src/cli/commands/web-api/utils.ts +27 -0
  180. package/src/cli/commands/web.ts +105 -0
  181. package/src/cli/e2e/adapter-discord.test.ts +76 -0
  182. package/src/cli/e2e/agents.test.ts +140 -0
  183. package/src/cli/e2e/basic.test.ts +43 -0
  184. package/src/cli/e2e/cron.test.ts +132 -0
  185. package/src/cli/e2e/daemon.test.ts +293 -0
  186. package/src/cli/e2e/environments.test.ts +66 -0
  187. package/src/cli/e2e/export-lite-func.test.ts +155 -0
  188. package/src/cli/e2e/export-lite.test.ts +51 -0
  189. package/src/cli/e2e/fallbacks.test.ts +169 -0
  190. package/src/cli/e2e/global-setup.ts +15 -0
  191. package/src/cli/e2e/init.test.ts +70 -0
  192. package/src/cli/e2e/messages.test.ts +294 -0
  193. package/src/cli/e2e/requests.test.ts +165 -0
  194. package/src/cli/e2e/utils.ts +66 -0
  195. package/src/cli/index.test.ts +7 -0
  196. package/src/cli/index.ts +29 -0
  197. package/src/cli/lite.ts +247 -0
  198. package/src/cli/utils.ts +4 -0
  199. package/src/daemon/auth.test.ts +50 -0
  200. package/src/daemon/auth.ts +69 -0
  201. package/src/daemon/chats.ts +26 -0
  202. package/src/daemon/cron.test.ts +28 -0
  203. package/src/daemon/cron.ts +159 -0
  204. package/src/daemon/events.ts +15 -0
  205. package/src/daemon/index.ts +212 -0
  206. package/src/daemon/message-agent.test.ts +132 -0
  207. package/src/daemon/message-extraction.test.ts +166 -0
  208. package/src/daemon/message-fallbacks.test.ts +313 -0
  209. package/src/daemon/message-interruption.test.ts +125 -0
  210. package/src/daemon/message-queue.test.ts +143 -0
  211. package/src/daemon/message-router.test.ts +106 -0
  212. package/src/daemon/message-session.test.ts +127 -0
  213. package/src/daemon/message-test-utils.ts +41 -0
  214. package/src/daemon/message-typing.test.ts +93 -0
  215. package/src/daemon/message-verbosity.test.ts +127 -0
  216. package/src/daemon/message.ts +600 -0
  217. package/src/daemon/observation.test.ts +118 -0
  218. package/src/daemon/policy-request-service.test.ts +87 -0
  219. package/src/daemon/policy-request-service.ts +62 -0
  220. package/src/daemon/policy-utils.test.ts +138 -0
  221. package/src/daemon/policy-utils.ts +152 -0
  222. package/src/daemon/queue.test.ts +89 -0
  223. package/src/daemon/queue.ts +87 -0
  224. package/src/daemon/request-store.test.ts +103 -0
  225. package/src/daemon/request-store.ts +96 -0
  226. package/src/daemon/router-policy-request.test.ts +99 -0
  227. package/src/daemon/router.test.ts +380 -0
  228. package/src/daemon/router.ts +510 -0
  229. package/src/daemon/routers/slash-command.test.ts +145 -0
  230. package/src/daemon/routers/slash-command.ts +58 -0
  231. package/src/daemon/routers/slash-interrupt.test.ts +30 -0
  232. package/src/daemon/routers/slash-interrupt.ts +7 -0
  233. package/src/daemon/routers/slash-new.test.ts +59 -0
  234. package/src/daemon/routers/slash-new.ts +14 -0
  235. package/src/daemon/routers/slash-policies.test.ts +167 -0
  236. package/src/daemon/routers/slash-policies.ts +131 -0
  237. package/src/daemon/routers/slash-stop.test.ts +30 -0
  238. package/src/daemon/routers/slash-stop.ts +3 -0
  239. package/src/daemon/routers/types.ts +10 -0
  240. package/src/daemon/routers/utils.ts +22 -0
  241. package/src/daemon/routers.test.ts +141 -0
  242. package/src/daemon/routers.ts +115 -0
  243. package/src/daemon/utils/spawn.ts +61 -0
  244. package/src/shared/agent-utils.ts +30 -0
  245. package/src/shared/chats.test.ts +112 -0
  246. package/src/shared/chats.ts +164 -0
  247. package/src/shared/config.test.ts +90 -0
  248. package/src/shared/config.ts +100 -0
  249. package/src/shared/event-source.ts +121 -0
  250. package/src/shared/fetch.ts +45 -0
  251. package/src/shared/lite.ts +129 -0
  252. package/src/shared/policies.ts +24 -0
  253. package/src/shared/utils/env.ts +27 -0
  254. package/src/shared/utils/fs.ts +13 -0
  255. package/src/shared/workspace.test.ts +345 -0
  256. package/src/shared/workspace.ts +500 -0
  257. package/templates/environments/cladding/env.json +7 -0
  258. package/templates/environments/macos/env.json +8 -0
  259. package/templates/environments/macos/sandbox.sb +21 -0
  260. package/templates/environments/macos-proxy/allowlist.txt +1 -0
  261. package/templates/environments/macos-proxy/env.json +14 -0
  262. package/templates/environments/macos-proxy/proxy.mjs +86 -0
  263. package/templates/environments/macos-proxy/sandbox.sb +34 -0
  264. package/templates/gemini/settings.json +11 -0
  265. package/templates/gemini-claw/.gemini/hooks/clawmini-logging.sh +17 -0
  266. package/templates/gemini-claw/.gemini/settings.json +24 -0
  267. package/templates/gemini-claw/.gemini/skills/clawmini-jobs/SKILL.md +40 -0
  268. package/templates/gemini-claw/.gemini/system.md +98 -0
  269. package/templates/gemini-claw/BOOTSTRAP.md +54 -0
  270. package/templates/gemini-claw/GEMINI.md +107 -0
  271. package/templates/gemini-claw/HEARTBEAT.md +3 -0
  272. package/templates/gemini-claw/MEMORY.md +2 -0
  273. package/templates/gemini-claw/SOUL.md +42 -0
  274. package/templates/gemini-claw/TOOLS.md +38 -0
  275. package/templates/gemini-claw/USER.md +15 -0
  276. package/templates/gemini-claw/memory/.gitkeep +0 -0
  277. package/templates/gemini-claw/settings.json +24 -0
  278. package/templates/opencode/settings.json +11 -0
  279. package/tsconfig.json +42 -0
  280. package/tsdown.config.ts +19 -0
  281. package/vitest.config.ts +9 -0
  282. package/web/.svelte-kit/ambient.d.ts +382 -0
  283. package/web/.svelte-kit/generated/client/app.js +35 -0
  284. package/web/.svelte-kit/generated/client/matchers.js +1 -0
  285. package/web/.svelte-kit/generated/client/nodes/0.js +3 -0
  286. package/web/.svelte-kit/generated/client/nodes/1.js +1 -0
  287. package/web/.svelte-kit/generated/client/nodes/2.js +1 -0
  288. package/web/.svelte-kit/generated/client/nodes/3.js +1 -0
  289. package/web/.svelte-kit/generated/client/nodes/4.js +3 -0
  290. package/web/.svelte-kit/generated/client/nodes/5.js +3 -0
  291. package/web/.svelte-kit/generated/client-optimized/app.js +35 -0
  292. package/web/.svelte-kit/generated/client-optimized/matchers.js +1 -0
  293. package/web/.svelte-kit/generated/client-optimized/nodes/0.js +3 -0
  294. package/web/.svelte-kit/generated/client-optimized/nodes/1.js +1 -0
  295. package/web/.svelte-kit/generated/client-optimized/nodes/2.js +1 -0
  296. package/web/.svelte-kit/generated/client-optimized/nodes/3.js +1 -0
  297. package/web/.svelte-kit/generated/client-optimized/nodes/4.js +3 -0
  298. package/web/.svelte-kit/generated/client-optimized/nodes/5.js +3 -0
  299. package/web/.svelte-kit/generated/root.js +3 -0
  300. package/web/.svelte-kit/generated/root.svelte +68 -0
  301. package/web/.svelte-kit/generated/server/internal.js +53 -0
  302. package/web/.svelte-kit/non-ambient.d.ts +46 -0
  303. package/web/.svelte-kit/output/client/.vite/manifest.json +251 -0
  304. package/web/.svelte-kit/output/client/_app/immutable/assets/0.GI4C4dpV.css +1 -0
  305. package/web/.svelte-kit/output/client/_app/immutable/chunks/B5abRDXp.js +1 -0
  306. package/web/.svelte-kit/output/client/_app/immutable/chunks/B8yYFADm.js +1 -0
  307. package/web/.svelte-kit/output/client/_app/immutable/chunks/BPy8HLo7.js +5 -0
  308. package/web/.svelte-kit/output/client/_app/immutable/chunks/Bi0jeV7Q.js +1 -0
  309. package/web/.svelte-kit/output/client/_app/immutable/chunks/BmUXQ3wy.js +2 -0
  310. package/web/.svelte-kit/output/client/_app/immutable/chunks/C3k55nDF.js +1 -0
  311. package/web/.svelte-kit/output/client/_app/immutable/chunks/COekwvP2.js +1 -0
  312. package/web/.svelte-kit/output/client/_app/immutable/chunks/CSvS_NwK.js +1 -0
  313. package/web/.svelte-kit/output/client/_app/immutable/chunks/CpaGRn9L.js +1 -0
  314. package/web/.svelte-kit/output/client/_app/immutable/chunks/CyNaE55B.js +1 -0
  315. package/web/.svelte-kit/output/client/_app/immutable/chunks/DG5RZBw-.js +2 -0
  316. package/web/.svelte-kit/output/client/_app/immutable/chunks/Dc-UOHw9.js +1 -0
  317. package/web/.svelte-kit/output/client/_app/immutable/chunks/DcrmIfTj.js +1 -0
  318. package/web/.svelte-kit/output/client/_app/immutable/chunks/ZkLyk0mE.js +1 -0
  319. package/web/.svelte-kit/output/client/_app/immutable/entry/app.B-vZe7PN.js +2 -0
  320. package/web/.svelte-kit/output/client/_app/immutable/entry/start.oP1AgKhs.js +1 -0
  321. package/web/.svelte-kit/output/client/_app/immutable/nodes/0.B5WFN0zw.js +1 -0
  322. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.D1wtJb2k.js +1 -0
  323. package/web/.svelte-kit/output/client/_app/immutable/nodes/2.CK3CLC0f.js +1 -0
  324. package/web/.svelte-kit/output/client/_app/immutable/nodes/3.BB5wCoBf.js +4 -0
  325. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.Dr2jvAXK.js +1 -0
  326. package/web/.svelte-kit/output/client/_app/immutable/nodes/5.BJl7oM3b.js +1 -0
  327. package/web/.svelte-kit/output/client/_app/version.json +1 -0
  328. package/web/.svelte-kit/output/client/robots.txt +3 -0
  329. package/web/.svelte-kit/output/prerendered/dependencies/_app/env.js +1 -0
  330. package/web/.svelte-kit/output/server/.vite/manifest.json +215 -0
  331. package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.GI4C4dpV.css +1 -0
  332. package/web/.svelte-kit/output/server/chunks/Icon.js +153 -0
  333. package/web/.svelte-kit/output/server/chunks/bot.js +2753 -0
  334. package/web/.svelte-kit/output/server/chunks/client.js +47 -0
  335. package/web/.svelte-kit/output/server/chunks/environment.js +34 -0
  336. package/web/.svelte-kit/output/server/chunks/exports.js +231 -0
  337. package/web/.svelte-kit/output/server/chunks/false.js +4 -0
  338. package/web/.svelte-kit/output/server/chunks/index-server.js +20 -0
  339. package/web/.svelte-kit/output/server/chunks/index.js +24 -0
  340. package/web/.svelte-kit/output/server/chunks/internal.js +133 -0
  341. package/web/.svelte-kit/output/server/chunks/plus.js +81 -0
  342. package/web/.svelte-kit/output/server/chunks/root.js +4076 -0
  343. package/web/.svelte-kit/output/server/chunks/shared.js +789 -0
  344. package/web/.svelte-kit/output/server/chunks/utils.js +43 -0
  345. package/web/.svelte-kit/output/server/entries/fallbacks/error.svelte.js +11 -0
  346. package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +3944 -0
  347. package/web/.svelte-kit/output/server/entries/pages/_layout.ts.js +28 -0
  348. package/web/.svelte-kit/output/server/entries/pages/_page.svelte.js +7 -0
  349. package/web/.svelte-kit/output/server/entries/pages/agents/_page.svelte.js +379 -0
  350. package/web/.svelte-kit/output/server/entries/pages/chats/_id_/_page.svelte.js +292 -0
  351. package/web/.svelte-kit/output/server/entries/pages/chats/_id_/_page.ts.js +17 -0
  352. package/web/.svelte-kit/output/server/entries/pages/chats/_id_/settings/_page.svelte.js +259 -0
  353. package/web/.svelte-kit/output/server/entries/pages/chats/_id_/settings/_page.ts.js +17 -0
  354. package/web/.svelte-kit/output/server/index.js +3748 -0
  355. package/web/.svelte-kit/output/server/internal.js +14 -0
  356. package/web/.svelte-kit/output/server/manifest-full.js +63 -0
  357. package/web/.svelte-kit/output/server/manifest.js +63 -0
  358. package/web/.svelte-kit/output/server/nodes/0.js +13 -0
  359. package/web/.svelte-kit/output/server/nodes/1.js +8 -0
  360. package/web/.svelte-kit/output/server/nodes/2.js +8 -0
  361. package/web/.svelte-kit/output/server/nodes/3.js +8 -0
  362. package/web/.svelte-kit/output/server/nodes/4.js +13 -0
  363. package/web/.svelte-kit/output/server/nodes/5.js +13 -0
  364. package/web/.svelte-kit/output/server/remote-entry.js +557 -0
  365. package/web/.svelte-kit/tsconfig.json +67 -0
  366. package/web/.svelte-kit/types/route_meta_data.json +17 -0
  367. package/web/.svelte-kit/types/src/routes/$types.d.ts +26 -0
  368. package/web/.svelte-kit/types/src/routes/agents/$types.d.ts +18 -0
  369. package/web/.svelte-kit/types/src/routes/chats/[id]/$types.d.ts +21 -0
  370. package/web/.svelte-kit/types/src/routes/chats/[id]/proxy+page.ts +20 -0
  371. package/web/.svelte-kit/types/src/routes/chats/[id]/settings/$types.d.ts +21 -0
  372. package/web/.svelte-kit/types/src/routes/chats/[id]/settings/proxy+page.ts +19 -0
  373. package/web/.svelte-kit/types/src/routes/proxy+layout.ts +35 -0
  374. package/web/README.md +42 -0
  375. package/web/components.json +16 -0
  376. package/web/package.json +41 -0
  377. package/web/src/app.css +121 -0
  378. package/web/src/app.d.ts +13 -0
  379. package/web/src/app.html +11 -0
  380. package/web/src/demo.spec.ts +7 -0
  381. package/web/src/lib/app-state.svelte.ts +3 -0
  382. package/web/src/lib/assets/favicon.svg +1 -0
  383. package/web/src/lib/components/app/app-sidebar-test-wrapper.svelte +10 -0
  384. package/web/src/lib/components/app/app-sidebar.svelte +171 -0
  385. package/web/src/lib/components/app/app-sidebar.svelte.spec.ts +13 -0
  386. package/web/src/lib/components/ui/button/button.svelte +82 -0
  387. package/web/src/lib/components/ui/button/index.ts +17 -0
  388. package/web/src/lib/components/ui/dialog/dialog-close.svelte +7 -0
  389. package/web/src/lib/components/ui/dialog/dialog-content.svelte +45 -0
  390. package/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  391. package/web/src/lib/components/ui/dialog/dialog-footer.svelte +20 -0
  392. package/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  393. package/web/src/lib/components/ui/dialog/dialog-overlay.svelte +20 -0
  394. package/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  395. package/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  396. package/web/src/lib/components/ui/dialog/dialog-trigger.svelte +7 -0
  397. package/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
  398. package/web/src/lib/components/ui/dialog/index.ts +34 -0
  399. package/web/src/lib/components/ui/input/index.ts +7 -0
  400. package/web/src/lib/components/ui/input/input.svelte +52 -0
  401. package/web/src/lib/components/ui/separator/index.ts +7 -0
  402. package/web/src/lib/components/ui/separator/separator.svelte +21 -0
  403. package/web/src/lib/components/ui/sheet/index.ts +34 -0
  404. package/web/src/lib/components/ui/sheet/sheet-close.svelte +7 -0
  405. package/web/src/lib/components/ui/sheet/sheet-content.svelte +60 -0
  406. package/web/src/lib/components/ui/sheet/sheet-description.svelte +17 -0
  407. package/web/src/lib/components/ui/sheet/sheet-footer.svelte +20 -0
  408. package/web/src/lib/components/ui/sheet/sheet-header.svelte +20 -0
  409. package/web/src/lib/components/ui/sheet/sheet-overlay.svelte +20 -0
  410. package/web/src/lib/components/ui/sheet/sheet-portal.svelte +7 -0
  411. package/web/src/lib/components/ui/sheet/sheet-title.svelte +17 -0
  412. package/web/src/lib/components/ui/sheet/sheet-trigger.svelte +7 -0
  413. package/web/src/lib/components/ui/sheet/sheet.svelte +7 -0
  414. package/web/src/lib/components/ui/sidebar/constants.ts +6 -0
  415. package/web/src/lib/components/ui/sidebar/context.svelte.ts +79 -0
  416. package/web/src/lib/components/ui/sidebar/index.ts +75 -0
  417. package/web/src/lib/components/ui/sidebar/sidebar-content.svelte +24 -0
  418. package/web/src/lib/components/ui/sidebar/sidebar-footer.svelte +21 -0
  419. package/web/src/lib/components/ui/sidebar/sidebar-group-action.svelte +36 -0
  420. package/web/src/lib/components/ui/sidebar/sidebar-group-content.svelte +21 -0
  421. package/web/src/lib/components/ui/sidebar/sidebar-group-label.svelte +34 -0
  422. package/web/src/lib/components/ui/sidebar/sidebar-group.svelte +21 -0
  423. package/web/src/lib/components/ui/sidebar/sidebar-header.svelte +21 -0
  424. package/web/src/lib/components/ui/sidebar/sidebar-input.svelte +21 -0
  425. package/web/src/lib/components/ui/sidebar/sidebar-inset.svelte +24 -0
  426. package/web/src/lib/components/ui/sidebar/sidebar-menu-action.svelte +43 -0
  427. package/web/src/lib/components/ui/sidebar/sidebar-menu-badge.svelte +29 -0
  428. package/web/src/lib/components/ui/sidebar/sidebar-menu-button.svelte +103 -0
  429. package/web/src/lib/components/ui/sidebar/sidebar-menu-item.svelte +21 -0
  430. package/web/src/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte +36 -0
  431. package/web/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte +43 -0
  432. package/web/src/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte +21 -0
  433. package/web/src/lib/components/ui/sidebar/sidebar-menu-sub.svelte +25 -0
  434. package/web/src/lib/components/ui/sidebar/sidebar-menu.svelte +21 -0
  435. package/web/src/lib/components/ui/sidebar/sidebar-provider.svelte +53 -0
  436. package/web/src/lib/components/ui/sidebar/sidebar-rail.svelte +36 -0
  437. package/web/src/lib/components/ui/sidebar/sidebar-separator.svelte +19 -0
  438. package/web/src/lib/components/ui/sidebar/sidebar-trigger.svelte +35 -0
  439. package/web/src/lib/components/ui/sidebar/sidebar.svelte +104 -0
  440. package/web/src/lib/components/ui/skeleton/index.ts +7 -0
  441. package/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
  442. package/web/src/lib/components/ui/switch/index.ts +7 -0
  443. package/web/src/lib/components/ui/switch/switch.svelte +29 -0
  444. package/web/src/lib/components/ui/textarea/index.ts +7 -0
  445. package/web/src/lib/components/ui/textarea/textarea.svelte +23 -0
  446. package/web/src/lib/components/ui/tooltip/index.ts +19 -0
  447. package/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
  448. package/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  449. package/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  450. package/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  451. package/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
  452. package/web/src/lib/hooks/is-mobile.svelte.ts +9 -0
  453. package/web/src/lib/index.ts +1 -0
  454. package/web/src/lib/types.ts +23 -0
  455. package/web/src/lib/utils.ts +13 -0
  456. package/web/src/routes/+layout.svelte +67 -0
  457. package/web/src/routes/+layout.ts +34 -0
  458. package/web/src/routes/+page.svelte +7 -0
  459. package/web/src/routes/agents/+page.svelte +206 -0
  460. package/web/src/routes/chats/[id]/+page.svelte +406 -0
  461. package/web/src/routes/chats/[id]/+page.ts +19 -0
  462. package/web/src/routes/chats/[id]/page.svelte.spec.ts +102 -0
  463. package/web/src/routes/chats/[id]/settings/+page.svelte +165 -0
  464. package/web/src/routes/chats/[id]/settings/+page.ts +18 -0
  465. package/web/src/routes/page.svelte.spec.ts +13 -0
  466. package/web/static/robots.txt +3 -0
  467. package/web/svelte.config.js +21 -0
  468. package/web/tsconfig.json +20 -0
  469. package/web/vite.config.ts +41 -0
@@ -0,0 +1,293 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import { spawn } from 'node:child_process';
3
+ import path from 'node:path';
4
+ import fs from 'node:fs';
5
+ import type { ChatMessage } from '../../shared/chats.js';
6
+ import { createE2EContext } from './utils.js';
7
+
8
+ const { runCli, e2eDir, binPath, setupE2E, teardownE2E } = createE2EContext('e2e-tmp-daemon');
9
+
10
+ describe('E2E Daemon and Web Tests', () => {
11
+ beforeAll(async () => {
12
+ await setupE2E();
13
+ await runCli(['init']);
14
+ }, 30000);
15
+
16
+ afterAll(teardownE2E, 30000);
17
+
18
+ it('should explicitly start the daemon via up command', async () => {
19
+ const { stdout, code } = await runCli(['up']);
20
+ expect(code).toBe(0);
21
+ // Since the daemon is likely running from previous tests or init, it should say so
22
+ // or it will start successfully.
23
+ expect(stdout).toMatch(/(Daemon is already running\.|Successfully started clawmini daemon\.)/);
24
+ });
25
+
26
+ it('should successfully shut down the daemon', async () => {
27
+ const { stdout, code } = await runCli(['down']);
28
+
29
+ expect(code).toBe(0);
30
+ expect(stdout).toContain('Successfully shut down clawmini daemon.');
31
+
32
+ await new Promise((resolve) => setTimeout(resolve, 500));
33
+
34
+ const socketPath = path.resolve(e2eDir, '.clawmini/daemon.sock');
35
+ expect(fs.existsSync(socketPath)).toBe(false);
36
+
37
+ const { stdout: stdoutAgain, code: codeAgain } = await runCli(['down']);
38
+ expect(codeAgain).toBe(0);
39
+ expect(stdoutAgain).toContain('Daemon is not running.');
40
+
41
+ const { stdout: stdoutUp, code: codeUp } = await runCli(['up']);
42
+ expect(codeUp).toBe(0);
43
+ expect(stdoutUp).toContain('Successfully started clawmini daemon.');
44
+ });
45
+
46
+ it('should run web command and serve static files', async () => {
47
+ const webPort = 8081;
48
+ const child = spawn('node', [binPath, 'web', '--port', webPort.toString()], {
49
+ cwd: e2eDir,
50
+ env: { ...process.env },
51
+ });
52
+
53
+ let output = '';
54
+ child.stdout.on('data', (d) => {
55
+ output += d.toString();
56
+ });
57
+ child.stderr.on('data', (d) => {
58
+ output += d.toString();
59
+ });
60
+
61
+ await new Promise<void>((resolve, reject) => {
62
+ const timeout = setTimeout(() => {
63
+ clearInterval(check);
64
+ reject(new Error('Timeout waiting for web server: ' + output));
65
+ }, 5000);
66
+ const check = setInterval(() => {
67
+ if (output.includes('Clawmini web interface running')) {
68
+ clearInterval(check);
69
+ clearTimeout(timeout);
70
+ resolve();
71
+ }
72
+ }, 100);
73
+ });
74
+
75
+ const res = await fetch(`http://127.0.0.1:${webPort}/`);
76
+ expect(res.status).toBe(200);
77
+ const html = await res.text();
78
+ expect(html.toLowerCase()).toContain('<!doctype html>');
79
+ expect(html).toContain('<html');
80
+
81
+ const res404 = await fetch(`http://127.0.0.1:${webPort}/some-non-existent-route`);
82
+ expect(res404.status).toBe(200);
83
+ const html404 = await res404.text();
84
+ expect(html404.toLowerCase()).toContain('<!doctype html>');
85
+
86
+ await runCli(['chats', 'add', 'api-test-chat']);
87
+
88
+ const resChats = await fetch(`http://127.0.0.1:${webPort}/api/chats`);
89
+ expect(resChats.status).toBe(200);
90
+ const chats = (await resChats.json()) as string[];
91
+ expect(chats).toContain('api-test-chat');
92
+
93
+ const resPost = await fetch(`http://127.0.0.1:${webPort}/api/chats/api-test-chat/messages`, {
94
+ method: 'POST',
95
+ headers: { 'Content-Type': 'application/json' },
96
+ body: JSON.stringify({ message: 'api test message' }),
97
+ });
98
+ expect(resPost.status).toBe(200);
99
+ const postData = (await resPost.json()) as { success: boolean };
100
+ expect(postData.success).toBe(true);
101
+
102
+ await new Promise((resolve) => setTimeout(resolve, 500));
103
+
104
+ const resHistory = await fetch(`http://127.0.0.1:${webPort}/api/chats/api-test-chat`);
105
+ expect(resHistory.status).toBe(200);
106
+ const history = (await resHistory.json()) as ChatMessage[];
107
+ expect(history.length).toBeGreaterThan(0);
108
+ expect(history[0]?.role).toBe('user');
109
+ expect(history[0]?.content).toBe('api test message');
110
+
111
+ const sseResponse = await fetch(`http://127.0.0.1:${webPort}/api/chats/api-test-chat/stream`);
112
+ expect(sseResponse.status).toBe(200);
113
+ expect(sseResponse.headers.get('content-type')).toContain('text/event-stream');
114
+
115
+ if (!sseResponse.body) {
116
+ throw new Error('SSE response body is null');
117
+ }
118
+ const reader = sseResponse.body.getReader();
119
+ const decoder = new TextDecoder();
120
+
121
+ const chatLogPath = path.resolve(e2eDir, '.clawmini/chats/api-test-chat/chat.jsonl');
122
+ const mockMessage = {
123
+ id: 'mock-1',
124
+ role: 'user',
125
+ content: 'sse test message',
126
+ timestamp: new Date().toISOString(),
127
+ };
128
+ fs.appendFileSync(chatLogPath, JSON.stringify(mockMessage) + '\n');
129
+
130
+ let sseData = '';
131
+ while (true) {
132
+ const { value, done } = await reader.read();
133
+ if (done) break;
134
+ sseData += decoder.decode(value, { stream: true });
135
+ if (sseData.includes('sse test message')) {
136
+ break;
137
+ }
138
+ }
139
+
140
+ expect(sseData).toContain('data: {"id":"mock-1","role":"user","content":"sse test message"');
141
+
142
+ await reader.cancel();
143
+
144
+ const resPostAgent = await fetch(`http://127.0.0.1:${webPort}/api/agents`, {
145
+ method: 'POST',
146
+ headers: { 'Content-Type': 'application/json' },
147
+ body: JSON.stringify({
148
+ id: 'api-agent-1',
149
+ directory: './api-agent-dir',
150
+ env: { API_KEY: 'test-key' },
151
+ }),
152
+ });
153
+ expect(resPostAgent.status).toBe(201);
154
+ const postAgentData = (await resPostAgent.json()) as Record<string, unknown>;
155
+ expect(postAgentData.id).toBe('api-agent-1');
156
+ expect(postAgentData.directory).toBe('./api-agent-dir');
157
+ expect((postAgentData.env as Record<string, string>).API_KEY).toBe('test-key');
158
+
159
+ const resGetAgents = await fetch(`http://127.0.0.1:${webPort}/api/agents`);
160
+ expect(resGetAgents.status).toBe(200);
161
+ const agentsList = (await resGetAgents.json()) as Record<string, unknown>[];
162
+ expect(agentsList.some((a) => a.id === 'api-agent-1')).toBe(true);
163
+
164
+ const resGetAgent = await fetch(`http://127.0.0.1:${webPort}/api/agents/api-agent-1`);
165
+ expect(resGetAgent.status).toBe(200);
166
+ const getAgentData = (await resGetAgent.json()) as Record<string, unknown>;
167
+ expect(getAgentData.id).toBe('api-agent-1');
168
+ expect(getAgentData.directory).toBe('./api-agent-dir');
169
+
170
+ const resPutAgent = await fetch(`http://127.0.0.1:${webPort}/api/agents/api-agent-1`, {
171
+ method: 'PUT',
172
+ headers: { 'Content-Type': 'application/json' },
173
+ body: JSON.stringify({ directory: './updated-dir' }),
174
+ });
175
+ expect(resPutAgent.status).toBe(200);
176
+ const putAgentData = (await resPutAgent.json()) as Record<string, unknown>;
177
+ expect(putAgentData.directory).toBe('./updated-dir');
178
+ expect((putAgentData.env as Record<string, string>).API_KEY).toBe('test-key');
179
+
180
+ const resDeleteAgent = await fetch(`http://127.0.0.1:${webPort}/api/agents/api-agent-1`, {
181
+ method: 'DELETE',
182
+ });
183
+ expect(resDeleteAgent.status).toBe(200);
184
+
185
+ const resGetAgentsAfterDelete = await fetch(`http://127.0.0.1:${webPort}/api/agents`);
186
+ const agentsListAfterDelete = (await resGetAgentsAfterDelete.json()) as Record<
187
+ string,
188
+ unknown
189
+ >[];
190
+ expect(agentsListAfterDelete.some((a) => a.id === 'api-agent-1')).toBe(false);
191
+
192
+ child.kill();
193
+ await new Promise((resolve) => child.on('close', resolve));
194
+ }, 30000);
195
+
196
+ it('should optionally start an HTTP API server for the daemon when configured', async () => {
197
+ await runCli(['down']);
198
+
199
+ const settingsPath = path.resolve(e2eDir, '.clawmini/settings.json');
200
+ let originalSettings = '{}';
201
+ if (fs.existsSync(settingsPath)) {
202
+ originalSettings = fs.readFileSync(settingsPath, 'utf8');
203
+ }
204
+
205
+ fs.writeFileSync(
206
+ settingsPath,
207
+ JSON.stringify({
208
+ ...JSON.parse(originalSettings),
209
+ api: { host: '127.0.0.1', port: 3005 },
210
+ })
211
+ );
212
+
213
+ const { stdout, code } = await runCli(['up']);
214
+ expect(code).toBe(0);
215
+ expect(stdout).toContain('Successfully started clawmini daemon.');
216
+
217
+ await new Promise((resolve) => setTimeout(resolve, 500));
218
+
219
+ const res = await fetch('http://127.0.0.1:3005/ping');
220
+ expect(res.status).toBe(200);
221
+ const data = (await res.json()) as { result: { data: { status: string } } };
222
+ expect(data.result.data.status).toBe('ok');
223
+
224
+ await runCli(['down']);
225
+ fs.writeFileSync(settingsPath, originalSettings);
226
+ await runCli(['up']);
227
+ });
228
+
229
+ it('should inject CLAW_API_URL and CLAW_API_TOKEN into spawned agents when API is enabled', async () => {
230
+ await runCli(['down']);
231
+ const settingsPath = path.resolve(e2eDir, '.clawmini/settings.json');
232
+ let originalSettings = '{}';
233
+ if (fs.existsSync(settingsPath)) {
234
+ originalSettings = fs.readFileSync(settingsPath, 'utf8');
235
+ }
236
+ fs.writeFileSync(
237
+ settingsPath,
238
+ JSON.stringify({
239
+ ...JSON.parse(originalSettings),
240
+ api: { host: '127.0.0.1', port: 3006 },
241
+ })
242
+ );
243
+ await runCli(['up']);
244
+
245
+ await runCli(['agents', 'add', 'env-dumper', '--dir', 'env-dumper']);
246
+ const envDumperSettingsPath = path.resolve(e2eDir, '.clawmini/agents/env-dumper/settings.json');
247
+ fs.mkdirSync(path.dirname(envDumperSettingsPath), { recursive: true });
248
+
249
+ // Create the actual agent working directory so spawn doesn't fail with ENOENT
250
+ const agentWorkingDir = path.resolve(e2eDir, 'env-dumper');
251
+ fs.mkdirSync(agentWorkingDir, { recursive: true });
252
+
253
+ fs.writeFileSync(
254
+ envDumperSettingsPath,
255
+ JSON.stringify({
256
+ commands: {
257
+ new: process.platform === 'win32' ? 'set' : 'env',
258
+ },
259
+ })
260
+ );
261
+
262
+ await runCli(['chats', 'add', 'env-chat']);
263
+ const { stdout, stderr, code } = await runCli([
264
+ 'messages',
265
+ 'send',
266
+ 'dump it',
267
+ '--chat',
268
+ 'env-chat',
269
+ '--agent',
270
+ 'env-dumper',
271
+ ]);
272
+ if (code !== 0) {
273
+ console.error('send failed:', stdout, stderr);
274
+ }
275
+
276
+ await new Promise((resolve) => setTimeout(resolve, 2000));
277
+
278
+ const chatLogPath = path.resolve(e2eDir, '.clawmini/chats/env-chat/chat.jsonl');
279
+ expect(fs.existsSync(chatLogPath)).toBe(true);
280
+ const chatLogContent = fs.readFileSync(chatLogPath, 'utf8');
281
+
282
+ if (!chatLogContent.includes('CLAW_API_URL')) {
283
+ console.error('CHAT LOG:', chatLogContent);
284
+ }
285
+
286
+ expect(chatLogContent).toContain('CLAW_API_URL=http://127.0.0.1:3006');
287
+ expect(chatLogContent).toContain('CLAW_API_TOKEN=');
288
+
289
+ await runCli(['down']);
290
+ fs.writeFileSync(settingsPath, originalSettings);
291
+ await runCli(['up']);
292
+ }, 15000);
293
+ });
@@ -0,0 +1,66 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import { createE2EContext } from './utils.js';
5
+
6
+ describe('Environments E2E', () => {
7
+ const { runCli, e2eDir, setupE2E, teardownE2E } = createE2EContext('e2e-env');
8
+
9
+ beforeAll(async () => {
10
+ await setupE2E();
11
+ await runCli(['init']);
12
+ }, 30000);
13
+
14
+ afterAll(teardownE2E, 30000);
15
+
16
+ it('should run environment up and down commands on daemon start and stop', async () => {
17
+ // Create an environment with up and down commands
18
+ const envDir = path.join(e2eDir, '.clawmini', 'environments', 'test-env');
19
+ fs.mkdirSync(envDir, { recursive: true });
20
+
21
+ const upHookPath = path.join(e2eDir, 'up-hook-run.txt');
22
+ const downHookPath = path.join(e2eDir, 'down-hook-run.txt');
23
+
24
+ fs.writeFileSync(
25
+ path.join(envDir, 'env.json'),
26
+ JSON.stringify({
27
+ up: `echo "env-up" > ${JSON.stringify(upHookPath)}`,
28
+ down: `echo "env-down" > ${JSON.stringify(downHookPath)}`,
29
+ })
30
+ );
31
+
32
+ // Enable the environment
33
+ await runCli(['environments', 'enable', 'test-env']);
34
+
35
+ // Start the daemon (should trigger up hook)
36
+ const { stdout: upStdout, code: upCode } = await runCli(['up']);
37
+ expect(upCode).toBe(0);
38
+ expect(upStdout).toMatch(
39
+ /(Daemon is already running\.|Successfully started clawmini daemon\.)/
40
+ );
41
+
42
+ // Wait for up hook to complete (daemon start might be slightly async in executing hooks)
43
+ await new Promise((resolve) => setTimeout(resolve, 2000));
44
+
45
+ // The daemon might have already been running since beforeAll init might start it.
46
+ // So let's actually shut it down, then start it to be sure.
47
+ await runCli(['down']);
48
+ await new Promise((resolve) => setTimeout(resolve, 1000));
49
+
50
+ // Clear out files if they exist
51
+ if (fs.existsSync(upHookPath)) fs.unlinkSync(upHookPath);
52
+ if (fs.existsSync(downHookPath)) fs.unlinkSync(downHookPath);
53
+
54
+ // Start daemon
55
+ await runCli(['up']);
56
+ await new Promise((resolve) => setTimeout(resolve, 1000));
57
+ expect(fs.existsSync(upHookPath)).toBe(true);
58
+ expect(fs.readFileSync(upHookPath, 'utf8').trim()).toBe('env-up');
59
+
60
+ // Stop daemon
61
+ await runCli(['down']);
62
+ await new Promise((resolve) => setTimeout(resolve, 1000));
63
+ expect(fs.existsSync(downHookPath)).toBe(true);
64
+ expect(fs.readFileSync(downHookPath, 'utf8').trim()).toBe('env-down');
65
+ }, 30000);
66
+ });
@@ -0,0 +1,155 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import { spawn } from 'node:child_process';
3
+ import path from 'node:path';
4
+ import fs from 'node:fs';
5
+ import { createE2EContext } from './utils.js';
6
+
7
+ const { runCli, e2eDir, setupE2E, teardownE2E } = createE2EContext('e2e-exp-lite');
8
+
9
+ describe('E2E Export Lite Functionality Tests', () => {
10
+ beforeAll(async () => {
11
+ await setupE2E();
12
+ await runCli(['init']);
13
+ }, 30000);
14
+
15
+ afterAll(teardownE2E, 30000);
16
+
17
+ it('should run exported clawmini-lite script and verify its functionality', async () => {
18
+ await runCli(['down']);
19
+ const settingsPath = path.resolve(e2eDir, '.clawmini/settings.json');
20
+ let originalSettings = '{}';
21
+ if (fs.existsSync(settingsPath)) {
22
+ originalSettings = fs.readFileSync(settingsPath, 'utf8');
23
+ }
24
+ fs.writeFileSync(
25
+ settingsPath,
26
+ JSON.stringify({
27
+ ...JSON.parse(originalSettings),
28
+ api: { host: '127.0.0.1', port: 3007 },
29
+ })
30
+ );
31
+ await runCli(['up']);
32
+
33
+ // Export lite script
34
+ const litePath = path.resolve(e2eDir, 'clawmini-lite.js');
35
+ await runCli(['export-lite', '--out', litePath]);
36
+ expect(fs.existsSync(litePath)).toBe(true);
37
+
38
+ const envDumperAgentDir = path.resolve(e2eDir, 'lite-env-dumper');
39
+ fs.mkdirSync(envDumperAgentDir, { recursive: true });
40
+ await runCli(['agents', 'add', 'lite-env-dumper', '--dir', 'lite-env-dumper']);
41
+
42
+ const dumperSettings = path.resolve(e2eDir, '.clawmini/agents/lite-env-dumper/settings.json');
43
+ fs.mkdirSync(path.dirname(dumperSettings), { recursive: true });
44
+
45
+ const dumperScript = process.platform === 'win32' ? 'set > env.txt' : 'env > env.txt';
46
+ fs.writeFileSync(dumperSettings, JSON.stringify({ commands: { new: dumperScript } }));
47
+
48
+ await runCli(['chats', 'add', 'lite-chat']);
49
+ await runCli(['messages', 'send', 'dump', '--chat', 'lite-chat', '--agent', 'lite-env-dumper']);
50
+
51
+ await new Promise((resolve) => setTimeout(resolve, 2000));
52
+
53
+ const envTxtPath = path.resolve(envDumperAgentDir, 'env.txt');
54
+ expect(fs.existsSync(envTxtPath)).toBe(true);
55
+ const envContent = fs.readFileSync(envTxtPath, 'utf8');
56
+
57
+ const urlMatch = envContent.match(/CLAW_API_URL=(.+)/);
58
+ const tokenMatch = envContent.match(/CLAW_API_TOKEN=(.+)/);
59
+
60
+ expect(urlMatch).toBeTruthy();
61
+ expect(tokenMatch).toBeTruthy();
62
+
63
+ if (!urlMatch || !tokenMatch) {
64
+ throw new Error('Could not find API credentials');
65
+ }
66
+
67
+ const envUrl = urlMatch[1]!.trim();
68
+ const envToken = tokenMatch[1]!.trim();
69
+ // 1. Test log
70
+ const logProcess = spawn('node', [litePath, 'log', 'hello from lite client'], {
71
+ env: { ...process.env, CLAW_API_URL: envUrl, CLAW_API_TOKEN: envToken },
72
+ });
73
+
74
+ let logStdout = '';
75
+ logProcess.stdout.on('data', (d) => (logStdout += d.toString()));
76
+ logProcess.stderr.on('data', (d) => (logStdout += d.toString()));
77
+ await new Promise((resolve) => logProcess.on('close', resolve));
78
+ expect(logStdout).toContain('Log message appended');
79
+
80
+ const chatLogPath = path.resolve(e2eDir, '.clawmini/chats/lite-chat/chat.jsonl');
81
+ const chatLogContent = fs.readFileSync(chatLogPath, 'utf8');
82
+ expect(chatLogContent).toContain('hello from lite client');
83
+ expect(chatLogContent).toContain('"role":"log"');
84
+
85
+ // 1.5 Test log with file
86
+ const logFileProcess = spawn(
87
+ 'node',
88
+ [litePath, 'log', 'hello with file', '--file', 'env.txt'],
89
+ {
90
+ env: { ...process.env, CLAW_API_URL: envUrl, CLAW_API_TOKEN: envToken },
91
+ cwd: envDumperAgentDir,
92
+ }
93
+ );
94
+
95
+ let logFileStdout = '';
96
+ logFileProcess.stdout.on('data', (d) => (logFileStdout += d.toString()));
97
+ logFileProcess.stderr.on('data', (d) => (logFileStdout += d.toString()));
98
+ await new Promise((resolve) => logFileProcess.on('close', resolve));
99
+ expect(logFileStdout).toContain('Log message appended');
100
+
101
+ const chatLogContentUpdated = fs.readFileSync(chatLogPath, 'utf8');
102
+ expect(chatLogContentUpdated).toContain('hello with file');
103
+ expect(chatLogContentUpdated).toContain('"files":["lite-env-dumper/env.txt"]');
104
+
105
+ // 2. Test jobs add
106
+ const addProcess = spawn(
107
+ 'node',
108
+ [
109
+ litePath,
110
+ 'jobs',
111
+ 'add',
112
+ 'lite-job',
113
+ '--cron',
114
+ '* * * * *',
115
+ '--message',
116
+ 'lite message',
117
+ '--chat',
118
+ 'lite-chat',
119
+ ],
120
+ {
121
+ env: { ...process.env, CLAW_API_URL: envUrl, CLAW_API_TOKEN: envToken },
122
+ }
123
+ );
124
+ let addStdout = '';
125
+ addProcess.stdout.on('data', (d) => (addStdout += d.toString()));
126
+ addProcess.stderr.on('data', (d) => (addStdout += d.toString()));
127
+ await new Promise((resolve) => addProcess.on('close', resolve));
128
+ expect(addStdout).toContain("Job 'lite-job' created successfully.");
129
+
130
+ // 3. Test jobs list
131
+ const listProcess = spawn('node', [litePath, 'jobs', 'list'], {
132
+ env: { ...process.env, CLAW_API_URL: envUrl, CLAW_API_TOKEN: envToken },
133
+ });
134
+ let listStdout = '';
135
+ listProcess.stdout.on('data', (d) => (listStdout += d.toString()));
136
+ listProcess.stderr.on('data', (d) => (listStdout += d.toString()));
137
+ await new Promise((resolve) => listProcess.on('close', resolve));
138
+ expect(listStdout).toContain('lite-job');
139
+ expect(listStdout).toContain('* * * * *');
140
+
141
+ // 4. Test jobs delete
142
+ const delProcess = spawn('node', [litePath, 'jobs', 'delete', 'lite-job', '-c', 'lite-chat'], {
143
+ env: { ...process.env, CLAW_API_URL: envUrl, CLAW_API_TOKEN: envToken },
144
+ });
145
+ let delStdout = '';
146
+ delProcess.stdout.on('data', (d) => (delStdout += d.toString()));
147
+ delProcess.stderr.on('data', (d) => (delStdout += d.toString()));
148
+ await new Promise((resolve) => delProcess.on('close', resolve));
149
+ expect(delStdout).toContain("Job 'lite-job' deleted successfully.");
150
+
151
+ await runCli(['down']);
152
+ fs.writeFileSync(settingsPath, originalSettings);
153
+ await runCli(['up']);
154
+ }, 30000);
155
+ });
@@ -0,0 +1,51 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import { createE2EContext } from './utils.js';
5
+
6
+ const { runCli, e2eDir, setupE2E, teardownE2E } = createE2EContext('e2e-export-lite');
7
+
8
+ describe('E2E Export Lite Tests', () => {
9
+ beforeAll(setupE2E, 30000);
10
+ afterAll(teardownE2E, 30000);
11
+
12
+ it('should export clawmini-lite script to current directory', async () => {
13
+ // Current directory context in runCli is e2eDir
14
+ const { stdout, code } = await runCli(['export-lite']);
15
+ expect(code).toBe(0);
16
+ expect(stdout).toContain('Successfully exported clawmini-lite to');
17
+
18
+ const expectedPath = path.join(e2eDir, 'clawmini-lite.js');
19
+ expect(fs.existsSync(expectedPath)).toBe(true);
20
+
21
+ const content = fs.readFileSync(expectedPath, 'utf8');
22
+ expect(content).toContain('clawmini-lite - A standalone client');
23
+ });
24
+
25
+ it('should export clawmini-lite script to stdout', async () => {
26
+ const { stdout, code } = await runCli(['export-lite', '--stdout']);
27
+ expect(code).toBe(0);
28
+ expect(stdout).toContain('clawmini-lite - A standalone client');
29
+ expect(stdout).not.toContain('Successfully exported clawmini-lite to');
30
+ });
31
+
32
+ it('should export clawmini-lite script to specified file path', async () => {
33
+ const customPath = path.join(e2eDir, 'custom-lite.js');
34
+ const { stdout, code } = await runCli(['export-lite', '--out', customPath]);
35
+ expect(code).toBe(0);
36
+ expect(stdout).toContain(`Successfully exported clawmini-lite to ${customPath}`);
37
+ expect(fs.existsSync(customPath)).toBe(true);
38
+ });
39
+
40
+ it('should export clawmini-lite script to specified directory path', async () => {
41
+ const customDir = path.join(e2eDir, 'custom-dir');
42
+ fs.mkdirSync(customDir);
43
+
44
+ const { stdout, code } = await runCli(['export-lite', '--out', customDir]);
45
+ expect(code).toBe(0);
46
+
47
+ const expectedPath = path.join(customDir, 'clawmini-lite.js');
48
+ expect(stdout).toContain(`Successfully exported clawmini-lite to ${expectedPath}`);
49
+ expect(fs.existsSync(expectedPath)).toBe(true);
50
+ });
51
+ });