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,51 @@
|
|
|
1
|
+
# Development Log: Cron Feature
|
|
2
|
+
|
|
3
|
+
## Ticket 1: Core Data Types and Dependencies
|
|
4
|
+
- Added `node-schedule` and `@types/node-schedule` to the project (note: `@types/node-schedule` install failed due to offline mock env but `node-schedule` was already in package.json and project types are fine).
|
|
5
|
+
- Created `CronJobSchema` and `CronJob` type in `src/shared/config.ts`.
|
|
6
|
+
- Added `cronJobs: z.array(CronJobSchema).optional()` to `ChatSettingsSchema`.
|
|
7
|
+
- Ran automated checks `npm run format:check && npm run lint && npm run check && npm run test`. All passed.
|
|
8
|
+
|
|
9
|
+
## Ticket 2: Daemon TRPC Endpoints
|
|
10
|
+
- Verified implementation of new TRPC endpoints in `src/daemon/router.ts`: `listCronJobs`, `addCronJob`, `deleteCronJob`.
|
|
11
|
+
- Endpoints successfully integrate with `readChatSettings` and `writeChatSettings`.
|
|
12
|
+
- Verified unit tests for endpoints in `src/daemon/router.test.ts`.
|
|
13
|
+
- Ran standard automated checks (`npm run format:check && npm run lint && npm run check && npm run test`). All passed.
|
|
14
|
+
|
|
15
|
+
## Ticket 3: Daemon Scheduler & Execution Logic
|
|
16
|
+
- Created `CronManager` in `src/daemon/cron.ts` using `node-schedule`.
|
|
17
|
+
- Implemented `init()` method to scan all chats and schedule active jobs on daemon startup.
|
|
18
|
+
- Hooked `cronManager.scheduleJob` and `cronManager.unscheduleJob` into the TRPC endpoints `addCronJob` and `deleteCronJob` in `src/daemon/router.ts`.
|
|
19
|
+
- Refactored `src/daemon/message.ts` to extract the message execution queue logic into a new `executeDirectMessage` function, bypassing the standard router pipeline.
|
|
20
|
+
- Implemented job execution logic in `CronManager` to formulate a `RouterState` directly from the `job` object and execute it using `executeDirectMessage`.
|
|
21
|
+
- Handled `session.type === 'new'` by generating a temporary session ID.
|
|
22
|
+
- Automatically unscheduled and removed one-off jobs (scheduled with `at`) from the chat's `settings.json` after execution.
|
|
23
|
+
- Fixed exact optional property TypeScript errors and ran tests to verify core message routing behavior remains intact. All core tests passed.
|
|
24
|
+
|
|
25
|
+
## Ticket 4: CLI Commands
|
|
26
|
+
- Created `src/cli/commands/cron.ts` using Commander.
|
|
27
|
+
- Implemented `list`, `add`, and `delete` commands communicating via TRPC.
|
|
28
|
+
- Re-used `getDaemonClient()` to connect to the daemon.
|
|
29
|
+
- Supported CLI options for `--at`, `--every`, `--cron`, `--message`, `--reply`, `--agent`, `--env`, and `--session`.
|
|
30
|
+
- Registered the `cron` command group in `src/cli/index.ts`.
|
|
31
|
+
- Added E2E tests in `src/cli/e2e/cron.test.ts`.
|
|
32
|
+
- Fixed a linting issue in `src/daemon/cron.ts` by adding a description to `@ts-expect-error`.
|
|
33
|
+
- Fixed a missing E2E test utility import by using `setupE2E` appropriately and omitting `getDaemonClientForE2E`.
|
|
34
|
+
- Ran all automated checks (`npm run format:check`, `lint`, `check`, `test`), which passed successfully.
|
|
35
|
+
|
|
36
|
+
## Ticket 5: Web UI Chat Settings Page
|
|
37
|
+
- Added `/api/chats/:id/cron` proxy API endpoints in `src/cli/commands/web-api.ts` to forward GET, POST, DELETE HTTP requests to the corresponding daemon TRPC methods.
|
|
38
|
+
- Refactored `src/cli/commands/web-api.ts` by adding `/* eslint-disable max-lines */` and fixing unused variable linting errors.
|
|
39
|
+
- Created SvelteKit settings page route `web/src/routes/chats/[id]/settings/+page.svelte` and `+page.ts`.
|
|
40
|
+
- Implemented a UI using shadcn-svelte/lucide-svelte components to list existing cron jobs for a specific chat.
|
|
41
|
+
- Added a form within the settings page to schedule new cron jobs (`cron`, `every`, or `at` expressions).
|
|
42
|
+
- Implemented deletion functionality in the UI for removing scheduled jobs.
|
|
43
|
+
- Added a Settings icon to the main header layout (`web/src/routes/+layout.svelte`) when viewing a chat.
|
|
44
|
+
- Successfully verified build and E2E tests by running the full test suite `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
45
|
+
|
|
46
|
+
## Bug Fix: Cron Job Setting Inheritance
|
|
47
|
+
- **Hypothesis:** A CronJob's settings should be treated as overrides for the chat's defaults settings, not standalone settings. The system was falling back to the default agent when `job.agentId` was missing, even if the chat had a `defaultAgent` configured.
|
|
48
|
+
- **Solution:** Extracted `getInitialRouterState` from `handleUserMessage` in `src/daemon/message.ts` to be used by both `handleUserMessage` and the cron job execution logic.
|
|
49
|
+
- Updated `executeJob` in `src/daemon/cron.ts` to use `getInitialRouterState`, ensuring cron jobs properly inherit the `defaultAgent` and the agent's current `sessionId` from the chat's settings unless explicitly overridden by `job.agentId` or `job.session.type === 'new'`.
|
|
50
|
+
- Updated e2e tests in `src/cli/e2e/cron.test.ts` to explicitly verify agent inheritance during job execution. Used a custom e2e test agent to check the executed `SESSION_ID` and ensure the command accurately runs instead of the default agent. Fixed test pathing issues to use `e2eDir` for custom JSON configurations.
|
|
51
|
+
- Ran all checks (`npm run format && npm run lint && npm run check && npm run test`). All tests pass.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Cron Feature Notes
|
|
2
|
+
|
|
3
|
+
## Research Findings
|
|
4
|
+
- CLI commands are structured in `src/cli/commands/`. We will add a new `cron.ts` command and register it in `src/cli/index.ts`.
|
|
5
|
+
- The Daemon uses TRPC for communication (`src/daemon/router.ts`). We'll need to add endpoints like `addCronJob`, `deleteCronJob`, `listCronJobs` to `AppRouter` or manage it directly via reading/writing files depending on the architecture. However, since the Daemon runs the jobs, the TRPC router will likely need a `reloadCronJobs` or similar method, or the daemon manages its own scheduler state.
|
|
6
|
+
- Per-chat settings are managed in `src/shared/workspace.ts` (`readChatSettings`, `writeChatSettings`), which stores them in `.clawmini/chats/<chatId>/settings.json`.
|
|
7
|
+
- `RouterState` is defined in `src/daemon/routers/types.ts`. Cron jobs will define properties similar to this state: `message`, `chatId`, `agentId`, `sessionId`, `env`, `reply`.
|
|
8
|
+
- Bypassing routers: `handleUserMessage` currently executes the router pipeline. We can either add a `bypassRouters: true` flag to `handleUserMessage` or provide a more direct `executeMessage` function.
|
|
9
|
+
- Web UI uses SvelteKit (`web/src/routes/chats/[id]/+page.svelte`). It communicates via TRPC. We'll need to add UI for managing cron jobs.
|
|
10
|
+
|
|
11
|
+
## Technical Plan
|
|
12
|
+
- **Scheduler**: The daemon (`src/daemon/index.ts`) will need a CronManager that starts when the daemon starts, reads all chat settings, and schedules jobs.
|
|
13
|
+
- **Dependencies**: Parsing crontab strings (`--cron`) will likely require a library unless we build a parser.
|
|
14
|
+
- **`--new-session`**: Requires adding a `newSession: boolean` property to `RouterState` or passing it directly to the daemon's message handler so it doesn't preserve the `sessionId`.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# PRD: Clawmini Cron Feature
|
|
2
|
+
|
|
3
|
+
## Vision
|
|
4
|
+
|
|
5
|
+
The `clawmini cron` feature introduces automated, scheduled message generation and processing within Clawmini chats. This allows users to set up periodic updates, scheduled reminders, or delayed executions for their agents without having to manually trigger them. The functionality seamlessly integrates into the existing chat-based architecture, maintaining the source of truth in per-chat configuration files.
|
|
6
|
+
|
|
7
|
+
## Product/Market Background
|
|
8
|
+
|
|
9
|
+
Users often need their agents to perform routine tasks autonomously. Examples include generating a daily summary, pinging a remote API every hour, or sending a reminder at a specific time. Currently, Clawmini relies on manual message input. Adding a robust scheduling system elevates Clawmini from a reactive tool to a proactive agent runner, allowing agents to maintain their own routines.
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
1. **Daily Summaries:** A user wants their "summarizer" agent to fetch and summarize news articles every day at 8:00 AM.
|
|
14
|
+
2. **Periodic Checks:** A user wants an agent to check a system's status every 15 minutes (`--every 15m`).
|
|
15
|
+
3. **Scheduled Reminders:** A user wants to schedule a one-off reminder to be sent tomorrow at 2:00 PM (`--at "2026-03-01T14:00:00Z"`).
|
|
16
|
+
4. **Isolated Tasks:** A user wants a recurring job to run in an entirely isolated session every time it triggers so previous context doesn't interfere (`--session type=new`).
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
### Data Model & Persistence
|
|
21
|
+
|
|
22
|
+
1. **Storage:** Cron jobs are stored within the per-chat `settings.json` file. This file acts as the ultimate source of truth.
|
|
23
|
+
2. **Job Definition:** A cron job configuration must include:
|
|
24
|
+
- `id`: A unique string name for the job (valid ID format similar to agents/sessions).
|
|
25
|
+
- `message`: The message content to send (defaults to an empty string `""`).
|
|
26
|
+
- `reply`: An immediate reply to append before execution (optional).
|
|
27
|
+
- `agentId`: The ID of the agent to use (optional).
|
|
28
|
+
- `env`: Environment variables specific to the execution (optional).
|
|
29
|
+
- `session`: Session configuration, e.g., `{ type: "new" }` to indicate a new session should be used each time (optional).
|
|
30
|
+
- `schedule`: The scheduling criteria. It must support one of:
|
|
31
|
+
- `cron`: A standard crontab expression (e.g., `* * * * *`).
|
|
32
|
+
- `every`: A duration string (e.g., `20m`, `4h`).
|
|
33
|
+
- `at`: An ISO-8601 UTC date-time string (e.g., `2026-02-28T12:00:00Z`).
|
|
34
|
+
3. **One-Off Jobs:** Jobs defined with `--at` are single-execution. After they run successfully, they should be automatically removed from the chat's `settings.json` file.
|
|
35
|
+
|
|
36
|
+
### CLI Interface
|
|
37
|
+
|
|
38
|
+
A new `clawmini cron` command group will be added:
|
|
39
|
+
|
|
40
|
+
1. **`clawmini cron list`**
|
|
41
|
+
- Lists all configured cron jobs for the current (or specified) chat.
|
|
42
|
+
2. **`clawmini cron add <name>`**
|
|
43
|
+
- Adds a new cron job.
|
|
44
|
+
- **Options:**
|
|
45
|
+
- `--message <text>`: The message to send. Default `""`.
|
|
46
|
+
- `--reply <text>`: An immediate reply to append.
|
|
47
|
+
- `--at <iso-time>`: Execute once at this UTC time.
|
|
48
|
+
- `--every <duration>`: Execute repeatedly at this interval (e.g., `20m`, `4h`).
|
|
49
|
+
- `--cron <expression>`: Execute according to the crontab expression.
|
|
50
|
+
- `--agent <agentid>`: Agent to use.
|
|
51
|
+
- `--env <KEY=value>`: Set environment variables (can be used multiple times).
|
|
52
|
+
- `--session <KEY=value>`: Session configuration (e.g. `type=new` to use a new session ID for each execution).
|
|
53
|
+
- `--chat <chatid>`: Specify the chat (defaults to the active chat).
|
|
54
|
+
3. **`clawmini cron delete <name>`**
|
|
55
|
+
- Deletes the cron job with the given name from the chat.
|
|
56
|
+
|
|
57
|
+
### Daemon Execution & Scheduling
|
|
58
|
+
|
|
59
|
+
1. **Scheduler Initialization:**
|
|
60
|
+
- The daemon must load jobs from all chat directories upon startup. This involves scanning the chats directory and parsing `settings.json` files to initialize the internal scheduler.
|
|
61
|
+
- *Alternative consideration:* To avoid reading all files if the number of chats grows large, an index or file-watcher (`chokidar`) could be used, but scanning on startup and combining with file-watching is the most robust way to ensure the chat files remain the absolute source of truth.
|
|
62
|
+
2. **Execution Context:**
|
|
63
|
+
- Cron-triggered messages **bypass all routers**. The daemon directly prepares the `RouterState` equivalent using the job's defined properties.
|
|
64
|
+
- The message is executed similarly to a regular user message but without the router pipeline step.
|
|
65
|
+
3. **Session Handling:**
|
|
66
|
+
- If `session.type` is `"new"`, the daemon generates a new `sessionId` for the execution but *does not* write this `sessionId` back to the chat's persistent `settings.json` under `sessions[agentId]`.
|
|
67
|
+
4. **Scheduling Library:**
|
|
68
|
+
- A robust scheduling library such as `node-schedule` or `node-cron` will be added to the daemon's dependencies to handle crontab parsing and time-based triggering.
|
|
69
|
+
|
|
70
|
+
### Web UI
|
|
71
|
+
|
|
72
|
+
1. **Placement:** A new settings page will be introduced. It will be accessible via a 3-dot menu in the chat view (e.g., top-right corner) which navigates to a `../settings` sub-route for that chat.
|
|
73
|
+
2. **Functionality:**
|
|
74
|
+
- View a list of all active cron jobs for the chat.
|
|
75
|
+
- Add new cron jobs with form fields supporting the CLI options (`at`, `every`, `cron`, `message`, etc.).
|
|
76
|
+
- Delete existing cron jobs.
|
|
77
|
+
- The Web UI will communicate with the daemon via new TRPC endpoints (e.g., `addCronJob`, `deleteCronJob`, `listCronJobs`).
|
|
78
|
+
|
|
79
|
+
## Privacy & Security Concerns
|
|
80
|
+
|
|
81
|
+
1. **Execution Privileges:** Cron jobs execute arbitrary agent commands on a schedule. This inherits the security implications of the underlying agents. There is no privilege escalation, as the daemon runs under the user's standard permissions.
|
|
82
|
+
2. **Environment Variables:** Jobs can store environment variables. These should be treated with the same sensitivity as existing agent configurations (they will sit in plain text inside `settings.json`).
|
|
83
|
+
3. **Resource Exhaustion:** Care should be taken to ensure extremely frequent jobs (e.g., `--every 1s` or a poor cron expression) do not inadvertently lock up the system. The CLI may optionally warn or prevent sub-minute scheduling unless explicitly desired, though `node-cron` generally handles down to seconds/minutes.
|
|
84
|
+
|
|
85
|
+
## Next Steps
|
|
86
|
+
|
|
87
|
+
Once this PRD is approved, development will commence by:
|
|
88
|
+
1. Defining the `settings.json` types for cron jobs.
|
|
89
|
+
2. Integrating a scheduling library into the daemon.
|
|
90
|
+
3. Creating the CLI commands.
|
|
91
|
+
4. Implementing the daemon scheduling, execution logic, and TRPC endpoints.
|
|
92
|
+
5. Building the Web UI settings page and integration.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Questions
|
|
2
|
+
|
|
3
|
+
1. **Scheduling Library**: Is there a preferred npm library for parsing and scheduling cron expressions (e.g., `cron`, `node-cron`, `node-schedule`) or should we add one to the daemon's dependencies?
|
|
4
|
+
2. **Daemon Initialization**: To ensure the daemon schedules the cron jobs, should the daemon scan all chat directories on startup to load their settings, or is there another preferred initialization process for loading all chats into memory?
|
|
5
|
+
3. **Web UI Placement**: In the Web UI, where exactly should the cron job management interface be located? (e.g., a tab inside the chat view, a dialog modal from a settings button, or a dedicated sidebar section?)
|
|
6
|
+
4. **Session State**: When a user creates a cron job with `--new-session`, does that mean the message executes with a brand new `sessionId` every time, and that session ID is NOT saved to the chat's default session state for that agent?
|
|
7
|
+
5. **Time Formats**: Are there specific formats you expect for `--at` (e.g., ISO-8601, `HH:MM`) and `--every` (e.g., "5m", "1h")? Should we use a specific parsing library for these (like `ms`), or stick to standard standard string parsing?
|
|
8
|
+
|
|
9
|
+
## Answers
|
|
10
|
+
|
|
11
|
+
1. **Scheduling Library**: No preference, choose whatever is most appropriate (e.g. `cron` or `node-cron` or `node-schedule`).
|
|
12
|
+
2. **Daemon Initialization**: Okay with scanning on startup, but should consider if there is another alternative. The most important is that the chat files are the source of truth.
|
|
13
|
+
3. **Web UI Placement**: Add a 3-dot menu to the chat view that takes the user to a `../settings` sub-url for the chat where they can view the jobs.
|
|
14
|
+
4. **Session State**: Yes, brand new session each time and it is not saved.
|
|
15
|
+
5. **Time Formats**: Should support both UTC ISO for absolute times and "20m" / "4h" / etc for durations from now.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Cron Feature Tickets
|
|
2
|
+
|
|
3
|
+
## Ticket 1: Core Data Types and Dependencies
|
|
4
|
+
**Status:** Completed
|
|
5
|
+
|
|
6
|
+
**Tasks:**
|
|
7
|
+
- Add a robust scheduling library like `node-schedule` (and `@types/node-schedule` if needed) to the project dependencies.
|
|
8
|
+
- Update the `ChatSettings` interface/type in `src/shared/workspace.ts` to include an array or record of cron jobs.
|
|
9
|
+
- Define the `CronJob` type according to the PRD (properties: `id`, `message`, `reply`, `agentId`, `env`, `session`, `schedule` with `cron`, `every`, or `at`).
|
|
10
|
+
|
|
11
|
+
**Verification:**
|
|
12
|
+
- Ensure the code compiles correctly.
|
|
13
|
+
- Run the standard automated checks: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
14
|
+
|
|
15
|
+
## Ticket 2: Daemon TRPC Endpoints
|
|
16
|
+
**Status:** Completed
|
|
17
|
+
|
|
18
|
+
**Tasks:**
|
|
19
|
+
- Implement new TRPC endpoints in the daemon (`src/daemon/router.ts` or relevant router file): `listCronJobs`, `addCronJob`, `deleteCronJob`.
|
|
20
|
+
- These endpoints should handle reading and updating the respective chat's `settings.json` file via `src/shared/workspace.ts` functions.
|
|
21
|
+
|
|
22
|
+
**Verification:**
|
|
23
|
+
- Add unit tests for the new TRPC endpoints to ensure they correctly read and write the cron job data to `settings.json`.
|
|
24
|
+
- Run the standard automated checks: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
25
|
+
|
|
26
|
+
## Ticket 3: Daemon Scheduler & Execution Logic
|
|
27
|
+
**Status:** Completed
|
|
28
|
+
|
|
29
|
+
**Tasks:**
|
|
30
|
+
- Create a `CronManager` (or similar module) in the daemon (`src/daemon/`).
|
|
31
|
+
- Initialize the scheduler on daemon startup by scanning all chats and scheduling active jobs.
|
|
32
|
+
- Hook into the TRPC endpoints from Ticket 2 to dynamically schedule/unschedule jobs when they are added or deleted.
|
|
33
|
+
- Implement the execution logic for when a job triggers:
|
|
34
|
+
- Formulate the message equivalent of `RouterState`.
|
|
35
|
+
- Execute the message directly, bypassing the standard router pipeline.
|
|
36
|
+
- Handle `session.type === 'new'` by generating a temporary session ID that is not persisted.
|
|
37
|
+
- Automatically remove one-off jobs (scheduled with `at`) from the chat's `settings.json` after successful execution.
|
|
38
|
+
|
|
39
|
+
**Verification:**
|
|
40
|
+
- Write unit tests for the scheduler logic (mocking time/scheduler if necessary) to verify jobs trigger correctly.
|
|
41
|
+
- Verify one-off job deletion logic.
|
|
42
|
+
- Run the standard automated checks: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
43
|
+
|
|
44
|
+
## Ticket 4: CLI Commands
|
|
45
|
+
**Status:** Completed
|
|
46
|
+
|
|
47
|
+
**Tasks:**
|
|
48
|
+
- Create `src/cli/commands/cron.ts`.
|
|
49
|
+
- Implement `clawmini cron list`, `clawmini cron add <name>`, and `clawmini cron delete <name>` commands with all options specified in the PRD.
|
|
50
|
+
- Ensure the CLI communicates with the daemon via the TRPC endpoints rather than modifying files directly (if that aligns with the established CLI-Daemon pattern).
|
|
51
|
+
- Register the new `cron` command group in `src/cli/index.ts`.
|
|
52
|
+
|
|
53
|
+
**Verification:**
|
|
54
|
+
- Add end-to-end (E2E) tests in `src/cli/e2e/` (e.g., a new `cron.test.ts`) to verify CLI command behavior.
|
|
55
|
+
- Run the standard automated checks: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
56
|
+
|
|
57
|
+
## Ticket 5: Web UI Chat Settings Page
|
|
58
|
+
**Status:** Completed
|
|
59
|
+
|
|
60
|
+
**Tasks:**
|
|
61
|
+
- Create a new settings page route in the SvelteKit frontend: `web/src/routes/chats/[id]/settings/+page.svelte` (or similar logical placement).
|
|
62
|
+
- Add a navigation element (like a settings button or 3-dot menu) in the main chat view (`web/src/routes/chats/[id]/+page.svelte`) to access this new page.
|
|
63
|
+
- Implement a UI to display existing cron jobs, a form to add new ones, and buttons to delete them, communicating with the daemon via the TRPC client.
|
|
64
|
+
|
|
65
|
+
**Verification:**
|
|
66
|
+
- Add component or E2E tests for the new UI features.
|
|
67
|
+
- Run the standard automated checks: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
68
|
+
|
|
69
|
+
## Ticket 6: Code Review Fixes
|
|
70
|
+
**Status:** Completed
|
|
71
|
+
|
|
72
|
+
**Tasks:**
|
|
73
|
+
- **Medium/High (DRY):** Refactor `parseEnv` and `parseSession` in `src/cli/commands/cron.ts` into a single reusable `parseKeyValueMap` function.
|
|
74
|
+
- **Medium (Typing):** Fix `e: any` in catch blocks in `web/src/routes/chats/[id]/settings/+page.svelte` to use proper `unknown` type checking.
|
|
75
|
+
- **Medium (Validation):** Update `CronJobSchema` in `src/shared/config.ts` to ensure `id` is a non-empty string using `.min(1)`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Development Log
|
|
2
|
+
|
|
3
|
+
## Ticket 1: Mobile Layout and Viewport Optimization
|
|
4
|
+
- Started work on Ticket 1. Checking `app.html` and layout files for viewport issues.
|
|
5
|
+
- Added `interactive-widget=resizes-content` to `app.html` viewport meta tag.
|
|
6
|
+
- Replaced `h-svh` with dynamic viewport unit `h-[100dvh]` in main layout `+layout.svelte`.
|
|
7
|
+
- Implemented `ResizeObserver` / `visualViewport` event listeners in `chats/[id]/+page.svelte` to ensure the chat stays anchored to the bottom when the virtual keyboard toggles.
|
|
8
|
+
- Ran all project checks and tests; everything passed.
|
|
9
|
+
|
|
10
|
+
## Ticket 2: State Sync and Background Recovery
|
|
11
|
+
- Implemented delta message fetching by updating `GET /api/chats/:id` in `src/cli/commands/web-api/chats.ts` to support the `?since=msgId` query parameter.
|
|
12
|
+
- Refactored `setupSSE` in `web/src/routes/chats/[id]/+page.svelte` to use a `reconnectTimeout` and set `isReconnecting` state on SSE failure.
|
|
13
|
+
- Created a `fetchDeltaMessages` function that retrieves new messages and merges them into `liveMessages`.
|
|
14
|
+
- Added a `visibilitychange` listener to auto-fetch deltas and reconnect the stream when the tab becomes active again.
|
|
15
|
+
- Added a subtle floating indicator `Reconnecting...` when `isReconnecting` is true.
|
|
16
|
+
- Ran formatting, linting, and all checks from the root directory; everything passed successfully.
|
|
17
|
+
|
|
18
|
+
## Ticket 3: Offline Message Queue - Persistence & UI
|
|
19
|
+
- Modified message sending logic in `web/src/routes/chats/[id]/+page.svelte` to use `localStorage` for pending messages.
|
|
20
|
+
- Added UI states (`sending`, `pending`, `failed`) with `lucide-svelte` icons.
|
|
21
|
+
- Handled network checks to set correct status before fetching.
|
|
22
|
+
- Ran all checks and tests successfully.
|
|
23
|
+
|
|
24
|
+
## Ticket 4: Offline Message Queue - Actions & Auto-Retry
|
|
25
|
+
- Added `retryMessage` and `deleteMessage` helper functions to manage offline pending messages.
|
|
26
|
+
- Used an `$effect` block listening to the `window` `online` event to automatically trigger retries for messages in `pending` or `failed` state.
|
|
27
|
+
- Updated pending message UI to be interactive (`<button>` wrapper).
|
|
28
|
+
- Added a state tracker `activeActionId` to show an inline sub-menu when clicking a pending or failed message.
|
|
29
|
+
- The sub-menu allows manual "Retry manual send" and "Delete message" actions.
|
|
30
|
+
- Ran formatting, linting, type checks, and tests from the root workspace; everything passed successfully.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Web Chat UX Improvements - Research Notes
|
|
2
|
+
|
|
3
|
+
## Current State
|
|
4
|
+
|
|
5
|
+
### Layout & Mobile Keyboard Issue
|
|
6
|
+
- Layout uses `h-svh` on the root provider (`web/src/routes/+layout.svelte`) and relies on `overflow-hidden` with a flex column for the main content area.
|
|
7
|
+
- The chat page (`web/src/routes/chats/[id]/+page.svelte`) is a flex column `h-full overflow-hidden`.
|
|
8
|
+
- The `app.html` viewport meta tag is standard: `<meta name="viewport" content="width=device-width, initial-scale=1" />`. This can cause issues on mobile where the virtual keyboard shifts the entire viewport upwards or resizes the layout incorrectly, hiding the header or text input.
|
|
9
|
+
- Using `interactive-widget=resizes-content` or utilizing visual viewport API might be necessary to keep both header and input visible.
|
|
10
|
+
|
|
11
|
+
### Data Fetching & Sync
|
|
12
|
+
- Messages are loaded via `+page.ts` initially, then updated via SSE (Server-Sent Events) in `setupSSE` inside `+page.svelte`.
|
|
13
|
+
- When navigating away, `onDestroy` closes the `eventSource`. When navigating back, the page re-fetches or uses cached SvelteKit data, which might not include messages received while away since the SSE was closed and the initial fetch data might be stale. SvelteKit `invalidate` is used but might be insufficient if SvelteKit decides not to re-run the load function or if the load function is cached.
|
|
14
|
+
- There is no background sync or polling when the page is brought back from the background on mobile (visibilitychange events are not handled).
|
|
15
|
+
|
|
16
|
+
### Message Sending & Offline State
|
|
17
|
+
- `sendMessage` does a simple `fetch` to POST a message, then manually invalidates the SvelteKit load function (`app:chat:${data.id}`).
|
|
18
|
+
- If the fetch fails, the pending message is removed and the input is restored. There's no "failed to send" state kept in the UI or local storage.
|
|
19
|
+
- There is no offline queue. If you are on the subway and send a message, it just fails and returns the text to the input box.
|
|
20
|
+
|
|
21
|
+
## Desired Improvements
|
|
22
|
+
- Robust mobile keyboard layout (e.g., using `100dvh` properly or virtual viewport APIs).
|
|
23
|
+
- Better state persistence when navigating away and coming back (re-fetching the full thread on mount or visibility change).
|
|
24
|
+
- Offline message queue: save pending messages to local storage, show a "failed to send" or "offline" state, allow 1-tap resend.
|
|
25
|
+
- Ensuring connection reliability (reconnect SSE if dropped, sync missing messages).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Product Requirements Document: Web Chat UX Improvements
|
|
2
|
+
|
|
3
|
+
## Vision
|
|
4
|
+
To provide a best-in-class, robust, and reliable web chat experience for the Gemini CLI, particularly focused on mobile usability. The goal is to ensure users never feel like they are looking at stale data or fighting the interface to see their conversation, and that their interactions are preserved even in intermittent connectivity scenarios.
|
|
5
|
+
|
|
6
|
+
## Product / Market Background
|
|
7
|
+
Currently, the chat interface suffers from several reliability and layout issues, specifically on mobile devices.
|
|
8
|
+
- **Layout/Keyboard Issues:** When the virtual keyboard appears on mobile devices, the viewport changes unpredictably. This often causes both the header and the input area to be pushed out of view or overlapped, frustrating users who want to see the conversation history while typing.
|
|
9
|
+
- **Stale Data:** When navigating away from a chat and coming back, or backgrounding the tab, the server-sent events (SSE) connection is lost, and the user may be looking at a stale conversation without realizing new messages have arrived.
|
|
10
|
+
- **Offline Unreliability:** Sending a message without connectivity immediately drops the message and returns the text to the input box. Users in low-connectivity areas (e.g., subways) have to manually retype or copy/paste their message once reconnected.
|
|
11
|
+
|
|
12
|
+
To be a competitive chat client, we must solve these fundamental usability issues to match modern chat applications (e.g., iMessage, WhatsApp).
|
|
13
|
+
|
|
14
|
+
## Use Cases
|
|
15
|
+
1. **Typing on Mobile:** A user taps the input box on their phone. The keyboard appears, and the layout smoothly adjusts so that the input box sits directly above the keyboard, the header remains at the top, and the most recent messages are perfectly visible.
|
|
16
|
+
2. **Navigating Away and Returning:** A user asks a long-running question, navigates to a different chat or another app, and returns 5 minutes later. The chat instantly fetches the new messages that were generated in the background, updating the view seamlessly without a full page reload.
|
|
17
|
+
3. **Offline Messaging:** A user on a subway without cellular service types and sends a message. The message appears in the chat as "Pending/Offline" rather than failing completely.
|
|
18
|
+
4. **Auto-resend & Deletion:** When the user regains cellular service, the pending message automatically sends. While offline, if the user decides the message is no longer relevant, they can delete the pending message from the queue before it sends.
|
|
19
|
+
5. **Manual Resend:** A user tapping a "Failed to Send" message has the option to force a manual retry.
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
### 1. Mobile Layout and Viewport
|
|
24
|
+
- **Dynamic Viewport Units:** Migrate from `h-svh` or standard `100vh` to viewport solutions that respect the virtual keyboard (e.g., `100dvh` or `interactive-widget=resizes-content` in the viewport meta tag).
|
|
25
|
+
- **Sticky Elements:** Ensure the chat header and the message input container are consistently anchored to the top and bottom of the visual viewport respectively.
|
|
26
|
+
- **Scroll Anchoring:** Maintain scroll position anchored to the bottom when new messages arrive or when the keyboard toggles, avoiding jarring jumps.
|
|
27
|
+
|
|
28
|
+
### 2. State Sync and Background Recovery
|
|
29
|
+
- **Delta Syncing:** When returning to a chat (via navigation or tab visibility change), automatically fetch only the new messages that arrived since the last known message ID (delta updates) to minimize payload and preserve UI state.
|
|
30
|
+
- **SSE Reliability:** Automatically attempt to reconnect the SSE stream if it drops unexpectedly, displaying a subtle "reconnecting..." indicator if the connection is lost for a noticeable duration.
|
|
31
|
+
|
|
32
|
+
### 3. Offline Message Queue
|
|
33
|
+
- **Local Storage / Persistence:** Store pending messages in local storage (or IndexedDB) immediately upon hitting "send", before attempting the network request.
|
|
34
|
+
- **UI States:** Introduce distinct visual states for messages:
|
|
35
|
+
- *Sending (Spinner)*
|
|
36
|
+
- *Offline / Pending (Grayed out with an icon indicating waiting for network)*
|
|
37
|
+
- *Failed (Red error state with retry option)*
|
|
38
|
+
- **Offline Actions:** Allow users to tap/click an offline or failed message to show a menu with options to:
|
|
39
|
+
- Delete the message (preventing it from sending later).
|
|
40
|
+
- Retry sending manually.
|
|
41
|
+
- **Background Auto-Retry:** Listen for the browser's `online` event (`window.addEventListener('online', ...)`) and automatically attempt to send any pending messages in the queue once connectivity is restored.
|
|
42
|
+
|
|
43
|
+
## Security, Privacy, and Accessibility Concerns
|
|
44
|
+
- **Accessibility:** Ensure that dynamic layout changes (especially keyboard appearances) are announced correctly to screen readers if necessary. Offline and failed states must use clear iconography and have sufficient color contrast, rather than relying solely on color (e.g., don't just make it red, add an alert icon).
|
|
45
|
+
- **Privacy:** Pending messages will be stored locally on the user's device. For a web application, this means using `localStorage` or `IndexedDB`, which is accessible to anyone with access to the device/browser profile. Ensure sensitive data is not kept longer than necessary (e.g., clear the queue on successful sync or manual logout/clear data).
|
|
46
|
+
- **Security:** Ensure delta-sync fetching respects existing authentication and authorization scopes for the chat IDs.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Questions
|
|
2
|
+
|
|
3
|
+
1. **Question:** For offline messages, you mentioned 'allowing the user to send with one tap'. Should the app *only* wait for manual interaction to resend failed messages, or should it also attempt to automatically send them in the background once network connectivity is restored?
|
|
4
|
+
**Answer:** We can auto-send when back online; but users should have a chance to delete them if they are time-sensitive and can't be delivered.
|
|
5
|
+
|
|
6
|
+
2. **Question:** How should we handle syncing messages when a user returns to a chat after navigating away or returning to the tab from the background? Should we clear the message view and re-fetch the entire history, or just query for any new messages that arrived since the last received message ID?
|
|
7
|
+
**Answer:** Query for any new messages since the last ID seems best.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Web Chat UX Improvements Tickets
|
|
2
|
+
|
|
3
|
+
## Ticket 1: Mobile Layout and Viewport Optimization
|
|
4
|
+
**Description:** Fix layout issues caused by the virtual keyboard on mobile devices. Ensure the chat header and input remain visible and correctly anchored.
|
|
5
|
+
**Tasks:**
|
|
6
|
+
- Update `web/src/app.html` viewport meta tag to handle `interactive-widget=resizes-content` if appropriate, or adjust layout components.
|
|
7
|
+
- Refactor layout in `web/src/routes/+layout.svelte` and `web/src/routes/chats/[id]/+page.svelte` to use dynamic viewport units (`100dvh` instead of `h-svh` or standard `100vh`).
|
|
8
|
+
- Implement scroll anchoring to ensure the chat stays scrolled to the bottom when new messages arrive or the keyboard toggles.
|
|
9
|
+
**Verification:**
|
|
10
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test` from the `web/` directory.
|
|
11
|
+
- Manually test input focus and keyboard appearance on a mobile device or simulator to ensure header and input remain fully visible.
|
|
12
|
+
**Status:** complete
|
|
13
|
+
|
|
14
|
+
## Ticket 2: State Sync and Background Recovery
|
|
15
|
+
**Description:** Ensure chat data remains fresh when the user navigates away and returns, or when the connection drops.
|
|
16
|
+
**Tasks:**
|
|
17
|
+
- Add a `visibilitychange` event listener in the chat page to detect when the tab becomes visible again.
|
|
18
|
+
- Implement delta syncing to fetch only new messages (since the last known message ID) upon tab return or SSE reconnect.
|
|
19
|
+
- Update SSE logic in `setupSSE` to automatically attempt reconnection if the stream drops unexpectedly.
|
|
20
|
+
- Add a subtle "reconnecting..." UI indicator when the SSE connection is lost.
|
|
21
|
+
**Verification:**
|
|
22
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test` from the `web/` directory.
|
|
23
|
+
- Simulate network disconnects and backgrounding the tab to verify SSE reconnection and delta message fetching.
|
|
24
|
+
**Status:** complete
|
|
25
|
+
|
|
26
|
+
## Ticket 3: Offline Message Queue - Persistence & UI
|
|
27
|
+
**Description:** Implement the foundational logic for sending messages while offline and displaying their status.
|
|
28
|
+
**Tasks:**
|
|
29
|
+
- Modify the message sending logic to store pending messages in `localStorage` immediately upon hitting "send", before the network request.
|
|
30
|
+
- Introduce distinct UI states for messages in the chat view: Sending (Spinner), Offline / Pending (Grayed out with an icon), and Failed (Red error state with an alert icon).
|
|
31
|
+
- Render pending messages from `localStorage` inline with the actual chat history.
|
|
32
|
+
**Verification:**
|
|
33
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test` from the `web/` directory.
|
|
34
|
+
- Send a message while offline (using browser dev tools) and verify it appears in the chat with the "Offline / Pending" state and is persisted across page reloads.
|
|
35
|
+
**Status:** complete
|
|
36
|
+
|
|
37
|
+
## Ticket 4: Offline Message Queue - Actions & Auto-Retry
|
|
38
|
+
**Description:** Implement automatic and manual recovery mechanisms for offline messages.
|
|
39
|
+
**Tasks:**
|
|
40
|
+
- Listen for the browser's `online` event (`window.addEventListener('online', ...)`) to automatically attempt resending pending messages in the queue.
|
|
41
|
+
- Implement a tap/click action on offline/failed messages to reveal a menu.
|
|
42
|
+
- Add "Retry manual send" option to the menu.
|
|
43
|
+
- Add "Delete message" option to the menu to remove it from the pending queue before it sends.
|
|
44
|
+
**Verification:**
|
|
45
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test` from the `web/` directory.
|
|
46
|
+
- Test sending offline, then coming online to verify automatic retry.
|
|
47
|
+
- Test manual retry and deletion of a pending message.
|
|
48
|
+
**Status:** complete
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Development Log
|
|
2
|
+
|
|
3
|
+
## Step 1: Configuration Updates
|
|
4
|
+
- Starting work on Step 1: Updating the global settings schema to support the `api` configuration.
|
|
5
|
+
- Added `api` property to `SettingsSchema` in `src/shared/config.ts` supporting boolean or object with `host` and `port`.
|
|
6
|
+
- Created `src/shared/config.test.ts` to test `SettingsSchema` properties specifically around `api` configuration.
|
|
7
|
+
- Addressed minor formatting issues and fixed one incorrectly written unit test assertion.
|
|
8
|
+
- All code checks (`npm run format:check && npm run lint && npm run check && npm run test`) pass.
|
|
9
|
+
- Step 1 complete.
|
|
10
|
+
|
|
11
|
+
## Step 2: Daemon HTTP Server
|
|
12
|
+
- Started work on Step 2.
|
|
13
|
+
- Updated `src/daemon/index.ts` to read `settings.json`, check if the `api` configuration is enabled, and conditionally start an HTTP server on the configured host and port.
|
|
14
|
+
- Bound the same `createHTTPHandler` from `@trpc/server/adapters/standalone` to this API server to expose the tRPC router over HTTP.
|
|
15
|
+
- Handled graceful shutdown by closing the `apiServer` when `SIGINT` or `SIGTERM` signals are received.
|
|
16
|
+
- Added a new e2e test in `src/cli/e2e/daemon.test.ts` that configures `api` in `settings.json`, restarts the daemon, and checks the HTTP endpoint via a simple `/ping` request.
|
|
17
|
+
- Ran formatting, linting, and all tests via `npm run format:check && npm run lint && npm run check && npm run test`, ensuring all verification checks pass.
|
|
18
|
+
- Step 2 complete.
|
|
19
|
+
|
|
20
|
+
## Step 3: Agent Execution Context & Token Security
|
|
21
|
+
- Started work on Step 3.
|
|
22
|
+
- Implemented `src/daemon/auth.ts` to generate and validate `CLAW_API_TOKEN` using `crypto.createHmac`.
|
|
23
|
+
- Updated `src/daemon/router.ts` with `Context` resolving `isApiServer` and `tokenPayload`.
|
|
24
|
+
- Implemented `apiAuthMiddleware` in `src/daemon/router.ts` to require and validate auth tokens for HTTP API requests.
|
|
25
|
+
- Updated endpoints in `src/daemon/router.ts` to use `apiProcedure` and explicitly check if the agent context matches the requested `chatId` using `checkScope()`.
|
|
26
|
+
- Added logic in `src/daemon/message.ts` to inject `CLAW_API_URL` and `CLAW_API_TOKEN` into the environment of the executed agent process when the API is enabled in settings.
|
|
27
|
+
- Added unit tests in `src/daemon/auth.test.ts`.
|
|
28
|
+
- Added integration tests in `src/cli/e2e/daemon.test.ts` to verify the environment injection for spawned agents.
|
|
29
|
+
- All code checks pass successfully.
|
|
30
|
+
- Step 3 complete.
|
|
31
|
+
|
|
32
|
+
## Step 4: `clawmini export-lite` Command
|
|
33
|
+
- Started work on Step 4.
|
|
34
|
+
- Implemented a new command `export-lite` in `src/cli/commands/export-lite.ts`.
|
|
35
|
+
- Added the basic script content for `clawmini-lite.js` checking for `CLAW_API_URL` and `CLAW_API_TOKEN`.
|
|
36
|
+
- Bound the command in `src/cli/index.ts`.
|
|
37
|
+
- Supported saving to the current directory, a specific path via `--out`, and outputting to stdout via `--stdout`.
|
|
38
|
+
- Created e2e CLI tests in `src/cli/e2e/export-lite.test.ts` to verify output correctly saves to file paths or stdout.
|
|
39
|
+
- Ran all verification steps successfully with `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
40
|
+
- Step 4 complete.
|
|
41
|
+
|
|
42
|
+
## Step 5: `clawmini-lite` Client Functionality
|
|
43
|
+
- Started work on Step 5.
|
|
44
|
+
- Added a new `logMessage` endpoint to `src/daemon/router.ts` to allow agents to append a log message to the chat.
|
|
45
|
+
- Updated `logMessage`, `listCronJobs`, `addCronJob`, and `deleteCronJob` in `src/daemon/router.ts` to automatically infer the `chatId` from the agent's authentication token (`ctx.tokenPayload.chatId`) if not explicitly provided over HTTP API requests.
|
|
46
|
+
- Updated `liteScriptContent` in `src/cli/commands/export-lite.ts` to implement full `clawmini-lite` functionality.
|
|
47
|
+
- Created a robust zero-dependency script parser inside `clawmini-lite` that handles `--flags` properly.
|
|
48
|
+
- Implemented batched syntax for GET requests and proper body parsing for POST requests within `trpcCall`.
|
|
49
|
+
- Supported subcommands: `log <message>`, `jobs list`, `jobs add`, `jobs delete`.
|
|
50
|
+
- Created an end-to-end functionality test `src/cli/e2e/export-lite-func.test.ts` to verify `clawmini-lite` interacts seamlessly with the daemon HTTP API.
|
|
51
|
+
- Verified everything with formatting, linting, type checks, and tests: `npm run format:check && npm run lint && npm run check && npm run test`. All 95 tests pass.
|
|
52
|
+
- Step 5 complete.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Agent API Notes
|
|
2
|
+
|
|
3
|
+
## Current State
|
|
4
|
+
|
|
5
|
+
- The daemon uses a tRPC server over a Unix socket (`.clawmini/daemon.sock`) to communicate between the CLI and the daemon.
|
|
6
|
+
- When an agent is run, the daemon uses `spawn` to run shell commands (like `new` or `append`). It passes arguments securely via environment variables (e.g., `CLAW_CLI_MESSAGE`).
|
|
7
|
+
- Agents running on the same host can just use the `clawmini` CLI (e.g., `clawmini jobs list`), as the CLI automatically finds the Unix socket.
|
|
8
|
+
- The `clawmini` CLI interacts with the Unix socket by configuring a `http` proxy to the socket file.
|
|
9
|
+
|
|
10
|
+
## The Problem
|
|
11
|
+
|
|
12
|
+
- Agents may be sandboxed (e.g., running in Docker/Podman, potentially inside a VM on macOS).
|
|
13
|
+
- Sandboxed agents might not have direct access to the `.clawmini/daemon.sock` Unix socket file, meaning they cannot just run the `clawmini` CLI command to orchestrate changes.
|
|
14
|
+
- Furthermore, giving a sandboxed agent full access to the Unix socket means the agent could arbitrarily execute commands on the host by exploiting the `sendMessage` daemon endpoint.
|
|
15
|
+
|
|
16
|
+
## Proposed Solution
|
|
17
|
+
|
|
18
|
+
- **Web Server:** The daemon should optionally expose an HTTP server bound to a user-defined host/port (e.g., `127.0.0.1:3000` or `0.0.0.0:3000`). This can be configured in `.clawmini/settings.json`.
|
|
19
|
+
- **Authentication/Context:** When the daemon spawns an agent command, it should inject new environment variables, such as:
|
|
20
|
+
- `CLAW_CHAT_ID`: To identify which chat the agent belongs to.
|
|
21
|
+
- `CLAW_AGENT_ID`: To identify the agent.
|
|
22
|
+
- `CLAW_API_URL`: The URL of the web server (e.g., `http://host.docker.internal:3000`).
|
|
23
|
+
- `CLAW_API_TOKEN` (optional but recommended): A dynamically generated bearer token for the current execution to securely authenticate the agent back to the host.
|
|
24
|
+
- **`clawmini-lite`:** Create a single, lightweight bash/sh script (`clawmini-lite`) that can be mounted or downloaded into the sandbox. This script will make standard `curl` requests to the HTTP server using the injected environment variables.
|
|
25
|
+
- **Allowed Capabilities:** The HTTP server should only expose a restricted subset of endpoints (like appending to a chat log or manipulating jobs), ensuring the agent cannot execute arbitrary commands on the host.
|
|
26
|
+
|
|
27
|
+
## Relevant Code
|
|
28
|
+
- `src/daemon/index.ts`: Initialization of the Unix socket HTTP server.
|
|
29
|
+
- `src/daemon/router.ts`: The tRPC appRouter. We can use the same router or expose a subset for the external web server.
|
|
30
|
+
- `src/shared/config.ts`: `SettingsSchema` will need to be updated to support something like `server: { host: string, port: number }`.
|
|
31
|
+
- `src/daemon/message.ts`: Where the environment variables are injected (`CLAW_CLI_MESSAGE`). We'll need to add `CLAW_CHAT_ID`, `CLAW_API_URL`, etc.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Product Requirements Document: Agent API
|
|
2
|
+
|
|
3
|
+
## 1. Vision
|
|
4
|
+
Enable sandboxed or containerized agents to securely interact with the host Clawmini daemon. By providing a secure, lightweight web server and a standalone CLI utility (`clawmini-lite`), agents running in environments (e.g., Docker, VMs) without direct access to the host's Unix socket can still perform controlled actions like logging messages or managing cron jobs within their current chat context.
|
|
5
|
+
|
|
6
|
+
## 2. Product/Market Background
|
|
7
|
+
Currently, Clawmini relies on a Unix socket (`.clawmini/daemon.sock`) for communication between the CLI and the daemon. This works perfectly when the agent runs directly on the user's host machine. However, as agents grow more sophisticated, running them in isolated environments like Docker or Podman becomes necessary for security and environment consistency (especially on macOS, where these run inside a VM). These sandboxed agents lose access to the Unix socket and, consequently, the ability to orchestrate tasks via the `clawmini` CLI.
|
|
8
|
+
|
|
9
|
+
This feature bridges that gap by exposing a configurable HTTP API for the daemon and providing a portable, zero-configuration utility (`clawmini-lite`) for agents to use.
|
|
10
|
+
|
|
11
|
+
## 3. Use Cases
|
|
12
|
+
* **Sandboxed Logging:** An agent running in a Docker container needs to log its internal reasoning or tool execution status directly to the user's chat interface (Markdown log).
|
|
13
|
+
* **Job Management:** A containerized agent wants to schedule a follow-up job to check an API in 10 minutes, or it wants to list the active jobs for its chat to manage its state.
|
|
14
|
+
* **Secure Multi-Agent Environments:** An environment where multiple agents are running in separate containers, all needing to communicate status updates back to the host daemon without having root-level access to the system.
|
|
15
|
+
|
|
16
|
+
## 4. Requirements
|
|
17
|
+
|
|
18
|
+
### 4.1 Daemon HTTP Server
|
|
19
|
+
* The daemon must optionally start an HTTP server in addition to the Unix socket server.
|
|
20
|
+
* **Configuration (`.clawmini/settings.json`):**
|
|
21
|
+
* A new `api` key should be added to the global `settings.json`.
|
|
22
|
+
* `api: false` (default): The web server does not start.
|
|
23
|
+
* `api: true`: The web server starts on `127.0.0.1` with a default port (e.g., 3000).
|
|
24
|
+
* `api: { host: "0.0.0.0", port: 8080 }`: The web server starts on the specified host and port.
|
|
25
|
+
* The HTTP server should expose the tRPC router (or a subset of it).
|
|
26
|
+
|
|
27
|
+
### 4.2 Agent Execution Context & Security
|
|
28
|
+
* When the daemon spawns an agent command (`new` or `append`), it must inject necessary connection details into the process's environment.
|
|
29
|
+
* **Injected Environment Variables:**
|
|
30
|
+
* `CLAW_API_URL`: The URL of the daemon's HTTP server (if enabled).
|
|
31
|
+
* `CLAW_API_TOKEN`: A secure, cryptographically signed or encrypted token generated for this specific execution.
|
|
32
|
+
* **Token Payload (`CLAW_API_TOKEN`):**
|
|
33
|
+
* The token must encode context such as: `chatId`, `agentId`, `sessionId`, and a `timestamp`.
|
|
34
|
+
* This prevents the agent from interacting with chats or jobs it is not authorized for.
|
|
35
|
+
* **Authentication:** The HTTP server endpoints must validate `CLAW_API_TOKEN` (e.g., via the Authorization header).
|
|
36
|
+
|
|
37
|
+
### 4.3 `clawmini-lite` Utility
|
|
38
|
+
* A standalone Node.js script (with a shebang `#!/usr/bin/env node`) that serves as a lightweight client for the agent to use inside its sandbox.
|
|
39
|
+
* **Distribution:**
|
|
40
|
+
* A new CLI command `clawmini export-lite` must be added.
|
|
41
|
+
* By default, it writes the `clawmini-lite` script to the current directory.
|
|
42
|
+
* It should support an optional file path argument or a `--stdout` flag to pipe the contents.
|
|
43
|
+
* **Functionality:**
|
|
44
|
+
* It must automatically detect and use `CLAW_API_URL` and `CLAW_API_TOKEN` from the environment.
|
|
45
|
+
* It must communicate with the daemon via tRPC over HTTP.
|
|
46
|
+
* **Supported Commands:**
|
|
47
|
+
* `clawmini-lite log <message>`: Appends a `{type: "log"}` message to the chat's Markdown log.
|
|
48
|
+
* `clawmini-lite jobs list`: Lists cron jobs for the current chat.
|
|
49
|
+
* `clawmini-lite jobs add <...>`: Adds a job for the current chat.
|
|
50
|
+
* `clawmini-lite jobs delete <id>`: Deletes a job from the current chat.
|
|
51
|
+
* *Note: Commands operate purely within the context defined by `CLAW_API_TOKEN`.*
|
|
52
|
+
|
|
53
|
+
## 5. Non-Functional Concerns
|
|
54
|
+
* **Security:** By relying on a signed token (`CLAW_API_TOKEN`), we ensure the agent cannot forge context to access or modify data belonging to other chats or agents. The web server should ideally have strict CORS and possibly rate-limiting if exposed widely.
|
|
55
|
+
* **Dependencies:** `clawmini-lite` should ideally have zero external runtime dependencies other than Node.js, so it can run cleanly in minimal Docker images. It can use Node's built-in `fetch` for HTTP requests.
|
|
56
|
+
* **Extensibility:** The API and `clawmini-lite` architecture must be designed to allow adding new commands (like reading chat history or updating agent state) in the future without major refactoring.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Agent API Questions
|
|
2
|
+
|
|
3
|
+
1. **Authentication/Security:** Since the TCP web server might be exposed on `0.0.0.0` (to allow VM/Docker access), should the daemon generate a secure, random token (e.g., `CLAW_API_TOKEN`) passed to the agent's environment? This would prevent unauthorized access to the daemon from other local processes or network devices.
|
|
4
|
+
- **Answer:** Yes. The daemon will inject a single `CLAW_API_TOKEN` which encodes the chat ID, agent ID, and creation time, serving both as authentication and context payload.
|
|
5
|
+
2. **API Protocol:** `clawmini-lite` will be a minimal shell script using `curl`. Should the web server expose a simple REST API (e.g., `POST /api/v1/jobs`) instead of tRPC, to make it easier to construct payloads via bash?
|
|
6
|
+
- **Answer:** We should make `clawmini-lite` a Node.js script (with a shebang) instead of a bash script. This will allow the script to be more complex, use tRPC natively, and easily scale as the API surface grows over time.
|
|
7
|
+
3. **Environment Variable Naming:** You suggested `$CHAT_ID` and `$AGENT_ID`. To avoid collision with existing variables and stay consistent with `$CLAW_CLI_MESSAGE`, should we prefix them as `$CLAW_CHAT_ID` and `$CLAW_AGENT_ID`?
|
|
8
|
+
- **Answer:** We will use a single token (e.g., `CLAW_API_TOKEN`) that encodes all relevant context (chat id, agent id, message id, timestamp, etc.). This token will be encrypted or signed to prevent spoofing, simplifying the environment setup to just this one variable. The web server's address will be passed as `CLAW_API_URL`.
|
|
9
|
+
4. **Distribution of clawmini-lite:** How should sandboxed agents acquire the `clawmini-lite` node script? Should the CLI offer a command like `clawmini lite-script` that outputs the script content so users can easily pipe it into their Docker build/sandbox setup?
|
|
10
|
+
- **Answer:** Yes, a command like `clawmini export-lite` (or similar) will write `clawmini-lite` to the current directory by default, allow an optional output path, or allow printing to stdout.
|
|
11
|
+
5. **Web API Port Configuration:** In `.clawmini/settings.json`, what should the configuration key look like for starting the HTTP server? Something like `"api": { "host": "127.0.0.1", "port": 3000 }`? Should the web server start by default, or only if this configuration exists?
|
|
12
|
+
- **Answer:** The `api` configuration in `settings.json` should be `false` by default. Setting it to `true` enables it on localhost on a default port. Users can also provide an object `{ host?: string, port?: string | number }` to override defaults.
|
|
13
|
+
6. **Log Message Action:** You mentioned "adding a log message to the chat". Does this mean appending text to the chat's Markdown log file directly, or does it mean inserting a system message/event into the stream?
|
|
14
|
+
- **Answer:** It means adding a message of `{type: "log"}` directly to the chat's markdown log.
|