clawmini 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gemini/settings.json +46 -0
- package/.prettierrc +7 -0
- package/GEMINI.md +11 -0
- package/README.md +137 -0
- package/dist/adapter-discord/index.d.mts +5 -0
- package/dist/adapter-discord/index.d.mts.map +1 -0
- package/dist/adapter-discord/index.mjs +456 -0
- package/dist/adapter-discord/index.mjs.map +1 -0
- package/dist/chats-DKgTeU7i.mjs +91 -0
- package/dist/chats-DKgTeU7i.mjs.map +1 -0
- package/dist/chats-Zd_HXDHx.mjs +29 -0
- package/dist/chats-Zd_HXDHx.mjs.map +1 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.mjs +850 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/cli/lite.d.mts +1 -0
- package/dist/cli/lite.mjs +4434 -0
- package/dist/cli/lite.mjs.map +1 -0
- package/dist/daemon/index.d.mts +5 -0
- package/dist/daemon/index.d.mts.map +1 -0
- package/dist/daemon/index.mjs +1222 -0
- package/dist/daemon/index.mjs.map +1 -0
- package/dist/fetch-BjZVyU3Z.mjs +37 -0
- package/dist/fetch-BjZVyU3Z.mjs.map +1 -0
- package/dist/fs-B5wW0oaH.mjs +14 -0
- package/dist/fs-B5wW0oaH.mjs.map +1 -0
- package/dist/lite-Dl7WXyaH.mjs +80 -0
- package/dist/lite-Dl7WXyaH.mjs.map +1 -0
- package/dist/rolldown-runtime-95iHPtFO.mjs +18 -0
- package/dist/web/_app/env.js +1 -0
- package/dist/web/_app/immutable/assets/0.GI4C4dpV.css +1 -0
- package/dist/web/_app/immutable/chunks/B5abRDXp.js +1 -0
- package/dist/web/_app/immutable/chunks/B8yYFADm.js +1 -0
- package/dist/web/_app/immutable/chunks/BPy8HLo7.js +5 -0
- package/dist/web/_app/immutable/chunks/Bi0jeV7Q.js +1 -0
- package/dist/web/_app/immutable/chunks/BmUXQ3wy.js +2 -0
- package/dist/web/_app/immutable/chunks/C3k55nDF.js +1 -0
- package/dist/web/_app/immutable/chunks/COekwvP2.js +1 -0
- package/dist/web/_app/immutable/chunks/CSvS_NwK.js +1 -0
- package/dist/web/_app/immutable/chunks/CpaGRn9L.js +1 -0
- package/dist/web/_app/immutable/chunks/CyNaE55B.js +1 -0
- package/dist/web/_app/immutable/chunks/DG5RZBw-.js +2 -0
- package/dist/web/_app/immutable/chunks/Dc-UOHw9.js +1 -0
- package/dist/web/_app/immutable/chunks/DcrmIfTj.js +1 -0
- package/dist/web/_app/immutable/chunks/ZkLyk0mE.js +1 -0
- package/dist/web/_app/immutable/entry/app.B-vZe7PN.js +2 -0
- package/dist/web/_app/immutable/entry/start.oP1AgKhs.js +1 -0
- package/dist/web/_app/immutable/nodes/0.B5WFN0zw.js +1 -0
- package/dist/web/_app/immutable/nodes/1.D1wtJb2k.js +1 -0
- package/dist/web/_app/immutable/nodes/2.CK3CLC0f.js +1 -0
- package/dist/web/_app/immutable/nodes/3.BB5wCoBf.js +4 -0
- package/dist/web/_app/immutable/nodes/4.Dr2jvAXK.js +1 -0
- package/dist/web/_app/immutable/nodes/5.BJl7oM3b.js +1 -0
- package/dist/web/_app/version.json +1 -0
- package/dist/web/index.html +37 -0
- package/dist/web/robots.txt +3 -0
- package/dist/workspace-CSgfo_2J.mjs +383 -0
- package/dist/workspace-CSgfo_2J.mjs.map +1 -0
- package/docs/01_chats/development_log.md +36 -0
- package/docs/01_chats/notes.md +27 -0
- package/docs/01_chats/prd.md +47 -0
- package/docs/01_chats/questions.md +19 -0
- package/docs/01_chats/tickets.md +67 -0
- package/docs/02_sessions/development_log.md +79 -0
- package/docs/02_sessions/notes.md +40 -0
- package/docs/02_sessions/prd.md +75 -0
- package/docs/02_sessions/questions.md +7 -0
- package/docs/02_sessions/tickets.md +68 -0
- package/docs/03_web_interface/development_log.md +60 -0
- package/docs/03_web_interface/notes.md +29 -0
- package/docs/03_web_interface/prd.md +42 -0
- package/docs/03_web_interface/questions.md +8 -0
- package/docs/03_web_interface/tickets.md +59 -0
- package/docs/04_agents/development_log.md +54 -0
- package/docs/04_agents/notes.md +45 -0
- package/docs/04_agents/prd.md +47 -0
- package/docs/04_agents/questions.md +13 -0
- package/docs/04_agents/tickets.md +107 -0
- package/docs/05_routers/development_log.md +13 -0
- package/docs/05_routers/notes.md +40 -0
- package/docs/05_routers/prd.md +55 -0
- package/docs/05_routers/questions.md +21 -0
- package/docs/05_routers/tickets.md +109 -0
- package/docs/06_agent_templates/development_log.md +38 -0
- package/docs/06_agent_templates/notes.md +25 -0
- package/docs/06_agent_templates/prd.md +34 -0
- package/docs/06_agent_templates/questions.md +11 -0
- package/docs/06_agent_templates/tickets.md +49 -0
- package/docs/06_cron/development_log.md +51 -0
- package/docs/06_cron/notes.md +14 -0
- package/docs/06_cron/prd.md +92 -0
- package/docs/06_cron/questions.md +15 -0
- package/docs/06_cron/tickets.md +75 -0
- package/docs/07_web_chat_ux/development_log.md +30 -0
- package/docs/07_web_chat_ux/notes.md +25 -0
- package/docs/07_web_chat_ux/prd.md +46 -0
- package/docs/07_web_chat_ux/questions.md +7 -0
- package/docs/07_web_chat_ux/tickets.md +48 -0
- package/docs/08_agent_api/development_log.md +52 -0
- package/docs/08_agent_api/notes.md +31 -0
- package/docs/08_agent_api/prd.md +56 -0
- package/docs/08_agent_api/questions.md +14 -0
- package/docs/08_agent_api/tickets.md +104 -0
- package/docs/09_agent_fallbacks/development_log.md +52 -0
- package/docs/09_agent_fallbacks/notes.md +40 -0
- package/docs/09_agent_fallbacks/prd.md +55 -0
- package/docs/09_agent_fallbacks/questions.md +10 -0
- package/docs/09_agent_fallbacks/tickets.md +88 -0
- package/docs/09_discord_adapter/development_log.md +95 -0
- package/docs/09_discord_adapter/notes.md +18 -0
- package/docs/09_discord_adapter/prd.md +57 -0
- package/docs/09_discord_adapter/questions.md +16 -0
- package/docs/09_discord_adapter/tickets.md +116 -0
- package/docs/10_file_attachments/development_log.md +55 -0
- package/docs/10_file_attachments/notes.md +59 -0
- package/docs/10_file_attachments/prd.md +73 -0
- package/docs/10_file_attachments/questions.md +15 -0
- package/docs/10_file_attachments/tickets.md +88 -0
- package/docs/11_message_verbosity/development_log.md +43 -0
- package/docs/11_message_verbosity/notes.md +26 -0
- package/docs/11_message_verbosity/prd.md +44 -0
- package/docs/11_message_verbosity/questions.md +8 -0
- package/docs/11_message_verbosity/tickets.md +33 -0
- package/docs/12_environments/development_log.md +43 -0
- package/docs/12_environments/notes.md +45 -0
- package/docs/12_environments/prd.md +113 -0
- package/docs/12_environments/questions.md +17 -0
- package/docs/12_environments/tickets.md +87 -0
- package/docs/12_setup_flow_improvements/development_log.md +40 -0
- package/docs/12_setup_flow_improvements/notes.md +34 -0
- package/docs/12_setup_flow_improvements/prd.md +35 -0
- package/docs/12_setup_flow_improvements/questions.md +8 -0
- package/docs/12_setup_flow_improvements/tickets.md +122 -0
- package/docs/13_discord_typing_indicators/development_log.md +38 -0
- package/docs/13_discord_typing_indicators/notes.md +18 -0
- package/docs/13_discord_typing_indicators/prd.md +41 -0
- package/docs/13_discord_typing_indicators/questions.md +6 -0
- package/docs/13_discord_typing_indicators/tickets.md +60 -0
- package/docs/14_interruptions/development_log.md +50 -0
- package/docs/14_interruptions/notes.md +38 -0
- package/docs/14_interruptions/prd.md +46 -0
- package/docs/14_interruptions/questions.md +12 -0
- package/docs/14_interruptions/tickets.md +69 -0
- package/docs/15_sandbox_policies/development_log.md +95 -0
- package/docs/15_sandbox_policies/notes.md +33 -0
- package/docs/15_sandbox_policies/prd.md +163 -0
- package/docs/15_sandbox_policies/questions.md +10 -0
- package/docs/15_sandbox_policies/tickets.md +196 -0
- package/docs/CHECKS.md +9 -0
- package/docs/guides/discord_adapter_setup.md +69 -0
- package/docs/guides/sandbox_policies.md +76 -0
- package/eslint.config.js +47 -0
- package/napkin.md +21 -0
- package/package.json +50 -0
- package/scripts/create_worktree.sh +49 -0
- package/scripts/get_pr_comments.sh +36 -0
- package/src/adapter-discord/client.test.ts +65 -0
- package/src/adapter-discord/client.ts +41 -0
- package/src/adapter-discord/config.test.ts +156 -0
- package/src/adapter-discord/config.ts +61 -0
- package/src/adapter-discord/forwarder.test.ts +493 -0
- package/src/adapter-discord/forwarder.ts +246 -0
- package/src/adapter-discord/index.test.ts +399 -0
- package/src/adapter-discord/index.ts +147 -0
- package/src/adapter-discord/state.test.ts +65 -0
- package/src/adapter-discord/state.ts +44 -0
- package/src/cli/client.ts +46 -0
- package/src/cli/commands/agents.ts +138 -0
- package/src/cli/commands/chats.ts +79 -0
- package/src/cli/commands/down.ts +32 -0
- package/src/cli/commands/environments.ts +39 -0
- package/src/cli/commands/export-lite.ts +62 -0
- package/src/cli/commands/init.ts +79 -0
- package/src/cli/commands/jobs.ts +141 -0
- package/src/cli/commands/messages.ts +103 -0
- package/src/cli/commands/up.ts +26 -0
- package/src/cli/commands/web-api/agents.ts +138 -0
- package/src/cli/commands/web-api/chats.ts +213 -0
- package/src/cli/commands/web-api/utils.ts +27 -0
- package/src/cli/commands/web.ts +105 -0
- package/src/cli/e2e/adapter-discord.test.ts +76 -0
- package/src/cli/e2e/agents.test.ts +140 -0
- package/src/cli/e2e/basic.test.ts +43 -0
- package/src/cli/e2e/cron.test.ts +132 -0
- package/src/cli/e2e/daemon.test.ts +293 -0
- package/src/cli/e2e/environments.test.ts +66 -0
- package/src/cli/e2e/export-lite-func.test.ts +155 -0
- package/src/cli/e2e/export-lite.test.ts +51 -0
- package/src/cli/e2e/fallbacks.test.ts +169 -0
- package/src/cli/e2e/global-setup.ts +15 -0
- package/src/cli/e2e/init.test.ts +70 -0
- package/src/cli/e2e/messages.test.ts +294 -0
- package/src/cli/e2e/requests.test.ts +165 -0
- package/src/cli/e2e/utils.ts +66 -0
- package/src/cli/index.test.ts +7 -0
- package/src/cli/index.ts +29 -0
- package/src/cli/lite.ts +247 -0
- package/src/cli/utils.ts +4 -0
- package/src/daemon/auth.test.ts +50 -0
- package/src/daemon/auth.ts +69 -0
- package/src/daemon/chats.ts +26 -0
- package/src/daemon/cron.test.ts +28 -0
- package/src/daemon/cron.ts +159 -0
- package/src/daemon/events.ts +15 -0
- package/src/daemon/index.ts +212 -0
- package/src/daemon/message-agent.test.ts +132 -0
- package/src/daemon/message-extraction.test.ts +166 -0
- package/src/daemon/message-fallbacks.test.ts +313 -0
- package/src/daemon/message-interruption.test.ts +125 -0
- package/src/daemon/message-queue.test.ts +143 -0
- package/src/daemon/message-router.test.ts +106 -0
- package/src/daemon/message-session.test.ts +127 -0
- package/src/daemon/message-test-utils.ts +41 -0
- package/src/daemon/message-typing.test.ts +93 -0
- package/src/daemon/message-verbosity.test.ts +127 -0
- package/src/daemon/message.ts +600 -0
- package/src/daemon/observation.test.ts +118 -0
- package/src/daemon/policy-request-service.test.ts +87 -0
- package/src/daemon/policy-request-service.ts +62 -0
- package/src/daemon/policy-utils.test.ts +138 -0
- package/src/daemon/policy-utils.ts +152 -0
- package/src/daemon/queue.test.ts +89 -0
- package/src/daemon/queue.ts +87 -0
- package/src/daemon/request-store.test.ts +103 -0
- package/src/daemon/request-store.ts +96 -0
- package/src/daemon/router-policy-request.test.ts +99 -0
- package/src/daemon/router.test.ts +380 -0
- package/src/daemon/router.ts +510 -0
- package/src/daemon/routers/slash-command.test.ts +145 -0
- package/src/daemon/routers/slash-command.ts +58 -0
- package/src/daemon/routers/slash-interrupt.test.ts +30 -0
- package/src/daemon/routers/slash-interrupt.ts +7 -0
- package/src/daemon/routers/slash-new.test.ts +59 -0
- package/src/daemon/routers/slash-new.ts +14 -0
- package/src/daemon/routers/slash-policies.test.ts +167 -0
- package/src/daemon/routers/slash-policies.ts +131 -0
- package/src/daemon/routers/slash-stop.test.ts +30 -0
- package/src/daemon/routers/slash-stop.ts +3 -0
- package/src/daemon/routers/types.ts +10 -0
- package/src/daemon/routers/utils.ts +22 -0
- package/src/daemon/routers.test.ts +141 -0
- package/src/daemon/routers.ts +115 -0
- package/src/daemon/utils/spawn.ts +61 -0
- package/src/shared/agent-utils.ts +30 -0
- package/src/shared/chats.test.ts +112 -0
- package/src/shared/chats.ts +164 -0
- package/src/shared/config.test.ts +90 -0
- package/src/shared/config.ts +100 -0
- package/src/shared/event-source.ts +121 -0
- package/src/shared/fetch.ts +45 -0
- package/src/shared/lite.ts +129 -0
- package/src/shared/policies.ts +24 -0
- package/src/shared/utils/env.ts +27 -0
- package/src/shared/utils/fs.ts +13 -0
- package/src/shared/workspace.test.ts +345 -0
- package/src/shared/workspace.ts +500 -0
- package/templates/environments/cladding/env.json +7 -0
- package/templates/environments/macos/env.json +8 -0
- package/templates/environments/macos/sandbox.sb +21 -0
- package/templates/environments/macos-proxy/allowlist.txt +1 -0
- package/templates/environments/macos-proxy/env.json +14 -0
- package/templates/environments/macos-proxy/proxy.mjs +86 -0
- package/templates/environments/macos-proxy/sandbox.sb +34 -0
- package/templates/gemini/settings.json +11 -0
- package/templates/gemini-claw/.gemini/hooks/clawmini-logging.sh +17 -0
- package/templates/gemini-claw/.gemini/settings.json +24 -0
- package/templates/gemini-claw/.gemini/skills/clawmini-jobs/SKILL.md +40 -0
- package/templates/gemini-claw/.gemini/system.md +98 -0
- package/templates/gemini-claw/BOOTSTRAP.md +54 -0
- package/templates/gemini-claw/GEMINI.md +107 -0
- package/templates/gemini-claw/HEARTBEAT.md +3 -0
- package/templates/gemini-claw/MEMORY.md +2 -0
- package/templates/gemini-claw/SOUL.md +42 -0
- package/templates/gemini-claw/TOOLS.md +38 -0
- package/templates/gemini-claw/USER.md +15 -0
- package/templates/gemini-claw/memory/.gitkeep +0 -0
- package/templates/gemini-claw/settings.json +24 -0
- package/templates/opencode/settings.json +11 -0
- package/tsconfig.json +42 -0
- package/tsdown.config.ts +19 -0
- package/vitest.config.ts +9 -0
- package/web/.svelte-kit/ambient.d.ts +382 -0
- package/web/.svelte-kit/generated/client/app.js +35 -0
- package/web/.svelte-kit/generated/client/matchers.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/0.js +3 -0
- package/web/.svelte-kit/generated/client/nodes/1.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/2.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/3.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/4.js +3 -0
- package/web/.svelte-kit/generated/client/nodes/5.js +3 -0
- package/web/.svelte-kit/generated/client-optimized/app.js +35 -0
- package/web/.svelte-kit/generated/client-optimized/matchers.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/0.js +3 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/1.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/2.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/3.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/4.js +3 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/5.js +3 -0
- package/web/.svelte-kit/generated/root.js +3 -0
- package/web/.svelte-kit/generated/root.svelte +68 -0
- package/web/.svelte-kit/generated/server/internal.js +53 -0
- package/web/.svelte-kit/non-ambient.d.ts +46 -0
- package/web/.svelte-kit/output/client/.vite/manifest.json +251 -0
- package/web/.svelte-kit/output/client/_app/immutable/assets/0.GI4C4dpV.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B5abRDXp.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B8yYFADm.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BPy8HLo7.js +5 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Bi0jeV7Q.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BmUXQ3wy.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/C3k55nDF.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/COekwvP2.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CSvS_NwK.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CpaGRn9L.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CyNaE55B.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DG5RZBw-.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Dc-UOHw9.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DcrmIfTj.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/ZkLyk0mE.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.B-vZe7PN.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.oP1AgKhs.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/0.B5WFN0zw.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.D1wtJb2k.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/2.CK3CLC0f.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/3.BB5wCoBf.js +4 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.Dr2jvAXK.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/5.BJl7oM3b.js +1 -0
- package/web/.svelte-kit/output/client/_app/version.json +1 -0
- package/web/.svelte-kit/output/client/robots.txt +3 -0
- package/web/.svelte-kit/output/prerendered/dependencies/_app/env.js +1 -0
- package/web/.svelte-kit/output/server/.vite/manifest.json +215 -0
- package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.GI4C4dpV.css +1 -0
- package/web/.svelte-kit/output/server/chunks/Icon.js +153 -0
- package/web/.svelte-kit/output/server/chunks/bot.js +2753 -0
- package/web/.svelte-kit/output/server/chunks/client.js +47 -0
- package/web/.svelte-kit/output/server/chunks/environment.js +34 -0
- package/web/.svelte-kit/output/server/chunks/exports.js +231 -0
- package/web/.svelte-kit/output/server/chunks/false.js +4 -0
- package/web/.svelte-kit/output/server/chunks/index-server.js +20 -0
- package/web/.svelte-kit/output/server/chunks/index.js +24 -0
- package/web/.svelte-kit/output/server/chunks/internal.js +133 -0
- package/web/.svelte-kit/output/server/chunks/plus.js +81 -0
- package/web/.svelte-kit/output/server/chunks/root.js +4076 -0
- package/web/.svelte-kit/output/server/chunks/shared.js +789 -0
- package/web/.svelte-kit/output/server/chunks/utils.js +43 -0
- package/web/.svelte-kit/output/server/entries/fallbacks/error.svelte.js +11 -0
- package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +3944 -0
- package/web/.svelte-kit/output/server/entries/pages/_layout.ts.js +28 -0
- package/web/.svelte-kit/output/server/entries/pages/_page.svelte.js +7 -0
- package/web/.svelte-kit/output/server/entries/pages/agents/_page.svelte.js +379 -0
- package/web/.svelte-kit/output/server/entries/pages/chats/_id_/_page.svelte.js +292 -0
- package/web/.svelte-kit/output/server/entries/pages/chats/_id_/_page.ts.js +17 -0
- package/web/.svelte-kit/output/server/entries/pages/chats/_id_/settings/_page.svelte.js +259 -0
- package/web/.svelte-kit/output/server/entries/pages/chats/_id_/settings/_page.ts.js +17 -0
- package/web/.svelte-kit/output/server/index.js +3748 -0
- package/web/.svelte-kit/output/server/internal.js +14 -0
- package/web/.svelte-kit/output/server/manifest-full.js +63 -0
- package/web/.svelte-kit/output/server/manifest.js +63 -0
- package/web/.svelte-kit/output/server/nodes/0.js +13 -0
- package/web/.svelte-kit/output/server/nodes/1.js +8 -0
- package/web/.svelte-kit/output/server/nodes/2.js +8 -0
- package/web/.svelte-kit/output/server/nodes/3.js +8 -0
- package/web/.svelte-kit/output/server/nodes/4.js +13 -0
- package/web/.svelte-kit/output/server/nodes/5.js +13 -0
- package/web/.svelte-kit/output/server/remote-entry.js +557 -0
- package/web/.svelte-kit/tsconfig.json +67 -0
- package/web/.svelte-kit/types/route_meta_data.json +17 -0
- package/web/.svelte-kit/types/src/routes/$types.d.ts +26 -0
- package/web/.svelte-kit/types/src/routes/agents/$types.d.ts +18 -0
- package/web/.svelte-kit/types/src/routes/chats/[id]/$types.d.ts +21 -0
- package/web/.svelte-kit/types/src/routes/chats/[id]/proxy+page.ts +20 -0
- package/web/.svelte-kit/types/src/routes/chats/[id]/settings/$types.d.ts +21 -0
- package/web/.svelte-kit/types/src/routes/chats/[id]/settings/proxy+page.ts +19 -0
- package/web/.svelte-kit/types/src/routes/proxy+layout.ts +35 -0
- package/web/README.md +42 -0
- package/web/components.json +16 -0
- package/web/package.json +41 -0
- package/web/src/app.css +121 -0
- package/web/src/app.d.ts +13 -0
- package/web/src/app.html +11 -0
- package/web/src/demo.spec.ts +7 -0
- package/web/src/lib/app-state.svelte.ts +3 -0
- package/web/src/lib/assets/favicon.svg +1 -0
- package/web/src/lib/components/app/app-sidebar-test-wrapper.svelte +10 -0
- package/web/src/lib/components/app/app-sidebar.svelte +171 -0
- package/web/src/lib/components/app/app-sidebar.svelte.spec.ts +13 -0
- package/web/src/lib/components/ui/button/button.svelte +82 -0
- package/web/src/lib/components/ui/button/index.ts +17 -0
- package/web/src/lib/components/ui/dialog/dialog-close.svelte +7 -0
- package/web/src/lib/components/ui/dialog/dialog-content.svelte +45 -0
- package/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
- package/web/src/lib/components/ui/dialog/dialog-footer.svelte +20 -0
- package/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
- package/web/src/lib/components/ui/dialog/dialog-overlay.svelte +20 -0
- package/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
- package/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
- package/web/src/lib/components/ui/dialog/dialog-trigger.svelte +7 -0
- package/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
- package/web/src/lib/components/ui/dialog/index.ts +34 -0
- package/web/src/lib/components/ui/input/index.ts +7 -0
- package/web/src/lib/components/ui/input/input.svelte +52 -0
- package/web/src/lib/components/ui/separator/index.ts +7 -0
- package/web/src/lib/components/ui/separator/separator.svelte +21 -0
- package/web/src/lib/components/ui/sheet/index.ts +34 -0
- package/web/src/lib/components/ui/sheet/sheet-close.svelte +7 -0
- package/web/src/lib/components/ui/sheet/sheet-content.svelte +60 -0
- package/web/src/lib/components/ui/sheet/sheet-description.svelte +17 -0
- package/web/src/lib/components/ui/sheet/sheet-footer.svelte +20 -0
- package/web/src/lib/components/ui/sheet/sheet-header.svelte +20 -0
- package/web/src/lib/components/ui/sheet/sheet-overlay.svelte +20 -0
- package/web/src/lib/components/ui/sheet/sheet-portal.svelte +7 -0
- package/web/src/lib/components/ui/sheet/sheet-title.svelte +17 -0
- package/web/src/lib/components/ui/sheet/sheet-trigger.svelte +7 -0
- package/web/src/lib/components/ui/sheet/sheet.svelte +7 -0
- package/web/src/lib/components/ui/sidebar/constants.ts +6 -0
- package/web/src/lib/components/ui/sidebar/context.svelte.ts +79 -0
- package/web/src/lib/components/ui/sidebar/index.ts +75 -0
- package/web/src/lib/components/ui/sidebar/sidebar-content.svelte +24 -0
- package/web/src/lib/components/ui/sidebar/sidebar-footer.svelte +21 -0
- package/web/src/lib/components/ui/sidebar/sidebar-group-action.svelte +36 -0
- package/web/src/lib/components/ui/sidebar/sidebar-group-content.svelte +21 -0
- package/web/src/lib/components/ui/sidebar/sidebar-group-label.svelte +34 -0
- package/web/src/lib/components/ui/sidebar/sidebar-group.svelte +21 -0
- package/web/src/lib/components/ui/sidebar/sidebar-header.svelte +21 -0
- package/web/src/lib/components/ui/sidebar/sidebar-input.svelte +21 -0
- package/web/src/lib/components/ui/sidebar/sidebar-inset.svelte +24 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu-action.svelte +43 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu-badge.svelte +29 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu-button.svelte +103 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu-item.svelte +21 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte +36 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte +43 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte +21 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu-sub.svelte +25 -0
- package/web/src/lib/components/ui/sidebar/sidebar-menu.svelte +21 -0
- package/web/src/lib/components/ui/sidebar/sidebar-provider.svelte +53 -0
- package/web/src/lib/components/ui/sidebar/sidebar-rail.svelte +36 -0
- package/web/src/lib/components/ui/sidebar/sidebar-separator.svelte +19 -0
- package/web/src/lib/components/ui/sidebar/sidebar-trigger.svelte +35 -0
- package/web/src/lib/components/ui/sidebar/sidebar.svelte +104 -0
- package/web/src/lib/components/ui/skeleton/index.ts +7 -0
- package/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
- package/web/src/lib/components/ui/switch/index.ts +7 -0
- package/web/src/lib/components/ui/switch/switch.svelte +29 -0
- package/web/src/lib/components/ui/textarea/index.ts +7 -0
- package/web/src/lib/components/ui/textarea/textarea.svelte +23 -0
- package/web/src/lib/components/ui/tooltip/index.ts +19 -0
- package/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
- package/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
- package/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
- package/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
- package/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
- package/web/src/lib/hooks/is-mobile.svelte.ts +9 -0
- package/web/src/lib/index.ts +1 -0
- package/web/src/lib/types.ts +23 -0
- package/web/src/lib/utils.ts +13 -0
- package/web/src/routes/+layout.svelte +67 -0
- package/web/src/routes/+layout.ts +34 -0
- package/web/src/routes/+page.svelte +7 -0
- package/web/src/routes/agents/+page.svelte +206 -0
- package/web/src/routes/chats/[id]/+page.svelte +406 -0
- package/web/src/routes/chats/[id]/+page.ts +19 -0
- package/web/src/routes/chats/[id]/page.svelte.spec.ts +102 -0
- package/web/src/routes/chats/[id]/settings/+page.svelte +165 -0
- package/web/src/routes/chats/[id]/settings/+page.ts +18 -0
- package/web/src/routes/page.svelte.spec.ts +13 -0
- package/web/static/robots.txt +3 -0
- package/web/svelte.config.js +21 -0
- package/web/tsconfig.json +20 -0
- package/web/vite.config.ts +41 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import fsPromises from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import {
|
|
8
|
+
type Agent,
|
|
9
|
+
AgentSchema,
|
|
10
|
+
type ChatSettings,
|
|
11
|
+
ChatSettingsSchema,
|
|
12
|
+
type AgentSessionSettings,
|
|
13
|
+
AgentSessionSettingsSchema,
|
|
14
|
+
type Environment,
|
|
15
|
+
EnvironmentSchema,
|
|
16
|
+
type Settings,
|
|
17
|
+
SettingsSchema,
|
|
18
|
+
} from './config.js';
|
|
19
|
+
import { pathIsInsideDir } from './utils/fs.js';
|
|
20
|
+
|
|
21
|
+
export function getWorkspaceRoot(startDir = process.cwd()): string {
|
|
22
|
+
let curr = startDir;
|
|
23
|
+
while (curr !== path.parse(curr).root) {
|
|
24
|
+
if (fs.existsSync(path.join(curr, '.clawmini'))) {
|
|
25
|
+
return curr;
|
|
26
|
+
}
|
|
27
|
+
if (fs.existsSync(path.join(curr, 'package.json')) || fs.existsSync(path.join(curr, '.git'))) {
|
|
28
|
+
return curr;
|
|
29
|
+
}
|
|
30
|
+
curr = path.dirname(curr);
|
|
31
|
+
}
|
|
32
|
+
return startDir;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function resolveAgentWorkDir(
|
|
36
|
+
agentId: string,
|
|
37
|
+
customDir?: string,
|
|
38
|
+
startDir = process.cwd()
|
|
39
|
+
): string {
|
|
40
|
+
const workspaceRoot = getWorkspaceRoot(startDir);
|
|
41
|
+
const dirPath = customDir
|
|
42
|
+
? path.resolve(workspaceRoot, customDir)
|
|
43
|
+
: path.resolve(workspaceRoot, agentId);
|
|
44
|
+
|
|
45
|
+
if (!pathIsInsideDir(dirPath, workspaceRoot, { allowSameDir: true })) {
|
|
46
|
+
throw new Error('Invalid agent directory: resolves outside the workspace.');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return dirPath;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function ensureAgentWorkDir(
|
|
53
|
+
agentId: string,
|
|
54
|
+
customDir?: string,
|
|
55
|
+
startDir = process.cwd()
|
|
56
|
+
): Promise<string> {
|
|
57
|
+
const dirPath = resolveAgentWorkDir(agentId, customDir, startDir);
|
|
58
|
+
|
|
59
|
+
if (!fs.existsSync(dirPath)) {
|
|
60
|
+
await fsPromises.mkdir(dirPath, { recursive: true });
|
|
61
|
+
console.log(`Created agent working directory at ${dirPath}`);
|
|
62
|
+
}
|
|
63
|
+
return dirPath;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getClawminiDir(startDir = process.cwd()): string {
|
|
67
|
+
return path.join(getWorkspaceRoot(startDir), '.clawmini');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function getSocketPath(startDir = process.cwd()): string {
|
|
71
|
+
return path.join(getClawminiDir(startDir), 'server.sock');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function getSettingsPath(startDir = process.cwd()): string {
|
|
75
|
+
return path.join(getClawminiDir(startDir), 'settings.json');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getPoliciesPath(startDir = process.cwd()): string {
|
|
79
|
+
return path.join(getClawminiDir(startDir), 'policies.json');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function getChatSettingsPath(chatId: string, startDir = process.cwd()): string {
|
|
83
|
+
return path.join(getClawminiDir(startDir), 'chats', chatId, 'settings.json');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function isValidAgentId(agentId: string): boolean {
|
|
87
|
+
if (!agentId || agentId.length === 0) return false;
|
|
88
|
+
return /^[a-zA-Z0-9_]+(?:-[a-zA-Z0-9_]+)*$/.test(agentId);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getAgentDir(agentId: string, startDir = process.cwd()): string {
|
|
92
|
+
if (!isValidAgentId(agentId)) {
|
|
93
|
+
throw new Error(`Invalid agent ID: ${agentId}`);
|
|
94
|
+
}
|
|
95
|
+
return path.join(getClawminiDir(startDir), 'agents', agentId);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function getAgentSettingsPath(agentId: string, startDir = process.cwd()): string {
|
|
99
|
+
return path.join(getAgentDir(agentId, startDir), 'settings.json');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function getAgentSessionSettingsPath(
|
|
103
|
+
agentId: string,
|
|
104
|
+
sessionId: string,
|
|
105
|
+
startDir = process.cwd()
|
|
106
|
+
): string {
|
|
107
|
+
if (!isValidAgentId(agentId)) {
|
|
108
|
+
throw new Error(`Invalid agent ID: ${agentId}`);
|
|
109
|
+
}
|
|
110
|
+
return path.join(
|
|
111
|
+
getClawminiDir(startDir),
|
|
112
|
+
'agents',
|
|
113
|
+
agentId,
|
|
114
|
+
'sessions',
|
|
115
|
+
sessionId,
|
|
116
|
+
'settings.json'
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function readJsonFile(filePath: string): Promise<Record<string, unknown> | null> {
|
|
121
|
+
try {
|
|
122
|
+
const data = await fsPromises.readFile(filePath, 'utf-8');
|
|
123
|
+
return JSON.parse(data) as Record<string, unknown>;
|
|
124
|
+
} catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function writeJsonFile(filePath: string, data: Record<string, unknown>): Promise<void> {
|
|
130
|
+
const dir = path.dirname(filePath);
|
|
131
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
132
|
+
await fsPromises.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function readChatSettings(
|
|
136
|
+
chatId: string,
|
|
137
|
+
startDir = process.cwd()
|
|
138
|
+
): Promise<ChatSettings | null> {
|
|
139
|
+
const data = await readJsonFile(getChatSettingsPath(chatId, startDir));
|
|
140
|
+
if (!data) return null;
|
|
141
|
+
const parsed = ChatSettingsSchema.safeParse(data);
|
|
142
|
+
return parsed.success ? parsed.data : null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export async function writeChatSettings(
|
|
146
|
+
chatId: string,
|
|
147
|
+
data: ChatSettings,
|
|
148
|
+
startDir = process.cwd()
|
|
149
|
+
): Promise<void> {
|
|
150
|
+
await writeJsonFile(getChatSettingsPath(chatId, startDir), data as Record<string, unknown>);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function readAgentSessionSettings(
|
|
154
|
+
agentId: string,
|
|
155
|
+
sessionId: string,
|
|
156
|
+
startDir = process.cwd()
|
|
157
|
+
): Promise<AgentSessionSettings | null> {
|
|
158
|
+
const data = await readJsonFile(getAgentSessionSettingsPath(agentId, sessionId, startDir));
|
|
159
|
+
if (!data) return null;
|
|
160
|
+
const parsed = AgentSessionSettingsSchema.safeParse(data);
|
|
161
|
+
return parsed.success ? parsed.data : null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export async function writeAgentSessionSettings(
|
|
165
|
+
agentId: string,
|
|
166
|
+
sessionId: string,
|
|
167
|
+
data: AgentSessionSettings,
|
|
168
|
+
startDir = process.cwd()
|
|
169
|
+
): Promise<void> {
|
|
170
|
+
await writeJsonFile(
|
|
171
|
+
getAgentSessionSettingsPath(agentId, sessionId, startDir),
|
|
172
|
+
data as Record<string, unknown>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function getAgent(agentId: string, startDir = process.cwd()): Promise<Agent | null> {
|
|
177
|
+
const filePath = getAgentSettingsPath(agentId, startDir);
|
|
178
|
+
let dataStr: string;
|
|
179
|
+
try {
|
|
180
|
+
dataStr = await fsPromises.readFile(filePath, 'utf-8');
|
|
181
|
+
} catch (err: unknown) {
|
|
182
|
+
if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT') return null;
|
|
183
|
+
throw err;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let data: unknown;
|
|
187
|
+
try {
|
|
188
|
+
data = JSON.parse(dataStr);
|
|
189
|
+
} catch (parseErr: unknown) {
|
|
190
|
+
const message = parseErr instanceof Error ? parseErr.message : String(parseErr);
|
|
191
|
+
throw new Error(`Invalid JSON in ${filePath}: ${message}`, { cause: parseErr });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const parsed = AgentSchema.safeParse(data);
|
|
195
|
+
if (!parsed.success) {
|
|
196
|
+
throw new Error(`Invalid schema in ${filePath}: ${parsed.error.message}`);
|
|
197
|
+
}
|
|
198
|
+
return parsed.data;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export async function writeAgentSettings(
|
|
202
|
+
agentId: string,
|
|
203
|
+
data: Agent,
|
|
204
|
+
startDir = process.cwd()
|
|
205
|
+
): Promise<void> {
|
|
206
|
+
await ensureAgentWorkDir(agentId, data.directory, startDir);
|
|
207
|
+
await writeJsonFile(getAgentSettingsPath(agentId, startDir), data as Record<string, unknown>);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function listAgents(startDir = process.cwd()): Promise<string[]> {
|
|
211
|
+
const agentsDir = path.join(getClawminiDir(startDir), 'agents');
|
|
212
|
+
try {
|
|
213
|
+
const entries = await fsPromises.readdir(agentsDir, { withFileTypes: true });
|
|
214
|
+
const agentIds = [];
|
|
215
|
+
for (const entry of entries) {
|
|
216
|
+
if (entry.isDirectory()) {
|
|
217
|
+
const settingsPath = path.join(agentsDir, entry.name, 'settings.json');
|
|
218
|
+
try {
|
|
219
|
+
await fsPromises.access(settingsPath);
|
|
220
|
+
agentIds.push(entry.name);
|
|
221
|
+
} catch {
|
|
222
|
+
// No settings.json, probably just a sessions dir for a non-existent agent or default agent
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return agentIds;
|
|
227
|
+
} catch {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export async function deleteAgent(agentId: string, startDir = process.cwd()): Promise<void> {
|
|
233
|
+
const dir = getAgentDir(agentId, startDir);
|
|
234
|
+
const agentsDir = path.join(getClawminiDir(startDir), 'agents');
|
|
235
|
+
|
|
236
|
+
if (!pathIsInsideDir(dir, agentsDir)) {
|
|
237
|
+
throw new Error(`Security Error: Cannot delete agent directory outside of ${agentsDir}`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
await fsPromises.rm(dir, { recursive: true, force: true });
|
|
242
|
+
} catch {
|
|
243
|
+
// Ignore if not found
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async function isDirectory(dirPath: string): Promise<boolean> {
|
|
248
|
+
try {
|
|
249
|
+
const stat = await fsPromises.stat(dirPath);
|
|
250
|
+
return stat.isDirectory();
|
|
251
|
+
} catch {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export async function resolveTemplatePathBase(
|
|
257
|
+
templateName: string,
|
|
258
|
+
startDir = process.cwd()
|
|
259
|
+
): Promise<string> {
|
|
260
|
+
const workspaceRoot = getWorkspaceRoot(startDir);
|
|
261
|
+
const localTemplatePath = path.join(workspaceRoot, '.clawmini', 'templates', templateName);
|
|
262
|
+
|
|
263
|
+
if (await isDirectory(localTemplatePath)) {
|
|
264
|
+
return localTemplatePath;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Fallback to built-in templates
|
|
268
|
+
// Find the clawmini package root by looking for package.json
|
|
269
|
+
let currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
270
|
+
while (
|
|
271
|
+
currentDir !== path.parse(currentDir).root &&
|
|
272
|
+
!fs.existsSync(path.join(currentDir, 'package.json'))
|
|
273
|
+
) {
|
|
274
|
+
currentDir = path.dirname(currentDir);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const searchPath = path.join(currentDir, 'templates', templateName);
|
|
278
|
+
|
|
279
|
+
if (await isDirectory(searchPath)) {
|
|
280
|
+
return searchPath;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
throw new Error(
|
|
284
|
+
`Template not found: ${templateName} (searched local: ${localTemplatePath}, built-in: ${searchPath})`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export async function resolveTemplatePath(
|
|
289
|
+
templateName: string,
|
|
290
|
+
startDir = process.cwd()
|
|
291
|
+
): Promise<string> {
|
|
292
|
+
if (templateName === 'environments' || templateName.startsWith('environments/')) {
|
|
293
|
+
throw new Error(`Template not found: ${templateName}`);
|
|
294
|
+
}
|
|
295
|
+
return resolveTemplatePathBase(templateName, startDir);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export async function resolveEnvironmentTemplatePath(
|
|
299
|
+
templateName: string,
|
|
300
|
+
startDir = process.cwd()
|
|
301
|
+
): Promise<string> {
|
|
302
|
+
return resolveTemplatePathBase(path.join('environments', templateName), startDir);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export async function copyTemplateBase(
|
|
306
|
+
templatePath: string,
|
|
307
|
+
targetDir: string,
|
|
308
|
+
allowMissingDir: boolean = false
|
|
309
|
+
): Promise<void> {
|
|
310
|
+
// Check if target directory exists and is not empty
|
|
311
|
+
try {
|
|
312
|
+
const entries = await fsPromises.readdir(targetDir);
|
|
313
|
+
if (entries.length > 0) {
|
|
314
|
+
throw new Error(`Target directory is not empty: ${targetDir}`);
|
|
315
|
+
}
|
|
316
|
+
} catch (err: unknown) {
|
|
317
|
+
if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT') {
|
|
318
|
+
if (allowMissingDir) {
|
|
319
|
+
await fsPromises.mkdir(targetDir, { recursive: true });
|
|
320
|
+
} else {
|
|
321
|
+
throw new Error(`Target directory does not exist: ${targetDir}`, { cause: err });
|
|
322
|
+
}
|
|
323
|
+
} else {
|
|
324
|
+
throw err;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Recursively copy
|
|
329
|
+
await fsPromises.cp(templatePath, targetDir, { recursive: true });
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export async function copyTemplate(
|
|
333
|
+
templateName: string,
|
|
334
|
+
targetDir: string,
|
|
335
|
+
startDir = process.cwd()
|
|
336
|
+
): Promise<void> {
|
|
337
|
+
const templatePath = await resolveTemplatePath(templateName, startDir);
|
|
338
|
+
await copyTemplateBase(templatePath, targetDir, false);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export async function copyEnvironmentTemplate(
|
|
342
|
+
templateName: string,
|
|
343
|
+
targetDir: string,
|
|
344
|
+
startDir = process.cwd()
|
|
345
|
+
): Promise<void> {
|
|
346
|
+
const templatePath = await resolveEnvironmentTemplatePath(templateName, startDir);
|
|
347
|
+
await copyTemplateBase(templatePath, targetDir, true);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export async function applyTemplateToAgent(
|
|
351
|
+
agentId: string,
|
|
352
|
+
templateName: string,
|
|
353
|
+
overrides: Agent,
|
|
354
|
+
startDir = process.cwd()
|
|
355
|
+
): Promise<void> {
|
|
356
|
+
const agentWorkDir = resolveAgentWorkDir(agentId, overrides.directory, startDir);
|
|
357
|
+
await copyTemplate(templateName, agentWorkDir, startDir);
|
|
358
|
+
|
|
359
|
+
const settingsPath = path.join(agentWorkDir, 'settings.json');
|
|
360
|
+
try {
|
|
361
|
+
const rawSettings = await fsPromises.readFile(settingsPath, 'utf-8');
|
|
362
|
+
const parsedSettings = JSON.parse(rawSettings);
|
|
363
|
+
const validation = AgentSchema.safeParse(parsedSettings);
|
|
364
|
+
|
|
365
|
+
if (validation.success) {
|
|
366
|
+
const templateData = validation.data;
|
|
367
|
+
if (templateData.directory) {
|
|
368
|
+
console.warn(
|
|
369
|
+
`Warning: Ignoring 'directory' field from template settings.json. Using default or provided directory.`
|
|
370
|
+
);
|
|
371
|
+
delete templateData.directory;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Merge: overrides take precedence over templateData
|
|
375
|
+
const mergedEnv = { ...(templateData.env || {}), ...(overrides.env || {}) };
|
|
376
|
+
const mergedData: Agent = { ...templateData, ...overrides };
|
|
377
|
+
if (Object.keys(mergedEnv).length > 0) {
|
|
378
|
+
mergedData.env = mergedEnv;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
await writeAgentSettings(agentId, mergedData, startDir);
|
|
382
|
+
}
|
|
383
|
+
} catch {
|
|
384
|
+
// Ignore parsing or file not found errors
|
|
385
|
+
} finally {
|
|
386
|
+
try {
|
|
387
|
+
await fsPromises.rm(settingsPath);
|
|
388
|
+
} catch {
|
|
389
|
+
// Ignore if it doesn't exist
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export async function readSettings(startDir = process.cwd()): Promise<Settings | null> {
|
|
395
|
+
const data = await readJsonFile(getSettingsPath(startDir));
|
|
396
|
+
if (!data) return null;
|
|
397
|
+
const parsed = SettingsSchema.safeParse(data);
|
|
398
|
+
return parsed.success ? parsed.data : null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export async function writeSettings(data: Settings, startDir = process.cwd()): Promise<void> {
|
|
402
|
+
await writeJsonFile(getSettingsPath(startDir), data as Record<string, unknown>);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export async function readPolicies(
|
|
406
|
+
startDir = process.cwd()
|
|
407
|
+
): Promise<import('./policies.js').PolicyConfig | null> {
|
|
408
|
+
const data = await readJsonFile(getPoliciesPath(startDir));
|
|
409
|
+
if (!data) return null;
|
|
410
|
+
// Basic validation, assuming PolicyConfig structure
|
|
411
|
+
if (data.policies && typeof data.policies === 'object') {
|
|
412
|
+
return data as unknown as import('./policies.js').PolicyConfig;
|
|
413
|
+
}
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export function getEnvironmentPath(name: string, startDir = process.cwd()): string {
|
|
418
|
+
return path.join(getClawminiDir(startDir), 'environments', name);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export async function readEnvironment(
|
|
422
|
+
name: string,
|
|
423
|
+
startDir = process.cwd()
|
|
424
|
+
): Promise<Environment | null> {
|
|
425
|
+
const data = await readJsonFile(path.join(getEnvironmentPath(name, startDir), 'env.json'));
|
|
426
|
+
if (!data) return null;
|
|
427
|
+
const parsed = EnvironmentSchema.safeParse(data);
|
|
428
|
+
return parsed.success ? parsed.data : null;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export async function getActiveEnvironmentInfo(
|
|
432
|
+
targetPath: string,
|
|
433
|
+
startDir = process.cwd()
|
|
434
|
+
): Promise<{ name: string; targetPath: string } | null> {
|
|
435
|
+
const settings = await readSettings(startDir);
|
|
436
|
+
if (!settings?.environments) return null;
|
|
437
|
+
|
|
438
|
+
const workspaceRoot = getWorkspaceRoot(startDir);
|
|
439
|
+
const resolvedTarget = path.resolve(workspaceRoot, targetPath);
|
|
440
|
+
|
|
441
|
+
let bestMatch: { name: string; targetPath: string } | null = null;
|
|
442
|
+
let maxDepth = -1;
|
|
443
|
+
|
|
444
|
+
for (const [envPath, envName] of Object.entries(settings.environments)) {
|
|
445
|
+
const resolvedEnvPath = path.resolve(workspaceRoot, envPath);
|
|
446
|
+
|
|
447
|
+
if (pathIsInsideDir(resolvedTarget, resolvedEnvPath, { allowSameDir: true })) {
|
|
448
|
+
const depth = resolvedEnvPath.split(path.sep).length;
|
|
449
|
+
if (depth > maxDepth) {
|
|
450
|
+
maxDepth = depth;
|
|
451
|
+
bestMatch = { name: envName, targetPath: resolvedEnvPath };
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return bestMatch;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export async function getActiveEnvironmentName(
|
|
460
|
+
targetPath: string,
|
|
461
|
+
startDir = process.cwd()
|
|
462
|
+
): Promise<string | null> {
|
|
463
|
+
const info = await getActiveEnvironmentInfo(targetPath, startDir);
|
|
464
|
+
return info ? info.name : null;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export async function enableEnvironment(
|
|
468
|
+
name: string,
|
|
469
|
+
targetPath: string = './',
|
|
470
|
+
startDir = process.cwd()
|
|
471
|
+
): Promise<void> {
|
|
472
|
+
const targetDir = getEnvironmentPath(name, startDir);
|
|
473
|
+
|
|
474
|
+
// Copy template to targetDir if it does not already exist
|
|
475
|
+
if (!fs.existsSync(targetDir)) {
|
|
476
|
+
await copyEnvironmentTemplate(name, targetDir, startDir);
|
|
477
|
+
console.log(`Copied environment template '${name}'.`);
|
|
478
|
+
} else {
|
|
479
|
+
console.log(`Environment template '${name}' already exists in workspace.`);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const settings = (await readSettings(startDir)) || { chats: { defaultId: '' } };
|
|
483
|
+
const environments = settings.environments || {};
|
|
484
|
+
|
|
485
|
+
environments[targetPath] = name;
|
|
486
|
+
settings.environments = environments;
|
|
487
|
+
|
|
488
|
+
await writeSettings(settings, startDir);
|
|
489
|
+
console.log(`Enabled environment '${name}' for path '${targetPath}'.`);
|
|
490
|
+
|
|
491
|
+
// Execute init command if present
|
|
492
|
+
const envConfig = await readEnvironment(name, startDir);
|
|
493
|
+
if (envConfig?.init) {
|
|
494
|
+
// Get the target directory for the environment
|
|
495
|
+
const workspaceRoot = getWorkspaceRoot(startDir);
|
|
496
|
+
const affectedDir = path.resolve(workspaceRoot, targetPath);
|
|
497
|
+
console.log(`Executing init command for environment '${name}': ${envConfig.init}`);
|
|
498
|
+
execSync(envConfig.init, { cwd: affectedDir, stdio: 'inherit' });
|
|
499
|
+
}
|
|
500
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prefix": "sandbox-exec -D WORKSPACE='{WORKSPACE_DIR}' -D AGENT='{AGENT_DIR}' -D HOME='{HOME_DIR}' -f '{ENV_DIR}/sandbox.sb' sh -c '{COMMAND}'",
|
|
3
|
+
"envFormat": "",
|
|
4
|
+
"env": {
|
|
5
|
+
"PATH": "{PATH}:{WORKSPACE_DIR}/bin"
|
|
6
|
+
},
|
|
7
|
+
"exportLiteTo": ".local/bin/clawmini-lite.js"
|
|
8
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
(version 1)
|
|
2
|
+
|
|
3
|
+
;; allow everything by default
|
|
4
|
+
(allow default)
|
|
5
|
+
|
|
6
|
+
;; deny all writes EXCEPT under specific paths
|
|
7
|
+
(deny file-write*)
|
|
8
|
+
(allow file-write*
|
|
9
|
+
(subpath (param "WORKSPACE"))
|
|
10
|
+
(subpath (string-append (param "HOME") "/.gemini"))
|
|
11
|
+
(subpath (string-append (param "HOME") "/.npm"))
|
|
12
|
+
(subpath (string-append (param "HOME") "/.cache"))
|
|
13
|
+
(subpath (string-append (param "HOME") "/.gitconfig"))
|
|
14
|
+
(subpath "/var")
|
|
15
|
+
(subpath "/private/var")
|
|
16
|
+
(literal "/dev/stdout")
|
|
17
|
+
(literal "/dev/stderr")
|
|
18
|
+
(literal "/dev/null")
|
|
19
|
+
(literal "/dev/ptmx")
|
|
20
|
+
(regex #"^/dev/ttys[0-9]*$")
|
|
21
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
generativelanguage.googleapis.com
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"up": "node \"$ENV_DIR/proxy.mjs\" > \"$ENV_DIR/proxy.log\" 2>&1 & echo $! > \"$ENV_DIR/proxy.pid\"",
|
|
3
|
+
"down": "if [ -f \"$ENV_DIR/proxy.pid\" ]; then kill $(cat \"$ENV_DIR/proxy.pid\") || true; rm -f \"$ENV_DIR/proxy.pid\"; fi",
|
|
4
|
+
"prefix": "sandbox-exec -D WORKSPACE='{WORKSPACE_DIR}' -D AGENT='{AGENT_DIR}' -D HOME='{HOME_DIR}' -f '{ENV_DIR}/sandbox.sb' sh -c '{COMMAND}'",
|
|
5
|
+
"envFormat": "",
|
|
6
|
+
"env": {
|
|
7
|
+
"HTTP_PROXY": "http://127.0.0.1:8888",
|
|
8
|
+
"http_proxy": "http://127.0.0.1:8888",
|
|
9
|
+
"HTTPS_PROXY": "http://127.0.0.1:8888",
|
|
10
|
+
"https_proxy": "http://127.0.0.1:8888",
|
|
11
|
+
"PATH": "{PATH}:{WORKSPACE_DIR}/bin"
|
|
12
|
+
},
|
|
13
|
+
"exportLiteTo": ".local/bin/clawmini-lite.js"
|
|
14
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import net from 'net';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
// eslint-disable-next-line no-undef
|
|
9
|
+
const envDir = process.env.ENV_DIR || __dirname;
|
|
10
|
+
const allowlistPath = path.join(envDir, 'allowlist.txt');
|
|
11
|
+
|
|
12
|
+
function isAllowed(hostname) {
|
|
13
|
+
try {
|
|
14
|
+
if (!fs.existsSync(allowlistPath)) {
|
|
15
|
+
return hostname === 'generativelanguage.googleapis.com';
|
|
16
|
+
}
|
|
17
|
+
const content = fs.readFileSync(allowlistPath, 'utf8');
|
|
18
|
+
const allowedDomains = content.split('\n')
|
|
19
|
+
.map(line => line.trim())
|
|
20
|
+
.filter(line => line.length > 0 && !line.startsWith('#'));
|
|
21
|
+
|
|
22
|
+
return allowedDomains.some(domain =>
|
|
23
|
+
hostname === domain || hostname.endsWith(`.${domain}`)
|
|
24
|
+
);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.error('Error reading allowlist:', err);
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const server = http.createServer((req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
const url = new URL(req.url);
|
|
34
|
+
if (!isAllowed(url.hostname)) {
|
|
35
|
+
console.log(`[HTTP] Blocked: ${url.hostname}`);
|
|
36
|
+
res.writeHead(403);
|
|
37
|
+
res.end('Domain not allowed by proxy allowlist\n');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
console.log(`[HTTP] Allowed: ${url.hostname}`);
|
|
41
|
+
|
|
42
|
+
const proxyReq = http.request(url, {
|
|
43
|
+
method: req.method,
|
|
44
|
+
headers: req.headers,
|
|
45
|
+
}, (proxyRes) => {
|
|
46
|
+
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
|
47
|
+
proxyRes.pipe(res, { end: true });
|
|
48
|
+
});
|
|
49
|
+
req.pipe(proxyReq, { end: true });
|
|
50
|
+
proxyReq.on('error', (err) => {
|
|
51
|
+
res.writeHead(500);
|
|
52
|
+
res.end(err.message);
|
|
53
|
+
});
|
|
54
|
+
} catch {
|
|
55
|
+
res.writeHead(400);
|
|
56
|
+
res.end('Bad request');
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
server.on('connect', (req, clientSocket, head) => {
|
|
61
|
+
try {
|
|
62
|
+
const { port, hostname } = new URL(`http://${req.url}`);
|
|
63
|
+
if (!isAllowed(hostname)) {
|
|
64
|
+
console.log(`[HTTPS] Blocked: ${hostname}`);
|
|
65
|
+
clientSocket.write('HTTP/1.1 403 Forbidden\r\n\r\nDomain not allowed by proxy allowlist\n');
|
|
66
|
+
clientSocket.end();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
console.log(`[HTTPS] Allowed: ${hostname}`);
|
|
70
|
+
|
|
71
|
+
const serverSocket = net.connect(port || 443, hostname, () => {
|
|
72
|
+
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
|
73
|
+
serverSocket.write(head);
|
|
74
|
+
serverSocket.pipe(clientSocket);
|
|
75
|
+
clientSocket.pipe(serverSocket);
|
|
76
|
+
});
|
|
77
|
+
serverSocket.on('error', () => clientSocket.end());
|
|
78
|
+
clientSocket.on('error', () => serverSocket.end());
|
|
79
|
+
} catch {
|
|
80
|
+
clientSocket.end();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
server.listen(8888, () => {
|
|
85
|
+
console.log('Proxy listening on port 8888');
|
|
86
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
(version 1)
|
|
2
|
+
|
|
3
|
+
;; allow everything by default
|
|
4
|
+
(allow default)
|
|
5
|
+
|
|
6
|
+
;; deny all writes EXCEPT under specific paths
|
|
7
|
+
(deny file-write*)
|
|
8
|
+
(allow file-write*
|
|
9
|
+
(subpath (param "WORKSPACE"))
|
|
10
|
+
(subpath (string-append (param "HOME") "/.gemini"))
|
|
11
|
+
(subpath (string-append (param "HOME") "/.npm"))
|
|
12
|
+
(subpath (string-append (param "HOME") "/.cache"))
|
|
13
|
+
(subpath (string-append (param "HOME") "/.gitconfig"))
|
|
14
|
+
(subpath "/var")
|
|
15
|
+
(subpath "/private/var")
|
|
16
|
+
(literal "/dev/stdout")
|
|
17
|
+
(literal "/dev/stderr")
|
|
18
|
+
(literal "/dev/null")
|
|
19
|
+
(literal "/dev/ptmx")
|
|
20
|
+
(regex #"^/dev/ttys[0-9]*$")
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
;; deny all network EXCEPT local proxy and basic network operations
|
|
24
|
+
(deny network-outbound)
|
|
25
|
+
|
|
26
|
+
;; Allow Clawmini API
|
|
27
|
+
(allow network-outbound (remote tcp "localhost:8888"))
|
|
28
|
+
(allow network-outbound (remote tcp "localhost:3000"))
|
|
29
|
+
|
|
30
|
+
(deny network-inbound)
|
|
31
|
+
|
|
32
|
+
;; Also allow local Unix domain sockets for mDNSResponder (DNS resolution via localhost proxy might need this or just general system functionality)
|
|
33
|
+
;; (allow network-outbound (literal "/private/var/run/mDNSResponder"))
|
|
34
|
+
;; (allow network-outbound (remote unix-socket))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"commands": {
|
|
3
|
+
"new": "gemini --output-format json --model $MODEL -p \"$CLAW_CLI_MESSAGE\"",
|
|
4
|
+
"append": "gemini --output-format json --model $MODEL --resume $SESSION_ID -p \"$CLAW_CLI_MESSAGE\"",
|
|
5
|
+
"getSessionId": "jq -r '.session_id'",
|
|
6
|
+
"getMessageContent": "jq -r '.response'"
|
|
7
|
+
},
|
|
8
|
+
"env": {
|
|
9
|
+
"MODEL": "gemini-3.1-pro-preview-customtools"
|
|
10
|
+
}
|
|
11
|
+
}
|