clawmini 0.0.7 → 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.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +14 -0
- package/.github/workflows/release.yml +49 -0
- package/CHANGELOG.md +36 -0
- package/README.md +5 -4
- package/dist/adapter-discord/index.d.mts.map +1 -1
- package/dist/adapter-discord/index.mjs +465 -282
- package/dist/adapter-discord/index.mjs.map +1 -1
- package/dist/adapter-google-chat/index.mjs +367 -243
- package/dist/adapter-google-chat/index.mjs.map +1 -1
- package/dist/cli/index.mjs +684 -24
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lite.mjs +43 -13
- package/dist/cli/lite.mjs.map +1 -1
- package/dist/cli/{propose-policy.mjs → manage-policies.mjs} +270 -47
- package/dist/cli/manage-policies.mjs.map +1 -0
- package/dist/cli/run-host.d.mts +1 -0
- package/dist/cli/run-host.mjs +3090 -0
- package/dist/cli/run-host.mjs.map +1 -0
- package/dist/config-CPFQIGdG.mjs +57 -0
- package/dist/config-CPFQIGdG.mjs.map +1 -0
- package/dist/config-Dvl-Pov4.mjs +76 -0
- package/dist/config-Dvl-Pov4.mjs.map +1 -0
- package/dist/daemon/index.d.mts.map +1 -1
- package/dist/daemon/index.mjs +970 -332
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/supervisor-actions-CiW56eLi.mjs +843 -0
- package/dist/supervisor-actions-CiW56eLi.mjs.map +1 -0
- package/dist/turn-log-buffer-DRgW53gl.mjs +767 -0
- package/dist/turn-log-buffer-DRgW53gl.mjs.map +1 -0
- package/dist/web/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
- package/dist/web/_app/immutable/chunks/BhRSsUCh.js +2 -0
- package/dist/web/_app/immutable/chunks/BiLeM2i1.js +1 -0
- package/{web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js → dist/web/_app/immutable/chunks/BmBj85Ll.js} +1 -1
- package/dist/web/_app/immutable/chunks/BrERcKAH.js +1 -0
- package/dist/web/_app/immutable/chunks/Bv9252RM.js +1 -0
- package/dist/web/_app/immutable/chunks/CIXNBPKi.js +1 -0
- package/dist/web/_app/immutable/chunks/DISKL3GN.js +2 -0
- package/dist/web/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
- package/dist/web/_app/immutable/chunks/DnQ3vS13.js +1 -0
- package/dist/web/_app/immutable/chunks/KsloHTKS.js +1 -0
- package/{web/.svelte-kit/output/client/_app/immutable/chunks/Ck-be5J2.js → dist/web/_app/immutable/chunks/RsHsUj-8.js} +2 -2
- package/dist/web/_app/immutable/chunks/{G_zz-Gou.js → wpfV79dV.js} +1 -1
- package/dist/web/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
- package/dist/web/_app/immutable/entry/start.Di0-Jhte.js +1 -0
- package/dist/web/_app/immutable/nodes/{0.CYS8iApT.js → 0.DYyUA1au.js} +1 -1
- package/dist/web/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
- package/dist/web/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
- package/{web/.svelte-kit/output/client/_app/immutable/nodes/3.Dr0ot9sV.js → dist/web/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
- package/dist/web/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
- package/dist/web/_app/immutable/nodes/{5.BBGQ_i84.js → 5.DLbPVJY2.js} +1 -1
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +12 -12
- package/dist/workspace-oWmVh5mi.mjs +1001 -0
- package/dist/workspace-oWmVh5mi.mjs.map +1 -0
- package/docs/23_adapter_slash_autocomplete/development_log.md +19 -0
- package/docs/23_adapter_slash_autocomplete/notes.md +18 -0
- package/docs/23_adapter_slash_autocomplete/prd.md +46 -0
- package/docs/23_adapter_slash_autocomplete/questions.md +6 -0
- package/docs/23_adapter_slash_autocomplete/tickets.md +21 -0
- package/docs/24_subagent_job_policy_fixes/development_log.md +22 -0
- package/docs/24_subagent_job_policy_fixes/notes.md +28 -0
- package/docs/24_subagent_job_policy_fixes/prd.md +59 -0
- package/docs/24_subagent_job_policy_fixes/questions.md +3 -0
- package/docs/24_subagent_job_policy_fixes/tickets.md +49 -0
- package/docs/25_e2e_test_improvements/development_log.md +30 -0
- package/docs/25_e2e_test_improvements/notes.md +29 -0
- package/docs/25_e2e_test_improvements/prd.md +43 -0
- package/docs/25_e2e_test_improvements/questions.md +12 -0
- package/docs/25_e2e_test_improvements/tickets-2.md +22 -0
- package/docs/25_e2e_test_improvements/tickets.md +22 -0
- package/docs/25_policy_cwd/development_log.md +30 -0
- package/docs/25_policy_cwd/notes.md +28 -0
- package/docs/25_policy_cwd/prd.md +77 -0
- package/docs/25_policy_cwd/questions.md +6 -0
- package/docs/25_policy_cwd/tickets.md +77 -0
- package/docs/CLI_REFERENCE.md +3 -1
- package/docs/PHILOSOPHY.md +35 -0
- package/docs/adapter-visibility/SPEC.md +461 -0
- package/docs/adapter-visibility/SPEC_v2.md +202 -0
- package/docs/auto-update/SPEC.md +344 -0
- package/docs/backups/SPEC.md +296 -0
- package/docs/backups/clawmini.gitignore +69 -0
- package/docs/guides/assets/clawmini-avatar.png +0 -0
- package/docs/guides/backups.md +332 -0
- package/docs/guides/discord_adapter_setup.md +1 -1
- package/docs/guides/google_chat_adapter_setup.md +81 -0
- package/docs/unified-startup/SPEC.md +203 -0
- package/e2e/_helpers/test-environment.test.ts +49 -0
- package/e2e/_helpers/test-environment.ts +548 -0
- package/e2e/adapters/_google-chat-fixtures.ts +340 -0
- package/{src/cli/e2e → e2e/adapters}/adapter-discord.test.ts +22 -23
- package/e2e/adapters/adapter-google-chat-downtime.test.ts +157 -0
- package/e2e/adapters/adapter-google-chat-inbound.test.ts +697 -0
- package/e2e/adapters/adapter-google-chat-outbound.test.ts +297 -0
- package/e2e/adapters/adapter-google-chat-roundtrip.test.ts +56 -0
- package/e2e/adapters/adapter-google-chat-threads.test.ts +1078 -0
- package/e2e/agents/custom-api-env.test.ts +80 -0
- package/e2e/agents/export-lite-func.test.ts +104 -0
- package/e2e/agents/fallbacks.test.ts +124 -0
- package/e2e/agents/interrupt.test.ts +50 -0
- package/e2e/agents/no-reply-necessary.test.ts +57 -0
- package/e2e/agents/session-timeout-subagents.test.ts +76 -0
- package/e2e/agents/subagent-authorization.test.ts +246 -0
- package/e2e/agents/subagent-env.test.ts +49 -0
- package/e2e/agents/subagent-lifecycle.test.ts +782 -0
- package/e2e/agents/subagents-depth.test.ts +47 -0
- package/e2e/cli/agents.test.ts +176 -0
- package/e2e/cli/auto-update.test.ts +741 -0
- package/e2e/cli/basic.test.ts +44 -0
- package/{src/cli/e2e → e2e/cli}/export-lite.test.ts +16 -12
- package/e2e/cli/init-gitignore.test.ts +86 -0
- package/e2e/cli/init.test.ts +76 -0
- package/e2e/cli/messages.test.ts +363 -0
- package/e2e/cli/serve.test.ts +76 -0
- package/{src/cli/e2e → e2e/cli}/skills.test.ts +11 -10
- package/{src/cli/e2e → e2e/daemon}/daemon.test.ts +57 -195
- package/e2e/jobs/agent-jobs.test.ts +216 -0
- package/e2e/jobs/cron.test.ts +64 -0
- package/e2e/jobs/restart.test.ts +108 -0
- package/e2e/policies/approval-session.test.ts +69 -0
- package/e2e/policies/auto-create-policies-file.test.ts +35 -0
- package/e2e/policies/builtin-manage-policies.test.ts +184 -0
- package/e2e/policies/builtin-run-host.test.ts +180 -0
- package/e2e/policies/environment-policies.test.ts +177 -0
- package/e2e/policies/manage-policies.test.ts +566 -0
- package/e2e/policies/output-size.test.ts +98 -0
- package/e2e/policies/policies-context-cwd.test.ts +160 -0
- package/e2e/policies/relative-script-path.test.ts +60 -0
- package/e2e/policies/requests-show.test.ts +135 -0
- package/e2e/policies/requests.test.ts +208 -0
- package/e2e/policies/slash-policies.test.ts +308 -0
- package/e2e/policies/startup-cleanup.test.ts +48 -0
- package/e2e/routers/session-timeout.test.ts +106 -0
- package/e2e/routers/slash-model.test.ts +152 -0
- package/e2e/routers/slash-new.test.ts +50 -0
- package/e2e/routers/slash-restart-adapter.test.ts +96 -0
- package/e2e/routers/slash-restart.test.ts +114 -0
- package/e2e/routers/slash-shutdown.test.ts +55 -0
- package/e2e/routers/slash-stop.test.ts +232 -0
- package/e2e/routers/slash-upgrade.test.ts +88 -0
- package/{src/cli/e2e → e2e/sandbox}/environments.test.ts +14 -13
- package/eslint.config.js +6 -0
- package/napkin.md +1 -1
- package/package.json +8 -3
- package/src/adapter-discord/commands.test.ts +42 -0
- package/src/adapter-discord/commands.ts +33 -0
- package/src/adapter-discord/config.ts +12 -0
- package/src/adapter-discord/forwarder.test.ts +499 -21
- package/src/adapter-discord/forwarder.ts +343 -124
- package/src/adapter-discord/inbound-cache.test.ts +47 -0
- package/src/adapter-discord/inbound-cache.ts +37 -0
- package/src/adapter-discord/index.test.ts +67 -2
- package/src/adapter-discord/index.ts +84 -216
- package/src/adapter-discord/interactions.test.ts +54 -3
- package/src/adapter-discord/interactions.ts +97 -53
- package/src/adapter-discord/processMessage.ts +239 -0
- package/src/adapter-discord/state.ts +1 -0
- package/src/adapter-google-chat/auth.test.ts +9 -5
- package/src/adapter-google-chat/auth.ts +29 -23
- package/src/adapter-google-chat/cards.ts +7 -2
- package/src/adapter-google-chat/client.test.ts +37 -2
- package/src/adapter-google-chat/client.ts +138 -38
- package/src/adapter-google-chat/config.ts +19 -0
- package/src/adapter-google-chat/forwarder.test.ts +81 -56
- package/src/adapter-google-chat/forwarder.ts +394 -185
- package/src/adapter-google-chat/inbound-cache.test.ts +61 -0
- package/src/adapter-google-chat/inbound-cache.ts +36 -0
- package/src/adapter-google-chat/state.test.ts +1 -0
- package/src/adapter-google-chat/state.ts +9 -1
- package/src/adapter-google-chat/subscriptions.ts +8 -6
- package/src/cli/builtin-policies.ts +44 -0
- package/src/cli/commands/agents.ts +59 -5
- package/src/cli/commands/down.ts +54 -2
- package/src/cli/commands/environments.ts +8 -2
- package/src/cli/commands/init.ts +31 -0
- package/src/cli/commands/logs.ts +116 -0
- package/src/cli/commands/policies.ts +6 -4
- package/src/cli/commands/serve.test.ts +67 -0
- package/src/cli/commands/serve.ts +284 -0
- package/src/cli/commands/up.ts +122 -2
- package/src/cli/commands/web-api/agents.ts +3 -2
- package/src/cli/index.ts +4 -0
- package/src/cli/install-detection.test.ts +72 -0
- package/src/cli/install-detection.ts +48 -0
- package/src/cli/lite.ts +54 -22
- package/src/cli/manage-policies-utils.ts +104 -0
- package/src/cli/manage-policies.ts +291 -0
- package/src/cli/run-host.ts +45 -0
- package/src/cli/supervisor-actions.ts +267 -0
- package/src/cli/supervisor-control.test.ts +129 -0
- package/src/cli/supervisor-control.ts +155 -0
- package/src/cli/supervisor-pid.ts +68 -0
- package/src/cli/supervisor.ts +277 -0
- package/src/daemon/agent/agent-context.ts +11 -11
- package/src/daemon/agent/agent-session.ts +8 -1
- package/src/daemon/agent/chat-logger.test.ts +78 -9
- package/src/daemon/agent/chat-logger.ts +25 -5
- package/src/daemon/agent/turn-registry.test.ts +89 -0
- package/src/daemon/agent/turn-registry.ts +94 -0
- package/src/daemon/agent/types.ts +2 -0
- package/src/daemon/api/agent-policy-endpoints.ts +263 -0
- package/src/daemon/api/agent-router.ts +47 -126
- package/src/daemon/api/index.test.ts +1 -0
- package/src/daemon/api/policy-request.test.ts +7 -5
- package/src/daemon/api/router-utils.ts +6 -5
- package/src/daemon/api/subagent-router.ts +110 -74
- package/src/daemon/api/subagent-utils.test.ts +60 -0
- package/src/daemon/api/subagent-utils.ts +113 -87
- package/src/daemon/api/user-router.ts +34 -8
- package/src/daemon/auth.ts +1 -0
- package/src/daemon/cron.test.ts +62 -4
- package/src/daemon/cron.ts +42 -16
- package/src/daemon/events.ts +65 -0
- package/src/daemon/index.ts +24 -1
- package/src/daemon/message-interruption.test.ts +1 -0
- package/src/daemon/message-jobs.test.ts +1 -0
- package/src/daemon/message.ts +78 -14
- package/src/daemon/observation.test.ts +26 -18
- package/src/daemon/pending-replies.test.ts +112 -0
- package/src/daemon/pending-replies.ts +162 -0
- package/src/daemon/policy-request-service.ts +3 -1
- package/src/daemon/policy-utils.test.ts +66 -1
- package/src/daemon/policy-utils.ts +126 -1
- package/src/daemon/request-store.ts +31 -0
- package/src/daemon/routers/session-timeout.ts +4 -0
- package/src/daemon/routers/slash-model.test.ts +344 -0
- package/src/daemon/routers/slash-model.ts +207 -0
- package/src/daemon/routers/slash-policies.test.ts +38 -32
- package/src/daemon/routers/slash-policies.ts +84 -33
- package/src/daemon/routers/slash-restart.test.ts +69 -0
- package/src/daemon/routers/slash-restart.ts +36 -0
- package/src/daemon/routers/slash-shutdown.test.ts +50 -0
- package/src/daemon/routers/slash-shutdown.ts +28 -0
- package/src/daemon/routers/slash-upgrade.test.ts +116 -0
- package/src/daemon/routers/slash-upgrade.ts +76 -0
- package/src/daemon/routers/types.ts +7 -0
- package/src/daemon/routers.ts +16 -0
- package/src/shared/adapters/blockquote.test.ts +28 -0
- package/src/shared/adapters/blockquote.ts +20 -0
- package/src/shared/adapters/filtering.test.ts +224 -10
- package/src/shared/adapters/filtering.ts +95 -7
- package/src/shared/adapters/inbound-cache.test.ts +48 -0
- package/src/shared/adapters/inbound-cache.ts +54 -0
- package/src/shared/adapters/turn-log-buffer.ts +266 -0
- package/src/shared/adapters/turn-log.test.ts +389 -0
- package/src/shared/adapters/turn-log.ts +357 -0
- package/src/shared/agent-utils.ts +12 -5
- package/src/shared/chats.test.ts +4 -0
- package/src/shared/chats.ts +9 -0
- package/src/shared/config.ts +16 -1
- package/src/shared/lite.ts +76 -2
- package/src/shared/policies.ts +26 -0
- package/src/shared/template-manifest.ts +267 -0
- package/src/shared/utils/shell.ts +61 -0
- package/src/shared/version.ts +34 -0
- package/src/shared/workspace.test.ts +217 -0
- package/src/shared/workspace.ts +626 -48
- package/templates/environments/cladding/allowlist-domain.mjs +125 -0
- package/templates/environments/cladding/env.json +21 -1
- package/templates/environments/cladding/run-with-network.mjs +54 -0
- package/templates/environments/macos-proxy/allowlist-domain.mjs +95 -0
- package/templates/environments/macos-proxy/env.json +8 -1
- package/templates/environments/macos-proxy/proxy.mjs +42 -13
- package/templates/gemini/template.json +5 -0
- package/templates/gemini-claw/template.json +13 -0
- package/templates/skills/clawmini-requests/SKILL.md +69 -10
- package/templates/skills/run-host/SKILL.md +51 -0
- package/templates/skills/skill-creator/SKILL.md +4 -3
- package/templates/skills/skill-creator/scripts/validate.sh +52 -0
- package/tsdown.config.ts +10 -1
- package/vitest.config.ts +2 -2
- package/web/.svelte-kit/ambient.d.ts +292 -176
- package/web/.svelte-kit/generated/server/internal.js +1 -1
- package/web/.svelte-kit/output/client/.vite/manifest.json +127 -137
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BhRSsUCh.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BiLeM2i1.js +1 -0
- package/{dist/web/_app/immutable/chunks/CME08kGM.js → web/.svelte-kit/output/client/_app/immutable/chunks/BmBj85Ll.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BrERcKAH.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Bv9252RM.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CIXNBPKi.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DISKL3GN.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DnQ3vS13.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/KsloHTKS.js +1 -0
- package/{dist/web/_app/immutable/chunks/Ck-be5J2.js → web/.svelte-kit/output/client/_app/immutable/chunks/RsHsUj-8.js} +2 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{G_zz-Gou.js → wpfV79dV.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.Di0-Jhte.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.CYS8iApT.js → 0.DYyUA1au.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
- package/{dist/web/_app/immutable/nodes/3.Dr0ot9sV.js → web/.svelte-kit/output/client/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.BBGQ_i84.js → 5.DLbPVJY2.js} +1 -1
- package/web/.svelte-kit/output/client/_app/version.json +1 -1
- package/web/.svelte-kit/output/server/.vite/manifest.json +12 -10
- package/web/.svelte-kit/output/server/chunks/Icon.js +1 -1
- package/web/.svelte-kit/output/server/chunks/client.js +1 -1
- package/web/.svelte-kit/output/server/chunks/exports.js +1 -1
- package/web/.svelte-kit/output/server/chunks/index-server.js +2 -1
- package/web/.svelte-kit/output/server/chunks/internal.js +1 -1
- package/web/.svelte-kit/output/server/chunks/render-context.js +77 -0
- package/web/.svelte-kit/output/server/chunks/root.js +739 -788
- package/web/.svelte-kit/output/server/chunks/shared.js +234 -21
- package/web/.svelte-kit/output/server/index.js +126 -90
- package/web/.svelte-kit/output/server/manifest-full.js +1 -1
- package/web/.svelte-kit/output/server/manifest.js +1 -1
- package/web/.svelte-kit/output/server/nodes/0.js +1 -1
- package/web/.svelte-kit/output/server/nodes/1.js +1 -1
- package/web/.svelte-kit/output/server/nodes/2.js +1 -1
- package/web/.svelte-kit/output/server/nodes/3.js +1 -1
- package/web/.svelte-kit/output/server/nodes/4.js +1 -1
- package/web/.svelte-kit/output/server/nodes/5.js +1 -1
- package/web/.svelte-kit/output/server/remote-entry.js +245 -81
- package/web/.svelte-kit/tsconfig.json +4 -1
- package/dist/cli/propose-policy.mjs.map +0 -1
- package/dist/lite-CBxOT1y5.mjs +0 -241
- package/dist/lite-CBxOT1y5.mjs.map +0 -1
- package/dist/routing-D8rTxtaV.mjs +0 -245
- package/dist/routing-D8rTxtaV.mjs.map +0 -1
- package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +0 -1
- package/dist/web/_app/immutable/chunks/BmRlVmv6.js +0 -1
- package/dist/web/_app/immutable/chunks/CK9JZLaG.js +0 -2
- package/dist/web/_app/immutable/chunks/Ck3rYNON.js +0 -1
- package/dist/web/_app/immutable/chunks/DMtIqaiV.js +0 -2
- package/dist/web/_app/immutable/chunks/DhD271EB.js +0 -1
- package/dist/web/_app/immutable/chunks/DpuLqk8d.js +0 -1
- package/dist/web/_app/immutable/chunks/DsIToJCP.js +0 -1
- package/dist/web/_app/immutable/chunks/bBmtyQMj.js +0 -1
- package/dist/web/_app/immutable/entry/app.CJmSwntr.js +0 -2
- package/dist/web/_app/immutable/entry/start.ZpUrT2ak.js +0 -1
- package/dist/web/_app/immutable/nodes/1.Bli0Hqzn.js +0 -1
- package/dist/web/_app/immutable/nodes/4.oBhvQhcA.js +0 -60
- package/dist/workspace-BJmJBfKi.mjs +0 -456
- package/dist/workspace-BJmJBfKi.mjs.map +0 -1
- package/src/cli/e2e/agents.test.ts +0 -140
- package/src/cli/e2e/basic.test.ts +0 -43
- package/src/cli/e2e/cron.test.ts +0 -132
- package/src/cli/e2e/export-lite-func.test.ts +0 -206
- package/src/cli/e2e/fallbacks.test.ts +0 -175
- package/src/cli/e2e/init.test.ts +0 -77
- package/src/cli/e2e/messages.test.ts +0 -332
- package/src/cli/e2e/propose-policy.test.ts +0 -203
- package/src/cli/e2e/requests.test.ts +0 -180
- package/src/cli/e2e/session-timeout.test.ts +0 -192
- package/src/cli/e2e/slash-new.test.ts +0 -93
- package/src/cli/e2e/subagents.test.ts +0 -106
- package/src/cli/e2e/utils.ts +0 -66
- package/src/cli/propose-policy.ts +0 -91
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BmRlVmv6.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DhD271EB.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DpuLqk8d.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/bBmtyQMj.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.CJmSwntr.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.ZpUrT2ak.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.Bli0Hqzn.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.oBhvQhcA.js +0 -60
- package/web/.svelte-kit/output/server/chunks/false.js +0 -4
- /package/dist/cli/{propose-policy.d.mts → manage-policies.d.mts} +0 -0
- /package/{src/cli/e2e → e2e/_helpers}/global-setup.ts +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
|
|
6
|
+
// cwd is guaranteed to sit inside the env's target directory, which is in
|
|
7
|
+
// turn inside the workspace. Walk up looking for .cladding/config, stopping
|
|
8
|
+
// at the workspace root (the dir containing .clawmini) so we never cross
|
|
9
|
+
// into an ancestor project.
|
|
10
|
+
function findCladdingConfigDir(startDir) {
|
|
11
|
+
let curr = path.resolve(startDir);
|
|
12
|
+
while (true) {
|
|
13
|
+
const candidate = path.join(curr, '.cladding', 'config');
|
|
14
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
15
|
+
if (fs.existsSync(path.join(curr, '.clawmini'))) return null;
|
|
16
|
+
const parent = path.dirname(curr);
|
|
17
|
+
if (parent === curr) return null;
|
|
18
|
+
curr = parent;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const domains = process.argv.slice(2).filter((arg) => arg.length > 0);
|
|
23
|
+
if (domains.length === 0) {
|
|
24
|
+
console.error('Usage: allowlist-domain <domain> [<domain>...]');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const domainPattern = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
29
|
+
for (const domain of domains) {
|
|
30
|
+
if (!domainPattern.test(domain)) {
|
|
31
|
+
console.error(`Invalid domain: ${domain}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const configDir = findCladdingConfigDir(process.cwd());
|
|
37
|
+
if (!configDir) {
|
|
38
|
+
console.error('Could not locate .cladding/config within the workspace.');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const allowlistPath = path.join(configDir, 'sandbox_domains.lst');
|
|
43
|
+
|
|
44
|
+
// O_NOFOLLOW on both read and write: a symlink at the allowlist path would
|
|
45
|
+
// otherwise redirect host-privileged writes to an attacker-chosen file.
|
|
46
|
+
function readAllowlist() {
|
|
47
|
+
let fd;
|
|
48
|
+
try {
|
|
49
|
+
fd = fs.openSync(allowlistPath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (err.code === 'ENOENT') return '';
|
|
52
|
+
if (err.code === 'ELOOP') {
|
|
53
|
+
console.error(`Refusing to follow symlink at allowlist path: ${allowlistPath}`);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const st = fs.fstatSync(fd);
|
|
60
|
+
const buf = Buffer.alloc(st.size);
|
|
61
|
+
fs.readSync(fd, buf, 0, st.size, 0);
|
|
62
|
+
return buf.toString('utf8');
|
|
63
|
+
} finally {
|
|
64
|
+
fs.closeSync(fd);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function appendAllowlist(text) {
|
|
69
|
+
let fd;
|
|
70
|
+
try {
|
|
71
|
+
fd = fs.openSync(
|
|
72
|
+
allowlistPath,
|
|
73
|
+
fs.constants.O_WRONLY |
|
|
74
|
+
fs.constants.O_APPEND |
|
|
75
|
+
fs.constants.O_CREAT |
|
|
76
|
+
fs.constants.O_NOFOLLOW,
|
|
77
|
+
0o644
|
|
78
|
+
);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
if (err.code === 'ELOOP') {
|
|
81
|
+
console.error(`Refusing to follow symlink at allowlist path: ${allowlistPath}`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
fs.writeSync(fd, text);
|
|
88
|
+
} finally {
|
|
89
|
+
fs.closeSync(fd);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const existing = readAllowlist();
|
|
94
|
+
const existingDomains = new Set(
|
|
95
|
+
existing
|
|
96
|
+
.split('\n')
|
|
97
|
+
.map((line) => line.trim())
|
|
98
|
+
.filter((line) => line.length > 0 && !line.startsWith('#'))
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const added = [];
|
|
102
|
+
for (const domain of domains) {
|
|
103
|
+
if (!existingDomains.has(domain)) {
|
|
104
|
+
existingDomains.add(domain);
|
|
105
|
+
added.push(domain);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (added.length === 0) {
|
|
110
|
+
console.log('No new domains to add; allowlist already contains all requested domains.');
|
|
111
|
+
process.exit(0);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const appendSuffix = existing.length > 0 && !existing.endsWith('\n') ? '\n' : '';
|
|
115
|
+
appendAllowlist(`${appendSuffix}${added.join('\n')}\n`);
|
|
116
|
+
console.log(`Added ${added.length} domain(s) to allowlist: ${added.join(', ')}`);
|
|
117
|
+
|
|
118
|
+
const reload = spawnSync('cladding', ['reload-proxy'], {
|
|
119
|
+
stdio: 'inherit',
|
|
120
|
+
cwd: path.dirname(configDir),
|
|
121
|
+
});
|
|
122
|
+
if (reload.status !== 0) {
|
|
123
|
+
console.error('Warning: `cladding reload-proxy` exited with code', reload.status);
|
|
124
|
+
process.exit(reload.status ?? 1);
|
|
125
|
+
}
|
|
@@ -3,5 +3,25 @@
|
|
|
3
3
|
"up": "cladding up",
|
|
4
4
|
"down": "cladding down",
|
|
5
5
|
"prefix": "cladding run {ENV_ARGS} sh -c '{COMMAND}'",
|
|
6
|
-
"envFormat": "--env {key}"
|
|
6
|
+
"envFormat": "--env {key}",
|
|
7
|
+
"exportLiteTo": ".cladding/tools/bin",
|
|
8
|
+
"baseDir": "/home/user/workspace",
|
|
9
|
+
"policies": {
|
|
10
|
+
"allowlist-domain": {
|
|
11
|
+
"description": "Add one or more domains to the proxy allowlist. Usage: allowlist-domain <domain> [<domain>...]",
|
|
12
|
+
"command": "./allowlist-domain.mjs",
|
|
13
|
+
"allowHelp": false
|
|
14
|
+
},
|
|
15
|
+
"run-with-network": {
|
|
16
|
+
"description": "Run a shell command with network access. May require first allowlisting domains. Pass the command via --command, e.g. --command \"npm install\". Supports pipes, &&, env vars, etc.",
|
|
17
|
+
"allowHelp": true,
|
|
18
|
+
"command": "./run-with-network.mjs"
|
|
19
|
+
},
|
|
20
|
+
"expose-port": {
|
|
21
|
+
"description": "Expose a port to the network. Use --help for more details.",
|
|
22
|
+
"allowHelp": true,
|
|
23
|
+
"command": "cladding",
|
|
24
|
+
"args": ["expose"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
7
27
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
|
|
4
|
+
const args = process.argv.slice(2);
|
|
5
|
+
|
|
6
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
7
|
+
process.stdout.write(
|
|
8
|
+
`run-with-network: Run a command with network access via cladding's sandbox.\n` +
|
|
9
|
+
`\n` +
|
|
10
|
+
`Usage:\n` +
|
|
11
|
+
` run-with-network --command "<shell command>"\n` +
|
|
12
|
+
`\n` +
|
|
13
|
+
`The command string is forwarded to \`sh -c\` inside the cladding sandbox,\n` +
|
|
14
|
+
`so it supports pipes, redirection, &&, ||, environment variables, multiple\n` +
|
|
15
|
+
`commands, etc.\n` +
|
|
16
|
+
`\n` +
|
|
17
|
+
`Examples:\n` +
|
|
18
|
+
` run-with-network --command "curl -sSL https://example.com | jq ."\n` +
|
|
19
|
+
` run-with-network --command "FOO=1 echo \\$FOO"\n` +
|
|
20
|
+
` run-with-network --command 'echo "hello" && echo "world"'\n`
|
|
21
|
+
);
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const idx = args.indexOf('--command');
|
|
26
|
+
if (idx === -1 || idx + 1 >= args.length) {
|
|
27
|
+
process.stderr.write(
|
|
28
|
+
`Error: --command <shell command> is required.\n` +
|
|
29
|
+
`Usage: run-with-network --command "<shell command>"\n`
|
|
30
|
+
);
|
|
31
|
+
process.exit(2);
|
|
32
|
+
}
|
|
33
|
+
const command = args[idx + 1];
|
|
34
|
+
|
|
35
|
+
// `cladding run-with-scissors` execs its argv directly inside the sandbox, so
|
|
36
|
+
// shell features (env-var prefixes, &&, pipes, multi-line) only work if we
|
|
37
|
+
// hand it an explicit shell. Wrap in `sh -c` so the user's command string is
|
|
38
|
+
// parsed as a script.
|
|
39
|
+
const child = spawn('cladding', ['run-with-scissors', 'sh', '-c', command], {
|
|
40
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
child.on('close', (code, signal) => {
|
|
44
|
+
if (signal) {
|
|
45
|
+
process.kill(process.pid, signal);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
process.exit(code ?? 1);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
child.on('error', (err) => {
|
|
52
|
+
process.stderr.write(`Failed to execute command: ${err.message}\n`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const allowlistPath = path.join(__dirname, 'allowlist.txt');
|
|
8
|
+
|
|
9
|
+
const domains = process.argv.slice(2).filter((arg) => arg.length > 0);
|
|
10
|
+
if (domains.length === 0) {
|
|
11
|
+
console.error('Usage: allowlist-domain <domain> [<domain>...]');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const domainPattern = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
16
|
+
for (const domain of domains) {
|
|
17
|
+
if (!domainPattern.test(domain)) {
|
|
18
|
+
console.error(`Invalid domain: ${domain}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// O_NOFOLLOW on both read and write: a symlink at the allowlist path would
|
|
24
|
+
// otherwise redirect host-privileged writes to an attacker-chosen file.
|
|
25
|
+
function readAllowlist() {
|
|
26
|
+
let fd;
|
|
27
|
+
try {
|
|
28
|
+
fd = fs.openSync(allowlistPath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
if (err.code === 'ENOENT') return '';
|
|
31
|
+
if (err.code === 'ELOOP') {
|
|
32
|
+
console.error(`Refusing to follow symlink at allowlist path: ${allowlistPath}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const st = fs.fstatSync(fd);
|
|
39
|
+
const buf = Buffer.alloc(st.size);
|
|
40
|
+
fs.readSync(fd, buf, 0, st.size, 0);
|
|
41
|
+
return buf.toString('utf8');
|
|
42
|
+
} finally {
|
|
43
|
+
fs.closeSync(fd);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function appendAllowlist(text) {
|
|
48
|
+
let fd;
|
|
49
|
+
try {
|
|
50
|
+
fd = fs.openSync(
|
|
51
|
+
allowlistPath,
|
|
52
|
+
fs.constants.O_WRONLY |
|
|
53
|
+
fs.constants.O_APPEND |
|
|
54
|
+
fs.constants.O_CREAT |
|
|
55
|
+
fs.constants.O_NOFOLLOW,
|
|
56
|
+
0o644
|
|
57
|
+
);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
if (err.code === 'ELOOP') {
|
|
60
|
+
console.error(`Refusing to follow symlink at allowlist path: ${allowlistPath}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
fs.writeSync(fd, text);
|
|
67
|
+
} finally {
|
|
68
|
+
fs.closeSync(fd);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const existing = readAllowlist();
|
|
73
|
+
const existingDomains = new Set(
|
|
74
|
+
existing
|
|
75
|
+
.split('\n')
|
|
76
|
+
.map((line) => line.trim())
|
|
77
|
+
.filter((line) => line.length > 0 && !line.startsWith('#'))
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const added = [];
|
|
81
|
+
for (const domain of domains) {
|
|
82
|
+
if (!existingDomains.has(domain)) {
|
|
83
|
+
existingDomains.add(domain);
|
|
84
|
+
added.push(domain);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (added.length === 0) {
|
|
89
|
+
console.log('No new domains to add; allowlist already contains all requested domains.');
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const appendSuffix = existing.length > 0 && !existing.endsWith('\n') ? '\n' : '';
|
|
94
|
+
appendAllowlist(`${appendSuffix}${added.join('\n')}\n`);
|
|
95
|
+
console.log(`Added ${added.length} domain(s) to allowlist: ${added.join(', ')}`);
|
|
@@ -10,5 +10,12 @@
|
|
|
10
10
|
"https_proxy": "http://127.0.0.1:8888",
|
|
11
11
|
"PATH": "{PATH}:{WORKSPACE_DIR}/.local/bin"
|
|
12
12
|
},
|
|
13
|
-
"exportLiteTo": ".local/bin/clawmini-lite.js"
|
|
13
|
+
"exportLiteTo": ".local/bin/clawmini-lite.js",
|
|
14
|
+
"policies": {
|
|
15
|
+
"allowlist-domain": {
|
|
16
|
+
"description": "Add one or more domains to the proxy allowlist. Usage: allowlist-domain <domain> [<domain>...]",
|
|
17
|
+
"command": "./allowlist-domain.mjs",
|
|
18
|
+
"allowHelp": false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
14
21
|
}
|
|
@@ -5,7 +5,6 @@ import path from 'path';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
|
|
7
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
// eslint-disable-next-line no-undef
|
|
9
8
|
const envDir = process.env.ENV_DIR || __dirname;
|
|
10
9
|
const allowlistPath = path.join(envDir, 'allowlist.txt');
|
|
11
10
|
|
|
@@ -28,10 +27,13 @@ function isAllowed(hostname) {
|
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
const server = http.createServer((req, res) => {
|
|
30
|
+
req.on('error', (err) => console.error('[HTTP] Client request error:', err.message));
|
|
31
|
+
res.on('error', (err) => console.error('[HTTP] Client response error:', err.message));
|
|
32
|
+
|
|
31
33
|
try {
|
|
32
34
|
const url = new URL(req.url);
|
|
33
35
|
if (!isAllowed(url.hostname)) {
|
|
34
|
-
console.log(`[
|
|
36
|
+
console.log(`[HTTP] Blocked: ${url.hostname}`);
|
|
35
37
|
res.writeHead(403);
|
|
36
38
|
res.end('Domain not allowed by proxy allowlist\n');
|
|
37
39
|
return;
|
|
@@ -45,32 +47,44 @@ const server = http.createServer((req, res) => {
|
|
|
45
47
|
headers: req.headers,
|
|
46
48
|
},
|
|
47
49
|
(proxyRes) => {
|
|
50
|
+
proxyRes.on('error', (err) => console.error('[HTTP] Proxy response error:', err.message));
|
|
48
51
|
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
|
49
52
|
proxyRes.pipe(res, { end: true });
|
|
50
53
|
}
|
|
51
54
|
);
|
|
52
|
-
|
|
55
|
+
|
|
53
56
|
proxyReq.on('error', (err) => {
|
|
54
|
-
|
|
57
|
+
console.error('[HTTP] Proxy request error:', err.message);
|
|
58
|
+
if (!res.headersSent) {
|
|
59
|
+
res.writeHead(500);
|
|
60
|
+
}
|
|
55
61
|
res.end(err.message);
|
|
56
62
|
});
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
|
|
64
|
+
req.pipe(proxyReq, { end: true });
|
|
65
|
+
} catch (err) {
|
|
66
|
+
console.error('[HTTP] Error handling request:', err.message);
|
|
67
|
+
if (!res.headersSent) {
|
|
68
|
+
res.writeHead(400);
|
|
69
|
+
}
|
|
59
70
|
res.end('Bad request');
|
|
60
71
|
}
|
|
61
72
|
});
|
|
62
73
|
|
|
63
74
|
server.on('connect', (req, clientSocket, head) => {
|
|
75
|
+
clientSocket.on('error', (err) => {
|
|
76
|
+
console.error(`[HTTPS] Client socket error:`, err.message);
|
|
77
|
+
clientSocket.destroy();
|
|
78
|
+
});
|
|
79
|
+
|
|
64
80
|
try {
|
|
65
81
|
const { port, hostname } = new URL(`http://${req.url}`);
|
|
66
82
|
if (!isAllowed(hostname)) {
|
|
67
|
-
|
|
68
|
-
console.log(`[${new Date().toISOString()}] [HTTPS] Blocked: ${hostname}`);
|
|
83
|
+
console.log(`[HTTPS] Blocked: ${hostname}`);
|
|
69
84
|
clientSocket.write('HTTP/1.1 403 Forbidden\r\n\r\nDomain not allowed by proxy allowlist\n');
|
|
70
85
|
clientSocket.end();
|
|
71
86
|
return;
|
|
72
87
|
}
|
|
73
|
-
// Only log blocked domains for now
|
|
74
88
|
// console.log(`[HTTPS] Allowed: ${hostname}`);
|
|
75
89
|
|
|
76
90
|
const serverSocket = net.connect(port || 443, hostname, () => {
|
|
@@ -79,13 +93,28 @@ server.on('connect', (req, clientSocket, head) => {
|
|
|
79
93
|
serverSocket.pipe(clientSocket);
|
|
80
94
|
clientSocket.pipe(serverSocket);
|
|
81
95
|
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
|
|
97
|
+
serverSocket.on('error', (err) => {
|
|
98
|
+
console.error(`[HTTPS] Server socket error for ${hostname}:`, err.message);
|
|
99
|
+
clientSocket.destroy();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Update client error handler to also destroy serverSocket if it exists
|
|
103
|
+
clientSocket.removeAllListeners('error');
|
|
104
|
+
clientSocket.on('error', (err) => {
|
|
105
|
+
console.error(`[HTTPS] Client socket error for ${hostname}:`, err.message);
|
|
106
|
+
serverSocket.destroy();
|
|
107
|
+
});
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error(`[HTTPS] Connection error:`, err.message);
|
|
110
|
+
clientSocket.destroy();
|
|
86
111
|
}
|
|
87
112
|
});
|
|
88
113
|
|
|
114
|
+
server.on('error', (err) => {
|
|
115
|
+
console.error('Proxy server error:', err);
|
|
116
|
+
});
|
|
117
|
+
|
|
89
118
|
server.listen(8888, () => {
|
|
90
119
|
console.log('Proxy listening on port 8888');
|
|
91
120
|
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": {
|
|
3
|
+
"GEMINI.md": "seed-once",
|
|
4
|
+
".gemini/": "track",
|
|
5
|
+
"SOUL.md": "seed-once",
|
|
6
|
+
"USER.md": "seed-once",
|
|
7
|
+
"MEMORY.md": "seed-once",
|
|
8
|
+
"memory/": "seed-once",
|
|
9
|
+
"BOOTSTRAP.md": "seed-once",
|
|
10
|
+
"TOOLS.md": "seed-once",
|
|
11
|
+
"HEARTBEAT.md": "seed-once"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -21,6 +21,18 @@ clawmini-lite.js requests list
|
|
|
21
21
|
|
|
22
22
|
This will output the available policy names and their descriptions.
|
|
23
23
|
|
|
24
|
+
### Inspecting a Single Policy
|
|
25
|
+
|
|
26
|
+
To see the full definition of a policy (its underlying command, args, and flags like `autoApprove` / `allowHelp`):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
clawmini-lite.js requests show <policy-name>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The output is JSON, followed by the script body when the policy's command points at a file inside `.clawmini/policy-scripts/`. Policies that wrap a system command print only the JSON — there is no script body to show, and the daemon refuses to read paths outside `policy-scripts/`. Reading is unrestricted — no approval is needed.
|
|
33
|
+
|
|
34
|
+
If the script body is large, it is copied to `./tmp/policy-script-<name><ext>` instead of being printed inline; `requests show` will tell you the path so you can `cat` or `Read` it on demand.
|
|
35
|
+
|
|
24
36
|
### Getting Help for a Policy
|
|
25
37
|
|
|
26
38
|
If a policy supports it, you can query it for help to understand what arguments it expects:
|
|
@@ -55,34 +67,81 @@ clawmini-lite.js request send-email --file body_txt=./report.txt -- --to admin@e
|
|
|
55
67
|
|
|
56
68
|
### What Happens Next
|
|
57
69
|
|
|
58
|
-
When you submit a request, the CLI
|
|
59
|
-
|
|
70
|
+
When you submit a request, the CLI usually returns a **Request ID** without blocking. **The request has not run yet** — it is queued for the user to review, and the underlying command will only execute once the user approves it.
|
|
71
|
+
|
|
72
|
+
When the user approves (or rejects) the request, the result will arrive as a **new user message in this chat**. **Do not poll** — do not run `requests show`, re-invoke the request, or otherwise loop checking for status. Finish any unrelated work that does not depend on this request, then end your turn with a brief message explaining you are blocked on this request.
|
|
60
73
|
|
|
61
74
|
- **If Approved:** The policy executes securely, and the STDOUT/STDERR results will be automatically sent back to you in the chat.
|
|
62
75
|
- **If Rejected:** The user may provide a reason for the rejection, allowing you to correct your request and try again.
|
|
63
76
|
|
|
64
|
-
##
|
|
77
|
+
## Managing Policies
|
|
78
|
+
|
|
79
|
+
The built-in `manage-policies` policy lets you add, update, or remove policies. Each invocation goes through the same approval workflow as any other policy — the user reviews exactly which subcommand and arguments you proposed before anything mutates `policies.json`. Reads do not go through this script; use `requests show <name>` (above) for read access.
|
|
65
80
|
|
|
66
|
-
|
|
81
|
+
The script has three subcommands: `add`, `update`, `remove`.
|
|
67
82
|
|
|
68
|
-
**Important Note for Large Outputs:** If a policy or command produces massive output (like raw API JSON responses), it will overwhelm your context window. In these cases, it is strongly recommended to
|
|
83
|
+
**Important Note for Large Outputs:** If a policy or command produces massive output (like raw API JSON responses), it will overwhelm your context window. In these cases, it is strongly recommended to register a custom policy script that uses tools like `jq` to parse, filter, and condense the data _before_ it is returned to you.
|
|
69
84
|
|
|
70
|
-
|
|
85
|
+
### Adding a New Policy (`add`)
|
|
86
|
+
|
|
87
|
+
Provide a `--name` and `--description`, and either a shell `--command` or a `--script-file`. The script refuses to overwrite an existing entry — use `update` (below) if the name already exists.
|
|
88
|
+
|
|
89
|
+
By default a new policy is **safe**: every invocation requires the user to approve it, and `--help` requests are blocked. You can opt in to looser behavior with two flags — both are prefixed `--dangerously-` because the user only sees them at proposal time:
|
|
90
|
+
|
|
91
|
+
- `--dangerously-auto-approve`: future invocations of this policy run without the user reviewing each request. Only use for fully sandboxed, side-effect-free commands (e.g. read-only listings of local files). Never use for anything that mutates state, talks to the network, or spends money.
|
|
92
|
+
- `--dangerously-allow-help`: lets you (the agent) run `<policy> --help` without approval. Safe only if the underlying command actually treats `--help` as read-only — many CLIs do, but custom scripts may not.
|
|
93
|
+
|
|
94
|
+
If neither flag is set, both default to `false`. Prefer the safe default; only request the dangerous flags when you can justify them in the policy description.
|
|
71
95
|
|
|
72
96
|
**Examples:**
|
|
73
97
|
|
|
74
|
-
1. **
|
|
98
|
+
1. **A simple command wrapper (safe defaults):**
|
|
75
99
|
|
|
76
100
|
```bash
|
|
77
|
-
clawmini-lite.js request
|
|
101
|
+
clawmini-lite.js request manage-policies -- add --name npm-install --description "Run npm install globally" --command "npm install -g"
|
|
78
102
|
```
|
|
79
103
|
|
|
80
|
-
2. **
|
|
104
|
+
2. **A custom script wrapper:**
|
|
81
105
|
First, write your complex logic to a file (e.g., `./script.sh`). **Note: The script file path MUST be inside your allowed workspace directory or use relative paths.**
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
clawmini-lite.js request manage-policies --file script=./script.sh -- add --name custom-action --description "Run a custom deployment script" --script-file "{{script}}"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
3. **A read-only policy that auto-approves and exposes `--help`:**
|
|
112
|
+
|
|
82
113
|
```bash
|
|
83
|
-
clawmini-lite.js request
|
|
114
|
+
clawmini-lite.js request manage-policies -- add --name list-files --description "List files in the workspace (read-only)" --command "ls" --dangerously-auto-approve --dangerously-allow-help
|
|
84
115
|
```
|
|
85
116
|
|
|
117
|
+
### Updating an Existing Policy (`update`)
|
|
118
|
+
|
|
119
|
+
Pass only the fields you want to change. The policy's name cannot be changed (`remove` + `add` if you need a rename).
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
clawmini-lite.js request manage-policies -- update --name <policy-name> [--description "..."] [--command "..."] [--script-file "{{script}}"] [--dangerously-auto-approve | --no-dangerously-auto-approve] [--dangerously-allow-help | --no-dangerously-allow-help]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The dangerous flags use the same bare-flag style as `add`: pass `--dangerously-auto-approve` to enable, `--no-dangerously-auto-approve` to disable, or omit it to leave the field unchanged.
|
|
126
|
+
|
|
127
|
+
This refuses to update a built-in policy. If you need to override a built-in, register your own version with `add` first; subsequent updates target that override.
|
|
128
|
+
|
|
129
|
+
If the policy is currently disabled (a `false` entry from `remove --disable-builtin`), `update` will tell you to clear the disable first via `remove --name <policy-name>` (without `--disable-builtin`), then re-register with `add`.
|
|
130
|
+
|
|
131
|
+
### Removing a Policy (`remove`)
|
|
132
|
+
|
|
133
|
+
Drops a registered policy entry:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
clawmini-lite.js request manage-policies -- remove --name <policy-name>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
To opt out of a built-in (write `false` so it stops being available even if its script is installed):
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
clawmini-lite.js request manage-policies -- remove --name <builtin-name> --disable-builtin
|
|
143
|
+
```
|
|
144
|
+
|
|
86
145
|
## Creating New Skills for Policies
|
|
87
146
|
|
|
88
147
|
When you discover or use a new policy frequently, you should create a dedicated Agent Skill for it. This guides developers and future agents on how to use the policy without needing to manually look up the `--help` each time.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: run-host
|
|
3
|
+
description: Last-resort escape hatch for running arbitrary shell commands on the host. Prefer registering a dedicated policy first.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Run Host
|
|
7
|
+
|
|
8
|
+
**Before using this, register a dedicated policy.** `run-host` is a generic escape hatch that forwards a command string to `sh -c`. It exists so you are never fully blocked, but it is the wrong tool for anything you will do more than once.
|
|
9
|
+
|
|
10
|
+
For any task you can describe — running tests, installing a package, calling a specific API — use `manage-policies add` to register a named policy instead. Dedicated policies are easier for the user to review, can be auto-approved when safe, and give you a clear skill to call next time. Reach for `run-host` only when:
|
|
11
|
+
|
|
12
|
+
- You need a genuinely one-off exploratory command (e.g. inspecting an unfamiliar file), **or**
|
|
13
|
+
- You truly cannot express the task as a reusable policy.
|
|
14
|
+
|
|
15
|
+
Because it can do anything the host shell can do, the user will be asked to approve every invocation, and repeated `run-host` requests for similar tasks are a signal that you should have registered a policy.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Pass the command to run as a single string via `--command`. The string is forwarded to `sh -c`, so you can use pipes, redirection, and chained operators.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
clawmini-lite.js request run-host -- --command "<your shell command>"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Examples
|
|
26
|
+
|
|
27
|
+
1. **Simple command:**
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
clawmini-lite.js request run-host -- --command "ls -la"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
2. **Pipes and redirection:**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
clawmini-lite.js request run-host -- --command "cat file.txt | grep error > errors.log"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
3. **Chained commands:**
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
clawmini-lite.js request run-host -- --command "npm install && npm test"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Getting Help
|
|
46
|
+
|
|
47
|
+
The policy supports `--help`, which prints argument documentation:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
clawmini-lite.js request run-host --help
|
|
51
|
+
```
|
|
@@ -11,8 +11,8 @@ This document provides comprehensive instructions on how to create, structure, a
|
|
|
11
11
|
|
|
12
12
|
You can create skills in two locations depending on their intended scope:
|
|
13
13
|
|
|
14
|
-
- **Project-Specific:** Create skills in `.
|
|
15
|
-
- **Global:** Create skills in `~/.
|
|
14
|
+
- **Project-Specific:** Create skills in `.agents/skills/<skill-name>/` at the root of your project. These will only be available when working within this project.
|
|
15
|
+
- **Global:** Create skills in `~/.agents/skills/<skill-name>/` in your home directory. These will be available to agents across all projects on your machine.
|
|
16
16
|
|
|
17
17
|
## 1. Specification & Directory Structure
|
|
18
18
|
|
|
@@ -21,7 +21,7 @@ A skill is defined by a directory containing a mandatory `SKILL.md` file. The di
|
|
|
21
21
|
**Example Structure:**
|
|
22
22
|
|
|
23
23
|
```text
|
|
24
|
-
.
|
|
24
|
+
.agents/skills/my-awesome-skill/
|
|
25
25
|
├── SKILL.md # Mandatory: Contains metadata and instructions
|
|
26
26
|
├── scripts/ # Optional: Executable code or helper scripts
|
|
27
27
|
├── references/ # Optional: Documentation or long-form context
|
|
@@ -47,6 +47,7 @@ The `SKILL.md` file must begin with YAML frontmatter containing metadata, follow
|
|
|
47
47
|
- **Checklists:** Help the agent track progress in multi-step workflows.
|
|
48
48
|
- **Validation Loops:** Instruct the agent to "Plan-Validate-Execute" (especially for destructive actions) to ensure correctness before execution.
|
|
49
49
|
- **Calibrate Control:** Be highly prescriptive for fragile tasks, but allow flexibility for creative tasks. Provide clear defaults rather than a menu of options.
|
|
50
|
+
- **Skill Validation:** Once you have generated a skill, you must always validate its folder structure and frontmatter by running `.agents/skills/skill-creator/scripts/validate.sh <path_to_skill_directory>`.
|
|
50
51
|
|
|
51
52
|
## 3. Optimizing Skill Descriptions
|
|
52
53
|
|