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,79 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { isValidAgentId, enableEnvironment } from '../../shared/workspace.js';
|
|
5
|
+
import { setDefaultChatId } from '../../shared/chats.js';
|
|
6
|
+
import { type Agent } from '../../shared/config.js';
|
|
7
|
+
import { createAgentWithChat } from '../../shared/agent-utils.js';
|
|
8
|
+
import { handleError } from '../utils.js';
|
|
9
|
+
|
|
10
|
+
export const initCmd = new Command('init')
|
|
11
|
+
.description('Initialize a new .clawmini settings folder')
|
|
12
|
+
.option('--agent <name>', 'Initialize with a specific agent')
|
|
13
|
+
.option('--agent-template <name>', 'Template to use for the agent')
|
|
14
|
+
.option('--environment <name>', 'Enable a specific environment')
|
|
15
|
+
.action(async (options: { agent?: string; agentTemplate?: string; environment?: string }) => {
|
|
16
|
+
if (options.agentTemplate && !options.agent) {
|
|
17
|
+
handleError('initialize', new Error('--agent-template cannot be used without --agent'));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (options.agent && !isValidAgentId(options.agent)) {
|
|
21
|
+
handleError('initialize', new Error(`Invalid agent ID: ${options.agent}`));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
const dirPath = path.join(cwd, '.clawmini');
|
|
26
|
+
const settingsPath = path.join(dirPath, 'settings.json');
|
|
27
|
+
|
|
28
|
+
if (fs.existsSync(settingsPath)) {
|
|
29
|
+
console.log('.clawmini already initialized');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const defaultSettings = {
|
|
34
|
+
defaultAgent: {
|
|
35
|
+
commands: {
|
|
36
|
+
new: 'echo $CLAW_CLI_MESSAGE',
|
|
37
|
+
},
|
|
38
|
+
env: {},
|
|
39
|
+
},
|
|
40
|
+
routers: [
|
|
41
|
+
'@clawmini/slash-new',
|
|
42
|
+
'@clawmini/slash-stop',
|
|
43
|
+
'@clawmini/slash-interrupt',
|
|
44
|
+
'@clawmini/slash-policies',
|
|
45
|
+
'@clawmini/slash-command',
|
|
46
|
+
],
|
|
47
|
+
api: true,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (!fs.existsSync(dirPath)) {
|
|
51
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fs.writeFileSync(settingsPath, JSON.stringify(defaultSettings, null, 2));
|
|
55
|
+
console.log('Initialized .clawmini/settings.json');
|
|
56
|
+
|
|
57
|
+
if (options.agent) {
|
|
58
|
+
try {
|
|
59
|
+
const agentId = options.agent;
|
|
60
|
+
const agentData: Agent = {};
|
|
61
|
+
await createAgentWithChat(agentId, agentData, options.agentTemplate);
|
|
62
|
+
|
|
63
|
+
console.log(`Agent ${agentId} created successfully.`);
|
|
64
|
+
|
|
65
|
+
await setDefaultChatId(agentId);
|
|
66
|
+
console.log(`Default chat set to ${agentId}.`);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
handleError('create agent', err);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (options.environment) {
|
|
73
|
+
try {
|
|
74
|
+
await enableEnvironment(options.environment);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
handleError('enable environment', err);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { getDaemonClient } from '../client.js';
|
|
3
|
+
import type { CronJob } from '../../shared/config.js';
|
|
4
|
+
|
|
5
|
+
export const jobsCmd = new Command('jobs').description('Manage background jobs');
|
|
6
|
+
|
|
7
|
+
function parseKeyValueArray(arr: string[] | undefined): Record<string, string> | undefined {
|
|
8
|
+
if (!arr || arr.length === 0) return undefined;
|
|
9
|
+
const result: Record<string, string> = {};
|
|
10
|
+
for (const item of arr) {
|
|
11
|
+
const [key, ...rest] = item.split('=');
|
|
12
|
+
if (key && rest.length >= 0) {
|
|
13
|
+
result[key] = rest.join('=');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function handleError(action: string, err: unknown): never {
|
|
20
|
+
console.error(`Failed to ${action}:`, err instanceof Error ? err.message : String(err));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
jobsCmd
|
|
25
|
+
.command('list')
|
|
26
|
+
.description('Display existing jobs')
|
|
27
|
+
.option('-c, --chat <id>', 'Specific chat to list jobs from')
|
|
28
|
+
.option('--json', 'Output full JSON for each job')
|
|
29
|
+
.action(async (options) => {
|
|
30
|
+
try {
|
|
31
|
+
const trpc = await getDaemonClient();
|
|
32
|
+
let jobs = await trpc.listCronJobs.query({ chatId: options.chat });
|
|
33
|
+
|
|
34
|
+
jobs = jobs.sort((a, b) => {
|
|
35
|
+
const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
|
36
|
+
const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
|
37
|
+
return timeA - timeB;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (options.json) {
|
|
41
|
+
console.log(JSON.stringify(jobs, null, 2));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (jobs.length === 0) {
|
|
46
|
+
console.log('No jobs found.');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
for (const job of jobs) {
|
|
50
|
+
let schedule = '';
|
|
51
|
+
if ('cron' in job.schedule) schedule = `cron: ${job.schedule.cron}`;
|
|
52
|
+
else if ('every' in job.schedule) schedule = `every: ${job.schedule.every}`;
|
|
53
|
+
else if ('at' in job.schedule) schedule = `at: ${job.schedule.at}`;
|
|
54
|
+
|
|
55
|
+
console.log(`- ${job.id} (${schedule})`);
|
|
56
|
+
}
|
|
57
|
+
} catch (err) {
|
|
58
|
+
handleError('list jobs', err);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
jobsCmd
|
|
63
|
+
.command('add <name>')
|
|
64
|
+
.description('Create a new job')
|
|
65
|
+
.option('-m, --message <text>', 'The message to send', '')
|
|
66
|
+
.option('-r, --reply <text>', 'An immediate reply to append')
|
|
67
|
+
.option(
|
|
68
|
+
'--at <time-or-interval>',
|
|
69
|
+
'Execute once at this UTC time or after an interval (e.g., 2m, 4h)'
|
|
70
|
+
)
|
|
71
|
+
.option('--every <duration>', 'Execute repeatedly at this interval (e.g., 20m, 4h)')
|
|
72
|
+
.option('--cron <expression>', 'Execute according to the crontab expression')
|
|
73
|
+
.option('-a, --agent <agentid>', 'Agent to use')
|
|
74
|
+
.option(
|
|
75
|
+
'-e, --env <env...>',
|
|
76
|
+
'Environment variables in KEY=VALUE format (can be specified multiple times)'
|
|
77
|
+
)
|
|
78
|
+
.option('-s, --session <type>', 'Session type (e.g. new)')
|
|
79
|
+
.option('-c, --chat <chatid>', 'Specify the chat')
|
|
80
|
+
.action(async (name, options) => {
|
|
81
|
+
try {
|
|
82
|
+
const schedules = [options.at, options.every, options.cron].filter(Boolean);
|
|
83
|
+
if (schedules.length > 1) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
'More than one schedule flag was set. Please use only one of --at, --every, or --cron.'
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (schedules.length === 0) {
|
|
89
|
+
throw new Error('A schedule must be specified (--at, --every, or --cron).');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let schedule: CronJob['schedule'];
|
|
93
|
+
if (options.at) schedule = { at: options.at };
|
|
94
|
+
else if (options.every) schedule = { every: options.every };
|
|
95
|
+
else schedule = { cron: options.cron };
|
|
96
|
+
|
|
97
|
+
const job: CronJob = {
|
|
98
|
+
id: name,
|
|
99
|
+
createdAt: new Date().toISOString(),
|
|
100
|
+
message: options.message,
|
|
101
|
+
schedule,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (options.reply) job.reply = options.reply;
|
|
105
|
+
if (options.agent) job.agentId = options.agent;
|
|
106
|
+
|
|
107
|
+
const env = parseKeyValueArray(options.env);
|
|
108
|
+
if (env) job.env = env;
|
|
109
|
+
|
|
110
|
+
if (options.session) {
|
|
111
|
+
if (options.session !== 'new') {
|
|
112
|
+
throw new Error('Only the "new" session type is supported.');
|
|
113
|
+
}
|
|
114
|
+
job.session = { type: options.session };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const trpc = await getDaemonClient();
|
|
118
|
+
await trpc.addCronJob.mutate({ chatId: options.chat, job });
|
|
119
|
+
console.log(`Job '${name}' created successfully.`);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
handleError('create job', err);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
jobsCmd
|
|
126
|
+
.command('delete <name>')
|
|
127
|
+
.description('Remove a job')
|
|
128
|
+
.option('-c, --chat <chatid>', 'Specify the chat')
|
|
129
|
+
.action(async (name, options) => {
|
|
130
|
+
try {
|
|
131
|
+
const trpc = await getDaemonClient();
|
|
132
|
+
const result = await trpc.deleteCronJob.mutate({ chatId: options.chat, id: name });
|
|
133
|
+
if (result.deleted) {
|
|
134
|
+
console.log(`Job '${name}' deleted successfully.`);
|
|
135
|
+
} else {
|
|
136
|
+
console.log(`Job '${name}' not found.`);
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
handleError('delete job', err);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { getDaemonClient } from '../client.js';
|
|
3
|
+
import { getMessages, getDefaultChatId } from '../../shared/chats.js';
|
|
4
|
+
import { getAgent, isValidAgentId, getClawminiDir } from '../../shared/workspace.js';
|
|
5
|
+
import * as fs from 'node:fs/promises';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
|
|
8
|
+
export const messagesCmd = new Command('messages').description('Manage messages');
|
|
9
|
+
|
|
10
|
+
messagesCmd
|
|
11
|
+
.command('send <message>')
|
|
12
|
+
.description('Send a new message')
|
|
13
|
+
.option('-c, --chat <id>', 'Specific chat to send the message to')
|
|
14
|
+
.option('-s, --session <id>', 'Specific session to send the message to')
|
|
15
|
+
.option('-a, --agent <name>', 'Specific agent to use for this message')
|
|
16
|
+
.option('--no-wait', 'Return immediately after the server queues the message')
|
|
17
|
+
.option('-f, --file <path>', 'File to attach', (val, prev: string[]) => prev.concat([val]), [])
|
|
18
|
+
.action(async (message, options) => {
|
|
19
|
+
try {
|
|
20
|
+
if (options.agent) {
|
|
21
|
+
if (!isValidAgentId(options.agent)) {
|
|
22
|
+
console.error(`Error: Invalid agent ID '${options.agent}'.`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (options.agent !== 'default') {
|
|
27
|
+
const agent = await getAgent(options.agent);
|
|
28
|
+
if (!agent) {
|
|
29
|
+
console.error(`Error: Agent '${options.agent}' not found.`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let finalFiles: string[] | undefined = undefined;
|
|
36
|
+
if (options.file && options.file.length > 0) {
|
|
37
|
+
finalFiles = [];
|
|
38
|
+
const tmpDir = path.join(getClawminiDir(process.cwd()), 'tmp');
|
|
39
|
+
await fs.mkdir(tmpDir, { recursive: true });
|
|
40
|
+
for (const f of options.file) {
|
|
41
|
+
const dest = path.join(
|
|
42
|
+
tmpDir,
|
|
43
|
+
`cli-${Date.now()}-${Math.random().toString(36).substring(2, 7)}-${path.basename(f)}`
|
|
44
|
+
);
|
|
45
|
+
await fs.copyFile(path.resolve(process.cwd(), f), dest);
|
|
46
|
+
finalFiles.push(dest);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const trpc = await getDaemonClient();
|
|
51
|
+
await trpc.sendMessage.mutate({
|
|
52
|
+
type: 'send-message',
|
|
53
|
+
client: 'cli',
|
|
54
|
+
data: {
|
|
55
|
+
message,
|
|
56
|
+
chatId: options.chat,
|
|
57
|
+
sessionId: options.session,
|
|
58
|
+
agentId: options.agent,
|
|
59
|
+
noWait: !options.wait,
|
|
60
|
+
files: finalFiles,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
console.log('Message sent successfully.');
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.error('Failed to send message:', err instanceof Error ? err.message : String(err));
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
messagesCmd
|
|
71
|
+
.command('tail')
|
|
72
|
+
.description('View message history')
|
|
73
|
+
.option('-n, --lines <number>', 'Number of messages to show', parseInt)
|
|
74
|
+
.option('--json', 'Output raw JSONL format')
|
|
75
|
+
.option('-c, --chat <id>', 'Specific chat to view')
|
|
76
|
+
.action(async (options) => {
|
|
77
|
+
try {
|
|
78
|
+
const chatId = options.chat ?? (await getDefaultChatId());
|
|
79
|
+
const messages = await getMessages(chatId, options.lines);
|
|
80
|
+
|
|
81
|
+
if (options.json) {
|
|
82
|
+
messages.forEach((msg) => console.log(JSON.stringify(msg)));
|
|
83
|
+
} else {
|
|
84
|
+
messages.forEach((msg) => {
|
|
85
|
+
if (msg.role === 'user') {
|
|
86
|
+
console.log(`[USER] ${msg.content}`);
|
|
87
|
+
} else if (msg.role === 'log') {
|
|
88
|
+
if (msg.content) {
|
|
89
|
+
console.log(`[LOG] ${msg.content.trim()}`);
|
|
90
|
+
} else if (msg.stderr) {
|
|
91
|
+
console.error(`[STDERR] ${msg.stderr.trim()}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error(
|
|
98
|
+
'Failed to retrieve messages:',
|
|
99
|
+
err instanceof Error ? err.message : String(err)
|
|
100
|
+
);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { getDaemonClient } from '../client.js';
|
|
3
|
+
import { getSocketPath } from '../../shared/workspace.js';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
|
|
6
|
+
export const upCmd = new Command('up')
|
|
7
|
+
.description('Start the local clawmini daemon server')
|
|
8
|
+
.action(async () => {
|
|
9
|
+
try {
|
|
10
|
+
const socketPath = getSocketPath();
|
|
11
|
+
const wasRunning = fs.existsSync(socketPath);
|
|
12
|
+
|
|
13
|
+
const client = await getDaemonClient({ autoStart: true });
|
|
14
|
+
// Perform a ping to ensure the server is responding
|
|
15
|
+
await client.ping.query();
|
|
16
|
+
|
|
17
|
+
if (wasRunning) {
|
|
18
|
+
console.log('Daemon is already running.');
|
|
19
|
+
} else {
|
|
20
|
+
console.log('Successfully started clawmini daemon.');
|
|
21
|
+
}
|
|
22
|
+
} catch (err: unknown) {
|
|
23
|
+
console.error('Failed to start daemon:', err instanceof Error ? err.message : String(err));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import {
|
|
4
|
+
listAgents,
|
|
5
|
+
getAgent,
|
|
6
|
+
writeAgentSettings,
|
|
7
|
+
deleteAgent,
|
|
8
|
+
isValidAgentId,
|
|
9
|
+
} from '../../../shared/workspace.js';
|
|
10
|
+
import { parseJsonBody, sendJsonResponse } from './utils.js';
|
|
11
|
+
|
|
12
|
+
export async function handleApiAgents(
|
|
13
|
+
req: http.IncomingMessage,
|
|
14
|
+
res: http.ServerResponse,
|
|
15
|
+
urlPath: string
|
|
16
|
+
) {
|
|
17
|
+
if (req.method === 'GET' && urlPath === '/api/agents') {
|
|
18
|
+
const agentIds = await listAgents();
|
|
19
|
+
const agents = [];
|
|
20
|
+
for (const id of agentIds) {
|
|
21
|
+
try {
|
|
22
|
+
const agent = await getAgent(id);
|
|
23
|
+
if (agent) {
|
|
24
|
+
agents.push({ id, ...agent });
|
|
25
|
+
}
|
|
26
|
+
} catch (err: unknown) {
|
|
27
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
28
|
+
console.error(`Failed to load agent ${id}: ${errorMessage}`);
|
|
29
|
+
agents.push({ id, error: errorMessage });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
sendJsonResponse(res, 200, agents);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (req.method === 'POST' && urlPath === '/api/agents') {
|
|
37
|
+
try {
|
|
38
|
+
const schema = z.object({
|
|
39
|
+
id: z.string().refine(isValidAgentId, { message: 'Invalid agent ID' }),
|
|
40
|
+
directory: z.string().optional(),
|
|
41
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
42
|
+
commands: z.record(z.string(), z.string()).optional(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const body = await parseJsonBody(req, schema);
|
|
46
|
+
|
|
47
|
+
const existing = await getAgent(body.id);
|
|
48
|
+
if (existing) {
|
|
49
|
+
sendJsonResponse(res, 409, { error: 'Agent already exists' });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const newAgent = {
|
|
54
|
+
directory: body.directory,
|
|
55
|
+
env: body.env || {},
|
|
56
|
+
commands: body.commands || {},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
await writeAgentSettings(body.id, newAgent);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
sendJsonResponse(res, 400, {
|
|
63
|
+
error: err instanceof Error ? err.message : 'Invalid agent directory',
|
|
64
|
+
});
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
sendJsonResponse(res, 201, { id: body.id, ...newAgent });
|
|
69
|
+
} catch {
|
|
70
|
+
sendJsonResponse(res, 500, { error: 'Failed to create agent' });
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const agentMatch = urlPath.match(/^\/api\/agents\/([^/]+)$/);
|
|
76
|
+
if (agentMatch && agentMatch[1]) {
|
|
77
|
+
const agentId = agentMatch[1];
|
|
78
|
+
|
|
79
|
+
if (!isValidAgentId(agentId)) {
|
|
80
|
+
sendJsonResponse(res, 400, { error: 'Invalid agent ID' });
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (req.method === 'GET') {
|
|
85
|
+
try {
|
|
86
|
+
const agent = await getAgent(agentId);
|
|
87
|
+
if (!agent) {
|
|
88
|
+
sendJsonResponse(res, 404, { error: 'Agent not found' });
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
sendJsonResponse(res, 200, { id: agentId, ...agent });
|
|
92
|
+
} catch (err: unknown) {
|
|
93
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
94
|
+
sendJsonResponse(res, 500, { error: errorMessage });
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (req.method === 'PUT' || req.method === 'POST') {
|
|
100
|
+
try {
|
|
101
|
+
const schema = z.object({
|
|
102
|
+
directory: z.string().optional(),
|
|
103
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
104
|
+
commands: z.record(z.string(), z.string()).optional(),
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const body = await parseJsonBody(req, schema);
|
|
108
|
+
|
|
109
|
+
const agent = (await getAgent(agentId)) || {};
|
|
110
|
+
if (body.directory !== undefined) agent.directory = body.directory;
|
|
111
|
+
if (body.env !== undefined) agent.env = body.env;
|
|
112
|
+
if (body.commands !== undefined) agent.commands = body.commands;
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
await writeAgentSettings(agentId, agent);
|
|
116
|
+
} catch (err) {
|
|
117
|
+
sendJsonResponse(res, 400, {
|
|
118
|
+
error: err instanceof Error ? err.message : 'Invalid agent directory',
|
|
119
|
+
});
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
sendJsonResponse(res, 200, { id: agentId, ...agent });
|
|
124
|
+
} catch {
|
|
125
|
+
sendJsonResponse(res, 500, { error: 'Failed to update agent' });
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (req.method === 'DELETE') {
|
|
131
|
+
await deleteAgent(agentId);
|
|
132
|
+
sendJsonResponse(res, 200, { success: true });
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import {
|
|
6
|
+
listChats,
|
|
7
|
+
getMessages,
|
|
8
|
+
getChatsDir,
|
|
9
|
+
createChat,
|
|
10
|
+
isValidChatId,
|
|
11
|
+
} from '../../../shared/chats.js';
|
|
12
|
+
import { writeChatSettings } from '../../../shared/workspace.js';
|
|
13
|
+
import { getDaemonClient } from '../../client.js';
|
|
14
|
+
import { parseJsonBody, sendJsonResponse } from './utils.js';
|
|
15
|
+
|
|
16
|
+
export async function handleApiChats(
|
|
17
|
+
req: http.IncomingMessage,
|
|
18
|
+
res: http.ServerResponse,
|
|
19
|
+
urlPath: string
|
|
20
|
+
) {
|
|
21
|
+
if (req.method === 'GET' && urlPath === '/api/chats') {
|
|
22
|
+
const chats = await listChats();
|
|
23
|
+
sendJsonResponse(res, 200, chats);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (req.method === 'POST' && urlPath === '/api/chats') {
|
|
28
|
+
try {
|
|
29
|
+
const schema = z.object({
|
|
30
|
+
id: z.string().refine(isValidChatId, {
|
|
31
|
+
message: 'Invalid chat ID. Must be alphanumeric with dashes or underscores.',
|
|
32
|
+
}),
|
|
33
|
+
agent: z.string().optional(),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const body = await parseJsonBody(req, schema);
|
|
37
|
+
|
|
38
|
+
await createChat(body.id);
|
|
39
|
+
if (body.agent) {
|
|
40
|
+
await writeChatSettings(body.id, { defaultAgent: body.agent });
|
|
41
|
+
}
|
|
42
|
+
sendJsonResponse(res, 201, { id: body.id, agent: body.agent });
|
|
43
|
+
} catch {
|
|
44
|
+
sendJsonResponse(res, 500, { error: 'Failed to create chat' });
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const chatMatch = urlPath.match(/^\/api\/chats\/([^/]+)$/);
|
|
50
|
+
if (req.method === 'GET' && chatMatch && chatMatch[1]) {
|
|
51
|
+
const chatId = chatMatch[1];
|
|
52
|
+
try {
|
|
53
|
+
const url = new URL(req.url || '', `http://${req.headers.host}`);
|
|
54
|
+
const since = url.searchParams.get('since');
|
|
55
|
+
|
|
56
|
+
let messages = await getMessages(chatId);
|
|
57
|
+
|
|
58
|
+
if (since) {
|
|
59
|
+
const sinceIndex = messages.findIndex((m) => m.id === since);
|
|
60
|
+
if (sinceIndex !== -1) {
|
|
61
|
+
messages = messages.slice(sinceIndex + 1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
sendJsonResponse(res, 200, messages);
|
|
66
|
+
} catch {
|
|
67
|
+
sendJsonResponse(res, 404, { error: 'Chat not found' });
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const streamMatch = urlPath.match(/^\/api\/chats\/([^/]+)\/stream$/);
|
|
73
|
+
if (req.method === 'GET' && streamMatch && streamMatch[1]) {
|
|
74
|
+
const chatId = streamMatch[1];
|
|
75
|
+
|
|
76
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
77
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
78
|
+
res.setHeader('Connection', 'keep-alive');
|
|
79
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
80
|
+
res.flushHeaders();
|
|
81
|
+
|
|
82
|
+
const chatsDir = await getChatsDir();
|
|
83
|
+
const chatFile = path.join(chatsDir, chatId, 'chat.jsonl');
|
|
84
|
+
|
|
85
|
+
if (!fs.existsSync(chatFile)) {
|
|
86
|
+
await createChat(chatId);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let currentSize = fs.statSync(chatFile).size;
|
|
90
|
+
|
|
91
|
+
const watcher = fs.watch(chatFile, (eventType) => {
|
|
92
|
+
if (eventType === 'change') {
|
|
93
|
+
try {
|
|
94
|
+
const stat = fs.statSync(chatFile);
|
|
95
|
+
if (stat.size > currentSize) {
|
|
96
|
+
const stream = fs.createReadStream(chatFile, {
|
|
97
|
+
start: currentSize,
|
|
98
|
+
end: stat.size - 1,
|
|
99
|
+
});
|
|
100
|
+
currentSize = stat.size;
|
|
101
|
+
|
|
102
|
+
let buffer = '';
|
|
103
|
+
stream.on('data', (chunk) => {
|
|
104
|
+
buffer += chunk.toString();
|
|
105
|
+
const parts = buffer.split('\n');
|
|
106
|
+
buffer = parts.pop() || '';
|
|
107
|
+
for (const line of parts) {
|
|
108
|
+
if (line.trim()) {
|
|
109
|
+
res.write(`data: ${line}\n\n`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
stream.on('end', () => {
|
|
114
|
+
if (buffer.trim()) {
|
|
115
|
+
res.write(`data: ${buffer}\n\n`);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
// File might be temporarily inaccessible
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
req.on('close', () => {
|
|
126
|
+
watcher.close();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Send an initial ping to establish connection
|
|
130
|
+
res.write(': connected\n\n');
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const messageMatch = urlPath.match(/^\/api\/chats\/([^/]+)\/messages$/);
|
|
135
|
+
if (req.method === 'POST' && messageMatch && messageMatch[1]) {
|
|
136
|
+
const chatId = messageMatch[1];
|
|
137
|
+
|
|
138
|
+
const schema = z.object({
|
|
139
|
+
message: z.string().min(1, 'Missing or invalid "message" field'),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
let body;
|
|
143
|
+
try {
|
|
144
|
+
body = await parseJsonBody(req, schema);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
sendJsonResponse(res, 400, {
|
|
147
|
+
error: err instanceof Error ? err.message : 'Invalid request',
|
|
148
|
+
});
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
const client = await getDaemonClient();
|
|
154
|
+
await client.sendMessage.mutate({
|
|
155
|
+
type: 'send-message',
|
|
156
|
+
client: 'cli',
|
|
157
|
+
data: {
|
|
158
|
+
message: body.message,
|
|
159
|
+
chatId,
|
|
160
|
+
noWait: true,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
sendJsonResponse(res, 200, { success: true });
|
|
164
|
+
} catch (err) {
|
|
165
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
166
|
+
sendJsonResponse(res, 500, { error: errorMessage || 'Internal Server Error' });
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const cronMatch = urlPath.match(/^\/api\/chats\/([^/]+)\/cron(?:\/([^/]+))?$/);
|
|
172
|
+
if (cronMatch && cronMatch[1]) {
|
|
173
|
+
const chatId = cronMatch[1];
|
|
174
|
+
const jobId = cronMatch[2]; // undefined if not present
|
|
175
|
+
|
|
176
|
+
if (req.method === 'GET') {
|
|
177
|
+
try {
|
|
178
|
+
const client = await getDaemonClient();
|
|
179
|
+
const jobs = await client.listCronJobs.query({ chatId });
|
|
180
|
+
sendJsonResponse(res, 200, jobs);
|
|
181
|
+
} catch {
|
|
182
|
+
sendJsonResponse(res, 500, { error: 'Failed to list cron jobs' });
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (req.method === 'POST') {
|
|
188
|
+
try {
|
|
189
|
+
const client = await getDaemonClient();
|
|
190
|
+
const body = await parseJsonBody(req);
|
|
191
|
+
await client.addCronJob.mutate({ chatId, job: body });
|
|
192
|
+
sendJsonResponse(res, 201, { success: true });
|
|
193
|
+
} catch (err) {
|
|
194
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
195
|
+
sendJsonResponse(res, 500, { error: errorMessage || 'Failed to add cron job' });
|
|
196
|
+
}
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (req.method === 'DELETE' && jobId) {
|
|
201
|
+
try {
|
|
202
|
+
const client = await getDaemonClient();
|
|
203
|
+
await client.deleteCronJob.mutate({ chatId, id: jobId });
|
|
204
|
+
sendJsonResponse(res, 200, { success: true });
|
|
205
|
+
} catch {
|
|
206
|
+
sendJsonResponse(res, 500, { error: 'Failed to delete cron job' });
|
|
207
|
+
}
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return false;
|
|
213
|
+
}
|