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,41 @@
|
|
|
1
|
+
# Discord Typing Indicators (Heartbeat) PRD
|
|
2
|
+
|
|
3
|
+
## Vision
|
|
4
|
+
Improve the user experience in the Discord adapter by providing visual feedback when an AI agent is processing a request. By leveraging Discord's native "typing" indicator, users will clearly see that the daemon is working on their command and has not stalled, even during long-running LLM inferences or background operations.
|
|
5
|
+
|
|
6
|
+
## Background
|
|
7
|
+
Currently, when a user sends a message to the Clawmini daemon via Discord, there can be a significant delay between the user's message and the agent's response, especially for complex tasks. Without any visual feedback during this delay, users might assume the command was lost or the bot crashed. Discord supports a `sendTyping()` API for channels/DMs, which displays a "Bot is typing..." indicator for up to 10 seconds. To maintain the typing indicator for longer commands, the bot needs to continuously emit this signal.
|
|
8
|
+
|
|
9
|
+
## Use Cases
|
|
10
|
+
* **Long-Running Commands:** A user asks the agent to perform an extensive codebase search and refactoring task. The Discord bot displays the typing indicator for the entire 30+ seconds it takes the daemon to respond, reassuring the user.
|
|
11
|
+
* **Preventing Double Inputs:** Seeing the typing indicator discourages users from repeatedly sending the same command or asking "are you there?".
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
### 1. Daemon Event Emission
|
|
16
|
+
* The daemon must emit a `DAEMON_EVENT_HEARTBEAT` (or similar) internal event while a command is actively running.
|
|
17
|
+
* In `src/daemon/message.ts` (specifically around `executeDirectMessage` where `runCommand` is called), an interval should be established to emit this heartbeat event every ~5 seconds.
|
|
18
|
+
* The interval MUST be reliably cleared once the command execution finishes (both on success and error).
|
|
19
|
+
* The heartbeat event payload must include at least the `chatId`.
|
|
20
|
+
|
|
21
|
+
### 2. tRPC Subscription Endpoint
|
|
22
|
+
* The daemon's `AppRouter` (`src/daemon/router.ts`) must expose a new `waitForTyping` subscription endpoint.
|
|
23
|
+
* This endpoint will listen to the internal `daemonEvents` for the `DAEMON_EVENT_HEARTBEAT` event.
|
|
24
|
+
* It should filter events by `chatId` (similar to the existing `waitForMessages` endpoint) and yield to connected clients.
|
|
25
|
+
|
|
26
|
+
### 3. Discord Adapter Integration
|
|
27
|
+
* The Discord forwarder (`src/adapter-discord/forwarder.ts`) must subscribe to the new `waitForTyping` endpoint.
|
|
28
|
+
* Upon receiving a typing event for an active chat, the adapter must fetch the corresponding Discord DM channel (using `client.users.fetch` and `user.createDM()`).
|
|
29
|
+
* The adapter must call `dm.sendTyping()`.
|
|
30
|
+
* The forwarder must handle potential errors from the `waitForTyping` subscription, similar to how it handles the `waitForMessages` stream, implementing automatic retries with exponential backoff if the connection drops.
|
|
31
|
+
|
|
32
|
+
## Non-Functional Requirements
|
|
33
|
+
* **Performance:** The interval and additional local SSE connection must have a negligible footprint.
|
|
34
|
+
* **Reliability:** The interval in the daemon must be properly cleaned up in a `finally` block or similar mechanism to prevent orphaned intervals from leaking memory or causing phantom typing indicators.
|
|
35
|
+
* **Backwards Compatibility:** Existing clients (CLI, Web interface) must not be negatively impacted by this new feature. The separation of the typing stream from the `waitForMessages` stream guarantees that the persistent message model remains intact.
|
|
36
|
+
|
|
37
|
+
## Implementation Steps
|
|
38
|
+
1. **Daemon Events (`src/daemon/events.ts`):** Define the new `DAEMON_EVENT_TYPING` event string.
|
|
39
|
+
2. **Daemon Message Logic (`src/daemon/message.ts`):** Wrap the `runCommand` execution in `executeDirectMessage` with a `setInterval` that emits the typing event every 5000ms. Ensure the interval is cleared via `clearInterval` when the command concludes.
|
|
40
|
+
3. **tRPC Router (`src/daemon/router.ts`):** Add the `waitForTyping` subscription endpoint to the `AppRouter`.
|
|
41
|
+
4. **Discord Adapter (`src/adapter-discord/forwarder.ts`):** Implement the `waitForTyping` subscription loop alongside the existing `waitForMessages` loop, triggering `dm.sendTyping()` when an event is received.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Questions
|
|
2
|
+
## Question 1
|
|
3
|
+
Q: How would you prefer the typing heartbeat to be transmitted over tRPC?
|
|
4
|
+
- Option A: Add a new `waitForTyping` subscription endpoint specifically for typing events. This clearly separates persistent messages from ephemeral UI state but requires clients to open an additional subscription.
|
|
5
|
+
- Option B: Introduce a temporary message type (e.g., `{ role: 'typing' }`) that gets emitted via the existing `waitForMessages` subscription (but isn't saved to the chat's JSONL file). This avoids a second subscription connection but mixes UI state into the chat model.
|
|
6
|
+
Recommendation: Option A is recommended. It keeps the persistent `ChatMessage` types pure and avoids unexpectedly breaking existing clients (like the CLI) that expect all incoming messages from `waitForMessages` to be saveable, renderable chat logs. Creating an additional SSE connection over the local Unix socket is very lightweight.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Discord Typing Indicators Tickets
|
|
2
|
+
|
|
3
|
+
## Ticket 1: Define Daemon Event
|
|
4
|
+
**Status**: Completed
|
|
5
|
+
|
|
6
|
+
**Description**:
|
|
7
|
+
Define the new `DAEMON_EVENT_TYPING` event string in the daemon's event definitions.
|
|
8
|
+
|
|
9
|
+
**Tasks**:
|
|
10
|
+
- Update `src/daemon/events.ts` to include a new `DAEMON_EVENT_TYPING` event constant.
|
|
11
|
+
- Define the payload type for this event, which must include at least the `chatId` (string).
|
|
12
|
+
|
|
13
|
+
**Verification**:
|
|
14
|
+
- Verify the code compiles without errors by running `npm run check`.
|
|
15
|
+
- Run all checks: `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
16
|
+
|
|
17
|
+
## Ticket 2: Add tRPC Subscription Endpoint
|
|
18
|
+
**Status**: Completed
|
|
19
|
+
|
|
20
|
+
**Description**:
|
|
21
|
+
Expose a new `waitForTyping` subscription endpoint on the daemon's `AppRouter` to allow clients to listen for typing events.
|
|
22
|
+
|
|
23
|
+
**Tasks**:
|
|
24
|
+
- Update `src/daemon/router.ts` to add a `waitForTyping` subscription endpoint.
|
|
25
|
+
- The endpoint should filter internal `DAEMON_EVENT_TYPING` events by `chatId` and yield them to connected clients.
|
|
26
|
+
|
|
27
|
+
**Verification**:
|
|
28
|
+
- Add or update unit tests to verify the `waitForTyping` subscription yields events for the correct `chatId` (e.g., in `src/daemon/router.test.ts`).
|
|
29
|
+
- Run all checks: `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
30
|
+
|
|
31
|
+
## Ticket 3: Emit Typing Events During Command Execution
|
|
32
|
+
**Status**: Completed
|
|
33
|
+
|
|
34
|
+
**Description**:
|
|
35
|
+
Update the daemon's message execution logic to periodically emit the typing event while a command is running.
|
|
36
|
+
|
|
37
|
+
**Tasks**:
|
|
38
|
+
- In `src/daemon/message.ts`, locate the `executeDirectMessage` function where `runCommand` is called.
|
|
39
|
+
- Before `runCommand` executes, set up a `setInterval` that emits the `DAEMON_EVENT_TYPING` event every 5000ms.
|
|
40
|
+
- Ensure the interval is cleared via `clearInterval` in a `finally` block to prevent orphaned intervals on both success and error.
|
|
41
|
+
|
|
42
|
+
**Verification**:
|
|
43
|
+
- Add or update tests to ensure the interval is set up and torn down correctly during command execution (e.g., in `src/daemon/message.test.ts` or `src/daemon/message-agent.test.ts`).
|
|
44
|
+
- Run all checks: `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
45
|
+
|
|
46
|
+
## Ticket 4: Discord Adapter Integration
|
|
47
|
+
**Status**: Completed
|
|
48
|
+
|
|
49
|
+
**Description**:
|
|
50
|
+
Integrate the typing event subscription into the Discord adapter to provide visual feedback to users.
|
|
51
|
+
|
|
52
|
+
**Tasks**:
|
|
53
|
+
- Update `src/adapter-discord/forwarder.ts` to implement a `waitForTyping` subscription loop alongside the existing `waitForMessages` loop.
|
|
54
|
+
- Upon receiving a typing event for a chat, fetch the corresponding Discord DM channel using `client.users.fetch` and `user.createDM()`.
|
|
55
|
+
- Call `dm.sendTyping()` to display the indicator in Discord.
|
|
56
|
+
- Ensure potential errors from the `waitForTyping` subscription are handled gracefully with automatic retries and exponential backoff, identical to `waitForMessages`.
|
|
57
|
+
|
|
58
|
+
**Verification**:
|
|
59
|
+
- Add or update tests in `src/adapter-discord/forwarder.test.ts` to verify the new subscription loop acts as expected, errors are handled, and `dm.sendTyping` is triggered.
|
|
60
|
+
- Run all checks: `npm run format:check && npm run lint && npm run check && npm run test`.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Development Log - 14_interruptions
|
|
2
|
+
|
|
3
|
+
## Progress
|
|
4
|
+
- **Step 1: Update Queue Management**
|
|
5
|
+
- Updated `src/daemon/queue.ts` to support aborting tasks via `AbortController`, clearing the queue, and extracting pending tasks.
|
|
6
|
+
- Ensured `enqueue` tracks `textPayload` for tasks to enable future batching.
|
|
7
|
+
- Wrote comprehensive unit tests in `src/daemon/queue.test.ts` ensuring all states and rejections are handled properly.
|
|
8
|
+
- Added `.catch` suppression in `message.ts` to gracefully handle `AbortError` and other rejections if `noWait` is enabled.
|
|
9
|
+
- Discovered and fixed an issue with macOS UNIX socket path length limits (`EINVAL`) during e2e testing by shortening test directory names (`e2e-env`, `e2e-discord`, `e2e-exp-lite`).
|
|
10
|
+
- Tests successfully verify sequential and aborted behavior without unhandled rejections.
|
|
11
|
+
|
|
12
|
+
- **Step 2: Update Command Execution with AbortSignal**
|
|
13
|
+
- Updated `RunCommandFn` signature in `src/daemon/message.ts` to include `signal?: AbortSignal | undefined`.
|
|
14
|
+
- Updated `runCommand` in `src/daemon/router.ts` and `src/daemon/cron.ts`, passing `signal` to `child_process.spawn`.
|
|
15
|
+
- Added error handlers to the `spawn` process resolving promises to handle `err.name === 'AbortError'` cleanly by rejecting the promise.
|
|
16
|
+
- Plumbed `signal` down from `queue.enqueue` callback through `executeDirectMessage` and `runExtractionCommand`.
|
|
17
|
+
- Ran validation checks to ensure tests continue to pass and `tsconfig.json` requirements (`exactOptionalPropertyTypes`) are met.
|
|
18
|
+
|
|
19
|
+
- **Step 3: Implement Interruption Routers**
|
|
20
|
+
- Added `action?: 'stop' | 'interrupt' | 'continue'` to `RouterState` interface in `src/daemon/routers/types.ts`.
|
|
21
|
+
- Created `@clawmini/slash-stop` router (`src/daemon/routers/slash-stop.ts`) to handle `/stop` command, which sets `action: 'stop'` and provides an acknowledgment reply.
|
|
22
|
+
- Created `@clawmini/slash-interrupt` router (`src/daemon/routers/slash-interrupt.ts`) to handle `/interrupt` command, which sets `action: 'interrupt'` and provides an acknowledgment reply.
|
|
23
|
+
- Plumbed `action` property parsing into the fallback shell execution logic within `executeCustomRouter` (`src/daemon/routers.ts`).
|
|
24
|
+
- Added `slashStop` and `slashInterrupt` to the `executeRouterPipeline` in `src/daemon/routers.ts`.
|
|
25
|
+
- Added the new routers to the default settings initialization list in `src/cli/commands/init.ts`.
|
|
26
|
+
- Wrote full test coverage in `src/daemon/routers/slash-stop.test.ts` and `src/daemon/routers/slash-interrupt.test.ts`, and updated `src/daemon/routers.test.ts`.
|
|
27
|
+
- Ensured all tests pass and typing is correct.
|
|
28
|
+
|
|
29
|
+
- **Step 4: Integrate Interruptions in Message Handler**
|
|
30
|
+
- Updated `src/daemon/message.ts` to intercept `stop` and `interrupt` actions from the `RouterState` inside `executeDirectMessage`.
|
|
31
|
+
- For `stop`, called `queue.abortCurrent()` and `queue.clear()`, avoiding queuing any new tasks.
|
|
32
|
+
- For `interrupt`, called `queue.abortCurrent()` and batching any pending tasks by extracting their payloads via `queue.extractPending()` and concatenating them into the new message.
|
|
33
|
+
- Updated `queue.enqueue()` call in `executeDirectMessage` to accept `state.message` as `textPayload` for the new task.
|
|
34
|
+
- Resolved type checking errors regarding `any` usage in `src/daemon/queue.ts` where `reject` expected `unknown`.
|
|
35
|
+
- Created new unit tests `src/daemon/message-interruption.test.ts` to cover the queue aborting and batching flow.
|
|
36
|
+
- Tests verify that stopping avoids queuing and clears the queue, while interrupting aggregates pending task messages.
|
|
37
|
+
- All format, lint, type-check, and vitest suites successfully pass.
|
|
38
|
+
|
|
39
|
+
## Next Steps
|
|
40
|
+
- Interruption handling feature is complete.
|
|
41
|
+
|
|
42
|
+
## Step 5: Final Checks
|
|
43
|
+
- Ran code quality checks (`npm run format:check && npm run lint && npm run check && npm run test`).
|
|
44
|
+
- Fixed type issues with `exactOptionalPropertyTypes: true` on `currentPayload` in `src/daemon/queue.ts`.
|
|
45
|
+
- Addressed code formatting issues.
|
|
46
|
+
- Confirmed all formatting, linting, type-checking, and tests now pass perfectly.
|
|
47
|
+
## Bug Fix: Map Router Action State in Message Handler
|
|
48
|
+
- **Hypothesis:** When `/stop` or `/interrupt` is sent, the router correctly sets `finalState.action = 'stop'`. However, `handleUserMessage` converts this `finalState` into a new `directState` object before passing it to `executeDirectMessage`. If `action` is not mapped over to the new object, the queue handler never receives the `action === 'stop'` flag and therefore never calls `queue.abortCurrent()`.
|
|
49
|
+
- **Plan:** Update `src/daemon/message.ts` where `directState` is constructed to map `if (finalState.action !== undefined) directState.action = finalState.action;`.
|
|
50
|
+
- **Result:** Applied the mapping fix and verified all tests pass. Interruption signals now properly reach the execution queue and instantly terminate running processes.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Interruptions Feature Notes
|
|
2
|
+
|
|
3
|
+
## Current Architecture
|
|
4
|
+
|
|
5
|
+
* **Message Processing:** Handled in `src/daemon/message.ts`. It takes user input, runs it through routers to determine the active agent and format the command, and queues it up for execution.
|
|
6
|
+
* **Execution Queue:** Managed in `src/daemon/queue.ts`. Currently, it's a simple Promise chain:
|
|
7
|
+
```typescript
|
|
8
|
+
export class Queue {
|
|
9
|
+
private queue: Promise<void> = Promise.resolve();
|
|
10
|
+
enqueue(task: Task): Promise<void> {
|
|
11
|
+
const next = this.queue.then(task).catch(() => {});
|
|
12
|
+
this.queue = next;
|
|
13
|
+
return next;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
This queue is per-directory. It does not currently have functionality to cancel running tasks or clear pending tasks.
|
|
18
|
+
* **Command Execution:** `runCommand` (used by `executeDirectMessage`) runs via `child_process.spawn`. It doesn't currently accept an `AbortSignal`.
|
|
19
|
+
* **Routers:** Located in `src/daemon/routers/` (e.g., `slash-command.ts`, `slash-new.ts`). They can mutate the `RouterState`, which determines the actual command and message sent to the agent.
|
|
20
|
+
|
|
21
|
+
## Implementation Requirements
|
|
22
|
+
|
|
23
|
+
1. **AbortController Integration:**
|
|
24
|
+
* Update `RunCommandFn` and `runCommand` in `src/cli/client.ts` (or daemon runner) to accept an `AbortSignal`.
|
|
25
|
+
* Pass the signal to `child_process.spawn(..., { signal })` so the OS sends a kill signal (typically `SIGTERM` or `SIGKILL`) when aborted.
|
|
26
|
+
2. **Queue Management:**
|
|
27
|
+
* Add the ability to track the currently running task's `AbortController` in the `Queue` class.
|
|
28
|
+
* Add a method to `Queue` (e.g., `abortCurrent()`) to trigger the abort.
|
|
29
|
+
* Potentially add a method to clear the queue if the user wants to cancel all pending messages (`/stop`).
|
|
30
|
+
3. **Router Support:**
|
|
31
|
+
* Create or update routers to parse interruption commands (e.g., `/stop`, `/interrupt`).
|
|
32
|
+
* The router needs a way to signal back to the message handler that an interruption is requested *before* the message is queued.
|
|
33
|
+
* Update `executeRouterPipeline` or `RouterState` to include an `interrupt` flag or an `action: 'stop' | 'interrupt'` payload.
|
|
34
|
+
4. **Message Handler Logic (`handleUserMessage` / `executeDirectMessage`):**
|
|
35
|
+
* Before queueing the new message, check if the `RouterState` requested an interruption.
|
|
36
|
+
* If yes, call the queue's abort method.
|
|
37
|
+
* Send an automatic reply (log message) to the chat confirming the abortion or interruption.
|
|
38
|
+
* Queue the new message (if not just `/stop`).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Product Requirements Document: Process Interruptions
|
|
2
|
+
|
|
3
|
+
## 1. Vision
|
|
4
|
+
To enhance the Gemini CLI's responsiveness and user control by allowing users to seamlessly halt or interrupt long-running background tasks (agents). Users should be able to abandon a task entirely or interrupt it to inject new context/instructions without waiting for the current task to finish.
|
|
5
|
+
|
|
6
|
+
## 2. Product/Market Background
|
|
7
|
+
Currently, the CLI processes messages in a sequential queue per directory. Once a command starts via `child_process.spawn`, it runs to completion (or failure). If an agent goes down the wrong path or a user realizes they forgot a crucial detail, they cannot intervene until the agent finishes. Providing explicit `/stop` and `/interrupt` commands gives users back control over long-running LLM processes.
|
|
8
|
+
|
|
9
|
+
## 3. Use Cases
|
|
10
|
+
1. **Runaway Agent:** A user asks an agent to "refactor the auth flow." The agent starts heavily modifying files incorrectly. The user quickly types `/stop` to kill the process and discard any queued follow-ups.
|
|
11
|
+
2. **Course Correction:** A user tasks the agent with "implementing the login page." Mid-execution, the user realizes they forgot to mention using TailwindCSS. They type `/interrupt also ensure you use Tailwind CSS.` The current agent run is killed, and the new context is batched with any other pending queued messages into a single, comprehensive follow-up task.
|
|
12
|
+
|
|
13
|
+
## 4. Requirements
|
|
14
|
+
|
|
15
|
+
### 4.1 Functional Requirements
|
|
16
|
+
1. **Slash Commands:**
|
|
17
|
+
* `/stop`: Kills the currently running task in the active queue and clears all other pending, unprocessed messages in that queue.
|
|
18
|
+
* `/interrupt [optional extra text]`: Kills the currently running task. Any text appended to the command is batched together with any other pending messages in the queue into a single, new message task.
|
|
19
|
+
2. **Process Termination:**
|
|
20
|
+
* The system must send a termination signal (`SIGTERM`) to the underlying spawned process when an interruption is requested.
|
|
21
|
+
3. **Queue Management:**
|
|
22
|
+
* The `Queue` (`src/daemon/queue.ts`) must support tracking the active task's `AbortController` and provide an interface to abort it.
|
|
23
|
+
* The `Queue` must support clearing its pending tasks (for the `/stop` command).
|
|
24
|
+
* The `Queue` must support batching pending tasks (for the `/interrupt` command).
|
|
25
|
+
4. **Router Integration:**
|
|
26
|
+
* A new or existing router must parse `/stop` and `/interrupt` commands.
|
|
27
|
+
* The router must set a flag or action on the `RouterState` (e.g., `action: 'stop' | 'interrupt'`) so the main message handler knows to invoke the queue interruption logic.
|
|
28
|
+
* The router should provide a simple acknowledgment back to the user via the existing `reply` field on the `RouterState` (e.g., `reply: "[@clawmini/interrupt] Task interrupted."`).
|
|
29
|
+
|
|
30
|
+
### 4.2 Technical Implementation Details
|
|
31
|
+
* **Daemon/Client Communication:** Update `runCommand` (and `RunCommandFn`) to accept and respect an `AbortSignal`. Pass this signal down to `spawn`.
|
|
32
|
+
* **Message Processing (`src/daemon/message.ts`):** In `handleUserMessage` or `executeDirectMessage`, check the resulting `RouterState`. If it indicates an interruption:
|
|
33
|
+
1. Call the queue's abort method.
|
|
34
|
+
2. If `/stop`, clear the queue.
|
|
35
|
+
3. If `/interrupt`, fetch pending queue items, merge their message strings, append the new message string, and enqueue this combined payload as a single task.
|
|
36
|
+
|
|
37
|
+
### 4.3 Out of Scope
|
|
38
|
+
* Handling complex fallback termination signals (e.g., escalating from `SIGTERM` to `SIGKILL` if the process hangs). We will start with standard `SIGTERM`.
|
|
39
|
+
* Interrupting tasks that are purely synchronous/CPU-bound within the Node daemon itself (this primarily targets spawned child processes).
|
|
40
|
+
|
|
41
|
+
## 5. Security & Privacy
|
|
42
|
+
* Process termination should only affect child processes spawned by the current workspace queue. It must not leak signals to sibling projects or the host daemon.
|
|
43
|
+
* Path traversal and command injection risks remain unchanged, as the inputs are standard chat messages routed normally.
|
|
44
|
+
|
|
45
|
+
## 6. Accessibility
|
|
46
|
+
* No new UI elements are required; the interface is purely text-based (slash commands) and relies on existing text rendering for router replies.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Questions for Interruptions Feature
|
|
2
|
+
|
|
3
|
+
1. **Queue behavior on Interrupt:** When a process is interrupted (via `/stop` or `/interrupt`), should we also clear any *other* pending messages currently in the queue for that directory, or just kill the currently active one?
|
|
4
|
+
* **Answer:** With `/stop`, kill the current task and ignore/clear any pending new messages that haven't been processed yet. With `/interrupt`, stop the current task and batch any other pending messages together into one new message.
|
|
5
|
+
|
|
6
|
+
2. **Command Syntax:** You mentioned `/interrupt borrow` vs `/stop`. Could you clarify the exact syntax and expected behavior of the slash commands you want to support by default? (e.g., what does `borrow` do specifically?).
|
|
7
|
+
* **Answer:** "borrow" was just a transcription error. The syntax is `/interrupt` or `/interrupt [extra text]` (e.g., `/interrupt oh also remember to...`), and `/stop`.
|
|
8
|
+
3. **Signal Type:** When we send a kill signal, Node.js's `AbortController` with `spawn` defaults to `SIGTERM`. Is this sufficient, or do we need a more aggressive force-kill (`SIGKILL`) or a tiered approach?
|
|
9
|
+
* **Answer:** Start with `SIGTERM` and see how it works.
|
|
10
|
+
|
|
11
|
+
4. **System Messages:** Should the automatic reply ("task aborted" or "task interrupted") be appended as a standard `CommandLogMessage` in the chat history?
|
|
12
|
+
* **Answer:** Keep it simple; use the existing `reply` field that routers can provide.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Implementation Tickets: Process Interruptions
|
|
2
|
+
|
|
3
|
+
## Step 1: Update Queue Management
|
|
4
|
+
**Description:** Update the `Queue` class to support aborting the currently running task, clearing pending tasks, and retrieving pending tasks for batching.
|
|
5
|
+
**Tasks:**
|
|
6
|
+
- Modify `src/daemon/queue.ts` to track an `AbortController` for the currently executing task.
|
|
7
|
+
- Add a method `abortCurrent()` that triggers the `AbortController`.
|
|
8
|
+
- Add a method `clear()` or `clearQueue()` that removes all pending, non-executing tasks.
|
|
9
|
+
- Add a method to retrieve and remove pending tasks (e.g., `extractPending()`) to allow for batching.
|
|
10
|
+
- Update `src/daemon/queue.test.ts` to cover these new methods and ensure promises are handled correctly without unhandled rejections.
|
|
11
|
+
**Verification:**
|
|
12
|
+
- Run: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
13
|
+
**Status:** Complete
|
|
14
|
+
|
|
15
|
+
## Step 2: Update Command Execution with AbortSignal
|
|
16
|
+
**Description:** Plumb the `AbortSignal` down to the actual process execution so that `child_process.spawn` can terminate the task.
|
|
17
|
+
**Tasks:**
|
|
18
|
+
- Locate where `runCommand` or `RunCommandFn` is defined and used (likely in `src/cli/client.ts`, `src/daemon/message.ts`, or similar).
|
|
19
|
+
- Update the signature to accept an `AbortSignal`.
|
|
20
|
+
- Pass the `signal` option to `child_process.spawn`.
|
|
21
|
+
- Ensure that the resulting promise resolves or rejects cleanly when aborted (catching `AbortError` or checking process termination signal).
|
|
22
|
+
- Add or update relevant unit tests to verify the abort behavior.
|
|
23
|
+
**Verification:**
|
|
24
|
+
- Run: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
25
|
+
**Status:** Complete
|
|
26
|
+
|
|
27
|
+
## Step 3: Implement Interruption Routers
|
|
28
|
+
**Description:** Create slash command routers to detect `/stop` and `/interrupt` commands from the user and signal the intended action via the `RouterState`.
|
|
29
|
+
**Tasks:**
|
|
30
|
+
- Update the `RouterState` interface (e.g., in `src/daemon/routers.ts`) to include an `action: 'stop' | 'interrupt' | 'continue'` field or similar interrupt flag.
|
|
31
|
+
- Create a new router for `/stop` (e.g., `src/daemon/routers/slash-stop.ts`) that sets the action to 'stop' and provides an acknowledgment in the `reply` field.
|
|
32
|
+
- Create a new router for `/interrupt` (e.g., `src/daemon/routers/slash-interrupt.ts`) that sets the action to 'interrupt' and provides an acknowledgment.
|
|
33
|
+
- Update `src/daemon/routers/index.ts` to include the new routers in the pipeline.
|
|
34
|
+
- Write unit tests for the new routers in the appropriate `.test.ts` files.
|
|
35
|
+
**Verification:**
|
|
36
|
+
- Run: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
37
|
+
**Status:** Complete
|
|
38
|
+
|
|
39
|
+
## Step 4: Integrate Interruptions in Message Handler
|
|
40
|
+
**Description:** Wire up the router states to the queue methods within the main message processing loop.
|
|
41
|
+
**Tasks:**
|
|
42
|
+
- Update the message handling logic in `src/daemon/message.ts` (e.g., `handleUserMessage` or `executeDirectMessage`).
|
|
43
|
+
- After router execution, check the `RouterState` for interruption commands.
|
|
44
|
+
- If `action === 'stop'`: call `queue.abortCurrent()` and `queue.clear()`. Do not enqueue a new task.
|
|
45
|
+
- If `action === 'interrupt'`: call `queue.abortCurrent()`, extract pending tasks via `queue.extractPending()`, concatenate their text payloads with the new user message, and enqueue the combined payload as a single new task.
|
|
46
|
+
- Ensure the system replies to the user with the router's acknowledgment message.
|
|
47
|
+
- Update tests in `src/daemon/message.test.ts` (or similar) to verify the end-to-end interruption flow.
|
|
48
|
+
**Verification:**
|
|
49
|
+
- Run: `npm run format:check && npm run lint && npm run check && npm run test`
|
|
50
|
+
**Status:** Complete
|
|
51
|
+
|
|
52
|
+
## Step 5: DRY Violation - Extract shared spawn logic
|
|
53
|
+
**Description:** The logic for `spawn` and wrapping it in a Promise for `runCommand` is duplicated in `src/daemon/cron.ts`, `src/daemon/router.ts`, and `src/daemon/message-test-utils.ts`. Extract it into a shared utility function.
|
|
54
|
+
**Tasks:**
|
|
55
|
+
- Create `src/daemon/utils/spawn.ts` or a suitable shared location.
|
|
56
|
+
- Extract the common `runCommand` Promise wrapper logic there.
|
|
57
|
+
- Update `cron.ts`, `router.ts`, and `message-test-utils.ts` to use this new utility.
|
|
58
|
+
- Ensure type definitions (`RunCommandFn` etc) are imported correctly.
|
|
59
|
+
**Status:** Complete
|
|
60
|
+
**Priority:** High
|
|
61
|
+
|
|
62
|
+
## Step 6: DRY Violation - Consolidate slash command routers
|
|
63
|
+
**Description:** `slash-stop.ts` and `slash-interrupt.ts` are almost identical. Refactor to use a shared factory or utility for creating these static action routers to follow DRY principles.
|
|
64
|
+
**Tasks:**
|
|
65
|
+
- Create a shared utility function in `src/daemon/routers/utils.ts` (or similar) that generates these basic slash command routers.
|
|
66
|
+
- Update `slash-stop.ts` and `slash-interrupt.ts` to use this utility.
|
|
67
|
+
- Verify tests still pass.
|
|
68
|
+
**Status:** Complete
|
|
69
|
+
**Priority:** Medium
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Development Log
|
|
2
|
+
|
|
3
|
+
## Ticket 1: Core Configuration and Request State Management
|
|
4
|
+
Starting implementation of Ticket 1.
|
|
5
|
+
|
|
6
|
+
**Notes:**
|
|
7
|
+
- Created `src/shared/policies.ts` defining `PolicyConfig`, `PolicyDefinition`, `PolicyRequest`, and `RequestState`.
|
|
8
|
+
- Implemented `RequestStore` in `src/daemon/request-store.ts` to manage requests persistently under `.clawmini/tmp/requests`.
|
|
9
|
+
- Added unit tests for `RequestStore` covering normal operations and graceful handling of corrupted JSON files.
|
|
10
|
+
- Ensured all tests, types, and formatting pass. Ticket 1 is complete.
|
|
11
|
+
|
|
12
|
+
## Ticket 2: File Snapshotting and Security Layer
|
|
13
|
+
**Notes:**
|
|
14
|
+
- `src/daemon/policy-utils.ts` and `src/daemon/policy-utils.test.ts` implement snapshotting, argument interpolation, and safe execution.
|
|
15
|
+
- Verified test coverage and passed formatting/linting checks.
|
|
16
|
+
- Ticket 2 is complete.
|
|
17
|
+
|
|
18
|
+
## Ticket 3: Daemon Request Service
|
|
19
|
+
**Notes:**
|
|
20
|
+
- Created `src/daemon/policy-request-service.ts` and `src/daemon/policy-request-service.test.ts`.
|
|
21
|
+
- The service enforces maximum limit of pending requests (100).
|
|
22
|
+
- Handled snapshot generation for mapping file paths using `createSnapshot`.
|
|
23
|
+
- Stored requested payloads via `RequestStore`.
|
|
24
|
+
- Authored passing unit tests for request creation, rejection (on threshold), and argument interpolation handling.
|
|
25
|
+
- Ensured all codebase formatting, linting, and tests passed via the required checks.
|
|
26
|
+
- Ticket 3 is complete.
|
|
27
|
+
## Ticket 4: CLI Agent Commands
|
|
28
|
+
**Notes:**
|
|
29
|
+
- Implemented `clawmini requests list` to view available policies.
|
|
30
|
+
- Implemented `clawmini request <cmd> [--help] [--file name=path] -- [args]` to spawn policies or send them as requests to the daemon.
|
|
31
|
+
- Added `listPolicies` and `createPolicyRequest` to the daemon's AppRouter.
|
|
32
|
+
- Handled Commander's excess argument parsing correctly to allow passing opaque arguments without errors.
|
|
33
|
+
- Created `src/cli/e2e/requests.test.ts` which tests the entire flow successfully.
|
|
34
|
+
- Ticket 4 is complete.
|
|
35
|
+
|
|
36
|
+
## Ticket 5: Chat UI Routing and User Slash Commands
|
|
37
|
+
**Notes:**
|
|
38
|
+
- Implemented `slashPolicies` router in `src/daemon/routers/slash-policies.ts` to process user messages directly.
|
|
39
|
+
- The router acts as an interceptor for `/approve <id>`, `/reject <id> [reason]`, and `/pending` commands.
|
|
40
|
+
- It guarantees strict spoofing prevention by being integrated natively into the router pipeline via `executeRouterPipeline` which strictly evaluates user inputs (`role: 'user'`).
|
|
41
|
+
- In `src/daemon/router.ts`, updated `createPolicyRequest` to generate and append a preview message inside the chat when requests are generated.
|
|
42
|
+
- The preview correctly abbreviates snapshotted file contents to 500 characters and handles failures safely.
|
|
43
|
+
- Wrote full unit test coverage for the preview message and the slash command router spoofing prevention mechanisms.
|
|
44
|
+
- Verified test suite and all quality checks successfully passed (`npm run format:check && npm run lint && npm run check && npm run test`).
|
|
45
|
+
- Ticket 5 is complete.
|
|
46
|
+
|
|
47
|
+
## Ticket 6: Execution and Feedback Loop
|
|
48
|
+
**Notes:**
|
|
49
|
+
- Implemented execution logic inside `src/daemon/routers/slash-policies.ts` for `/approve`.
|
|
50
|
+
- It dynamically reads the corresponding policy configuration, interpolates all arguments (both policy args and opaque user args) via `interpolateArgs`, and spawns the safe child process wrapper (`executeSafe`).
|
|
51
|
+
- Integrated automated system log messages. Upon resolving the request (approving or rejecting), a `CommandLogMessage` is constructed and injected into the target chat via `appendMessage` so the agent receives the feedback (`stdout`/`stderr` for approvals, rejection reason for rejections).
|
|
52
|
+
- Fixed unused variable lint error and unexpected any warnings in `src/daemon/router-policy-request.test.ts`.
|
|
53
|
+
- Added complete coverage unit tests for the `/approve` and `/reject` flows within `src/daemon/routers/slash-policies.test.ts`.
|
|
54
|
+
- All checks (`npm run format:check && npm run lint && npm run check && npm run test`) pass. Ticket 6 is complete.
|
|
55
|
+
|
|
56
|
+
## Ticket 8: Policy Utils Improvements
|
|
57
|
+
**Notes:**
|
|
58
|
+
- Exported `MAX_SNAPSHOT_SIZE` constant (5MB) in `src/daemon/policy-utils.ts` and enforced its usage.
|
|
59
|
+
- Refactored `createSnapshot` to receive `agentDir` instead of `workspaceRoot`.
|
|
60
|
+
- Enforced strict symlink rejection by replacing `fs.realpath` with `fs.lstat` during snapshot creation, rejecting any symlinks to avoid TOCTOU attacks.
|
|
61
|
+
- Modified the snapshot logic to guarantee unique filenames by leveraging `fs.constants.COPYFILE_EXCL` within a retry loop to prevent silent overwrites.
|
|
62
|
+
- Updated `PolicyRequestService` and the `createPolicyRequest` router TRPC procedure to retrieve and pass `agentDir`.
|
|
63
|
+
- Fully updated and expanded `policy-utils.test.ts` to assert against symlink rejection and new size limit constants.
|
|
64
|
+
- Successfully ran all tests, including formatting, linting, type checks, and full unit test suites. Ticket 8 is complete.
|
|
65
|
+
|
|
66
|
+
## Ticket 9: Policy Request Metadata & Validation Enhancements
|
|
67
|
+
**Notes:**
|
|
68
|
+
- Updated request ID generation to use a 3-character random alphanumeric string using `crypto.randomBytes`.
|
|
69
|
+
- Added `chatId` and `agentId` to `PolicyRequest` and properly populated them inside `createRequest` via `src/daemon/router.ts`.
|
|
70
|
+
- Implemented `PolicyRequestSchema` utilizing Zod within `request-store.ts` to validate disk reads dynamically.
|
|
71
|
+
- Handled mock tests properly in `policy-request-service.test.ts`, `router-policy-request.test.ts`, and `request-store.test.ts` adapting to the new metadata fields.
|
|
72
|
+
- Successfully executed formatting, linting, unit tests, and integration tests (`npm run format`, `npm run lint:fix`, `npm run check`, `npm run test`).
|
|
73
|
+
- Ticket 9 is complete.
|
|
74
|
+
|
|
75
|
+
## Ticket 10: Router State & Configuration Fixes
|
|
76
|
+
**Notes:**
|
|
77
|
+
- Updated `src/daemon/routers.ts` to execute `slash-policies` dynamically as part of the router pipeline loop, removing hardcoded top-level logic.
|
|
78
|
+
- Extended `RouterState` interface in `src/daemon/routers/types.ts` to explicitly include `messageId` tracking the user's incoming message ID.
|
|
79
|
+
- Passed `messageId` properly down to the state configuration within `src/daemon/message.ts` via `getInitialRouterState` and `handleUserMessage`.
|
|
80
|
+
- Modified `src/daemon/routers/slash-policies.ts` so that `/approve`, `/reject`, and error flows no longer force an abrupt `action: 'stop'`.
|
|
81
|
+
- Ensured errors update `state.reply` with `state.message` cleared, while correct executions update `state.message` safely.
|
|
82
|
+
- Validated `req.chatId` matches the incoming request context to prevent unauthorized cross-chat executions.
|
|
83
|
+
- Updated all unit tests across the test suite to include mock `messageId` and adapted the modified assertions for success and error behaviors.
|
|
84
|
+
- All code checks format, lint, tests compiled correctly and successfully passed without exceptions.
|
|
85
|
+
- Ticket 10 is complete.
|
|
86
|
+
|
|
87
|
+
## Ticket 11: CLI Commands Relocation
|
|
88
|
+
**Notes:**
|
|
89
|
+
- Relocated `request` and `requests` commands from `src/cli/index.ts` to `src/cli/lite.ts`.
|
|
90
|
+
- Deleted `src/cli/commands/request.ts`.
|
|
91
|
+
- Updated `request` and `requests` logic to use `createTRPCClient` configured in `clawmini-lite` via `CLAW_API_URL` and `CLAW_API_TOKEN` instead of using the local Unix Socket daemon client.
|
|
92
|
+
- Updated `src/cli/e2e/requests.test.ts` to test against the exported `clawmini-lite` client by starting the daemon with an API server enabled and obtaining an API token via a mock `env-dumper` agent.
|
|
93
|
+
- Resolved a path validation security error in `requests.test.ts` by ensuring `dummy.txt` test files correctly live inside the mock agent's directory, conforming to `policy-utils.ts` security limits from Ticket 8.
|
|
94
|
+
- Ran formatting, lint checks, type checks, and tests successfully (`npm run format && npm run lint:fix && npm run check && npm run test`).
|
|
95
|
+
- Ticket 11 is complete.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Sandbox Policies Research Notes
|
|
2
|
+
|
|
3
|
+
## Current State
|
|
4
|
+
- The product (clawmini/Gemini CLI) currently has a daemon that manages chats, messages, agents, and routing.
|
|
5
|
+
- Adapters exist for Discord and Web UI.
|
|
6
|
+
- CLI handles various commands: agents, chats, environments, jobs, messages.
|
|
7
|
+
- There is currently no `sandbox` command in the CLI.
|
|
8
|
+
|
|
9
|
+
## Feature Requirements
|
|
10
|
+
- A `sandbox` CLI available to the agent inside its restricted environment.
|
|
11
|
+
- The agent uses this CLI to request user approval for "sensitive actions" that require elevated privileges or network access.
|
|
12
|
+
- Requests are asynchronous. AI agents don't block, but scripts/workflows could.
|
|
13
|
+
- Examples of actions:
|
|
14
|
+
- Move files to a read-only network-enabled directory.
|
|
15
|
+
- Send an email.
|
|
16
|
+
- The system must capture/snapshot any files related to the request at the time it is made, storing them safely outside the sandbox to prevent tampering while waiting for approval.
|
|
17
|
+
- User needs a way to register new commands/actions easily.
|
|
18
|
+
- Support for callbacks when the user approves/rejects a request (to notify the agent or trigger a workflow).
|
|
19
|
+
|
|
20
|
+
## Ambiguities / Open Questions
|
|
21
|
+
- Where is the approval surfaced to the user? (Web UI, CLI, Discord?)
|
|
22
|
+
- How are actions configured? (YAML, TS, JSON?)
|
|
23
|
+
- Where do callbacks execute? (Inside sandbox or outside on host?)
|
|
24
|
+
- How does the snapshot mechanism identify which files to capture? (Does the action definition specify file arguments?)
|
|
25
|
+
|
|
26
|
+
## PR #71 Feedback Notes
|
|
27
|
+
- **Constants:** Move max snapshot size limit to a constant.
|
|
28
|
+
- **Security:** Ensure snapshots resolve to the *agent's directory*, not just the workspace root. Do not follow symlinks (reject them immediately with lstat). Ensure the generated snapshot filename does not already exist.
|
|
29
|
+
- **Router Configuration:** The `slash-policies` router must be an optional router in `init.ts` and loaded dynamically via the pipeline like other routers, not hardcoded.
|
|
30
|
+
- **Router State Handling:** Do not use `action: 'stop'` on `/approve` or `/reject` or error cases, as that kills running processes. Instead, use `{ message: '...' }` to update the message the agent sees, and empty message with `reply` for user errors. Include `messageId` for replies.
|
|
31
|
+
- **Request Metadata & Validation:** Use shorter, typing-friendly IDs for requests instead of UUIDs. Save `chatId` and `agentId` with the request. Validate the chat ID matches when approving/rejecting. Add Zod validation to `request-store.ts` when loading from disk.
|
|
32
|
+
- **Code Cleanup:** Remove inline `await import(...)` in `src/daemon/router.ts` and move them to top-level imports.
|
|
33
|
+
- **CLI Commands:** The `request` and `requests` commands should be moved to `src/cli/lite.ts` so they are accessible by the agent.
|