clawmini 0.0.8 → 0.0.9

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 (367) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +14 -0
  3. package/.github/workflows/release.yml +49 -0
  4. package/CHANGELOG.md +36 -0
  5. package/README.md +5 -4
  6. package/dist/adapter-discord/index.d.mts.map +1 -1
  7. package/dist/adapter-discord/index.mjs +465 -282
  8. package/dist/adapter-discord/index.mjs.map +1 -1
  9. package/dist/adapter-google-chat/index.mjs +367 -243
  10. package/dist/adapter-google-chat/index.mjs.map +1 -1
  11. package/dist/cli/index.mjs +684 -24
  12. package/dist/cli/index.mjs.map +1 -1
  13. package/dist/cli/lite.mjs +43 -13
  14. package/dist/cli/lite.mjs.map +1 -1
  15. package/dist/cli/{propose-policy.mjs → manage-policies.mjs} +270 -47
  16. package/dist/cli/manage-policies.mjs.map +1 -0
  17. package/dist/cli/run-host.d.mts +1 -0
  18. package/dist/cli/run-host.mjs +3090 -0
  19. package/dist/cli/run-host.mjs.map +1 -0
  20. package/dist/config-CPFQIGdG.mjs +57 -0
  21. package/dist/config-CPFQIGdG.mjs.map +1 -0
  22. package/dist/config-Dvl-Pov4.mjs +76 -0
  23. package/dist/config-Dvl-Pov4.mjs.map +1 -0
  24. package/dist/daemon/index.d.mts.map +1 -1
  25. package/dist/daemon/index.mjs +970 -332
  26. package/dist/daemon/index.mjs.map +1 -1
  27. package/dist/supervisor-actions-CiW56eLi.mjs +843 -0
  28. package/dist/supervisor-actions-CiW56eLi.mjs.map +1 -0
  29. package/dist/turn-log-buffer-DRgW53gl.mjs +767 -0
  30. package/dist/turn-log-buffer-DRgW53gl.mjs.map +1 -0
  31. package/dist/web/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
  32. package/dist/web/_app/immutable/chunks/BhRSsUCh.js +2 -0
  33. package/dist/web/_app/immutable/chunks/BiLeM2i1.js +1 -0
  34. package/{web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js → dist/web/_app/immutable/chunks/BmBj85Ll.js} +1 -1
  35. package/dist/web/_app/immutable/chunks/BrERcKAH.js +1 -0
  36. package/dist/web/_app/immutable/chunks/Bv9252RM.js +1 -0
  37. package/dist/web/_app/immutable/chunks/CIXNBPKi.js +1 -0
  38. package/dist/web/_app/immutable/chunks/DISKL3GN.js +2 -0
  39. package/dist/web/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
  40. package/dist/web/_app/immutable/chunks/DnQ3vS13.js +1 -0
  41. package/dist/web/_app/immutable/chunks/KsloHTKS.js +1 -0
  42. package/{web/.svelte-kit/output/client/_app/immutable/chunks/Ck-be5J2.js → dist/web/_app/immutable/chunks/RsHsUj-8.js} +2 -2
  43. package/dist/web/_app/immutable/chunks/{vDehDcuJ.js → wpfV79dV.js} +1 -1
  44. package/dist/web/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
  45. package/dist/web/_app/immutable/entry/start.Di0-Jhte.js +1 -0
  46. package/dist/web/_app/immutable/nodes/{0.CUGC2p-K.js → 0.DYyUA1au.js} +1 -1
  47. package/dist/web/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
  48. package/dist/web/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
  49. package/{web/.svelte-kit/output/client/_app/immutable/nodes/3.0arZe_Uf.js → dist/web/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
  50. package/dist/web/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
  51. package/dist/web/_app/immutable/nodes/{5.Bq2JzCEj.js → 5.DLbPVJY2.js} +1 -1
  52. package/dist/web/_app/version.json +1 -1
  53. package/dist/web/index.html +12 -12
  54. package/dist/workspace-oWmVh5mi.mjs +1001 -0
  55. package/dist/workspace-oWmVh5mi.mjs.map +1 -0
  56. package/docs/23_adapter_slash_autocomplete/development_log.md +19 -0
  57. package/docs/23_adapter_slash_autocomplete/notes.md +18 -0
  58. package/docs/23_adapter_slash_autocomplete/prd.md +46 -0
  59. package/docs/23_adapter_slash_autocomplete/questions.md +6 -0
  60. package/docs/23_adapter_slash_autocomplete/tickets.md +21 -0
  61. package/docs/24_subagent_job_policy_fixes/development_log.md +22 -0
  62. package/docs/24_subagent_job_policy_fixes/notes.md +28 -0
  63. package/docs/24_subagent_job_policy_fixes/prd.md +59 -0
  64. package/docs/24_subagent_job_policy_fixes/questions.md +3 -0
  65. package/docs/24_subagent_job_policy_fixes/tickets.md +49 -0
  66. package/docs/25_e2e_test_improvements/development_log.md +30 -0
  67. package/docs/25_e2e_test_improvements/notes.md +29 -0
  68. package/docs/25_e2e_test_improvements/prd.md +43 -0
  69. package/docs/25_e2e_test_improvements/questions.md +12 -0
  70. package/docs/25_e2e_test_improvements/tickets-2.md +22 -0
  71. package/docs/25_e2e_test_improvements/tickets.md +22 -0
  72. package/docs/25_policy_cwd/development_log.md +30 -0
  73. package/docs/25_policy_cwd/notes.md +28 -0
  74. package/docs/25_policy_cwd/prd.md +77 -0
  75. package/docs/25_policy_cwd/questions.md +6 -0
  76. package/docs/25_policy_cwd/tickets.md +77 -0
  77. package/docs/CLI_REFERENCE.md +3 -1
  78. package/docs/PHILOSOPHY.md +35 -0
  79. package/docs/adapter-visibility/SPEC.md +461 -0
  80. package/docs/adapter-visibility/SPEC_v2.md +202 -0
  81. package/docs/auto-update/SPEC.md +344 -0
  82. package/docs/backups/SPEC.md +296 -0
  83. package/docs/backups/clawmini.gitignore +69 -0
  84. package/docs/guides/assets/clawmini-avatar.png +0 -0
  85. package/docs/guides/backups.md +332 -0
  86. package/docs/guides/discord_adapter_setup.md +1 -1
  87. package/docs/guides/google_chat_adapter_setup.md +81 -0
  88. package/docs/unified-startup/SPEC.md +203 -0
  89. package/e2e/_helpers/test-environment.test.ts +49 -0
  90. package/e2e/_helpers/test-environment.ts +548 -0
  91. package/e2e/adapters/_google-chat-fixtures.ts +340 -0
  92. package/{src/cli/e2e → e2e/adapters}/adapter-discord.test.ts +22 -23
  93. package/e2e/adapters/adapter-google-chat-downtime.test.ts +157 -0
  94. package/e2e/adapters/adapter-google-chat-inbound.test.ts +697 -0
  95. package/e2e/adapters/adapter-google-chat-outbound.test.ts +297 -0
  96. package/e2e/adapters/adapter-google-chat-roundtrip.test.ts +56 -0
  97. package/e2e/adapters/adapter-google-chat-threads.test.ts +1078 -0
  98. package/e2e/agents/custom-api-env.test.ts +80 -0
  99. package/e2e/agents/export-lite-func.test.ts +104 -0
  100. package/e2e/agents/fallbacks.test.ts +124 -0
  101. package/e2e/agents/interrupt.test.ts +50 -0
  102. package/e2e/agents/no-reply-necessary.test.ts +57 -0
  103. package/e2e/agents/session-timeout-subagents.test.ts +76 -0
  104. package/e2e/agents/subagent-authorization.test.ts +246 -0
  105. package/e2e/agents/subagent-env.test.ts +49 -0
  106. package/e2e/agents/subagent-lifecycle.test.ts +782 -0
  107. package/e2e/agents/subagents-depth.test.ts +47 -0
  108. package/e2e/cli/agents.test.ts +176 -0
  109. package/e2e/cli/auto-update.test.ts +741 -0
  110. package/e2e/cli/basic.test.ts +44 -0
  111. package/{src/cli/e2e → e2e/cli}/export-lite.test.ts +16 -12
  112. package/e2e/cli/init-gitignore.test.ts +86 -0
  113. package/e2e/cli/init.test.ts +76 -0
  114. package/e2e/cli/messages.test.ts +363 -0
  115. package/e2e/cli/serve.test.ts +76 -0
  116. package/{src/cli/e2e → e2e/cli}/skills.test.ts +11 -10
  117. package/{src/cli/e2e → e2e/daemon}/daemon.test.ts +57 -195
  118. package/e2e/jobs/agent-jobs.test.ts +216 -0
  119. package/e2e/jobs/cron.test.ts +64 -0
  120. package/e2e/jobs/restart.test.ts +108 -0
  121. package/e2e/policies/approval-session.test.ts +69 -0
  122. package/e2e/policies/auto-create-policies-file.test.ts +35 -0
  123. package/e2e/policies/builtin-manage-policies.test.ts +184 -0
  124. package/e2e/policies/builtin-run-host.test.ts +180 -0
  125. package/e2e/policies/environment-policies.test.ts +177 -0
  126. package/e2e/policies/manage-policies.test.ts +566 -0
  127. package/e2e/policies/output-size.test.ts +98 -0
  128. package/e2e/policies/policies-context-cwd.test.ts +160 -0
  129. package/e2e/policies/relative-script-path.test.ts +60 -0
  130. package/e2e/policies/requests-show.test.ts +135 -0
  131. package/e2e/policies/requests.test.ts +208 -0
  132. package/e2e/policies/slash-policies.test.ts +308 -0
  133. package/e2e/policies/startup-cleanup.test.ts +48 -0
  134. package/e2e/routers/session-timeout.test.ts +106 -0
  135. package/e2e/routers/slash-model.test.ts +152 -0
  136. package/e2e/routers/slash-new.test.ts +50 -0
  137. package/e2e/routers/slash-restart-adapter.test.ts +96 -0
  138. package/e2e/routers/slash-restart.test.ts +114 -0
  139. package/e2e/routers/slash-shutdown.test.ts +55 -0
  140. package/e2e/routers/slash-stop.test.ts +232 -0
  141. package/e2e/routers/slash-upgrade.test.ts +88 -0
  142. package/{src/cli/e2e → e2e/sandbox}/environments.test.ts +14 -13
  143. package/eslint.config.js +6 -0
  144. package/napkin.md +1 -1
  145. package/package.json +8 -3
  146. package/src/adapter-discord/commands.test.ts +42 -0
  147. package/src/adapter-discord/commands.ts +33 -0
  148. package/src/adapter-discord/config.ts +12 -0
  149. package/src/adapter-discord/forwarder.test.ts +499 -21
  150. package/src/adapter-discord/forwarder.ts +343 -124
  151. package/src/adapter-discord/inbound-cache.test.ts +47 -0
  152. package/src/adapter-discord/inbound-cache.ts +37 -0
  153. package/src/adapter-discord/index.test.ts +67 -2
  154. package/src/adapter-discord/index.ts +84 -216
  155. package/src/adapter-discord/interactions.test.ts +54 -3
  156. package/src/adapter-discord/interactions.ts +97 -53
  157. package/src/adapter-discord/processMessage.ts +239 -0
  158. package/src/adapter-discord/state.ts +1 -0
  159. package/src/adapter-google-chat/auth.test.ts +9 -5
  160. package/src/adapter-google-chat/auth.ts +29 -23
  161. package/src/adapter-google-chat/cards.ts +7 -2
  162. package/src/adapter-google-chat/client.test.ts +37 -2
  163. package/src/adapter-google-chat/client.ts +138 -38
  164. package/src/adapter-google-chat/config.ts +19 -0
  165. package/src/adapter-google-chat/forwarder.test.ts +81 -56
  166. package/src/adapter-google-chat/forwarder.ts +394 -185
  167. package/src/adapter-google-chat/inbound-cache.test.ts +61 -0
  168. package/src/adapter-google-chat/inbound-cache.ts +36 -0
  169. package/src/adapter-google-chat/state.test.ts +1 -0
  170. package/src/adapter-google-chat/state.ts +9 -1
  171. package/src/adapter-google-chat/subscriptions.ts +8 -6
  172. package/src/cli/builtin-policies.ts +44 -0
  173. package/src/cli/commands/agents.ts +59 -5
  174. package/src/cli/commands/down.ts +54 -2
  175. package/src/cli/commands/environments.ts +8 -2
  176. package/src/cli/commands/init.ts +31 -0
  177. package/src/cli/commands/logs.ts +116 -0
  178. package/src/cli/commands/policies.ts +6 -4
  179. package/src/cli/commands/serve.test.ts +67 -0
  180. package/src/cli/commands/serve.ts +284 -0
  181. package/src/cli/commands/up.ts +122 -2
  182. package/src/cli/commands/web-api/agents.ts +3 -2
  183. package/src/cli/index.ts +4 -0
  184. package/src/cli/install-detection.test.ts +72 -0
  185. package/src/cli/install-detection.ts +48 -0
  186. package/src/cli/lite.ts +54 -22
  187. package/src/cli/manage-policies-utils.ts +104 -0
  188. package/src/cli/manage-policies.ts +291 -0
  189. package/src/cli/run-host.ts +45 -0
  190. package/src/cli/supervisor-actions.ts +267 -0
  191. package/src/cli/supervisor-control.test.ts +129 -0
  192. package/src/cli/supervisor-control.ts +155 -0
  193. package/src/cli/supervisor-pid.ts +68 -0
  194. package/src/cli/supervisor.ts +277 -0
  195. package/src/daemon/agent/agent-context.ts +11 -11
  196. package/src/daemon/agent/agent-session.ts +8 -1
  197. package/src/daemon/agent/chat-logger.test.ts +78 -9
  198. package/src/daemon/agent/chat-logger.ts +25 -5
  199. package/src/daemon/agent/turn-registry.test.ts +89 -0
  200. package/src/daemon/agent/turn-registry.ts +94 -0
  201. package/src/daemon/agent/types.ts +2 -0
  202. package/src/daemon/api/agent-policy-endpoints.ts +263 -0
  203. package/src/daemon/api/agent-router.ts +47 -126
  204. package/src/daemon/api/index.test.ts +1 -0
  205. package/src/daemon/api/policy-request.test.ts +7 -5
  206. package/src/daemon/api/router-utils.ts +6 -5
  207. package/src/daemon/api/subagent-router.ts +110 -74
  208. package/src/daemon/api/subagent-utils.test.ts +60 -0
  209. package/src/daemon/api/subagent-utils.ts +113 -87
  210. package/src/daemon/api/user-router.ts +34 -8
  211. package/src/daemon/auth.ts +1 -0
  212. package/src/daemon/cron.test.ts +62 -4
  213. package/src/daemon/cron.ts +42 -16
  214. package/src/daemon/events.ts +65 -0
  215. package/src/daemon/index.ts +24 -1
  216. package/src/daemon/message-interruption.test.ts +1 -0
  217. package/src/daemon/message-jobs.test.ts +1 -0
  218. package/src/daemon/message.ts +78 -14
  219. package/src/daemon/observation.test.ts +26 -18
  220. package/src/daemon/pending-replies.test.ts +112 -0
  221. package/src/daemon/pending-replies.ts +162 -0
  222. package/src/daemon/policy-request-service.ts +3 -1
  223. package/src/daemon/policy-utils.test.ts +66 -1
  224. package/src/daemon/policy-utils.ts +126 -1
  225. package/src/daemon/request-store.ts +31 -0
  226. package/src/daemon/routers/session-timeout.ts +4 -0
  227. package/src/daemon/routers/slash-model.test.ts +344 -0
  228. package/src/daemon/routers/slash-model.ts +207 -0
  229. package/src/daemon/routers/slash-policies.test.ts +38 -32
  230. package/src/daemon/routers/slash-policies.ts +84 -33
  231. package/src/daemon/routers/slash-restart.test.ts +69 -0
  232. package/src/daemon/routers/slash-restart.ts +36 -0
  233. package/src/daemon/routers/slash-shutdown.test.ts +50 -0
  234. package/src/daemon/routers/slash-shutdown.ts +28 -0
  235. package/src/daemon/routers/slash-upgrade.test.ts +116 -0
  236. package/src/daemon/routers/slash-upgrade.ts +76 -0
  237. package/src/daemon/routers/types.ts +7 -0
  238. package/src/daemon/routers.ts +16 -0
  239. package/src/shared/adapters/blockquote.test.ts +28 -0
  240. package/src/shared/adapters/blockquote.ts +20 -0
  241. package/src/shared/adapters/filtering.test.ts +224 -10
  242. package/src/shared/adapters/filtering.ts +95 -7
  243. package/src/shared/adapters/inbound-cache.test.ts +48 -0
  244. package/src/shared/adapters/inbound-cache.ts +54 -0
  245. package/src/shared/adapters/turn-log-buffer.ts +266 -0
  246. package/src/shared/adapters/turn-log.test.ts +389 -0
  247. package/src/shared/adapters/turn-log.ts +357 -0
  248. package/src/shared/agent-utils.ts +12 -5
  249. package/src/shared/chats.test.ts +4 -0
  250. package/src/shared/chats.ts +9 -0
  251. package/src/shared/config.ts +16 -1
  252. package/src/shared/lite.ts +76 -2
  253. package/src/shared/policies.ts +26 -0
  254. package/src/shared/template-manifest.ts +267 -0
  255. package/src/shared/utils/shell.ts +61 -0
  256. package/src/shared/version.ts +34 -0
  257. package/src/shared/workspace.test.ts +217 -0
  258. package/src/shared/workspace.ts +626 -48
  259. package/templates/environments/cladding/allowlist-domain.mjs +125 -0
  260. package/templates/environments/cladding/env.json +21 -1
  261. package/templates/environments/cladding/run-with-network.mjs +54 -0
  262. package/templates/environments/macos-proxy/allowlist-domain.mjs +95 -0
  263. package/templates/environments/macos-proxy/env.json +8 -1
  264. package/templates/environments/macos-proxy/proxy.mjs +0 -1
  265. package/templates/gemini/template.json +5 -0
  266. package/templates/gemini-claw/template.json +13 -0
  267. package/templates/skills/clawmini-requests/SKILL.md +69 -10
  268. package/templates/skills/run-host/SKILL.md +51 -0
  269. package/templates/skills/skill-creator/SKILL.md +4 -3
  270. package/templates/skills/skill-creator/scripts/validate.sh +52 -0
  271. package/tsdown.config.ts +10 -1
  272. package/vitest.config.ts +2 -2
  273. package/web/.svelte-kit/ambient.d.ts +292 -118
  274. package/web/.svelte-kit/generated/server/internal.js +1 -1
  275. package/web/.svelte-kit/output/client/.vite/manifest.json +126 -136
  276. package/web/.svelte-kit/output/client/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
  277. package/web/.svelte-kit/output/client/_app/immutable/chunks/BhRSsUCh.js +2 -0
  278. package/web/.svelte-kit/output/client/_app/immutable/chunks/BiLeM2i1.js +1 -0
  279. package/{dist/web/_app/immutable/chunks/CME08kGM.js → web/.svelte-kit/output/client/_app/immutable/chunks/BmBj85Ll.js} +1 -1
  280. package/web/.svelte-kit/output/client/_app/immutable/chunks/BrERcKAH.js +1 -0
  281. package/web/.svelte-kit/output/client/_app/immutable/chunks/Bv9252RM.js +1 -0
  282. package/web/.svelte-kit/output/client/_app/immutable/chunks/CIXNBPKi.js +1 -0
  283. package/web/.svelte-kit/output/client/_app/immutable/chunks/DISKL3GN.js +2 -0
  284. package/web/.svelte-kit/output/client/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
  285. package/web/.svelte-kit/output/client/_app/immutable/chunks/DnQ3vS13.js +1 -0
  286. package/web/.svelte-kit/output/client/_app/immutable/chunks/KsloHTKS.js +1 -0
  287. package/{dist/web/_app/immutable/chunks/Ck-be5J2.js → web/.svelte-kit/output/client/_app/immutable/chunks/RsHsUj-8.js} +2 -2
  288. package/web/.svelte-kit/output/client/_app/immutable/chunks/{vDehDcuJ.js → wpfV79dV.js} +1 -1
  289. package/web/.svelte-kit/output/client/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
  290. package/web/.svelte-kit/output/client/_app/immutable/entry/start.Di0-Jhte.js +1 -0
  291. package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.CUGC2p-K.js → 0.DYyUA1au.js} +1 -1
  292. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
  293. package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
  294. package/{dist/web/_app/immutable/nodes/3.0arZe_Uf.js → web/.svelte-kit/output/client/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
  295. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
  296. package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.Bq2JzCEj.js → 5.DLbPVJY2.js} +1 -1
  297. package/web/.svelte-kit/output/client/_app/version.json +1 -1
  298. package/web/.svelte-kit/output/server/.vite/manifest.json +12 -10
  299. package/web/.svelte-kit/output/server/chunks/Icon.js +1 -1
  300. package/web/.svelte-kit/output/server/chunks/client.js +1 -1
  301. package/web/.svelte-kit/output/server/chunks/exports.js +1 -1
  302. package/web/.svelte-kit/output/server/chunks/index-server.js +2 -1
  303. package/web/.svelte-kit/output/server/chunks/internal.js +1 -1
  304. package/web/.svelte-kit/output/server/chunks/render-context.js +77 -0
  305. package/web/.svelte-kit/output/server/chunks/root.js +739 -788
  306. package/web/.svelte-kit/output/server/chunks/shared.js +234 -21
  307. package/web/.svelte-kit/output/server/index.js +126 -90
  308. package/web/.svelte-kit/output/server/manifest-full.js +1 -1
  309. package/web/.svelte-kit/output/server/manifest.js +1 -1
  310. package/web/.svelte-kit/output/server/nodes/0.js +1 -1
  311. package/web/.svelte-kit/output/server/nodes/1.js +1 -1
  312. package/web/.svelte-kit/output/server/nodes/2.js +1 -1
  313. package/web/.svelte-kit/output/server/nodes/3.js +1 -1
  314. package/web/.svelte-kit/output/server/nodes/4.js +1 -1
  315. package/web/.svelte-kit/output/server/nodes/5.js +1 -1
  316. package/web/.svelte-kit/output/server/remote-entry.js +245 -81
  317. package/web/.svelte-kit/tsconfig.json +4 -1
  318. package/dist/cli/propose-policy.mjs.map +0 -1
  319. package/dist/lite-CBxOT1y5.mjs +0 -241
  320. package/dist/lite-CBxOT1y5.mjs.map +0 -1
  321. package/dist/routing-D8rTxtaV.mjs +0 -245
  322. package/dist/routing-D8rTxtaV.mjs.map +0 -1
  323. package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +0 -1
  324. package/dist/web/_app/immutable/chunks/BmRlVmv6.js +0 -1
  325. package/dist/web/_app/immutable/chunks/CK9JZLaG.js +0 -2
  326. package/dist/web/_app/immutable/chunks/Ck3rYNON.js +0 -1
  327. package/dist/web/_app/immutable/chunks/D5iV40bG.js +0 -1
  328. package/dist/web/_app/immutable/chunks/DMtIqaiV.js +0 -2
  329. package/dist/web/_app/immutable/chunks/DhD271EB.js +0 -1
  330. package/dist/web/_app/immutable/chunks/DpuLqk8d.js +0 -1
  331. package/dist/web/_app/immutable/chunks/DsIToJCP.js +0 -1
  332. package/dist/web/_app/immutable/entry/app.BCSV3nrG.js +0 -2
  333. package/dist/web/_app/immutable/entry/start.D4eLEZUM.js +0 -1
  334. package/dist/web/_app/immutable/nodes/1.CGC_42IQ.js +0 -1
  335. package/dist/web/_app/immutable/nodes/4.ClM1bXLE.js +0 -60
  336. package/dist/workspace-BJmJBfKi.mjs +0 -456
  337. package/dist/workspace-BJmJBfKi.mjs.map +0 -1
  338. package/src/cli/e2e/agents.test.ts +0 -140
  339. package/src/cli/e2e/basic.test.ts +0 -43
  340. package/src/cli/e2e/cron.test.ts +0 -132
  341. package/src/cli/e2e/export-lite-func.test.ts +0 -206
  342. package/src/cli/e2e/fallbacks.test.ts +0 -175
  343. package/src/cli/e2e/init.test.ts +0 -77
  344. package/src/cli/e2e/messages.test.ts +0 -332
  345. package/src/cli/e2e/propose-policy.test.ts +0 -203
  346. package/src/cli/e2e/requests.test.ts +0 -180
  347. package/src/cli/e2e/session-timeout.test.ts +0 -192
  348. package/src/cli/e2e/slash-new.test.ts +0 -93
  349. package/src/cli/e2e/subagents.test.ts +0 -106
  350. package/src/cli/e2e/utils.ts +0 -66
  351. package/src/cli/propose-policy.ts +0 -91
  352. package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +0 -1
  353. package/web/.svelte-kit/output/client/_app/immutable/chunks/BmRlVmv6.js +0 -1
  354. package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +0 -2
  355. package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +0 -1
  356. package/web/.svelte-kit/output/client/_app/immutable/chunks/D5iV40bG.js +0 -1
  357. package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +0 -2
  358. package/web/.svelte-kit/output/client/_app/immutable/chunks/DhD271EB.js +0 -1
  359. package/web/.svelte-kit/output/client/_app/immutable/chunks/DpuLqk8d.js +0 -1
  360. package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +0 -1
  361. package/web/.svelte-kit/output/client/_app/immutable/entry/app.BCSV3nrG.js +0 -2
  362. package/web/.svelte-kit/output/client/_app/immutable/entry/start.D4eLEZUM.js +0 -1
  363. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.CGC_42IQ.js +0 -1
  364. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.ClM1bXLE.js +0 -60
  365. package/web/.svelte-kit/output/server/chunks/false.js +0 -4
  366. /package/dist/cli/{propose-policy.d.mts → manage-policies.d.mts} +0 -0
  367. /package/{src/cli/e2e → e2e/_helpers}/global-setup.ts +0 -0
package/src/cli/lite.ts CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import { createTRPCClient, httpLink } from '@trpc/client';
5
- import type { AgentRouter as AppRouter } from '../daemon/api/index.js';
6
- import type { CronJob } from '../shared/config.js';
5
+ import type { AgentRouter as AppRouter, AgentCronJobInput } from '../daemon/api/index.js';
7
6
  import { registerSubagentCommands } from './subagent-commands.js';
8
7
 
9
8
  /**
@@ -135,15 +134,7 @@ jobs
135
134
  .option('--cron <cron>', 'Schedule via cron expression')
136
135
  .option('-m, --message <msg>', 'Message to send')
137
136
  .option('-r, --reply <reply>', 'Reply text')
138
- .option('-a, --agent <agentId>', 'Agent ID')
139
137
  .option('-s, --session <type>', 'Session type (must be "new")')
140
- .option(
141
- '-e, --env <env>',
142
- 'Environment variables in key=value format',
143
- (val: string, prev: string[]) => prev.concat([val]),
144
- []
145
- )
146
- .option('-c, --chat <chatId>', 'Chat ID')
147
138
  .action(async (name, options) => {
148
139
  try {
149
140
  let schedule;
@@ -152,29 +143,18 @@ jobs
152
143
  else if (options.cron) schedule = { cron: options.cron };
153
144
  else throw new Error('A schedule must be specified (--at, --every, or --cron).');
154
145
 
155
- const job: CronJob = {
146
+ const job: AgentCronJobInput = {
156
147
  id: name,
157
- createdAt: new Date().toISOString(),
158
148
  message: options.message || '',
159
149
  schedule,
160
150
  };
161
151
 
162
152
  if (options.reply) job.reply = options.reply;
163
- if (options.agent) job.agentId = options.agent;
164
153
  if (options.session) {
165
154
  if (options.session !== 'new') throw new Error('Only "new" session type is supported.');
166
155
  job.session = { type: 'new' };
167
156
  }
168
157
 
169
- if (options.env && options.env.length > 0) {
170
- const jobEnv: Record<string, string> = {};
171
- for (const e of options.env) {
172
- const [k, ...v] = e.split('=');
173
- if (k) jobEnv[k] = v.join('=');
174
- }
175
- job.env = jobEnv;
176
- }
177
-
178
158
  const client = getClient();
179
159
  await client.addCronJob.mutate({ job });
180
160
  console.log(`Job '${name}' created successfully.`);
@@ -230,6 +210,51 @@ requests
230
210
  }
231
211
  });
232
212
 
213
+ requests
214
+ .command('show <name>')
215
+ .description(
216
+ 'Show full details of a single policy. Includes the script body when the command points inside .clawmini/policy-scripts/.'
217
+ )
218
+ .action(async (name: string) => {
219
+ try {
220
+ const client = getClient();
221
+ const config = await client.listPolicies.query();
222
+ const policy = config?.policies?.[name];
223
+
224
+ if (!policy) {
225
+ console.error(`Policy not found: ${name}`);
226
+ process.exit(1);
227
+ }
228
+
229
+ console.log(JSON.stringify({ name, ...policy }, null, 2));
230
+
231
+ try {
232
+ const script = await client.readPolicyScript.query({ commandName: name });
233
+ console.log(`\n--- Script: ${script.path} (${script.size} bytes) ---`);
234
+ if ('spilledTo' in script && script.spilledTo) {
235
+ console.log(`(script body too large to inline; copied to ${script.spilledTo})`);
236
+ } else if ('content' in script && typeof script.content === 'string') {
237
+ process.stdout.write(script.content);
238
+ if (!script.content.endsWith('\n')) process.stdout.write('\n');
239
+ }
240
+ } catch (err) {
241
+ // Distinguish "no script body to show" (policy wraps a system command,
242
+ // script file missing, too large, etc.) from a real failure (auth,
243
+ // network, daemon down). Re-raise the latter so the outer catch surfaces it.
244
+ const code = (err as { data?: { code?: string } })?.data?.code;
245
+ if (code === 'BAD_REQUEST' || code === 'NOT_FOUND') {
246
+ const msg = err instanceof Error ? err.message : String(err);
247
+ console.log(`\n(no script body: ${msg})`);
248
+ } else {
249
+ throw err;
250
+ }
251
+ }
252
+ } catch (err) {
253
+ console.error('Error:', err instanceof Error ? err.message : err);
254
+ process.exit(1);
255
+ }
256
+ });
257
+
233
258
  program
234
259
  .command('request <cmd>')
235
260
  .description('Submit a sandbox policy request')
@@ -280,6 +305,7 @@ program
280
305
  commandName: cmdName,
281
306
  args: opaqueArgs,
282
307
  fileMappings,
308
+ cwd: process.cwd(),
283
309
  });
284
310
 
285
311
  if (request.executionResult) {
@@ -293,6 +319,12 @@ program
293
319
  } else {
294
320
  console.log(`Request created successfully.`);
295
321
  console.log(`Request ID: ${request.id}`);
322
+ console.log('');
323
+ console.log('This request has not run yet — it is queued for user approval. When the');
324
+ console.log('user approves (or rejects) it, the result will arrive as a new user');
325
+ console.log('message in this chat; do not poll. Finish any unrelated work that does');
326
+ console.log('not depend on this request, then end your turn with a brief message');
327
+ console.log('explaining you are blocked on this request.');
296
328
  }
297
329
  } catch (err) {
298
330
  console.error('Error:', err instanceof Error ? err.message : err);
@@ -0,0 +1,104 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import type { PolicyConfigFile, PolicyDefinition } from '../shared/policies.js';
5
+ import { parseShellArgs } from '../shared/utils/shell.js';
6
+ import { getClawminiDir } from '../shared/workspace.js';
7
+
8
+ const NAME_RE = /^[a-z0-9-]+$/;
9
+
10
+ export function fail(message: string): never {
11
+ console.error(`Error: ${message}`);
12
+ process.exit(1);
13
+ }
14
+
15
+ export function assertValidName(name: string): void {
16
+ if (!NAME_RE.test(name)) {
17
+ fail('Policy name must only contain lowercase letters, numbers, and hyphens.');
18
+ }
19
+ }
20
+
21
+ export function loadPolicies(): {
22
+ dirPath: string;
23
+ policies: PolicyConfigFile;
24
+ policiesPath: string;
25
+ } {
26
+ const dirPath = getClawminiDir();
27
+ const policiesPath = path.join(dirPath, 'policies.json');
28
+ if (!fs.existsSync(dirPath)) {
29
+ fail('.clawmini directory not found. Please run "clawmini init" first.');
30
+ }
31
+ let policies: PolicyConfigFile = { policies: {} };
32
+ if (fs.existsSync(policiesPath)) {
33
+ policies = JSON.parse(fs.readFileSync(policiesPath, 'utf8'));
34
+ }
35
+ return { dirPath, policies, policiesPath };
36
+ }
37
+
38
+ export function writePolicies(policiesPath: string, policies: PolicyConfigFile): void {
39
+ // policies.json gates every policy invocation; a partial write would brick
40
+ // policy resolution. Stage to a sibling tempfile and rename — rename(2) on
41
+ // the same filesystem is atomic, so readers see either the old or new file.
42
+ const tmpPath = `${policiesPath}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
43
+ try {
44
+ fs.writeFileSync(tmpPath, JSON.stringify(policies, null, 2));
45
+ fs.renameSync(tmpPath, policiesPath);
46
+ } catch (err) {
47
+ try {
48
+ fs.unlinkSync(tmpPath);
49
+ } catch {
50
+ // tmpfile may not exist if writeFileSync threw before creating it.
51
+ }
52
+ throw err;
53
+ }
54
+ }
55
+
56
+ export function installScript(dirPath: string, name: string, scriptFile: string): string {
57
+ const scriptsDir = path.join(dirPath, 'policy-scripts');
58
+ if (!fs.existsSync(scriptsDir)) {
59
+ fs.mkdirSync(scriptsDir, { recursive: true });
60
+ }
61
+ const ext = path.extname(scriptFile) || '.sh';
62
+ const destScript = path.join(scriptsDir, `${name}${ext}`);
63
+ fs.copyFileSync(scriptFile, destScript);
64
+ fs.chmodSync(destScript, 0o755);
65
+ return `./.clawmini/policy-scripts/${path.basename(destScript)}`;
66
+ }
67
+
68
+ // Resolves a stored policy.command (relative to the workspace root) and
69
+ // returns its absolute path if it lives inside the managed `policy-scripts/`
70
+ // directory, else null. We compare absolute paths so basename collisions
71
+ // outside the dir cannot trigger an unintended unlink.
72
+ export function scriptInsidePolicyScripts(dirPath: string, command: string): string | null {
73
+ const workspaceRoot = path.dirname(dirPath);
74
+ const abs = path.resolve(workspaceRoot, command);
75
+ const scriptsDir = path.join(dirPath, 'policy-scripts');
76
+ const sep = path.sep;
77
+ const dirWithSep = scriptsDir.endsWith(sep) ? scriptsDir : scriptsDir + sep;
78
+ return abs.startsWith(dirWithSep) ? abs : null;
79
+ }
80
+
81
+ export function unlinkIfExists(filePath: string): void {
82
+ try {
83
+ fs.unlinkSync(filePath);
84
+ } catch (err) {
85
+ if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;
86
+ }
87
+ }
88
+
89
+ export function applyCommandString(definition: PolicyDefinition, commandStr: string): void {
90
+ let parts: string[];
91
+ try {
92
+ parts = parseShellArgs(commandStr);
93
+ } catch (err) {
94
+ fail(`--command: ${err instanceof Error ? err.message : String(err)}`);
95
+ }
96
+ const [head, ...rest] = parts;
97
+ if (head === undefined) {
98
+ fail('--command must contain a command to run.');
99
+ }
100
+ definition.command = head;
101
+ if (rest.length > 0) {
102
+ definition.args = rest;
103
+ }
104
+ }
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { BUILTIN_POLICIES, type PolicyDefinition } from '../shared/policies.js';
5
+ import {
6
+ applyCommandString,
7
+ assertValidName,
8
+ fail,
9
+ installScript,
10
+ loadPolicies,
11
+ scriptInsidePolicyScripts,
12
+ unlinkIfExists,
13
+ writePolicies,
14
+ } from './manage-policies-utils.js';
15
+
16
+ const root = new Command('manage-policies');
17
+ root.description(
18
+ 'Manage clawmini policies. Subcommands: add, update, remove. Reads are unrestricted — use `clawmini-lite requests show <name>` instead.'
19
+ );
20
+
21
+ root
22
+ .command('add')
23
+ .description('Register a new policy. Errors if the name already exists.')
24
+ .requiredOption('--name <policy_name>', 'Name of the policy')
25
+ .requiredOption('--description <description>', 'Description of the policy')
26
+ .option('--command <command_string>', 'The shell command to run (e.g. "npm install -g")')
27
+ .option('--script-file <path>', 'Path to a script file (mapped securely via --file)')
28
+ .option(
29
+ '--dangerously-auto-approve',
30
+ 'Skip user approval for every invocation of this policy. Only safe for fully sandboxed, side-effect-free commands.',
31
+ false
32
+ )
33
+ .option(
34
+ '--dangerously-allow-help',
35
+ 'Allow the agent to run the policy with `--help` without approval. Only safe if the underlying command treats `--help` as read-only.',
36
+ false
37
+ )
38
+ .addHelpText(
39
+ 'after',
40
+ `
41
+ Examples:
42
+ 1. Add a policy that wraps a shell command:
43
+ clawmini-lite request manage-policies -- add --name npm-install --description "Run npm install" --command "npm install"
44
+
45
+ 2. Add a policy backed by a script file:
46
+ clawmini-lite request manage-policies --file script=./install.sh -- add --name custom-install --description "Run custom install script" --script-file "{{script}}"
47
+
48
+ 3. Add a read-only policy that auto-approves and exposes --help:
49
+ clawmini-lite request manage-policies -- add --name list-files --description "List files" --command "ls" --dangerously-auto-approve --dangerously-allow-help
50
+ `
51
+ )
52
+ .action((options) => {
53
+ const name: string = options.name;
54
+ const description: string = options.description;
55
+ const commandStr: string | undefined = options.command;
56
+ const scriptFile: string | undefined = options.scriptFile;
57
+ const autoApprove = !!options.dangerouslyAutoApprove;
58
+ const allowHelp = !!options.dangerouslyAllowHelp;
59
+
60
+ assertValidName(name);
61
+
62
+ if (!commandStr && !scriptFile) {
63
+ fail('Must provide either --command or --script-file.');
64
+ }
65
+ if (commandStr && scriptFile) {
66
+ fail('--command and --script-file are mutually exclusive.');
67
+ }
68
+
69
+ const { dirPath, policies, policiesPath } = loadPolicies();
70
+
71
+ if (Object.prototype.hasOwnProperty.call(policies.policies, name)) {
72
+ fail(
73
+ `Policy '${name}' is already registered. Use 'manage-policies update' to modify it, or 'manage-policies remove' first.`
74
+ );
75
+ }
76
+
77
+ const definition: PolicyDefinition = {
78
+ description,
79
+ allowHelp,
80
+ autoApprove,
81
+ command: '',
82
+ };
83
+
84
+ if (scriptFile) {
85
+ definition.command = installScript(dirPath, name, scriptFile);
86
+ } else if (commandStr) {
87
+ applyCommandString(definition, commandStr);
88
+ }
89
+
90
+ policies.policies[name] = definition;
91
+ writePolicies(policiesPath, policies);
92
+ console.log(`Successfully added policy '${name}'.`);
93
+ });
94
+
95
+ root
96
+ .command('update')
97
+ .description('Modify fields on an existing user-registered policy.')
98
+ .requiredOption('--name <policy_name>', 'Name of the policy to update')
99
+ .option('--description <description>', 'New description')
100
+ .option('--command <command_string>', 'Replace the shell command (e.g. "npm install -g")')
101
+ .option('--script-file <path>', 'Replace the policy with a script file (mapped via --file)')
102
+ .option(
103
+ '--dangerously-auto-approve',
104
+ 'Enable autoApprove. Only safe for fully sandboxed, side-effect-free commands.'
105
+ )
106
+ .option('--no-dangerously-auto-approve', 'Disable autoApprove.')
107
+ .option(
108
+ '--dangerously-allow-help',
109
+ 'Enable allowHelp. Only safe if the underlying command treats `--help` as read-only.'
110
+ )
111
+ .option('--no-dangerously-allow-help', 'Disable allowHelp.')
112
+ .addHelpText(
113
+ 'after',
114
+ `
115
+ Examples:
116
+ 1. Update the description of an existing policy:
117
+ clawmini-lite request manage-policies -- update --name npm-install --description "Run npm install (with cache)"
118
+
119
+ 2. Replace the command:
120
+ clawmini-lite request manage-policies -- update --name npm-install --command "npm ci"
121
+
122
+ 3. Enable the dangerous flags:
123
+ clawmini-lite request manage-policies -- update --name list-files --dangerously-auto-approve --dangerously-allow-help
124
+
125
+ 4. Turn a dangerous flag off again:
126
+ clawmini-lite request manage-policies -- update --name list-files --no-dangerously-auto-approve
127
+ `
128
+ )
129
+ .action((options) => {
130
+ const name: string = options.name;
131
+ const description: string | undefined = options.description;
132
+ const commandStr: string | undefined = options.command;
133
+ const scriptFile: string | undefined = options.scriptFile;
134
+ const autoApprove: boolean | undefined = options.dangerouslyAutoApprove;
135
+ const allowHelp: boolean | undefined = options.dangerouslyAllowHelp;
136
+
137
+ assertValidName(name);
138
+
139
+ if (commandStr && scriptFile) {
140
+ fail('--command and --script-file are mutually exclusive.');
141
+ }
142
+
143
+ const noChange =
144
+ description === undefined &&
145
+ commandStr === undefined &&
146
+ scriptFile === undefined &&
147
+ autoApprove === undefined &&
148
+ allowHelp === undefined;
149
+ if (noChange) {
150
+ fail(
151
+ 'No fields specified to update. Pass at least one of --description, --command, --script-file, --dangerously-auto-approve, --dangerously-allow-help.'
152
+ );
153
+ }
154
+
155
+ const { dirPath, policies, policiesPath } = loadPolicies();
156
+ const existing = policies.policies[name];
157
+
158
+ if (existing === false) {
159
+ // The user previously disabled this entry with `remove --disable-builtin`.
160
+ // We don't auto-clear that here — the agent must reaffirm intent via remove
161
+ // (which clears the false) and then add. Otherwise an update could silently
162
+ // re-enable a policy the user explicitly opted out of.
163
+ fail(
164
+ `Policy '${name}' is currently disabled. Run 'manage-policies remove --name ${name}' to clear the disable, then 'manage-policies add' to register it.`
165
+ );
166
+ }
167
+ if (existing === undefined) {
168
+ // Built-ins are only modifiable by writing an explicit user override
169
+ // (which is what `add` does). We refuse here so updates can't silently
170
+ // shadow a built-in the user never opted into.
171
+ fail(
172
+ `No user-registered policy '${name}' to update. Use 'manage-policies add' to register one.`
173
+ );
174
+ }
175
+
176
+ // Capture before mutating: if the policy currently points at a managed
177
+ // script file, we may need to unlink it after replacing the command.
178
+ const priorScriptAbs = scriptInsidePolicyScripts(dirPath, existing.command);
179
+
180
+ const updated: PolicyDefinition = { ...existing };
181
+ if (description !== undefined) updated.description = description;
182
+ if (scriptFile !== undefined) {
183
+ updated.command = installScript(dirPath, name, scriptFile);
184
+ delete updated.args;
185
+ } else if (commandStr !== undefined) {
186
+ delete updated.args;
187
+ applyCommandString(updated, commandStr);
188
+ }
189
+ if (autoApprove !== undefined) updated.autoApprove = autoApprove;
190
+ if (allowHelp !== undefined) updated.allowHelp = allowHelp;
191
+
192
+ policies.policies[name] = updated;
193
+ writePolicies(policiesPath, policies);
194
+
195
+ // Now that policies.json points at the new command, drop the orphaned
196
+ // prior script (e.g. `<name>.sh` left behind when updating to `<name>.py`,
197
+ // or any script file when switching to --command). Done after the json
198
+ // write so a failure here cannot strand policies.json pointing at a
199
+ // file we just deleted.
200
+ const newScriptAbs = scriptInsidePolicyScripts(dirPath, updated.command);
201
+ if (priorScriptAbs && priorScriptAbs !== newScriptAbs) {
202
+ unlinkIfExists(priorScriptAbs);
203
+ }
204
+
205
+ console.log(`Successfully updated policy '${name}'.`);
206
+ });
207
+
208
+ root
209
+ .command('remove')
210
+ .description('Remove (or disable) a registered policy.')
211
+ .requiredOption('--name <policy_name>', 'Name of the policy to remove')
212
+ .option(
213
+ '--disable-builtin',
214
+ 'When the name matches a built-in policy, write `false` to opt out instead of just deleting the user override.',
215
+ false
216
+ )
217
+ .addHelpText(
218
+ 'after',
219
+ `
220
+ Examples:
221
+ 1. Remove a user-registered policy:
222
+ clawmini-lite request manage-policies -- remove --name npm-install
223
+
224
+ 2. Disable a built-in policy (writes \`false\` to opt out):
225
+ clawmini-lite request manage-policies -- remove --name manage-policies --disable-builtin
226
+
227
+ 3. Drop a user override of a built-in (the built-in then surfaces again):
228
+ clawmini-lite request manage-policies -- remove --name manage-policies
229
+ `
230
+ )
231
+ .action((options) => {
232
+ const name: string = options.name;
233
+ const disableBuiltin: boolean = !!options.disableBuiltin;
234
+
235
+ assertValidName(name);
236
+
237
+ const { policies, policiesPath } = loadPolicies();
238
+ const isBuiltin = name in BUILTIN_POLICIES;
239
+ const existing = policies.policies[name];
240
+
241
+ if (disableBuiltin) {
242
+ if (!isBuiltin) {
243
+ fail(
244
+ `--disable-builtin can only be used for built-in policies; '${name}' is not a built-in.`
245
+ );
246
+ }
247
+ if (existing === false) {
248
+ fail(`Built-in policy '${name}' is already disabled.`);
249
+ }
250
+ // A user override (object) is a deliberate customization; silently
251
+ // replacing it with `false` would destroy approved work. Force the
252
+ // agent to drop the override first, then re-run with --disable-builtin.
253
+ if (existing !== undefined) {
254
+ fail(
255
+ `Policy '${name}' has a user override that would be lost. Run 'manage-policies remove --name ${name}' first, then re-run with --disable-builtin.`
256
+ );
257
+ }
258
+ policies.policies[name] = false;
259
+ writePolicies(policiesPath, policies);
260
+ console.log(`Successfully disabled built-in policy '${name}'.`);
261
+ return;
262
+ }
263
+
264
+ if (existing === undefined) {
265
+ const hint = isBuiltin
266
+ ? ` '${name}' is a built-in. To opt out, re-run with --disable-builtin.`
267
+ : '';
268
+ fail(`No policy entry '${name}' to remove.${hint}`);
269
+ }
270
+
271
+ delete policies.policies[name];
272
+ writePolicies(policiesPath, policies);
273
+
274
+ if (existing === false) {
275
+ console.log(
276
+ `Successfully cleared the disable entry for '${name}'.${
277
+ isBuiltin ? ' The built-in will surface again.' : ''
278
+ }`
279
+ );
280
+ } else if (isBuiltin) {
281
+ console.log(
282
+ `Successfully removed user override of built-in policy '${name}'. The built-in will surface again.`
283
+ );
284
+ } else {
285
+ console.log(`Successfully removed policy '${name}'.`);
286
+ }
287
+ });
288
+
289
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
290
+ root.parse(process.argv);
291
+ }
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { spawn } from 'node:child_process';
4
+ import { pathToFileURL } from 'node:url';
5
+
6
+ const runHostCmd = new Command('run-host');
7
+
8
+ runHostCmd
9
+ .description('Run an arbitrary shell command on the host via `sh -c`.')
10
+ .requiredOption(
11
+ '--command <command_string>',
12
+ 'The shell command to execute. Supports pipes, redirection, &&, ||, etc.'
13
+ )
14
+ .addHelpText(
15
+ 'after',
16
+ `
17
+ Examples:
18
+ 1. Run a simple command:
19
+ clawmini-lite request run-host -- --command "ls -la"
20
+
21
+ 2. Run a command with pipes and redirection:
22
+ clawmini-lite request run-host -- --command "cat file.txt | grep error > errors.log"
23
+
24
+ 3. Chain commands:
25
+ clawmini-lite request run-host -- --command "npm install && npm test"
26
+ `
27
+ )
28
+ .action((options: { command: string }) => {
29
+ const child = spawn('sh', ['-c', options.command], {
30
+ stdio: ['ignore', 'inherit', 'inherit'],
31
+ });
32
+
33
+ child.on('close', (code) => {
34
+ process.exit(code ?? 1);
35
+ });
36
+
37
+ child.on('error', (err) => {
38
+ console.error(`Failed to execute command: ${err.message}`);
39
+ process.exit(1);
40
+ });
41
+ });
42
+
43
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
44
+ runHostCmd.parse(process.argv);
45
+ }