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,116 @@
|
|
|
1
|
+
# Tickets: Discord Adapter for Clawmini
|
|
2
|
+
|
|
3
|
+
## Step 1: Scaffold Discord Adapter
|
|
4
|
+
- **Description:**
|
|
5
|
+
- Create the `src/adapter-discord` directory.
|
|
6
|
+
- Create a basic entry point in `src/adapter-discord/index.ts` that logs a startup message.
|
|
7
|
+
- Update `tsdown.config.ts` to include the new entry point.
|
|
8
|
+
- Add `discord.js` to `package.json` dependencies.
|
|
9
|
+
- **Verification:**
|
|
10
|
+
- `npm run check` passes.
|
|
11
|
+
- `npm run build` generates `dist/adapter-discord/index.mjs`.
|
|
12
|
+
- Running `node dist/adapter-discord/index.mjs` prints the startup message.
|
|
13
|
+
- **Status:** completed
|
|
14
|
+
|
|
15
|
+
## Step 2: Configuration & Security Implementation
|
|
16
|
+
- **Description:**
|
|
17
|
+
- Define the configuration schema using Zod in `src/adapter-discord/config.ts`.
|
|
18
|
+
- Implement logic to load configuration from `.clawmini/adapters/discord/config.json`.
|
|
19
|
+
- Implement an `isAuthorized(userId: string)` helper to filter Discord messages.
|
|
20
|
+
- **Verification:**
|
|
21
|
+
- Unit tests in `src/adapter-discord/config.test.ts` for schema validation and file loading.
|
|
22
|
+
- Unit tests for the authorization filter.
|
|
23
|
+
- `npm run format:check && npm run lint && npm run check && npm run test` passes.
|
|
24
|
+
- **Status:** completed
|
|
25
|
+
|
|
26
|
+
## Step 3: TRPC Client Connection
|
|
27
|
+
- **Description:**
|
|
28
|
+
- Implement a TRPC client in `src/adapter-discord/client.ts` that connects to the daemon via the Unix socket, leveraging the shared logic in `src/shared/fetch.ts` if possible.
|
|
29
|
+
- **Verification:**
|
|
30
|
+
- Integration test mocking the Unix socket and verifying TRPC calls from the adapter client.
|
|
31
|
+
- `npm run check && npm run test` passes.
|
|
32
|
+
- **Status:** completed
|
|
33
|
+
|
|
34
|
+
## Step 4: Discord to Daemon Forwarding
|
|
35
|
+
- **Description:**
|
|
36
|
+
- Initialize the `discord.js` client in `src/adapter-discord/index.ts`.
|
|
37
|
+
- Listen for `messageCreate` events in DM channels.
|
|
38
|
+
- Validate the sender using the authorized user ID.
|
|
39
|
+
- Forward the message content to the daemon using the `sendMessage` TRPC endpoint.
|
|
40
|
+
- **Verification:**
|
|
41
|
+
- Mocked `discord.js` event test verifying that receiving a DM triggers a TRPC `sendMessage` call.
|
|
42
|
+
- `npm run format:check && npm run lint && npm run check && npm run test` passes.
|
|
43
|
+
- **Status:** completed
|
|
44
|
+
|
|
45
|
+
## Step 5: Daemon Message Observation Enhancement
|
|
46
|
+
- **Description:**
|
|
47
|
+
- Update `src/daemon/router.ts` and related files to support message observation.
|
|
48
|
+
- Since TRPC 11 is used, consider adding an SSE or long-polling endpoint if full subscriptions aren't trivial in the current Unix socket setup, or just a `getMessagesAfter(timestamp)` endpoint.
|
|
49
|
+
- *Note:* The PRD suggests "message subscription/observation mechanism".
|
|
50
|
+
- **Verification:**
|
|
51
|
+
- Unit/Integration tests for the new observation endpoint.
|
|
52
|
+
- Verify that sending a message via TRPC results in the observer being notified.
|
|
53
|
+
- `npm run check && npm run test` passes.
|
|
54
|
+
- **Status:** completed
|
|
55
|
+
|
|
56
|
+
## Step 6: Daemon to Discord Forwarding
|
|
57
|
+
- **Description:**
|
|
58
|
+
- In the adapter, use the new observation mechanism to listen for new messages from the daemon.
|
|
59
|
+
- When a new message is received, send it to the authorized user's Discord DM channel using the bot client.
|
|
60
|
+
- **Verification:**
|
|
61
|
+
- Integration test verifying that a message appearing in the daemon's observation stream is forwarded to the Discord mock client.
|
|
62
|
+
- `npm run check && npm run test` passes.
|
|
63
|
+
- **Status:** completed
|
|
64
|
+
|
|
65
|
+
## Step 7: State Management & Startup Sync
|
|
66
|
+
- **Description:**
|
|
67
|
+
- Implement `src/adapter-discord/state.ts` to manage `.clawmini/adapters/discord/state.json`.
|
|
68
|
+
- Track the `lastSyncedMessageId` or timestamp.
|
|
69
|
+
- On adapter startup, fetch all messages from the daemon after the stored cursor and send them to Discord.
|
|
70
|
+
- **Verification:**
|
|
71
|
+
- Unit tests for state persistence.
|
|
72
|
+
- Integration test for the startup sync logic.
|
|
73
|
+
- `npm run check && npm run test` passes.
|
|
74
|
+
- **Status:** completed
|
|
75
|
+
|
|
76
|
+
## Step 8: Debouncing & Robustness
|
|
77
|
+
- **Description:**
|
|
78
|
+
- Add debouncing logic to handle rapid Discord messages (if necessary for the daemon's message queue).
|
|
79
|
+
- Improve error handling (e.g., bot reconnect logic, daemon connection retry).
|
|
80
|
+
- **Verification:**
|
|
81
|
+
- Unit tests for debouncing.
|
|
82
|
+
- `npm run format:check && npm run lint && npm run check && npm run test` passes.
|
|
83
|
+
- **Status:** completed
|
|
84
|
+
|
|
85
|
+
## Step 9: Documentation
|
|
86
|
+
- **Description:**
|
|
87
|
+
- Create `./docs/guides/discord_adapter_setup.md` with full setup instructions.
|
|
88
|
+
- **Verification:**
|
|
89
|
+
- File exists and contains clear steps for Bot creation, Token retrieval, and Configuration.
|
|
90
|
+
- **Status:** completed
|
|
91
|
+
|
|
92
|
+
## Issue 1: Performance bug in `waitForMessages`
|
|
93
|
+
- **Priority:** High
|
|
94
|
+
- **Description:**
|
|
95
|
+
- In `src/daemon/router.ts`, `waitForMessages` reads the entire `chat.jsonl` file to check for new messages even when `input.lastMessageId` is undefined. This causes unnecessary and expensive file I/O operations every time the long-polling request fires.
|
|
96
|
+
- Fix by wrapping the initial `getMessages` call in an `if (input.lastMessageId)` block.
|
|
97
|
+
- **Status:** completed
|
|
98
|
+
|
|
99
|
+
## Issue 2: `chunkString` breaks multi-byte characters (emojis/unicode)
|
|
100
|
+
- **Priority:** High
|
|
101
|
+
- **Description:**
|
|
102
|
+
- In `src/adapter-discord/forwarder.ts`, `chunkString` uses `String.prototype.slice()` directly. This splits strings by UTF-16 code units rather than code points, which will corrupt emojis and special characters if they land on a chunk boundary.
|
|
103
|
+
- Fix by using `Array.from(str)` to safely count and chunk by unicode characters.
|
|
104
|
+
- **Status:** completed
|
|
105
|
+
|
|
106
|
+
## Issue 3: Redundant existence check in `initDiscordConfig`
|
|
107
|
+
- **Priority:** Medium
|
|
108
|
+
- **Description:**
|
|
109
|
+
- `fs.existsSync(configDir)` check is redundant in `initDiscordConfig` (`src/adapter-discord/config.ts`) because `fsPromises.mkdir(configDir, { recursive: true })` handles existing directories natively.
|
|
110
|
+
- **Status:** completed
|
|
111
|
+
|
|
112
|
+
## Issue 4: Unnecessary `GatewayIntentBits.Guilds` requested
|
|
113
|
+
- **Priority:** Low
|
|
114
|
+
- **Description:**
|
|
115
|
+
- In `src/adapter-discord/index.ts`, `GatewayIntentBits.Guilds` is requested but the bot explicitly ignores all guild messages (`if (message.guild) return;`). It should be removed to follow the principle of least privilege.
|
|
116
|
+
- **Status:** completed
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Development Log
|
|
2
|
+
|
|
3
|
+
- Implemented Ticket 1: Configuration Updates.
|
|
4
|
+
- Added optional `files` string property (defaulting to `"./attachments"`) to `SettingsSchema` and `AgentSchema` in `src/shared/config.ts`.
|
|
5
|
+
- Added optional `maxAttachmentSizeMB` number property (defaulting to `25`) to `DiscordConfigSchema` in `src/adapter-discord/config.ts`.
|
|
6
|
+
- Added unit tests for these new properties in `src/shared/config.test.ts` and `src/adapter-discord/config.test.ts`.
|
|
7
|
+
- Updated test for `Agent Settings read/write` in `src/shared/workspace.test.ts` to accommodate the default `files` parameter.
|
|
8
|
+
- Ran all verification checks (`npm run format:check && npm run lint && npm run check && npm run test`), successfully passing.
|
|
9
|
+
|
|
10
|
+
- Implemented Ticket 2: TRPC Schema and Discord Adapter Download.
|
|
11
|
+
- Updated `sendMessage` payload schema in `src/daemon/router.ts` to accept an optional array of strings for `files`.
|
|
12
|
+
- Modified `src/adapter-discord/index.ts` to download Discord attachments to a temporary directory (`.gemini/tmp/discord-files/`), respecting the `maxAttachmentSizeMB` limit.
|
|
13
|
+
- Updated `messageDebouncer` in the Discord adapter to aggregate both message content and temporary file paths before forwarding to the daemon.
|
|
14
|
+
- Added comprehensive unit tests in `src/adapter-discord/index.test.ts` for downloading attachments, size limit enforcement, and updated mock dependencies appropriately.
|
|
15
|
+
- Fixed a minor logging bug regarding the fallback default for `maxAttachmentSizeMB`.
|
|
16
|
+
- Re-ran all tests and formatting checks successfully.
|
|
17
|
+
|
|
18
|
+
- Implemented Ticket 3: Daemon Processing of Incoming Files.
|
|
19
|
+
- Updated `sendMessage` schema in `src/daemon/router.ts` to include an optional `adapter` property.
|
|
20
|
+
- Modified the Discord adapter in `src/adapter-discord/index.ts` to explicitly provide `adapter: 'discord'`.
|
|
21
|
+
- Intercepted incoming file paths in `src/daemon/router.ts` immediately before `handleUserMessage`.
|
|
22
|
+
- Moved temporary files into the configured agent's `files` directory (namespaced by the adapter name).
|
|
23
|
+
- Implemented file name collision resolution using a timestamp suffix.
|
|
24
|
+
- Appended the finalized relative file paths to the user's message context automatically.
|
|
25
|
+
- Added comprehensive unit tests in `src/daemon/router.test.ts` to cover file moving logic, collision handling, and message text formatting.
|
|
26
|
+
- Updated the existing mock configurations and fixed linting warnings (e.g. `import('node:fs').Stats`, unused errors).
|
|
27
|
+
- All checks (`npm run format:check && npm run lint && npm run check && npm run test`) pass successfully.
|
|
28
|
+
|
|
29
|
+
- Implemented Ticket 4: Outgoing Files via CLI & Daemon (Agent to User).
|
|
30
|
+
- Updated the internal `CommandLogMessage` schema in `src/shared/chats.ts` to include an optional `file` property.
|
|
31
|
+
- Modified the `logMessage` endpoint in `src/daemon/router.ts` to accept an optional `file` path, with robust path traversal validation ensuring the file resolves inside the agent workspace.
|
|
32
|
+
- Disabled `max-lines` for `src/daemon/router.ts` due to expanded file logging checks.
|
|
33
|
+
- Updated `messagesCmd` in `src/cli/commands/messages.ts` to parse a new `-f, --file <path>` argument.
|
|
34
|
+
- Enhanced `clawmini-lite log` command in `src/cli/lite.ts` to support the `--file` flag and pass it to the `logMessage` endpoint.
|
|
35
|
+
- Added comprehensive unit tests in `src/daemon/router.test.ts` verifying path validation and log schemas.
|
|
36
|
+
- Expanded end-to-end tests in `src/cli/e2e/messages.test.ts` and `src/cli/e2e/export-lite-func.test.ts` for explicit file handling and logging functionalities.
|
|
37
|
+
- Ran all format, lint, and type checking pipelines successfully.
|
|
38
|
+
|
|
39
|
+
- Implemented Ticket 5: Discord Adapter Forwarding Outgoing Files.
|
|
40
|
+
- Updated `src/adapter-discord/forwarder.ts` to check for `message.file` when processing log messages from the daemon.
|
|
41
|
+
- Updated `dm.send()` to include file attachments using the `files` array option in Discord.js.
|
|
42
|
+
- Handled the 2000 character limit by correctly splitting messages into chunks, attaching the file only to the final chunk.
|
|
43
|
+
- Updated existing forwarder tests in `src/adapter-discord/forwarder.test.ts` to use object payloads instead of string values.
|
|
44
|
+
- Added comprehensive test cases ensuring files are forwarded, chunked messages handle attachments correctly, and empty messages with just file paths work without errors.
|
|
45
|
+
- Ran formatting, linting, and tests successfully.
|
|
46
|
+
|
|
47
|
+
- Implemented Ticket 7: Path Validation Security Enhancements.
|
|
48
|
+
- Updated `sendMessage` mutation in `src/daemon/router.ts` to strictly validate `targetDir` is within the workspace using `pathIsInsideDir`.
|
|
49
|
+
- Ensured all incoming `files` are strictly inside `$WORKSPACE/.clawmini/tmp/` and actually exist via `fs.access`.
|
|
50
|
+
- Updated `logMessage` mutation to forbid absolute paths and path traversal `..` in the `file` input.
|
|
51
|
+
- Validated that the resolved file path in `logMessage` stays strictly within both the agent's folder and the overall workspace.
|
|
52
|
+
- Enforced file existence checks on disk before persisting log entries.
|
|
53
|
+
- Modified `src/cli/commands/messages.ts` (CLI send command) to automatically copy attached files to `.clawmini/tmp` prior to submitting them to the daemon.
|
|
54
|
+
- Enhanced tests in `src/daemon/router.test.ts` to assert security validations for both `sendMessage` and `logMessage`.
|
|
55
|
+
- Tests all run successfully including format, lint, type checking, and test suites.- Implemented Ticket 6: Code Critique and Fixes. Fixed DRY violation in src/daemon/router.ts when resolving agent.directory by creating resolveAgentDir and getUniquePath utilities. Other tasks in Ticket 6 were already completed.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# File Attachments - Research Notes
|
|
2
|
+
|
|
3
|
+
## Current Architecture
|
|
4
|
+
- Incoming messages from Discord are received in `src/adapter-discord/index.ts` via `Events.MessageCreate`.
|
|
5
|
+
- Only `message.content` is currently processed and added to the debouncer, then sent to the daemon via `trpc.sendMessage.mutate`.
|
|
6
|
+
- The daemon appends a `UserMessage` to the chat log (`chat.jsonl`).
|
|
7
|
+
- The agent is executed and logs the result as a `CommandLogMessage` (or a router log).
|
|
8
|
+
- `src/adapter-discord/forwarder.ts` subscribes to new messages via `trpc.waitForMessages`. It reads `CommandLogMessage` logs and forwards `message.content` via `dm.send()`.
|
|
9
|
+
|
|
10
|
+
## Missing Features for Attachments
|
|
11
|
+
1. **Downloading incoming attachments:**
|
|
12
|
+
- Discord's `message.attachments` contains attachments.
|
|
13
|
+
- We need to download them locally to a directory.
|
|
14
|
+
- Proposed location: `[workspace_root]/.gemini/chats/[chatId]/files/` or a temporary directory like `.gemini/tmp/discord-files/`.
|
|
15
|
+
2. **Referencing attachments in the input message:**
|
|
16
|
+
- Once downloaded, we need to append or prepend `File attached: <path>` to the user's message before sending it to the daemon.
|
|
17
|
+
3. **Path Translation:**
|
|
18
|
+
- The user noted that the agent might be running in a VM/container with different absolute paths.
|
|
19
|
+
- If we save the file to the host's `/home/user/workspace/discord-files/...` and pass this absolute path, the container won't find it.
|
|
20
|
+
- **Solution ideas:**
|
|
21
|
+
- Use relative paths from the workspace root (e.g., `.gemini/chats/default/files/file.txt`).
|
|
22
|
+
- Introduce path mapping in the configuration (e.g., `pathMappings: [{ host: '/home/user/...', container: '/workspace/...' }]`).
|
|
23
|
+
4. **Outgoing attachments:**
|
|
24
|
+
- The agent will output `File attached: <path>`.
|
|
25
|
+
- The Discord adapter needs to parse this from the `content` or have it explicitly represented in the `CommandLogMessage` schema.
|
|
26
|
+
- It will need to read the file from the filesystem and attach it using `dm.send({ files: [path] })`.
|
|
27
|
+
|
|
28
|
+
## Refined approach (Q1)
|
|
29
|
+
- Agent settings will define a `files` directory (e.g., `./attachments`).
|
|
30
|
+
- Discord adapter saves incoming files to a temporary location: `.clawmini/adapters/discord/files/foo.png`.
|
|
31
|
+
- The adapter includes the paths to these temp files in the RPC message sent to the daemon.
|
|
32
|
+
- The daemon intercepts these paths, moves the files into the agent's configured `files` directory, namespaced by the adapter (e.g., `./attachments/discord/foo.png`), and prepends these final relative/absolute paths to the user message.
|
|
33
|
+
|
|
34
|
+
## Refined approach (Q2)
|
|
35
|
+
- To avoid absolute path mapping issues for containerized agents, pass the file paths relative to the agent's working directory (e.g., `./attachments/discord/foo.png`), leveraging the fact that the agent executes within its specific folder.
|
|
36
|
+
|
|
37
|
+
## Refined approach (Q3)
|
|
38
|
+
- For outgoing files, instead of relying on parsing log messages, agents will use the `clawmini-lite` client to explicitly send a file back: `clawmini-lite messages send --file ./path/to/file "here you go"`.
|
|
39
|
+
- This API call will be authenticated via `$CLAW_API_TOKEN`, routed to the daemon, and appended to the chat, subsequently picked up by the adapter and sent to Discord.
|
|
40
|
+
|
|
41
|
+
## Refined approach (Q4)
|
|
42
|
+
- File limits: allow configuration in discord adapter settings, with reasonable defaults (e.g. 10MB or 25MB).
|
|
43
|
+
- Default agent files directory: `./attachments`.
|
|
44
|
+
|
|
45
|
+
## Path Validation Security Enhancements
|
|
46
|
+
Based on the new request, strict path validation is required for both incoming and outgoing files to ensure security and prevent path traversal or leaking arbitrary files.
|
|
47
|
+
|
|
48
|
+
**For incoming messages (User -> Agent):**
|
|
49
|
+
- In `sendMessage` TRPC endpoint (`src/daemon/router.ts`), before processing `input.data.files`:
|
|
50
|
+
- Verify every file path exists.
|
|
51
|
+
- Verify every file path is strictly located within `$WORKSPACE/.clawmini/tmp/`.
|
|
52
|
+
- Verify that the target directory (`targetDir`) where files are being moved is strictly within `$WORKSPACE`.
|
|
53
|
+
|
|
54
|
+
**For outgoing files (Agent -> User):**
|
|
55
|
+
- In `logMessage` TRPC endpoint (`src/daemon/router.ts`), when processing `input.file`:
|
|
56
|
+
- Ensure `input.file` is a relative path (e.g., does not start with `/` or `C:\`).
|
|
57
|
+
- Ensure the resolved path is within the agent's designated directory.
|
|
58
|
+
- Ensure the resolved path is within the overall `$WORKSPACE`.
|
|
59
|
+
- Ensure the file actually exists on the filesystem *before* resolving it or recording it in the log message.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Product Requirements Document (PRD): File Attachments
|
|
2
|
+
|
|
3
|
+
## 1. Vision
|
|
4
|
+
Enable seamless sharing of files and attachments between users (via Discord) and the backend agents executing inside containers or local environments. This functionality provides a crucial building block for multimodal interactions and more sophisticated workflows where agents manipulate, review, or generate binary/text artifacts.
|
|
5
|
+
|
|
6
|
+
## 2. Product/Market Background
|
|
7
|
+
Currently, the Discord adapter receives incoming text messages and forwards them to the Clawmini daemon. The daemon writes these to `chat.jsonl` and invokes the configured agent, capturing stdout/stderr as logs and text responses.
|
|
8
|
+
However, modern generative AI and bot interactions often involve files—such as sending a source code file to be debugged, an image to be analyzed, or requesting the bot to generate and return a PDF.
|
|
9
|
+
|
|
10
|
+
By supporting attachments natively:
|
|
11
|
+
- **Users** can simply upload files in Discord and get them analyzed by an agent.
|
|
12
|
+
- **Agents** can generate files (logs, assets, exported data) and send them explicitly back to the user on Discord.
|
|
13
|
+
|
|
14
|
+
## 3. Use Cases
|
|
15
|
+
- **User to Agent (Incoming):** A user drag-and-drops an image or a `.csv` file into a Discord DM. The agent receives the path to the file on its local filesystem, reads it, processes it, and returns an analysis in text.
|
|
16
|
+
- **Agent to User (Outgoing):** An agent is tasked with scraping a website and generating a `.zip` archive. Once complete, the agent uses the `clawmini-lite` CLI tool to send the archive directly back to the user on Discord alongside a confirmation message.
|
|
17
|
+
|
|
18
|
+
## 4. Requirements
|
|
19
|
+
|
|
20
|
+
### 4.1 Configuration Updates
|
|
21
|
+
1. **Agent Configuration (`SettingsSchema` / `AgentSchema`)**
|
|
22
|
+
- Agents should support a new configuration property for defining the files directory, with a default of `./attachments`.
|
|
23
|
+
- Example: `files: "./attachments"`
|
|
24
|
+
|
|
25
|
+
2. **Discord Adapter Configuration (`DiscordConfigSchema`)**
|
|
26
|
+
- The Discord adapter should support configurable file size limits for incoming files to prevent abuse or disk space exhaustion.
|
|
27
|
+
- New optional config values:
|
|
28
|
+
- `maxAttachmentSizeMB`: e.g., default `25` (to match Discord's standard limits).
|
|
29
|
+
|
|
30
|
+
### 4.2 Incoming File Attachments (Discord -> Agent)
|
|
31
|
+
1. **Adapter Processing:**
|
|
32
|
+
- On receiving a `MessageCreate` event with `message.attachments`, the Discord adapter will download the files to a local, temporary directory (e.g., `.clawmini/adapters/discord/files/`).
|
|
33
|
+
- The adapter will construct a message payload to send to the daemon via TRPC (`sendMessage.mutate`) that includes both the user's text and a list of temporary file paths.
|
|
34
|
+
- *Note: This implies extending the TRPC payload or embedding the file data/paths in a structured way.*
|
|
35
|
+
|
|
36
|
+
2. **Daemon Processing:**
|
|
37
|
+
- The daemon intercepts the TRPC message containing the temporary file paths.
|
|
38
|
+
- It resolves the target agent and determines the agent's `files` directory (defaulting to `./attachments`).
|
|
39
|
+
- The daemon moves the temporary files from the adapter's directory to the agent's files directory, namespaced by the adapter (e.g., `./attachments/discord/<filename>`).
|
|
40
|
+
- The daemon prepends or appends a standard reference to these files in the input message string provided to the agent:
|
|
41
|
+
- Example format: `Attached files:
|
|
42
|
+
- ./attachments/discord/foo.png
|
|
43
|
+
|
|
44
|
+
<user message>`
|
|
45
|
+
- The agent is then executed within its directory, allowing it to reliably find the files using the relative paths.
|
|
46
|
+
|
|
47
|
+
### 4.3 Outgoing File Attachments (Agent -> Discord)
|
|
48
|
+
1. **Agent Execution:**
|
|
49
|
+
- Rather than parsing text logs for magic strings (e.g., `File attached:`), agents will use an explicit API via the `clawmini-lite` client to send files back to the user.
|
|
50
|
+
- Example CLI usage: `clawmini-lite messages send --file ./attachments/out/foo.png "Here is your generated file."`
|
|
51
|
+
|
|
52
|
+
2. **Daemon / CLI Integration:**
|
|
53
|
+
- The `clawmini-lite messages send` command will be updated to accept a `--file` flag.
|
|
54
|
+
- It will use the `$CLAW_API_TOKEN` and `$CLAW_API_URL` to authenticate and route the file-sending request to the daemon.
|
|
55
|
+
- The daemon will record a `CommandLogMessage` (or a new message type) in the `chat.jsonl` that explicitly defines the file path to be returned.
|
|
56
|
+
|
|
57
|
+
3. **Discord Adapter Forwarding:**
|
|
58
|
+
- The `forwarder.ts` process, which subscribes to the `waitForMessages` TRPC endpoint, will read these new structured messages.
|
|
59
|
+
- If a message contains an outgoing file path, it will verify the file exists locally and attach it to the Discord DM using `dm.send({ content: message.content, files: [filePath] })`.
|
|
60
|
+
|
|
61
|
+
### 4.4 Technical Constraints & Security
|
|
62
|
+
- **File Limits:** Enforce `maxAttachmentSizeMB` in the Discord adapter. If a file exceeds this limit, ignore it or notify the user.
|
|
63
|
+
- **Strict Path Validation (Incoming):** For incoming files, the daemon must verify that all provided temporary file paths exist and are strictly located within `$WORKSPACE/.clawmini/tmp/`. It must also ensure the target destination is within the `$WORKSPACE`.
|
|
64
|
+
- **Strict Path Validation (Outgoing):** For outgoing files logged by the agent, the daemon must ensure the file path is a relative path, that it resolves to a location within the agent's subfolder and the overall `$WORKSPACE`, and that the file actually exists before processing the log.
|
|
65
|
+
- **Path Traversal:** Ensure that file paths submitted by `clawmini-lite` or handled by the daemon do not allow directory traversal (e.g., `../../etc/passwd`). Validate that target paths stay within the `files` directory or the agent's workspace.
|
|
66
|
+
- **File Name Collisions:** If two files with the same name are uploaded, standard conflict resolution should occur (e.g., appending a timestamp or UUID to the filename before saving to the agent's directory).
|
|
67
|
+
|
|
68
|
+
## 5. Next Steps
|
|
69
|
+
- Expand the TRPC `sendMessage` schema to accept file paths.
|
|
70
|
+
- Update `adapter-discord` to handle downloads and configuration updates.
|
|
71
|
+
- Update the daemon router pipeline to process and move incoming files.
|
|
72
|
+
- Update `clawmini-lite` and the daemon to support explicit outbound file sharing.
|
|
73
|
+
- Update the `adapter-discord` forwarder to handle outbound files.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# File Attachments - Questions & Answers
|
|
2
|
+
|
|
3
|
+
## Questions
|
|
4
|
+
|
|
5
|
+
1. Where should downloaded incoming file attachments be stored on the host filesystem?
|
|
6
|
+
**Answer:** They could be in a per-agent directory, like `./my-agent/attachments/discord/`. The agent settings can define a files directory (`./attachments`), and we can create folders/files as appropriate. The Discord adapter could save the file initially to `.clawmini/adapters/discord/files/foo.png`, then include those paths in the chat message to the daemon; then once the daemon figures out the agent's files directory it can move the file there (namespaced by the adapter) and prepend the file paths to the message.
|
|
7
|
+
|
|
8
|
+
2. To handle path translation between the host (where the daemon runs) and the agent container/VM, should we just pass the file paths relative to the agent's working directory (e.g., `attachments/discord/foo.png`), or do we need explicit path mapping configurations in the agent's settings to map absolute host paths to absolute container paths?
|
|
9
|
+
**Answer:** Yes, we should do something like `./attachments/discord/foo.png`, since we know that the agent will be run in its agent folder.
|
|
10
|
+
|
|
11
|
+
3. For outgoing file attachments (from the agent back to Discord), how should the agent signal this to the daemon/adapter? Should the adapter parse a specific string format (e.g., `File attached: ./attachments/out/foo.png`) from the message content, or should we introduce a new command extraction method (like `getAttachedFiles`) in the agent's schema to explicitly parse out the file paths into a structured array on the `CommandLogMessage` payload?
|
|
12
|
+
**Answer:** Perhaps we can use the clawmini-lite script to let agents send a file back to the user. For instance, `clawmini-lite messages send --file ./path/to/file "here you go"`. It would go to the corresponding chat, and be sent from the corresponding agent; according to the `$CLAW_API_TOKEN`.
|
|
13
|
+
|
|
14
|
+
4. Are there any maximum file size limits or file type restrictions we should enforce, either when downloading from Discord or when an agent sends a file back via `clawmini-lite`? Also, what should the daemon do if an incoming message has attachments but the selected agent hasn't configured a `files` directory?
|
|
15
|
+
**Answer:** For file size limits, we should let the user set limits in the discord adapter settings; but we should set reasonable defaults if none are specified. we should default to ./attachments as the file's directory.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# File Attachments Implementation Tickets
|
|
2
|
+
|
|
3
|
+
## Ticket 1: Configuration Updates
|
|
4
|
+
**Description:** Update the configuration schemas for both the Agent and the Discord Adapter to support file attachments.
|
|
5
|
+
**Tasks:**
|
|
6
|
+
- Update `SettingsSchema` / `AgentSchema` to include a new optional `files` string property (defaulting to `"./attachments"`).
|
|
7
|
+
- Update `DiscordConfigSchema` to include an optional `maxAttachmentSizeMB` number property (defaulting to `25`).
|
|
8
|
+
**Verification:**
|
|
9
|
+
- Add unit tests validating the new properties and defaults in both schemas.
|
|
10
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
11
|
+
**Status:** Complete
|
|
12
|
+
|
|
13
|
+
## Ticket 2: TRPC Schema and Discord Adapter Download
|
|
14
|
+
**Description:** Update the message payload schema to accept file paths and implement downloading incoming attachments in the Discord adapter.
|
|
15
|
+
**Tasks:**
|
|
16
|
+
- Extend the TRPC `sendMessage` payload schema to optionally include a list of temporary file paths.
|
|
17
|
+
- In `src/adapter-discord/index.ts` (or the relevant event handler), implement downloading of Discord `message.attachments` to a temporary directory (e.g., `.gemini/tmp/discord-files/`).
|
|
18
|
+
- Enforce the `maxAttachmentSizeMB` limit during the download process.
|
|
19
|
+
- Pass the downloaded temporary file paths to the daemon via the updated `sendMessage.mutate` TRPC call.
|
|
20
|
+
**Verification:**
|
|
21
|
+
- Write unit/integration tests for the Discord adapter verifying that attachments are correctly downloaded and size limits are respected.
|
|
22
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
23
|
+
**Status:** Complete
|
|
24
|
+
|
|
25
|
+
## Ticket 3: Daemon Processing of Incoming Files
|
|
26
|
+
**Description:** Implement the daemon logic to intercept the incoming temporary files, move them to the agent's workspace, and format the user message.
|
|
27
|
+
**Tasks:**
|
|
28
|
+
- Update the daemon's message processing pipeline (e.g., `src/daemon/router.ts` or relevant message handler) to intercept `sendMessage` requests containing file paths.
|
|
29
|
+
- Resolve the target agent's `files` configuration directory.
|
|
30
|
+
- Move the temporary files to the agent's files directory, namespacing them by the adapter (e.g., `<agent_files_dir>/discord/<filename>`).
|
|
31
|
+
- Implement file name collision resolution (e.g., appending a timestamp or short UUID to duplicate filenames).
|
|
32
|
+
- Prepend or append the list of finalized relative file paths to the user's input message text before passing it to the agent.
|
|
33
|
+
**Verification:**
|
|
34
|
+
- Add unit tests for the daemon's file moving logic, collision resolution, and message text formatting.
|
|
35
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
36
|
+
**Status:** Complete
|
|
37
|
+
|
|
38
|
+
## Ticket 4: Outgoing Files via CLI & Daemon (Agent to User)
|
|
39
|
+
**Description:** Enable agents to send files back to the user explicitly via the CLI, and update the daemon to record these paths.
|
|
40
|
+
**Tasks:**
|
|
41
|
+
- Update the `messages send` command in the `lite` CLI (`src/cli/commands/messages.ts` / `src/cli/lite.ts`) to accept a new `--file` argument.
|
|
42
|
+
- Update the underlying API/TRPC endpoint used by the CLI to accept and process this outgoing file path.
|
|
43
|
+
- In the daemon, implement path validation to ensure the provided file path does not contain directory traversal vulnerabilities (e.g., `../../`) and resolves within the agent's workspace.
|
|
44
|
+
- Update the internal chat log schema (e.g., `CommandLogMessage`) to store the explicit outgoing file path.
|
|
45
|
+
**Verification:**
|
|
46
|
+
- Add unit tests for the CLI's `--file` argument parsing.
|
|
47
|
+
- Add unit tests for the daemon's path traversal validation and log recording.
|
|
48
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
49
|
+
**Status:** Complete
|
|
50
|
+
|
|
51
|
+
## Ticket 5: Discord Adapter Forwarding Outgoing Files
|
|
52
|
+
**Description:** Update the Discord adapter's forwarder to read outgoing file paths from the chat log and send them as Discord attachments.
|
|
53
|
+
**Tasks:**
|
|
54
|
+
- Update `src/adapter-discord/forwarder.ts` to detect when a new message/log from the daemon contains an outgoing file path.
|
|
55
|
+
- Read the file from the local filesystem.
|
|
56
|
+
- Modify the `dm.send()` call to include the file as an attachment (`files: [path]`) alongside the message content.
|
|
57
|
+
**Verification:**
|
|
58
|
+
- Add tests for the forwarder verifying that messages with attached file paths result in the correct `dm.send` payload.
|
|
59
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
60
|
+
**Status:** Complete
|
|
61
|
+
|
|
62
|
+
## Ticket 6: Code Critique and Fixes
|
|
63
|
+
**Description:** Address DRY, YAGNI, naming, comments, and path violations in the initial file attachment implementation.
|
|
64
|
+
**Tasks:**
|
|
65
|
+
- High Priority: Update temporary download path for discord attachments to `.clawmini/adapters/discord/tmp` instead of `.gemini/tmp/discord-files`.
|
|
66
|
+
- Medium Priority: Fix DRY violation and bug in `src/daemon/router.ts` where `sendMessage` did not correctly respect `agent.directory` when resolving the target files directory.
|
|
67
|
+
- Medium Priority: Create a local `getUniquePath` utility in `src/daemon/router.ts` for DRYer renaming logic.
|
|
68
|
+
- Low Priority: Remove `JSON.stringify` workaround in `src/adapter-discord/index.ts` Debouncer instantiation by updating the `Debouncer` class to accept an optional custom `isEqual` function.
|
|
69
|
+
- Low Priority: Fix `any` typings in `src/adapter-discord/forwarder.ts` by using `MessageCreateOptions`.
|
|
70
|
+
- Low Priority: Fix flaky e2e test `should maintain atomic ordering of user and log messages with --no-wait`.
|
|
71
|
+
**Status:** Complete
|
|
72
|
+
|
|
73
|
+
## Ticket 7: Path Validation Security Enhancements
|
|
74
|
+
**Description:** Implement strict path validation and checks for incoming and outgoing file attachments to ensure security and prevent path traversal.
|
|
75
|
+
**Tasks:**
|
|
76
|
+
- Update `src/daemon/router.ts` (or relevant handler) for incoming files (`sendMessage` mutation):
|
|
77
|
+
- Verify that all files in `input.data.files` exist on the filesystem.
|
|
78
|
+
- Verify that all files are strictly within the `$WORKSPACE/.clawmini/tmp/` directory.
|
|
79
|
+
- Verify that the target directory (`targetDir`) where files will be moved is strictly within `$WORKSPACE`.
|
|
80
|
+
- Update `src/daemon/router.ts` for outgoing files (`logMessage` mutation):
|
|
81
|
+
- Ensure `input.file` is a relative path.
|
|
82
|
+
- Ensure the file path resolves to a location within the agent's subfolder AND within `$WORKSPACE`.
|
|
83
|
+
- Verify the file actually exists on the filesystem *before* resolving it to an absolute path and recording it.
|
|
84
|
+
- Ensure all relevant checks use a secure path comparison method (e.g., `pathIsInsideDir`).
|
|
85
|
+
**Verification:**
|
|
86
|
+
- Add unit tests verifying validation failures for absolute paths, non-existent files, files outside `.clawmini/tmp/` (for incoming), and files outside the agent folder/workspace (for outgoing).
|
|
87
|
+
- Run `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
88
|
+
**Status:** Complete
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Development Log: 11_message_verbosity
|
|
2
|
+
|
|
3
|
+
## Ticket 1: Update Data Model
|
|
4
|
+
- Updated `src/shared/chats.ts` to add the optional `level` property to the `CommandLogMessage` interface. The property can be `'default' | 'debug' | 'verbose'`.
|
|
5
|
+
- Ran tests (`npm run format:check && npm run lint && npm run check && npm run test`) and confirmed that they all passed successfully.
|
|
6
|
+
|
|
7
|
+
## Ticket 2: Update Daemon Message Generation
|
|
8
|
+
- Modified `src/daemon/message.ts` to add `level: 'verbose'` conditionally when generating `CommandLogMessage` objects for router, retry, and main results if `NO_REPLY_NECESSARY` is present in their contents.
|
|
9
|
+
- Fixed TypeScript `exactOptionalPropertyTypes` constraint by conditionally spreading the `level` property and using `delete logMsg.level` instead of setting it to `undefined`.
|
|
10
|
+
- Added unit tests in `src/daemon/message-verbosity.test.ts` to verify log messages correctly receive the `verbose` level when `NO_REPLY_NECESSARY` is printed.
|
|
11
|
+
- Configured ESLint overrides and formatting in the new test file to resolve linting failures.
|
|
12
|
+
- Ran all required validation checks (`npm run format:check`, `npm run lint`, `npm run check`, `npm run test`) and confirmed full suite success.
|
|
13
|
+
|
|
14
|
+
## Ticket 3: Update Web UI State Management
|
|
15
|
+
- Replaced the boolean `debugView` with a string `verbosityLevel` (values: `'default' | 'debug' | 'verbose'`) in `web/src/lib/app-state.svelte.ts`.
|
|
16
|
+
- Implemented temporary shims in `web/src/routes/+layout.svelte` and `web/src/routes/chats/[id]/+page.svelte` to translate the new string type back to the boolean checks expected by existing UI components in order to maintain a passing build until subsequent UI tickets are fulfilled.
|
|
17
|
+
- Updated `web/src/routes/chats/[id]/page.svelte.spec.ts` to use `appState.verbosityLevel = 'verbose'`.
|
|
18
|
+
- Verified changes by successfully running all typechecks and tests (`npm run check && npm run test`).
|
|
19
|
+
|
|
20
|
+
## Ticket 4: Update Web UI Controls
|
|
21
|
+
- Replaced the boolean `Switch` component in `web/src/routes/+layout.svelte` with a cyclical toggle button that iterates through `default`, `debug`, and `verbose` levels.
|
|
22
|
+
- Added visual distinctions using `lucide-svelte` icons (`MessageSquare` for default, `Bug` for debug, `Terminal` for verbose) and varied text colors.
|
|
23
|
+
- Ensured a dynamic `aria-label` is used for accessibility, indicating the current verbosity level.
|
|
24
|
+
- Ran formatting, linting, type-checking, and tests (`npm run format:check && npm run lint && npm run check && npm run test`), all passing successfully.
|
|
25
|
+
|
|
26
|
+
## Ticket 5: Update Web UI Message Filtering and Display
|
|
27
|
+
- Updated `web/src/routes/chats/[id]/+page.svelte` to implement filtering and detailed views based on `verbosityLevel`.
|
|
28
|
+
- Added a `$derived` state `filteredMessages` to filter log messages appropriately for `default`, `debug`, and `verbose` levels.
|
|
29
|
+
- Distinct styling added for `verbose` messages (primary background tint with border).
|
|
30
|
+
- Detailed output (`command`, `stdout`, `stderr`, and `exitCode`) now display conditionally when in `verbose` mode.
|
|
31
|
+
- Added `level` property to `CommandLogMessage` type in `web/src/lib/types.ts` to fix TypeScript issues and properly align with `shared/chats.ts`.
|
|
32
|
+
- Updated `web/src/routes/chats/[id]/page.svelte.spec.ts` to include multiple test cases verifying the filtering behavior for `default`, `debug`, and `verbose` verbosity levels.
|
|
33
|
+
- Ran formatting, linting, type-checking, and tests (`npm run format && npm run lint:fix && npm run check && npm run test`) and successfully passed all checks.
|
|
34
|
+
|
|
35
|
+
## Ticket 6: Update Discord Forwarder
|
|
36
|
+
- Modified `src/adapter-discord/forwarder.ts` to filter out `CommandLogMessage`s with `level: 'verbose'` from being forwarded to Discord.
|
|
37
|
+
- Ensured that `writeDiscordState` is still correctly called for ignored verbose messages to keep `lastSyncedMessageId` updated, preventing an infinite loop or repeated fetches.
|
|
38
|
+
- Updated unit tests in `src/adapter-discord/forwarder.test.ts` to mock and verify that verbose messages are ignored by `mockDm.send` but state gets updated via `writeDiscordState`.
|
|
39
|
+
- Ran all required validation checks (`npm run format:check`, `npm run lint`, `npm run check`, `npm run test`) and confirmed they all passed successfully.
|
|
40
|
+
|
|
41
|
+
## Ticket 7: Final Quality Check
|
|
42
|
+
- Ran formatting, linting, type-checking, and tests (`npm run format:check && npm run lint && npm run check && npm run test`) across the entire repository.
|
|
43
|
+
- Confirmed that all code meets the project's standards and all tests pass cleanly.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Notes on Message Verbosity Feature
|
|
2
|
+
|
|
3
|
+
## Current State
|
|
4
|
+
- `CommandLogMessage` in `src/shared/chats.ts` currently does not have a `level` property.
|
|
5
|
+
- WebUI has a boolean `appState.debugView` toggled by a `Switch` component (`web/src/routes/+layout.svelte` and `web/src/routes/chats/[id]/+page.svelte`). This toggle currently shows/hides stderr, exit codes, and command paths on log messages.
|
|
6
|
+
- The Discord forwarder (`src/adapter-discord/forwarder.ts`) currently forwards all messages with `role: 'log'` as long as they have content or files.
|
|
7
|
+
- Agent output is captured in `src/daemon/message.ts` via `runCommand`, putting `stdout` into the message `content`.
|
|
8
|
+
- Some internal messages (like retry delays or router messages) are also stored as `CommandLogMessage`.
|
|
9
|
+
|
|
10
|
+
## Requirements
|
|
11
|
+
- Add `level` property to `CommandLogMessage` (optional).
|
|
12
|
+
- Define enums for log levels (e.g., `default`, `debug`, `verbose`).
|
|
13
|
+
- Replace the boolean toggle in the WebUI with a cyclic toggle button to switch between these three states, using good icons/colors.
|
|
14
|
+
- Discord forwarder should ignore the most verbose setting by default.
|
|
15
|
+
- Any message content containing `"NO_REPLY_NECESSARY"` should automatically be labeled as verbose.
|
|
16
|
+
|
|
17
|
+
## Files to Update
|
|
18
|
+
- **Data Model**: `src/shared/chats.ts` (Add `level` to `CommandLogMessage`, define `LogLevel` enum/type).
|
|
19
|
+
- **Daemon Generation**: `src/daemon/message.ts`, `src/daemon/router.ts` (When generating a message, check if `"NO_REPLY_NECESSARY"` is in the content and set `level` to `'verbose'`. Otherwise maybe `'default'` or `'debug'` depending on the type of message - wait, the prompt says "To start, any message containing NO_REPLY_NECESSARY will be labeled as verbose").
|
|
20
|
+
- **Web UI Data Model & Logic**: `web/src/lib/types.ts` (if exists), `web/src/lib/app-state.svelte.ts` (Change `debugView` to `verbosityLevel`), `web/src/routes/+layout.svelte` (Replace `Switch` with a 3-state icon button), `web/src/routes/chats/[id]/+page.svelte` (Filter or adjust display based on the selected level).
|
|
21
|
+
- **Discord Forwarder**: `src/adapter-discord/forwarder.ts` (Skip forwarding if `level === 'verbose'`).
|
|
22
|
+
|
|
23
|
+
## Open Questions
|
|
24
|
+
- What should be the exact names of the levels? (e.g., `'default' | 'debug' | 'verbose'`)
|
|
25
|
+
- What should determine if a message is `debug` vs `default` initially, other than the `NO_REPLY_NECESSARY` string rule? (Are standard agent responses `'default'`, and retry/error messages `'debug'`?)
|
|
26
|
+
- In the Web UI, should a `'default'` message be visible across all levels, and `'verbose'` messages *only* visible at the `'verbose'` level? (i.e., Level filters: Default -> shows only Default; Debug -> shows Default + Debug; Verbose -> shows Default + Debug + Verbose)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Feature: Message Verbosity Levels
|
|
2
|
+
|
|
3
|
+
## Vision
|
|
4
|
+
To provide users with more control over the signal-to-noise ratio in their interaction history by introducing message verbosity levels. This will allow the system to log detailed background actions or non-user-facing updates without cluttering the main conversation stream, while giving power users the ability to inspect exactly what the system is doing.
|
|
5
|
+
|
|
6
|
+
## Product/Market Background
|
|
7
|
+
Currently, all logs from the daemon (including agent responses, error messages, routing info, and executed commands) are grouped into a binary `debugView` toggle in the WebUI. Additionally, the Discord integration forwards every single log message to the user as long as it contains content or a file, which can lead to spam when agents are performing behind-the-scenes reasoning or repetitive tasks.
|
|
8
|
+
|
|
9
|
+
By categorizing messages into `default`, `debug`, and `verbose` levels, we align with standard software logging paradigms. The user experience is simplified for the average user, while maintaining complete transparency for developers and advanced users.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
### 1. Data Model (`CommandLogMessage`)
|
|
14
|
+
- Introduce an optional `level` property to the `CommandLogMessage` interface in `src/shared/chats.ts`.
|
|
15
|
+
- `level` should be of type `'default' | 'debug' | 'verbose'`.
|
|
16
|
+
- If `level` is missing or undefined on an existing message, it should be treated as `'default'`.
|
|
17
|
+
|
|
18
|
+
### 2. Message Generation (Daemon)
|
|
19
|
+
- When generating a `CommandLogMessage` in the daemon (e.g., in `src/daemon/message.ts`), assign the `level` property based on the message content.
|
|
20
|
+
- **Rule 1**: If the message content (e.g., agent stdout) contains the exact string `"NO_REPLY_NECESSARY"`, the message `level` must be set to `'verbose'`.
|
|
21
|
+
- All other messages can default to `'default'` for now (future iterations may use `'debug'` for retry logs, etc.).
|
|
22
|
+
|
|
23
|
+
### 3. Web UI Updates
|
|
24
|
+
- **State Management**: Replace the boolean `appState.debugView` with a string `appState.verbosityLevel` (with values `'default' | 'debug' | 'verbose'`) in `web/src/lib/app-state.svelte.ts`. The default value should be `'default'`.
|
|
25
|
+
- **UI Control**: Replace the `Switch` component in `web/src/routes/+layout.svelte` with a cyclical toggle button (e.g., an icon button that rotates between three distinct icons/colors representing Default, Debug, and Verbose states).
|
|
26
|
+
- **Message Filtering & Display** (`web/src/routes/chats/[id]/+page.svelte`):
|
|
27
|
+
- **Visibility**:
|
|
28
|
+
- When `verbosityLevel` is `'default'`, only show messages with `level: 'default'` (or undefined).
|
|
29
|
+
- When `verbosityLevel` is `'debug'`, show messages with `level: 'default'` and `'debug'`.
|
|
30
|
+
- When `verbosityLevel` is `'verbose'`, show all messages.
|
|
31
|
+
- **Detail Level**:
|
|
32
|
+
- When `verbosityLevel` is `'default'` or `'debug'`, only display the message `content`. Hide the `command`, `stderr`, and `stdout` raw views.
|
|
33
|
+
- When `verbosityLevel` is `'verbose'`, reveal all message details including `command` and `stderr` (similar to the current `debugView = true` state).
|
|
34
|
+
- **Visual Distinction**: Verbose messages must look visually distinct from `default`/`debug` messages (e.g., using a distinct background color, border, or icon indicating it is a verbose background task).
|
|
35
|
+
|
|
36
|
+
### 4. Discord Forwarder Updates
|
|
37
|
+
- Modify `src/adapter-discord/forwarder.ts` to check the `level` property of incoming `CommandLogMessage`s.
|
|
38
|
+
- Do not forward messages if their `level` is exactly `'verbose'`.
|
|
39
|
+
- Messages with `level: 'default'`, `'debug'`, or undefined should still be forwarded as normal.
|
|
40
|
+
|
|
41
|
+
## Privacy/Security/Accessibility Concerns
|
|
42
|
+
- **Accessibility**: The new cyclical toggle button in the WebUI must have an appropriate `aria-label` that dynamically updates to indicate the current verbosity level state, ensuring screen reader users can interact with it effectively.
|
|
43
|
+
- **Security**: No new security risks are introduced, as we are merely filtering the display of data the user already has access to.
|
|
44
|
+
- **Privacy**: No new privacy concerns. Data is stored locally as before.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
1. Should the new WebUI verbosity toggle control both which messages are visible (based on the message's `level` property) AND the level of detail shown for each message (e.g., hiding `stderr` and `command` on 'default', but showing them on 'debug'), or should it only control message visibility?
|
|
2
|
+
- **Answer**: Yes. The toggle controls both which messages are visible and the level of detail shown for each message. 'verbose' setting shows stderr/command, and 'verbose' messages should also appear visually distinct from 'default' and 'debug' messages.
|
|
3
|
+
2. For the `CommandLogMessage`'s `level` property, should it be explicitly defined for every message created by the daemon, or should it default to `'default'` if not specified? Also, when we label a message containing 'NO_REPLY_NECESSARY' as `'verbose'`, should the Discord forwarder only skip `'verbose'` messages, or should it also skip `'debug'` messages?
|
|
4
|
+
- **Answer**: Default to 'default' if not specified. Discord forwarder should only skip 'verbose' messages for now.
|
|
5
|
+
3. What should determine if a log message is classified as 'debug' instead of 'default' or 'verbose' initially? Do we have a specific type of message (e.g. error logs, retry delays, router logs) that should be mapped to the 'debug' level, or will everything remain 'default' except for messages containing 'NO_REPLY_NECESSARY' being mapped to 'verbose'?
|
|
6
|
+
- **Answer**: We will handle that later. For now we will only introduce 'verbose' and 'default'.
|
|
7
|
+
4. In the WebUI, when cycling the verbosity toggle, what should be the exact behavior of the three states: 1. Default (what is shown?), 2. Debug (what is shown?), 3. Verbose (what is shown?)? For instance, does Default show only 'default' level messages without command/stderr? Does Debug show both 'default' and 'debug' messages? Does Verbose show all messages and also reveal command/stderr details?
|
|
8
|
+
- **Answer**: Default shows just message content for 'default' messages. Debug shows message content for 'default' and 'debug' messages. Verbose shows all messages, along with command and stderr details.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Message Verbosity Feature Tickets
|
|
2
|
+
|
|
3
|
+
## 1. Update Data Model (Status: Complete)
|
|
4
|
+
- **Task**: Update `src/shared/chats.ts` to add an optional `level` property (`'default' | 'debug' | 'verbose'`) to the `CommandLogMessage` interface.
|
|
5
|
+
- **Verification**: Run `npm run check` and `npm run test` to ensure there are no TypeScript compilation errors resulting from this interface change.
|
|
6
|
+
|
|
7
|
+
## 2. Update Daemon Message Generation (Status: Complete)
|
|
8
|
+
- **Task**: Modify message generation logic in the daemon (e.g., `src/daemon/message.ts`) so that when a `CommandLogMessage` is generated, if its content includes the exact string `"NO_REPLY_NECESSARY"`, the `level` property is set to `'verbose'`.
|
|
9
|
+
- **Verification**: Write/update tests in `src/daemon/` to verify this behavior, and run `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
10
|
+
|
|
11
|
+
## 3. Update Web UI State Management (Status: Complete)
|
|
12
|
+
- **Task**: In `web/src/lib/app-state.svelte.ts` (or equivalent Web UI state file), replace the boolean `debugView` property with a string `verbosityLevel` initialized to `'default'`. The valid values should be `'default' | 'debug' | 'verbose'`.
|
|
13
|
+
- **Verification**: Run `npm run check` and `npm run test` to verify state changes compile and pass tests.
|
|
14
|
+
|
|
15
|
+
## 4. Update Web UI Controls (Status: Complete)
|
|
16
|
+
- **Task**: In `web/src/routes/+layout.svelte`, replace the existing `Switch` component used for `debugView` with a cyclical toggle button. This button should rotate between the three states ('default', 'debug', 'verbose') using distinct icons/colors and must include a dynamic `aria-label` for accessibility.
|
|
17
|
+
- **Verification**: Run `npm run check` and `npm run test`.
|
|
18
|
+
|
|
19
|
+
## 5. Update Web UI Message Filtering and Display (Status: Complete)
|
|
20
|
+
- **Task**: Update `web/src/routes/chats/[id]/+page.svelte` to implement filtering and detailed views based on `verbosityLevel`:
|
|
21
|
+
- `'default'` level: Show only `level: 'default'` (or undefined). Show only the message content.
|
|
22
|
+
- `'debug'` level: Show `level: 'default'` and `'debug'`. Show only the message content.
|
|
23
|
+
- `'verbose'` level: Show all messages. Reveal `command`, `stderr`, and `stdout` raw views.
|
|
24
|
+
- Ensure verbose messages look visually distinct (e.g., distinct background color, border, or icon).
|
|
25
|
+
- **Verification**: Run `npm run check` and `npm run test`.
|
|
26
|
+
|
|
27
|
+
## 6. Update Discord Forwarder (Status: Complete)
|
|
28
|
+
- **Task**: Modify `src/adapter-discord/forwarder.ts` to check the `level` property of incoming `CommandLogMessage`s. Ensure that messages with `level: 'verbose'` are NOT forwarded to Discord.
|
|
29
|
+
- **Verification**: Update Discord forwarder unit tests, then run `npm run check` and `npm run test`.
|
|
30
|
+
|
|
31
|
+
## 7. Final Quality Check (Status: Complete)
|
|
32
|
+
- **Task**: Ensure all code meets the project's formatting, linting, and testing standards.
|
|
33
|
+
- **Verification**: Run `npm run format:check && npm run lint && npm run check && npm run test` and confirm everything passes cleanly.
|