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,165 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import fsPromises from 'node:fs/promises';
5
+ import { spawn } from 'node:child_process';
6
+ import { createE2EContext } from './utils.js';
7
+
8
+ const { runCli, e2eDir, setupE2E, teardownE2E } = createE2EContext('e2e-tmp-requests');
9
+
10
+ describe('E2E Requests Tests (Lite)', () => {
11
+ let litePath = '';
12
+ let envUrl = '';
13
+ let envToken = '';
14
+
15
+ beforeAll(async () => {
16
+ await setupE2E();
17
+ await runCli(['init']);
18
+
19
+ // Setup policies.json
20
+ const policiesPath = path.join(e2eDir, '.clawmini', 'policies.json');
21
+ await fsPromises.writeFile(
22
+ policiesPath,
23
+ JSON.stringify({
24
+ policies: {
25
+ 'test-cmd': {
26
+ description: 'A test policy',
27
+ command: 'echo',
28
+ args: ['hello'],
29
+ allowHelp: true,
30
+ },
31
+ 'no-help-cmd': {
32
+ description: 'A no help policy',
33
+ command: 'echo',
34
+ args: ['nohelp'],
35
+ },
36
+ },
37
+ })
38
+ );
39
+
40
+ // Setup daemon with API enabled
41
+ const settingsPath = path.resolve(e2eDir, '.clawmini/settings.json');
42
+ let originalSettings = '{}';
43
+ if (fs.existsSync(settingsPath)) {
44
+ originalSettings = fs.readFileSync(settingsPath, 'utf8');
45
+ }
46
+ fs.writeFileSync(
47
+ settingsPath,
48
+ JSON.stringify({
49
+ ...JSON.parse(originalSettings),
50
+ api: { host: '127.0.0.1', port: 3008 },
51
+ })
52
+ );
53
+ await runCli(['up']);
54
+
55
+ // Export lite script
56
+ litePath = path.resolve(e2eDir, 'clawmini-lite.js');
57
+ await runCli(['export-lite', '--out', litePath]);
58
+
59
+ // Setup env-dumper agent
60
+ const envDumperAgentDir = path.resolve(e2eDir, 'lite-env-dumper');
61
+ fs.mkdirSync(envDumperAgentDir, { recursive: true });
62
+ await runCli(['agents', 'add', 'lite-env-dumper', '--dir', 'lite-env-dumper']);
63
+
64
+ const dumperSettings = path.resolve(e2eDir, '.clawmini/agents/lite-env-dumper/settings.json');
65
+ fs.mkdirSync(path.dirname(dumperSettings), { recursive: true });
66
+ const dumperScript = process.platform === 'win32' ? 'set > env.txt' : 'env > env.txt';
67
+ fs.writeFileSync(dumperSettings, JSON.stringify({ commands: { new: dumperScript } }));
68
+
69
+ await runCli(['chats', 'add', 'lite-chat']);
70
+ await runCli(['messages', 'send', 'dump', '--chat', 'lite-chat', '--agent', 'lite-env-dumper']);
71
+
72
+ await new Promise((resolve) => setTimeout(resolve, 3000));
73
+
74
+ const envTxtPath = path.resolve(envDumperAgentDir, 'env.txt');
75
+ if (!fs.existsSync(envTxtPath)) {
76
+ throw new Error('env.txt not generated by agent');
77
+ }
78
+ const envContent = fs.readFileSync(envTxtPath, 'utf8');
79
+ const urlMatch = envContent.match(/CLAW_API_URL=(.+)/);
80
+ const tokenMatch = envContent.match(/CLAW_API_TOKEN=(.+)/);
81
+
82
+ if (!urlMatch || !tokenMatch) {
83
+ throw new Error('Could not find API credentials');
84
+ }
85
+
86
+ envUrl = urlMatch[1]!.trim();
87
+ envToken = tokenMatch[1]!.trim();
88
+ }, 30000);
89
+
90
+ afterAll(teardownE2E, 30000);
91
+
92
+ function runLite(
93
+ args: string[]
94
+ ): Promise<{ stdout: string; stderr: string; code: number | null }> {
95
+ return new Promise((resolve) => {
96
+ const p = spawn('node', [litePath, ...args], {
97
+ env: { ...process.env, CLAW_API_URL: envUrl, CLAW_API_TOKEN: envToken },
98
+ cwd: e2eDir,
99
+ });
100
+ let stdout = '';
101
+ let stderr = '';
102
+ p.stdout.on('data', (d) => (stdout += d.toString()));
103
+ p.stderr.on('data', (d) => (stderr += d.toString()));
104
+ p.on('close', (code) => resolve({ stdout, stderr, code }));
105
+ });
106
+ }
107
+
108
+ it('should list policies', async () => {
109
+ const { stdout, code } = await runLite(['requests', 'list']);
110
+ expect(code).toBe(0);
111
+ expect(stdout).toContain('Available Policies:');
112
+ expect(stdout).toContain('- test-cmd');
113
+ expect(stdout).toContain('Description: A test policy');
114
+ });
115
+
116
+ it('should run --help on underlying command', async () => {
117
+ const { stdout, code } = await runLite(['request', 'test-cmd', '--help']);
118
+ expect(code).toBe(0);
119
+ expect(stdout).toBeTruthy();
120
+ });
121
+
122
+ it('should block --help if allowHelp is not true', async () => {
123
+ const { stderr, code } = await runLite(['request', 'no-help-cmd', '--help']);
124
+ expect(code).toBe(1);
125
+ expect(stderr).toContain('This command does not support --help');
126
+ });
127
+
128
+ it('should create a request and return an ID', async () => {
129
+ const dummyFilePath = path.join(e2eDir, 'lite-env-dumper', 'dummy.txt');
130
+ await fsPromises.writeFile(dummyFilePath, 'dummy content');
131
+
132
+ const { stdout, stderr, code } = await runLite([
133
+ 'request',
134
+ 'test-cmd',
135
+ '--file',
136
+ `target=${dummyFilePath}`,
137
+ '--',
138
+ 'extra1',
139
+ 'extra2',
140
+ ]);
141
+
142
+ expect(stderr).toBe('');
143
+ expect(code).toBe(0);
144
+ expect(stdout).toContain('Request created successfully.');
145
+ expect(stdout).toContain('Request ID:');
146
+
147
+ // Verify the request was saved
148
+ const requestsDir = path.join(e2eDir, '.clawmini', 'tmp', 'requests');
149
+ const files = await fsPromises.readdir(requestsDir);
150
+ const jsonFiles = files.filter((f) => f.endsWith('.json'));
151
+ expect(jsonFiles.length).toBe(1);
152
+
153
+ const reqData = await fsPromises.readFile(path.join(requestsDir, jsonFiles[0]!), 'utf8');
154
+ const req = JSON.parse(reqData);
155
+
156
+ expect(req.commandName).toBe('test-cmd');
157
+ expect(req.args).toEqual(['extra1', 'extra2']);
158
+ expect(req.fileMappings).toHaveProperty('target');
159
+
160
+ // Check snapshot exists
161
+ const snapshotPath = req.fileMappings.target;
162
+ const snapshotContent = await fsPromises.readFile(snapshotPath, 'utf8');
163
+ expect(snapshotContent).toBe('dummy content');
164
+ });
165
+ });
@@ -0,0 +1,66 @@
1
+ import { spawn, execSync } from 'node:child_process';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+
5
+ export function createE2EContext(dirName: string) {
6
+ const binPath = path.resolve(__dirname, '../../../dist/cli/index.mjs');
7
+ const e2eDir = path.resolve(__dirname, `../../../${dirName}`);
8
+
9
+ function runCli(
10
+ args: string[]
11
+ ): Promise<{ stdout: string; stderr: string; code: number | null }> {
12
+ const isInit = args[0] === 'init';
13
+ return new Promise((resolve) => {
14
+ const child = spawn('node', [binPath, ...args], {
15
+ cwd: e2eDir,
16
+ env: { ...process.env },
17
+ });
18
+
19
+ let stdout = '';
20
+ let stderr = '';
21
+
22
+ child.stdout.on('data', (data) => {
23
+ stdout += data.toString();
24
+ });
25
+
26
+ child.stderr.on('data', (data) => {
27
+ stderr += data.toString();
28
+ });
29
+
30
+ child.on('close', (code) => {
31
+ if (isInit && code === 0) {
32
+ // Update settings to set API port to 0, assigning a random available port
33
+ const settingsPath = path.resolve(e2eDir, '.clawmini/settings.json');
34
+ if (fs.existsSync(settingsPath)) {
35
+ try {
36
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
37
+ settings.api = { port: 0 }; // Use random available port to avoid EADDRINUSE during parallel e2e tests
38
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
39
+ } catch {
40
+ // ignore
41
+ }
42
+ }
43
+ }
44
+ resolve({ stdout, stderr, code });
45
+ });
46
+ });
47
+ }
48
+
49
+ async function setupE2E() {
50
+ if (fs.existsSync(e2eDir)) {
51
+ fs.rmSync(e2eDir, { recursive: true, force: true });
52
+ }
53
+ fs.mkdirSync(e2eDir, { recursive: true });
54
+ execSync('git init', { cwd: e2eDir, stdio: 'ignore' });
55
+ }
56
+
57
+ async function teardownE2E() {
58
+ await runCli(['down']);
59
+
60
+ if (fs.existsSync(e2eDir)) {
61
+ fs.rmSync(e2eDir, { recursive: true, force: true });
62
+ }
63
+ }
64
+
65
+ return { runCli, e2eDir, binPath, setupE2E, teardownE2E };
66
+ }
@@ -0,0 +1,7 @@
1
+ import { describe, it, expect } from 'vitest';
2
+
3
+ describe('CLI placeholder tests', () => {
4
+ it('should be true', () => {
5
+ expect(true).toBe(true);
6
+ });
7
+ });
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { initCmd } from './commands/init.js';
4
+ import { messagesCmd } from './commands/messages.js';
5
+ import { chatsCmd } from './commands/chats.js';
6
+ import { agentsCmd } from './commands/agents.js';
7
+ import { downCmd } from './commands/down.js';
8
+ import { upCmd } from './commands/up.js';
9
+ import { webCmd } from './commands/web.js';
10
+ import { jobsCmd } from './commands/jobs.js';
11
+ import { exportLiteCmd } from './commands/export-lite.js';
12
+ import { environmentsCmd } from './commands/environments.js';
13
+
14
+ const program = new Command();
15
+
16
+ program.name('clawmini').description('Clawmini CLI').version('0.0.1');
17
+
18
+ program.addCommand(initCmd);
19
+ program.addCommand(messagesCmd);
20
+ program.addCommand(chatsCmd);
21
+ program.addCommand(agentsCmd);
22
+ program.addCommand(environmentsCmd);
23
+ program.addCommand(downCmd);
24
+ program.addCommand(upCmd);
25
+ program.addCommand(webCmd);
26
+ program.addCommand(jobsCmd);
27
+ program.addCommand(exportLiteCmd);
28
+
29
+ program.parse();
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { createTRPCClient, httpLink } from '@trpc/client';
5
+ import type { AppRouter } from '../daemon/router.js';
6
+ import type { CronJob } from '../shared/config.js';
7
+
8
+ /**
9
+ * clawmini-lite - A standalone client
10
+ */
11
+ const API_URL = process.env.CLAW_API_URL;
12
+ const API_TOKEN = process.env.CLAW_API_TOKEN;
13
+
14
+ function getClient() {
15
+ return createTRPCClient<AppRouter>({
16
+ links: [
17
+ httpLink({
18
+ url: API_URL as string,
19
+ headers() {
20
+ return {
21
+ Authorization: `Bearer ${API_TOKEN}`,
22
+ 'Content-Type': 'application/json',
23
+ };
24
+ },
25
+ }),
26
+ ],
27
+ });
28
+ }
29
+
30
+ const program = new Command();
31
+
32
+ program
33
+ .name('clawmini-lite')
34
+ .description('A standalone client for clawmini')
35
+ .hook('preAction', () => {
36
+ if (!API_URL || !API_TOKEN) {
37
+ console.error('CLAW_API_URL and CLAW_API_TOKEN must be set in the environment.');
38
+ process.exit(1);
39
+ }
40
+ });
41
+
42
+ program
43
+ .command('log [message]')
44
+ .description('Log a message')
45
+ .option(
46
+ '-f, --file <path>',
47
+ 'File path(s) to attach (can specify multiple)',
48
+ (val: string, prev: string[]) => prev.concat([val]),
49
+ []
50
+ )
51
+ .action(async (message, options) => {
52
+ try {
53
+ const files = options.file.length > 0 ? options.file : undefined;
54
+ const payload: { message?: string; files?: string[] } = {};
55
+ if (message !== undefined) payload.message = message;
56
+ if (files !== undefined) payload.files = files;
57
+
58
+ const client = getClient();
59
+ await client.logMessage.mutate(payload);
60
+ console.log('Log message appended.');
61
+ } catch (err) {
62
+ console.error('Error:', err instanceof Error ? err.message : err);
63
+ process.exit(1);
64
+ }
65
+ });
66
+
67
+ const jobs = program.command('jobs').description('Manage cron jobs');
68
+
69
+ jobs
70
+ .command('list')
71
+ .description('List cron jobs')
72
+ .action(async () => {
73
+ try {
74
+ const client = getClient();
75
+ const jobsList = await client.listCronJobs.query({});
76
+ console.log(JSON.stringify(jobsList, null, 2));
77
+ } catch (err) {
78
+ console.error('Error:', err instanceof Error ? err.message : err);
79
+ process.exit(1);
80
+ }
81
+ });
82
+
83
+ jobs
84
+ .command('add <name>')
85
+ .description('Add a cron job')
86
+ .option('--at <time>', 'Schedule at specific time')
87
+ .option('--every <interval>', 'Schedule at interval')
88
+ .option('--cron <cron>', 'Schedule via cron expression')
89
+ .option('-m, --message <msg>', 'Message to send')
90
+ .option('-r, --reply <reply>', 'Reply text')
91
+ .option('-a, --agent <agentId>', 'Agent ID')
92
+ .option('-s, --session <type>', 'Session type (must be "new")')
93
+ .option(
94
+ '-e, --env <env>',
95
+ 'Environment variables in key=value format',
96
+ (val: string, prev: string[]) => prev.concat([val]),
97
+ []
98
+ )
99
+ .option('-c, --chat <chatId>', 'Chat ID')
100
+ .action(async (name, options) => {
101
+ try {
102
+ let schedule;
103
+ if (options.at) schedule = { at: options.at };
104
+ else if (options.every) schedule = { every: options.every };
105
+ else if (options.cron) schedule = { cron: options.cron };
106
+ else throw new Error('A schedule must be specified (--at, --every, or --cron).');
107
+
108
+ const job: CronJob = {
109
+ id: name,
110
+ createdAt: new Date().toISOString(),
111
+ message: options.message || '',
112
+ schedule,
113
+ };
114
+
115
+ if (options.reply) job.reply = options.reply;
116
+ if (options.agent) job.agentId = options.agent;
117
+ if (options.session) {
118
+ if (options.session !== 'new') throw new Error('Only "new" session type is supported.');
119
+ job.session = { type: 'new' };
120
+ }
121
+
122
+ if (options.env && options.env.length > 0) {
123
+ const jobEnv: Record<string, string> = {};
124
+ for (const e of options.env) {
125
+ const [k, ...v] = e.split('=');
126
+ if (k) jobEnv[k] = v.join('=');
127
+ }
128
+ job.env = jobEnv;
129
+ }
130
+
131
+ const client = getClient();
132
+ await client.addCronJob.mutate({ chatId: options.chat, job });
133
+ console.log(`Job '${name}' created successfully.`);
134
+ } catch (err) {
135
+ console.error('Error:', err instanceof Error ? err.message : err);
136
+ process.exit(1);
137
+ }
138
+ });
139
+
140
+ jobs
141
+ .command('delete <name>')
142
+ .description('Delete a cron job')
143
+ .option('-c, --chat <chatId>', 'Chat ID')
144
+ .action(async (name, options) => {
145
+ try {
146
+ const client = getClient();
147
+ const result = await client.deleteCronJob.mutate({ chatId: options.chat, id: name });
148
+ if (result && result.deleted) {
149
+ console.log(`Job '${name}' deleted successfully.`);
150
+ } else {
151
+ console.log(`Job '${name}' not found.`);
152
+ }
153
+ } catch (err) {
154
+ console.error('Error:', err instanceof Error ? err.message : err);
155
+ process.exit(1);
156
+ }
157
+ });
158
+
159
+ const requests = program.command('requests').description('Manage sandbox policy requests');
160
+
161
+ requests
162
+ .command('list')
163
+ .description('List available policies')
164
+ .action(async () => {
165
+ try {
166
+ const client = getClient();
167
+ const config = await client.listPolicies.query();
168
+
169
+ if (!config || !config.policies || Object.keys(config.policies).length === 0) {
170
+ console.log('No policies configured.');
171
+ return;
172
+ }
173
+
174
+ console.log('Available Policies:\n');
175
+ for (const [name, policy] of Object.entries(config.policies)) {
176
+ console.log(`- ${name}`);
177
+ if (policy.description) {
178
+ console.log(` Description: ${policy.description}`);
179
+ }
180
+ }
181
+ } catch (err) {
182
+ console.error('Error:', err instanceof Error ? err.message : err);
183
+ process.exit(1);
184
+ }
185
+ });
186
+
187
+ program
188
+ .command('request <cmd>')
189
+ .description('Submit a sandbox policy request')
190
+ .option('--help', 'Execute the underlying command with --help and print the output')
191
+ .option('-f, --file <mappings...>', 'File mappings in the format name=path')
192
+ .allowUnknownOption()
193
+ .allowExcessArguments(true)
194
+ .helpOption('-h, --cli-help', 'display CLI help for command')
195
+ .action(async (cmdName, options, command) => {
196
+ try {
197
+ const client = getClient();
198
+ const config = await client.listPolicies.query();
199
+ const policy = config?.policies?.[cmdName];
200
+
201
+ if (!policy) {
202
+ throw new Error(`Policy not found: ${cmdName}`);
203
+ }
204
+
205
+ if (options.help) {
206
+ // Execute underlying command with --help via the daemon
207
+ const helpOutput = await client.executePolicyHelp.query({ commandName: cmdName });
208
+ if (helpOutput.stdout) {
209
+ process.stdout.write(helpOutput.stdout);
210
+ }
211
+ if (helpOutput.stderr) {
212
+ process.stderr.write(helpOutput.stderr);
213
+ }
214
+ process.exit(helpOutput.exitCode);
215
+ }
216
+
217
+ const dashDashIndex = process.argv.indexOf('--');
218
+ const opaqueArgs =
219
+ dashDashIndex !== -1 ? process.argv.slice(dashDashIndex + 1) : command.args.slice(1);
220
+
221
+ const fileMappings: Record<string, string> = {};
222
+ if (options.file) {
223
+ for (const mapping of options.file) {
224
+ const [name, ...pathParts] = mapping.split('=');
225
+ const pathStr = pathParts.join('=');
226
+ if (!name || !pathStr) {
227
+ throw new Error(`Invalid file mapping: ${mapping}. Expected format name=path`);
228
+ }
229
+ fileMappings[name] = pathStr;
230
+ }
231
+ }
232
+
233
+ const request = await client.createPolicyRequest.mutate({
234
+ commandName: cmdName,
235
+ args: opaqueArgs,
236
+ fileMappings,
237
+ });
238
+
239
+ console.log(`Request created successfully.`);
240
+ console.log(`Request ID: ${request.id}`);
241
+ } catch (err) {
242
+ console.error('Error:', err instanceof Error ? err.message : err);
243
+ process.exit(1);
244
+ }
245
+ });
246
+
247
+ program.parse(process.argv);
@@ -0,0 +1,4 @@
1
+ export function handleError(action: string, err: unknown): never {
2
+ console.error(`Failed to ${action}:`, err instanceof Error ? err.message : String(err));
3
+ process.exit(1);
4
+ }
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { generateToken, validateToken, type TokenPayload } from './auth.js';
3
+
4
+ describe('Auth token generation and validation', () => {
5
+ it('should generate a valid token and validate it successfully', () => {
6
+ const payload: TokenPayload = {
7
+ chatId: 'chat-123',
8
+ agentId: 'agent-456',
9
+ sessionId: 'session-789',
10
+ timestamp: Date.now(),
11
+ };
12
+
13
+ const token = generateToken(payload);
14
+ expect(typeof token).toBe('string');
15
+ expect(token).toContain('.');
16
+
17
+ const validated = validateToken(token);
18
+ expect(validated).not.toBeNull();
19
+ expect(validated?.chatId).toBe(payload.chatId);
20
+ expect(validated?.agentId).toBe(payload.agentId);
21
+ expect(validated?.sessionId).toBe(payload.sessionId);
22
+ expect(validated?.timestamp).toBe(payload.timestamp);
23
+ });
24
+
25
+ it('should return null for invalid tokens', () => {
26
+ expect(validateToken('invalid-token')).toBeNull();
27
+ expect(validateToken('part1.part2')).toBeNull();
28
+ expect(validateToken('')).toBeNull();
29
+ });
30
+
31
+ it('should return null if token signature is modified', () => {
32
+ const payload: TokenPayload = {
33
+ chatId: 'chat-123',
34
+ agentId: 'agent-456',
35
+ sessionId: 'session-789',
36
+ timestamp: Date.now(),
37
+ };
38
+
39
+ const token = generateToken(payload);
40
+ const parts = token.split('.');
41
+ if (!parts[1]) throw new Error('Invalid token');
42
+
43
+ // Modify the signature slightly
44
+ const modifiedSignature =
45
+ parts[1].substring(0, parts[1].length - 1) + (parts[1].endsWith('a') ? 'b' : 'a');
46
+ const tamperedToken = `${parts[0]}.${modifiedSignature}`;
47
+
48
+ expect(validateToken(tamperedToken)).toBeNull();
49
+ });
50
+ });
@@ -0,0 +1,69 @@
1
+ import crypto from 'node:crypto';
2
+ import type { Settings } from '../shared/config.js';
3
+
4
+ // In-memory secret generated on daemon startup.
5
+ // Valid tokens will only last for the lifetime of the daemon process.
6
+ const DAEMON_SECRET = crypto.randomBytes(32);
7
+
8
+ export interface TokenPayload {
9
+ chatId: string;
10
+ agentId: string;
11
+ sessionId: string;
12
+ timestamp: number;
13
+ }
14
+
15
+ export function generateToken(payload: TokenPayload): string {
16
+ const payloadStr = Buffer.from(JSON.stringify(payload)).toString('base64');
17
+ const hmac = crypto.createHmac('sha256', DAEMON_SECRET).update(payloadStr).digest('hex');
18
+ return `${payloadStr}.${hmac}`;
19
+ }
20
+
21
+ export function validateToken(token: string): TokenPayload | null {
22
+ try {
23
+ const parts = token.split('.');
24
+ if (parts.length !== 2) return null;
25
+
26
+ const [payloadStr, signature] = parts;
27
+ if (!payloadStr || !signature) return null;
28
+
29
+ const expectedHmac = crypto
30
+ .createHmac('sha256', DAEMON_SECRET)
31
+ .update(payloadStr)
32
+ .digest('hex');
33
+
34
+ const signatureBuffer = Buffer.from(signature, 'hex');
35
+ const expectedHmacBuffer = Buffer.from(expectedHmac, 'hex');
36
+
37
+ if (
38
+ signatureBuffer.length !== expectedHmacBuffer.length ||
39
+ !crypto.timingSafeEqual(signatureBuffer, expectedHmacBuffer)
40
+ ) {
41
+ return null;
42
+ }
43
+
44
+ const payloadJson = Buffer.from(payloadStr, 'base64').toString('utf8');
45
+ return JSON.parse(payloadJson) as TokenPayload;
46
+ } catch {
47
+ return null;
48
+ }
49
+ }
50
+
51
+ export function getApiContext(settings?: Settings) {
52
+ if (settings?.api === undefined) return null;
53
+ let isApiEnabled = false;
54
+ let apiHost = '127.0.0.1';
55
+ let apiPort = 3000;
56
+ let proxyHost: string | undefined = undefined;
57
+
58
+ if (typeof settings.api === 'boolean') {
59
+ isApiEnabled = settings.api;
60
+ } else if (typeof settings.api === 'object') {
61
+ isApiEnabled = true;
62
+ apiHost = settings.api.host ?? '127.0.0.1';
63
+ apiPort = settings.api.port ?? 3000;
64
+ proxyHost = settings.api.proxy_host;
65
+ }
66
+
67
+ if (!isApiEnabled) return null;
68
+ return { host: apiHost, port: apiPort, proxy_host: proxyHost };
69
+ }
@@ -0,0 +1,26 @@
1
+ import * as shared from '../shared/chats.js';
2
+ import { emitMessageAppended } from './events.js';
3
+
4
+ export async function appendMessage(
5
+ id: string,
6
+ message: shared.ChatMessage,
7
+ startDir = process.cwd()
8
+ ): Promise<void> {
9
+ await shared.appendMessage(id, message, startDir);
10
+ emitMessageAppended(id, message);
11
+ }
12
+
13
+ export {
14
+ type ChatMessage,
15
+ type UserMessage,
16
+ type CommandLogMessage,
17
+ getChatsDir,
18
+ isValidChatId,
19
+ createChat,
20
+ listChats,
21
+ deleteChat,
22
+ getMessages,
23
+ getDefaultChatId,
24
+ setDefaultChatId,
25
+ DEFAULT_CHAT_ID,
26
+ } from '../shared/chats.js';