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,163 @@
1
+ # Product Requirements Document: Sandbox Policies
2
+
3
+ ## Vision
4
+ To provide a secure, extensible framework that empowers AI agents to request and execute sensitive or network-dependent operations safely from within a restricted sandbox. By enabling asynchronous, user-approved requests, agents can seamlessly integrate privileged tasks into their workflows without compromising system integrity.
5
+
6
+ ## Product/Market Background
7
+ AI agents often operate within highly restricted sandbox environments to prevent unintended destructive actions or unauthorized network communication. However, this safety comes at the cost of utility; an agent might deduce a solution that requires network access (e.g., sending an email or moving a file to a networked read-only volume) but is unable to act on it. By introducing a formal "request-and-approve" policy workflow, users retain full control via a familiar chat interface, while agents gain the ability to perform complex, privileged tasks.
8
+
9
+ ## Use Cases
10
+
11
+ ### 1. Moving Files to a Network-Enabled Directory
12
+ An agent needs to compile or transfer a file into a read-only area accessible by network-enabled host commands (e.g., `/home/users/has-network`). The agent generates the file and requests permission to move it. The user reviews the request and approves the move. (Note: Binaries are generally not supported for these workflows).
13
+
14
+ ### 2. Sending an Email
15
+ An agent compiles a status report and wants to email it to stakeholders. It uses the CLI to request permission to send the email, explicitly passing the file payload. The user previews the requested action in their chat UI and approves the action, which executes safely.
16
+
17
+ ### 3. Agent Workflow Orchestration
18
+ An automated script inside the sandbox coordinates a multi-step process. It makes an approval request via the CLI, which returns immediately. The agent relies on an automatically injected chat message from the daemon to know when the request is approved or rejected before proceeding with the next steps in its conversation.
19
+
20
+ ## Inspirational Flow Example
21
+
22
+ The following scenario illustrates an end-to-end interaction using this feature:
23
+
24
+ 1. **Discovery:** The user tells the LLM about a new capability. The LLM calls `clawmini requests list` to see what is available, along with descriptions.
25
+ 2. **Schema Generation:** The LLM then calls `clawmini request send-email --help` to execute the underlying command with `--help` and read its output to learn about the expected arguments.
26
+ 3. **Execution Request:** On a user's request, the LLM initiates the action. It explicitly tags a file for snapshotting and passes the rest of the arguments opaquely:
27
+ `clawmini request send-email --file body_txt=./body.txt -- --to foo@bar.com --subject hi --body "{{body_txt}}"`
28
+ 4. **Agent Acknowledgment:** The CLI command returns immediately, outputting: *"Submitted request (ID: 32). You will get a message in the chat if the user approves or rejects."* The daemon stores the request on disk to survive restarts.
29
+ 5. **User Preview & Decision:** The user sees a message in their chat interface: *"Request #32: Agent wants to run `send-email` with args: `--to foo@bar.com --subject hi --body /tmp/snapshot/.../body.txt`... use `/approve 32` or `/reject 32`..."* The preview also includes the contents of the file, abbreviated to ~500 characters (or up to ~2000 characters total across multiple files), providing the user with immediate context for what is being sent.
30
+ 6. **Resolution:** The user responds with `/reject 32 make it more formal`. (The system verifies this command originated from the user, not the agent).
31
+ 7. **Agent Feedback Loop:** The daemon automatically injects a message into the active chat session: `[Request 32] User rejected with message: make it more formal`. The agent can then adjust its inputs and try again.
32
+
33
+ ## Proposed Experience & CLI Design
34
+
35
+ ### Registration (JSON Configuration)
36
+ Users will register new commands in a concise JSON configuration file (e.g., `policies.json`). The framework adopts a **"Dumb Pipes, Smart Endpoints"** philosophy. The configuration avoids complex argument parsing. Instead, it merely provides a description and points to an executable wrapper script. If users want to restrict the flags an agent can use, they enforce those restrictions within their wrapper script. When the agent requests help for a command, the framework executes the wrapper script with `--help` and returns the output to the agent.
37
+
38
+ ```json
39
+ {
40
+ "actions": {
41
+ "promote-file": {
42
+ "description": "Move a file to the network-enabled read-only area.",
43
+ "execute": {
44
+ "environment": "host",
45
+ "command": "./scripts/promote-file.sh"
46
+ }
47
+ },
48
+ "send-email": {
49
+ "description": "Send an email.",
50
+ "execute": {
51
+ "environment": "sandbox",
52
+ "command": "./scripts/send-email-wrapper.py"
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### Security & Sanitization Strategy
60
+
61
+ To ensure robust security against command injection, path traversal, and race conditions, the system employs the following mechanisms:
62
+
63
+ 1. **Direct Exec Arrays (No Shell Injection):** The system completely bypasses shell string concatenation. The daemon executes commands directly via an OS-level exec array (e.g., `spawn('script.sh', ['--to', 'admin@foo.com'])`). This treats all arguments as pure literal data, making classic shell injection (like passing `&& rm -rf /`) impossible.
64
+ 2. **Explicit Named Variable Map for Files:** The daemon does not attempt to parse or guess which arguments are file paths. Instead, the LLM must explicitly declare files using `clawmini` flags (e.g., `--file var_name=./path`). The daemon validates and snapshots the file, then safely interpolates the absolute path of the snapshot into the opaque arguments array (replacing `{{var_name}}`). This provides structural safety without brittle naming conventions.
65
+ 3. **Immediate Snapshotting & TOCTOU Prevention:** To prevent Time-of-Check to Time-of-Use (TOCTOU) race conditions involving symlinks, the daemon resolves the real path (equivalent to `O_NOFOLLOW` and `realpath`) and creates the secure snapshot *immediately* upon receiving the request, before the user is ever prompted. The user reviews and approves the exact snapshot, not the live file, guaranteeing that background processes in the sandbox cannot swap the file during the approval window.
66
+
67
+ ### Clawmini CLI (Agent View)
68
+
69
+ The agent interacts with the `clawmini-lite` CLI using the POSIX standard `--` separator. Everything before `--` is processed by the daemon for security routing and snapshotting. Everything after `--` is passed opaquely to the target script.
70
+
71
+ **1. Discovery**
72
+ - `clawmini-lite requests list`: Outputs all registered policies and their descriptions.
73
+ - `clawmini-lite request <cmd> --help`: Executes the underlying command defined in the JSON configuration with the `--help` flag and outputs the result.
74
+
75
+ **2. Making a Request (Named Variable Mapping)**
76
+ ```bash
77
+ # Agent explicitly maps body_txt to a sandbox file, then uses it in the opaque args
78
+ clawmini-lite request send-email \
79
+ --file body_txt=./report.txt \
80
+ -- \
81
+ --to admin@example.com --subject "Daily Report" --body "{{body_txt}}"
82
+ ```
83
+
84
+ Behind the scenes:
85
+ 1. `clawmini-lite` parses `--file body_txt=./report.txt`.
86
+ 2. The daemon verifies the path is inside the agent's directory, rejects it if it's a symlink, and snapshots it to a secure location (e.g., `/tmp/snapshots/123_report.txt`).
87
+ 3. The daemon takes the opaque arguments `["--to", "admin@example.com", "--subject", "Daily Report", "--body", "{{body_txt}}"]` and performs a precise string replacement on array elements to swap `{{body_txt}}` with the safe snapshot path.
88
+ 4. The CLI returns immediately with the pending Request ID and exits.
89
+ 5. The daemon persists the request and routes the preview to the user's chat UI.
90
+ 6. Upon approval, the daemon `spawn`s the script with the safe argument array.
91
+
92
+ **3. Asynchronous Resolution & Automatic Messaging**
93
+ When the agent makes a request, the CLI immediately returns the Request ID and exits. The daemon tracks the request. Once the user resolves the request (approves or rejects), the daemon *automatically* injects a system message back into the active chat session. This message includes the "Approved/Rejected" status, any `stdout`/`stderr` from the executed command, and any feedback strings provided by the user upon rejection.
94
+
95
+ ### User Interface & Interactions
96
+
97
+ All requests are routed to the user's primary chat UI for review. To prevent unauthorized execution, the system relies on specific slash commands that must originate directly from the user.
98
+
99
+ When a request is made, the daemon presents the user with a preview message (e.g., "Request #32: Agent wants to run `send-email` with args..."). The preview displays the snapshot paths and includes abbreviated file contents (~500 chars per file, up to ~2000 chars total) so the user can see exactly what data is being requested.
100
+
101
+ Users can respond with:
102
+ - `/approve <id>`: Approve and execute the request.
103
+ - `/reject <id> [reason]`: Reject the request, optionally providing a natural language reason (e.g., `/reject 32 tone needs to be more formal`) so the agent can learn and retry.
104
+ - `/pending`: View a summarized list of all active pending requests.
105
+
106
+ ## Requirements
107
+
108
+ ### Core Requirements
109
+ 1. **CLI Extensibility:** Agents must have access to a `clawmini` CLI binary inside their environment.
110
+ 2. **Configuration:** Users define permissible actions via a centralized JSON configuration providing a `command` and `description` string. The framework acts as a "dumb pipe" for arguments.
111
+ 3. **Explicit File Templating & Snapshotting:** Agents declare files using `--file name=path` prior to the `--` argument separator. The daemon strictly bounds the path to the agent's directory, creates a secure snapshot (rejecting symlinks entirely to prevent TOCTOU), and replaces `{{name}}` in the opaque arguments with the snapshot's absolute path. Enforce strict file size limits on snapshots (e.g., max 5MB).
112
+ 4. **Chat Integration & Previews:** Requests must be routed to the user's Chat UI, showing the requested command, the snapshot paths, the exact opaque arguments, and abbreviated file contents to aid review.
113
+ 5. **Execution Engine:** Approved actions must execute safely using direct OS exec arrays (`spawn`), not shell execution.
114
+ 6. **Automatic Callbacks:** The daemon must automatically inject a message into the active chat session when a request is approved (along with command output) or rejected (along with user feedback).
115
+ 7. **State Management:** Request state should be saved locally as `.json` files (e.g., in `.gemini/tmp/requests/`) to gracefully handle daemon restarts and persist pending requests.
116
+
117
+ ### Non-Functional Requirements
118
+ - **Security:**
119
+ - **Input Sanitization (Command Injection):** The framework must strictly use direct exec arrays to completely mitigate shell command injection risks.
120
+ - **Path Bounding & Symlinks (TOCTOU):** The daemon must snapshot files immediately upon request creation. It must verify the file lies within the agent's directory and reject any symlinks entirely to prevent an agent from escaping the sandbox via background malicious symlink swapping during the approval window.
121
+ - **Denial of Service (DoS) Prevention:** The system must cap the number of pending requests (e.g., a maximum of 100 open requests) to prevent an agent from spamming requests and exhausting system resources (disk space, inodes, or memory).
122
+ - **Spoofing & Self-Approval Prevention:** The system must strictly verify the origin of `/approve` and `/reject` commands to ensure they come from direct user input (e.g., validating the `role: user` tag on the message), not from agent outputs or background jobs.
123
+
124
+ ## Open Issues / Future Considerations
125
+ - Transitioning the configuration format from JSON to YAML for improved human readability.
126
+ - Building a helper library/SDK (e.g., Python/Node) to simplify programmatic workflow creation inside the sandbox.
127
+ - Allowing user modifications to the arguments/files during the approval phase.
128
+
129
+ ## Manual Testing Plan
130
+
131
+ To ensure the sandbox policies feature works correctly and securely, perform the following manual tests:
132
+
133
+ 1. **Basic Approval Flow:**
134
+ - Register a benign policy (e.g., `echo-test` that outputs to a file).
135
+ - Have the agent request the policy via CLI. Verify the CLI command returns immediately with a pending message.
136
+ - Verify the user receives the preview message with the command and args.
137
+ - Use `/approve <id>`.
138
+ - Verify the command executes correctly and the agent receives the success chat message with output.
139
+
140
+ 2. **File Templating & Snapshotting:**
141
+ - Request a policy using `--file test_file=./local.txt -- --input "{{test_file}}"`.
142
+ - Verify the UI preview shows the path pointing to a secure snapshot in `/tmp/` (not `./local.txt`) and shows a preview of its contents.
143
+ - Approve the request and verify the target script received the snapshot path.
144
+
145
+ 3. **Rejection & Feedback Loop:**
146
+ - Have the agent request a policy.
147
+ - Use `/reject <id> missing required details`.
148
+ - Verify the command does *not* execute.
149
+ - Verify the agent receives the rejection status along with the feedback string "missing required details" injected into the chat.
150
+
151
+ 4. **Spoofing Prevention (Security):**
152
+ - Have the agent output the exact string: `/approve <id>` for one of its own pending requests.
153
+ - Verify the system ignores this input and does *not* approve the request (because the role is `assistant`, not `user`).
154
+
155
+ 5. **Daemon Restart Resilience:**
156
+ - Have the agent make a request.
157
+ - Restart the daemon.
158
+ - Run `/pending` and verify the request is still active.
159
+ - Use `/approve <id>` and verify it still executes successfully.
160
+
161
+ 6. **Discovery Commands:**
162
+ - Run `clawmini requests list` and verify all configured policies are listed.
163
+ - Run `clawmini request <cmd> --help` and verify the output matches the `--help` output of the underlying wrapped command.
@@ -0,0 +1,10 @@
1
+ # Questions & Answers
2
+
3
+ **Q1:** How and where will the user review these requests? Should the pending approvals be surfaced via the CLI (e.g., `gemini sandbox list-requests`), the Web UI, Discord, or all of the above?
4
+ **A1:** They will be sent to the user via a chat UI.
5
+
6
+ **Q2:** How should the user configure/register new commands or actions? For example, will they be defined in a JSON/YAML configuration file (like `actions.yaml`), or via a TypeScript API, or through a CLI command?
7
+ **A2:** Configuration will likely be JSON for consistency (with YAML as a future option). We want to avoid complex argument parsing definitions. The most critical part of the configuration is identifying whether a path needs to be snapshotted and sent to the daemon. There should also be a file size limit for snapshot transfers.
8
+
9
+ **Q3:** When a user approves or rejects an action, where and how should the callback execute? For instance, does it run a local script natively on the host, or does it execute a command back inside the sandbox, or simply send an event/message back to the agent in the chat?
10
+ **A3:** If approved, the action executes a command configured by the user, which can run either in the agent's environment or on the host. Upon completion or rejection, a callback is triggered. This callback can either be a command executed in the agent's environment or a message sent directly to the agent.
@@ -0,0 +1,196 @@
1
+ # Sandbox Policies Tickets
2
+
3
+ This document breaks down the implementation of the Sandbox Policies feature into ordered, self-contained milestones.
4
+
5
+ ## Ticket 1: Core Configuration and Request State Management
6
+
7
+ **Description:** Define the data structures for policy configurations and requests, and implement persistent state management for requests so they survive daemon restarts.
8
+ **Tasks:**
9
+
10
+ - Define TypeScript types for `policies.json` configuration.
11
+ - Define types for Request states (`Pending`, `Approved`, `Rejected`).
12
+ - Implement a `RequestStore` service that saves, loads, and lists requests from a persistent directory (e.g., `.gemini/tmp/requests/`).
13
+ **Verification:**
14
+ - Write unit tests for `RequestStore` verifying save, load, list operations, and graceful handling of corrupted files.
15
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
16
+ **Status:** completed
17
+
18
+ ## Ticket 2: File Snapshotting and Security Layer
19
+
20
+ **Description:** Implement the core security mechanisms to prevent TOCTOU attacks and command injection.
21
+ **Tasks:**
22
+
23
+ - Implement a secure file snapshotting utility that takes a requested file path, resolves its realpath (preventing symlink attacks), verifies it is within the allowed sandbox/workspace, and copies it to a secure temporary directory.
24
+ - Implement argument interpolation logic to safely replace named variables (e.g., `{{file_var}}`) in an arguments array with the absolute paths of the generated snapshots.
25
+ - Create a safe execution wrapper using `spawn` (direct exec array, no shell concatenation).
26
+ **Verification:**
27
+ - Write unit tests for the snapshotting utility, specifically testing path traversal attempts and symlink resolution.
28
+ - Write unit tests for the argument interpolation logic.
29
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
30
+ **Status:** completed
31
+
32
+ ## Ticket 3: Daemon Request Service
33
+
34
+ **Description:** Build the central service within the daemon that processes incoming requests, utilizing the security layer and state management.
35
+ **Tasks:**
36
+
37
+ - Create a `PolicyRequestService` that receives raw request data (command name, file mappings, opaque args).
38
+ - Integrate the file snapshotting and argument interpolation into the service.
39
+ - Enforce the maximum limit of pending requests (e.g., max 100 open requests) to prevent DoS.
40
+ - Store the resulting pending request using the `RequestStore`.
41
+ **Verification:**
42
+ - Write unit tests for `PolicyRequestService`, ensuring it correctly coordinates snapshotting and storage, and properly rejects requests when the pending limit is reached.
43
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
44
+ **Status:** completed
45
+
46
+ ## Ticket 4: CLI Agent Commands
47
+
48
+ **Description:** Expose the sandbox policies to the agent via the `clawmini` CLI.
49
+ **Tasks:**
50
+
51
+ - Implement `clawmini requests list` to fetch and display available policies and descriptions.
52
+ - Implement `clawmini request <cmd> --help` to execute the underlying command with `--help` and print the output.
53
+ - Implement `clawmini request <cmd> [--file name=path...] -- [args...]` to parse inputs and submit the request to the `PolicyRequestService` in the daemon, returning the Request ID immediately.
54
+ **Verification:**
55
+ - Write tests for the CLI commands, verifying correct argument parsing (especially the `--` separator) and interaction with the daemon service.
56
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
57
+ **Status:** completed
58
+
59
+ ## Ticket 5: Chat UI Routing and User Slash Commands
60
+
61
+ **Description:** Surface requests to the user for review and provide commands to act on them.
62
+ **Tasks:**
63
+
64
+ - Implement logic to intercept new pending requests and route a preview message to the Chat UI.
65
+ - The preview message must include the command, the opaque arguments, and abbreviated contents (~500 chars) of any snapshotted files.
66
+ - Implement user slash commands: `/approve <id>`, `/reject <id> [reason]`, and `/pending`.
67
+ - Implement strict spoofing prevention: ensure these commands only trigger if the message originates from the user (`role: user`).
68
+ **Verification:**
69
+ - Write unit tests for the preview message generation (ensuring files are abbreviated correctly).
70
+ - Write tests for the slash commands, explicitly testing the spoofing prevention mechanism.
71
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
72
+ **Status:** completed
73
+
74
+ ## Ticket 6: Execution and Feedback Loop
75
+
76
+ **Description:** Complete the workflow by executing approved requests and notifying the agent of the outcome.
77
+ **Tasks:**
78
+
79
+ - Connect the `/approve` command to the safe execution wrapper (`spawn`) implemented in Ticket 2.
80
+ - Implement an automatic feedback mechanism that injects a system/tool message back into the active chat session upon resolution.
81
+ - For approvals: include the `stdout`/`stderr` of the executed command.
82
+ - For rejections: include the user's rejection reason (if provided).
83
+ **Verification:**
84
+ - Write integration tests simulating the full end-to-end flow: request creation -> user approval -> execution -> feedback injection.
85
+ - Write integration tests for the rejection flow.
86
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
87
+ **Status:** completed
88
+
89
+ ## Ticket 7: Code Review Fixes
90
+
91
+ **Description:** Address code review feedback to improve performance and code quality.
92
+ **Tasks:**
93
+
94
+ - **High Priority:** In `src/daemon/routers/slash-policies.ts`, use `store.load(id)` instead of `store.list().find()` to fetch single requests in `/approve` and `/reject`, avoiding O(N) file reads.
95
+ - **Medium Priority:** In `src/daemon/request-store.ts`, extract the duplicated `ENOENT` error checking logic into a reusable helper function to adhere to DRY principles.
96
+ - **Low Priority:** In `src/cli/commands/request.ts`, simplify the opaque arguments fallback logic for argument extraction.
97
+ **Verification:**
98
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
99
+ **Status:** completed
100
+
101
+ ## Ticket 8: Policy Utils Improvements
102
+
103
+ **Description:** Address security and maintainability feedback for snapshotting utilities.
104
+ **Tasks:**
105
+
106
+ - Define the maximum snapshot size (5MB) as a named constant in `src/daemon/policy-utils.ts`.
107
+ - Update `createSnapshot` to receive the agent's directory instead of the workspace root, and strictly verify the file is within the agent's directory.
108
+ - Refactor snapshot generation to reject symlinks completely using `fs.lstat` instead of resolving them to prevent TOCTOU attacks.
109
+ - Ensure the newly generated unique snapshot filename does not already exist before copying.
110
+ **Verification:**
111
+ - Update and run unit tests for `policy-utils.ts` to assert symlinks are rejected and the agent directory is respected.
112
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
113
+ **Status:** completed
114
+
115
+ ## Ticket 9: Policy Request Metadata & Validation Enhancements
116
+
117
+ **Description:** Improve request ID generation and data integrity.
118
+ **Tasks:**
119
+
120
+ - Update request ID generation to use a short, typing-friendly string (e.g., 3 random alphanumeric characters) instead of UUIDs.
121
+ - Update `PolicyRequest` to include `chatId` and `agentId`, and populate these fields upon request creation in `policy-request-service.ts`.
122
+ - Update `request-store.ts` to validate the incoming JSON schema using Zod when loading requests from disk.
123
+ **Verification:**
124
+ - Update unit tests for `policy-request-service.ts` and `request-store.ts` to assert ID format, metadata presence, and Zod validation.
125
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
126
+ **Status:** completed
127
+
128
+ ## Ticket 10: Router State & Configuration Fixes
129
+
130
+ **Description:** Fix router pipeline handling to ensure processes are not incorrectly killed and that agents receive the correct feedback messages.
131
+ **Tasks:**
132
+
133
+ - Modify `src/daemon/routers.ts` to make `slash-policies` a dynamically loaded router (added via config) rather than a hardcoded step, and remove inline `await import(...)` statements by moving them to top-level imports.
134
+ - Update `slash-policies.ts` to ensure `action: 'stop'` is no longer returned for `/approve`, `/reject`, or error cases.
135
+ - For approvals/rejections, update the `state.message` so the agent receives the correct confirmation/output string, and return it without stopping the pipeline.
136
+ - For user errors (e.g., missing ID), set `state.reply` and return an empty `message`.
137
+ - Ensure `appendMessage` is provided with the correct `replyTo` parameter targeting the user's incoming message ID.
138
+ - During approval/rejection, verify that the `req.chatId` matches the current `state.chatId`.
139
+ **Verification:**
140
+ - Run integration tests simulating the new router behavior, verifying the agent message generation and that the pipeline does not stop.
141
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
142
+ **Status:** completed
143
+
144
+ ## Ticket 11: CLI Commands Relocation
145
+
146
+ **Description:** Move the sandbox request commands to the lite CLI so they are accessible by the agent.
147
+ **Tasks:**
148
+
149
+ - Relocate `requestCmd` and `requestsCmd` from `src/cli/index.ts` to `src/cli/lite.ts`.
150
+ **Verification:**
151
+ - Manually run `clawmini-lite --help` to verify the `request` commands are present.
152
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
153
+ **Status:** completed
154
+
155
+ ## Ticket 12: Router Slash Policies DRY Refactoring
156
+
157
+ **Priority:** High
158
+ **Description:** Address DRY violation in `src/daemon/routers/slash-policies.ts`.
159
+ **Tasks:**
160
+ - Extract the common request loading and validation logic shared between the `/approve` and `/reject` branches into a helper function (e.g., `loadAndValidateRequest`).
161
+ **Verification:**
162
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
163
+ **Status:** completed
164
+
165
+ ## Ticket 13: Secure and Collision-Resistant Request ID Generation
166
+
167
+ **Priority:** High
168
+ **Description:** Improve the Request ID generation to be more secure and resistant to collisions in `src/daemon/policy-request-service.ts`.
169
+ **Tasks:**
170
+ - Replace `randomBytes(2).toString('hex').slice(0, 3)` with a slightly longer secure string (e.g., 6 characters) or check against existing IDs in the `RequestStore` to ensure uniqueness before assigning the ID.
171
+ **Verification:**
172
+ - Update tests for `policy-request-service.ts`.
173
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
174
+ **Status:** completed
175
+
176
+ ## Ticket 14: Extract Preview Message Formatting
177
+
178
+ **Priority:** Medium
179
+ **Description:** Improve Separation of Concerns in `src/daemon/router.ts` by extracting the `previewContent` generation logic.
180
+ **Tasks:**
181
+ - Move the inline string formatting and dynamic file reading used to generate the preview message in `createPolicyRequest` to a new helper function `generateRequestPreview` in `src/daemon/policy-utils.ts`.
182
+ - Import `node:fs/promises` properly rather than dynamically inside the loop if moving to a utility file.
183
+ **Verification:**
184
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
185
+ **Status:** completed
186
+
187
+ ## Ticket 15: Modernize String Replacement
188
+
189
+ **Priority:** Low
190
+ **Description:** Modernize the argument interpolation string replacement in `src/daemon/policy-utils.ts`.
191
+ **Tasks:**
192
+ - Refactor `interpolateArgs` to use `replaceAll(variable, snapshotPath)` instead of `.split(variable).join(snapshotPath)`.
193
+ **Verification:**
194
+ - Ensure tests still pass.
195
+ - Run `npm run format:check && npm run lint && npm run check && npm run test`.
196
+ **Status:** completed
package/docs/CHECKS.md ADDED
@@ -0,0 +1,9 @@
1
+ # Automated Checks
2
+
3
+ Run the following command to ensure all code quality checks and tests pass after making changes to the codebase:
4
+
5
+ ```bash
6
+ npm run format:check && npm run lint && npm run check && npm run test
7
+ ```
8
+
9
+ *Note: You can also use `npm run format` and `npm run lint:fix` to automatically fix formatting and linting issues before running these checks.*
@@ -0,0 +1,69 @@
1
+ # Discord Adapter Setup Guide
2
+
3
+ This guide describes how to set up and configure the Discord adapter for Clawmini.
4
+
5
+ ## Prerequisites
6
+
7
+ - A Discord account.
8
+ - A Clawmini daemon running locally (the adapter communicates with it via TRPC over Unix sockets).
9
+
10
+ ## Step 1: Create a Discord Bot
11
+
12
+ 1. Go to the [Discord Developer Portal](https://discord.com/developers/applications).
13
+ 2. Click **New Application**.
14
+ 3. Give your application a name (e.g., "Clawmini-Bot") and click **Create**.
15
+ 4. In the left sidebar, click **Bot**.
16
+ 5. Under **Bot Token**, click **Reset Token** (or **Copy Token**) to retrieve your bot's token. **Save this token securely; you will need it later.**
17
+ 6. Scroll down to the **Privileged Gateway Intents** section.
18
+ 7. Enable **Message Content Intent**. This is required for the bot to read DM messages.
19
+ 8. Click **Save Changes**.
20
+
21
+ ## Step 2: Get Your Discord User ID
22
+
23
+ The adapter only responds to messages from a single authorized user. To find your Discord User ID:
24
+
25
+ 1. Open Discord and go to **User Settings** (the gear icon at the bottom left).
26
+ 2. Go to **Advanced**.
27
+ 3. Enable **Developer Mode**.
28
+ 4. Right-click on your profile picture or username in a server or DM and select **Copy User ID**.
29
+
30
+ ## Step 3: Invite the Bot to Your Direct Messages
31
+
32
+ Discord bots cannot initiate a DM conversation with a user unless the user has first interacted with the bot.
33
+
34
+ 1. In the Discord Developer Portal, go to **OAuth2** -> **URL Generator**.
35
+ 2. Select the `bot` scope.
36
+ 3. If prompted for an **Installation Method**, ensure you select **Guild Install**. The `bot` scope is not valid for "User Install" and will cause an error.
37
+ 4. Select the `Send Messages` and `Read Message History` permissions under **Bot Permissions**.
38
+ 5. Copy the generated URL and paste it into your browser.
39
+ 6. Select your personal server (or any server you share with the bot) to invite the bot.
40
+ 7. Once the bot is in a shared server, you can right-click the bot and select **Message** to start a DM conversation.
41
+
42
+ ## Step 4: Configure the Adapter
43
+
44
+ The adapter requires a configuration file with your bot token and user ID. You can generate a template configuration file by running the `init` command:
45
+
46
+ ```bash
47
+ npx clawmini-adapter-discord init
48
+ ```
49
+
50
+ This will create a `config.json` file at `.clawmini/adapters/discord/config.json`. Open this file and replace the placeholders with your actual bot token and user ID:
51
+
52
+ ```json
53
+ {
54
+ "botToken": "YOUR_DISCORD_BOT_TOKEN",
55
+ "authorizedUserId": "YOUR_DISCORD_USER_ID",
56
+ "chatId": "default"
57
+ }
58
+ ```
59
+ *(Note: `chatId` defaults to `"default"`. You can change this if you want the bot to associate with a different chat).*
60
+
61
+ ## Step 5: Start the Adapter
62
+
63
+ Ensure the Clawmini daemon is running, then start the Discord adapter:
64
+
65
+ ```bash
66
+ npx clawmini-adapter-discord
67
+ ```
68
+
69
+ The adapter will now forward authorized Discord DM messages to your Clawmini daemon and vice versa.
@@ -0,0 +1,76 @@
1
+ # Sandbox Policies Guide
2
+
3
+ The Sandbox Policies feature provides a secure framework for AI agents operating within restricted sandbox environments to request and execute sensitive or network-dependent operations. Using a formal "request-and-approve" workflow, users retain full control via their chat interface while agents gain the ability to perform complex, privileged tasks like sending emails or promoting files to external systems.
4
+
5
+ ## Registering a Policy
6
+
7
+ Policies are configured centrally in a JSON file located at `.clawmini/policies.json`. This configuration maps an easy-to-use policy command name to the actual script or binary you want to run when the request is approved.
8
+
9
+ The framework treats the command execution as a "dumb pipe". It executes the specified script using a secure execution wrapper (bypassing the shell to prevent injection attacks) and interpolates safe, verified file paths.
10
+
11
+ ### Example Configuration
12
+
13
+ Create or update `.clawmini/policies.json` in your workspace root:
14
+
15
+ ```json
16
+ {
17
+ "policies": {
18
+ "send-email": {
19
+ "description": "Sends an email using the specified body file.",
20
+ "command": "./.clawmini/policy-scripts/send-email.sh",
21
+ "args": ["--agent-email"],
22
+ "allowHelp": true
23
+ }
24
+ }
25
+ }
26
+ ```
27
+
28
+ In this example, the `send-email` policy uses a wrapper script located at `./.clawmini/policy-scripts/send-email.sh`. Any arguments defined in `args` will be prepended to the arguments the agent passes. The `allowHelp` flag must be set to `true` to enable the `--help` discovery feature for this policy.
29
+
30
+ ## Agent Access via clawmini-lite
31
+
32
+ Agents running within their environment can interact with the Policies feature using the `clawmini-lite` CLI.
33
+
34
+ 1. **Discovery:**
35
+ Agents can view available policies and their descriptions:
36
+ ```bash
37
+ clawmini-lite requests list
38
+ ```
39
+
40
+ 2. **Help Documentation:**
41
+ If a policy is configured with `"allowHelp": true`, agents can query it for help. This securely passes the `--help` flag to the underlying wrapper command and returns the output to the agent:
42
+ ```bash
43
+ clawmini-lite request send-email --help
44
+ ```
45
+ If `"allowHelp"` is missing or set to `false`, the agent will receive an error stating that `--help` is not supported.
46
+
47
+ 3. **Submitting a Request:**
48
+ Agents can submit a request to run a policy. The `--file` flag maps a file within the agent's sandbox to a variable name, which can be interpolated into the opaque arguments using `{{variable_name}}`. This ensures files are securely snapshotted to prevent TOCTOU (Time-of-Check to Time-of-Use) attacks.
49
+ ```bash
50
+ clawmini-lite request send-email --file body_txt=./report.txt -- --to admin@example.com --subject "Daily Report" --body "{{body_txt}}"
51
+ ```
52
+ The CLI returns a request ID immediately without blocking.
53
+
54
+ ## User Interaction
55
+
56
+ When an agent creates a request, the daemon intercepts it and sends a preview message to your chat session. This message includes the command, the requested arguments, and a truncated preview of the files involved.
57
+
58
+ You can then review and interact with the pending request using the following slash commands in your chat:
59
+
60
+ - **List Pending Requests:**
61
+ ```text
62
+ /pending
63
+ ```
64
+ *Lists all active pending requests that need review.*
65
+
66
+ - **Approve a Request:**
67
+ ```text
68
+ /approve <request_id>
69
+ ```
70
+ *Approves the request. The configured script executes securely, and the STDOUT/STDERR results are automatically sent back to the agent in the chat.*
71
+
72
+ - **Reject a Request:**
73
+ ```text
74
+ /reject <request_id> [reason]
75
+ ```
76
+ *Rejects the request. You can provide an optional natural language reason (e.g., `/reject 123 Tone needs to be more formal`) to help the agent correct its output and try again.*
@@ -0,0 +1,47 @@
1
+ import js from '@eslint/js';
2
+ import globals from 'globals';
3
+ import tseslint from 'typescript-eslint';
4
+ import { defineConfig } from 'eslint/config';
5
+ import eslintConfigPrettier from 'eslint-config-prettier';
6
+
7
+ export default defineConfig([
8
+ {
9
+ ignores: [
10
+ 'dist',
11
+ 'node_modules',
12
+ '.cladding',
13
+ '.clawmini',
14
+ '**/.svelte-kit',
15
+ '**/build',
16
+ 'web/.svelte-kit',
17
+ 'test-workspace*',
18
+ ],
19
+ },
20
+ {
21
+ files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
22
+ plugins: { js },
23
+ extends: ['js/recommended'],
24
+ languageOptions: {
25
+ globals: globals.browser,
26
+ parserOptions: {
27
+ tsconfigRootDir: import.meta.dirname,
28
+ },
29
+ },
30
+ },
31
+ tseslint.configs.recommended,
32
+ // Your custom rules
33
+ {
34
+ rules: {
35
+ '@typescript-eslint/no-explicit-any': 'warn',
36
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
37
+ 'max-lines': ['error', { max: 300, skipBlankLines: true, skipComments: true }],
38
+ },
39
+ },
40
+ {
41
+ files: ['**/*.test.ts', '**/*.spec.ts'],
42
+ rules: {
43
+ 'max-lines': 'off',
44
+ },
45
+ },
46
+ eslintConfigPrettier,
47
+ ]);
package/napkin.md ADDED
@@ -0,0 +1,21 @@
1
+ - **When you need to create or write multiline content to files**, use the native `write_file` tool instead of heredocs (`cat << EOF`) in `run_shell_command` to avoid whitespace/newline truncation or escaping issues.
2
+ - **When you need `fetch`, `Response`, or `Headers`**, rely exclusively on global Web APIs (`globalThis.Request`, `globalThis.Response`, `globalThis.Headers`) built directly into Node 18+ instead of using `undici` or external polyfills.
3
+ - **When you need to build a custom `fetch` wrapper for tRPC client adapters over UNIX sockets**, define the signature as `(input: string | URL | globalThis.Request, init?: unknown): Promise<globalThis.Response>` to satisfy TypeScript requirements. Note that the `httpLink` adapter still requires a valid `url` property (e.g., `http://localhost`) even if your interceptor ignores it.
4
+ - **When you need to test CLI instances that spin up background daemon processes**, use fully isolated E2E tests with `node:child_process.spawn` pointing to the pre-compiled `dist/cli/index.mjs` entry point.
5
+ - **When you need to run E2E CLI commands**, always run them in an isolated sandbox temporary directory (`cwd: e2eDir`) to prevent polluting the developer workspace with generated files or daemon logs.
6
+ - **When you need to tear down E2E tests**, explicitly run a cleanup command (e.g., `pkill -f "dist/daemon/index.mjs"`) in the `afterAll` hook to prevent zombie daemon processes from persisting.
7
+ - **When testing code that relies on `node:child_process.spawn`** and passing callbacks for side effects, consider mocking `spawn` inside the test and providing a matching mock implementation of your callback directly in the test suite.
8
+ - **When using Zod 4 for Record validation with string keys and string values**, use `z.record(z.string(), z.string())` rather than `z.record(z.string())`, as the newer Zod version requires two arguments for records when explicit types are needed.
9
+ - Updated logMsg construction to map extracted content directly to `content`, and preserve the raw output in `stdout` as per the new `CommandLogMessage` structure.
10
+ - **When building multi-target projects with tsdown and other bundlers (like Vite)**, ensure `tsdown` runs _first_ if `clean: true` is enabled in `tsdown.config.ts`, otherwise it will delete the artifacts output by other tools into the `dist` directory.
11
+ - **When integrating a separate frontend framework directory (like SvelteKit in `web/`) into a root TypeScript project**: Ensure the root `tsconfig.json` uses `exclude` to ignore the directory so its browser-specific globals (like `HTMLElement`) don't fail the Node.js focused root type-check. Instead, use an npm workspace or run the directory's own check script (e.g., `npm run check --prefix web`) alongside the root check.
12
+ - **When adding a frontend directory that relies on Prettier**: Extend the root `package.json` `format` and `format:check` scripts to explicitly include its source paths (e.g., `"web/src/**/*.ts"`) so that the root scripts maintain full codebase coverage.
13
+ - **When managing a separate embedded project (like SvelteKit in `web/`)**: Prefer setting it up as an **npm workspace** (by adding `"workspaces": ["web"]`) in the root `package.json` rather than maintaining duplicate `node_modules` and `package-lock.json` files. This unifies dependency resolution, hoists shared packages, and allows commands to be run from the root using the `-w web` flag (e.g., `npm run check -w web`).
14
+ - **When testing a root project with an embedded frontend workspace (like `web/`)**: Ensure the root project has a `vitest.config.ts` that explicitly excludes the frontend directory (e.g., `exclude: ['web/**']`). This prevents the root Node-based test runner from inappropriately picking up the frontend browser tests and crashing. Chain the root test script to also execute the workspace tests (e.g., `"test": "vitest run && npm run test -w web"`) to execute both environments completely and cleanly.
15
+ - **When creating test files for SvelteKit routes**: Do not prefix the test filename with `+` (e.g., `+page.svelte.spec.ts`). SvelteKit's router may try to interpret it. Always name test files without the `+`, like `page.svelte.spec.ts` for `+page.svelte`.
16
+ - Modified Sidebar.MenuButton in app-sidebar.svelte to use the child snippet and pass props to the anchor tag, resolving the wrapping issue and making the entire line item clickable.\n- Updated layout containers in +layout.svelte and +page.svelte to use 'h-svh' and proper 'flex-col overflow-hidden' behavior to confine scrolling to the message container and pin the chat header/input.
17
+ - Added a 'Debug view' toggle in the chat header, backed by a new Svelte 5 appState singleton. When off (default), logs only display the message content. When on, they show the full command, stdout, and stderr as previously configured.
18
+ - **shadcn-svelte commands:** Always use the `-y` flag when adding a component (e.g., `npx shadcn-svelte@latest add -y <component>`) to bypass the interactive prompt.\n- **Svelte Check:** Always run `npm run check -w web` instead of `npx svelte-check` to run Svelte diagnostics.
19
+ - Added shadcn-svelte dialog for chat creation and replaced native window.prompt.
20
+ - **E2E and Unit Test File Splitting:** When splitting `.test.ts` files, remember that `vi.mock()` must be at the top level of the file where the module is imported. Moving it to a shared setup utility will break mocking in Vitest.\nAlso, when splitting tests that share an environment setup (like E2E tests building dist), ensure tests run sequentially using `fileParallelism: false` in `vitest.config.ts` to prevent race conditions on shared global processes.
21
+ - **E2E Tests Performance Optimization:** To make E2E tests run faster, moved the `npm run build` command out of the repeated E2E file setup and into a Vitest `globalSetup` hook (`src/cli/e2e/global-setup.ts`). Restored `fileParallelism: true` to `vitest.config.ts`, so test files run concurrently in workers while sharing a single initial build output. This dropped test suite execution time from ~50s down to ~18s.