clawmini 0.0.3 → 0.0.5
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/README.md +19 -0
- package/dist/adapter-discord/index.d.mts.map +1 -1
- package/dist/adapter-discord/index.mjs +398 -193
- package/dist/adapter-discord/index.mjs.map +1 -1
- package/dist/adapter-google-chat/index.d.mts +5 -0
- package/dist/adapter-google-chat/index.d.mts.map +1 -0
- package/dist/adapter-google-chat/index.mjs +1077 -0
- package/dist/adapter-google-chat/index.mjs.map +1 -0
- package/dist/cli/index.mjs +107 -14
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lite.mjs +175 -16
- package/dist/cli/lite.mjs.map +1 -1
- package/dist/cli/propose-policy.d.mts +1 -0
- package/dist/cli/propose-policy.mjs +7159 -0
- package/dist/cli/propose-policy.mjs.map +1 -0
- package/dist/daemon/index.d.mts.map +1 -1
- package/dist/daemon/index.mjs +1427 -513
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/{lite-oSYSvaOr.mjs → lite-CBxOT1y5.mjs} +101 -24
- package/dist/lite-CBxOT1y5.mjs.map +1 -0
- package/dist/routing-D8rTxtaV.mjs +245 -0
- package/dist/routing-D8rTxtaV.mjs.map +1 -0
- package/dist/web/_app/immutable/assets/0.C-4eziNy.css +1 -0
- package/dist/web/_app/immutable/assets/4.Cc_xwLNl.css +1 -0
- package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +1 -0
- package/dist/web/_app/immutable/chunks/{Dc-UOHw9.js → BmRlVmv6.js} +1 -1
- package/{web/.svelte-kit/output/client/_app/immutable/chunks/8YNcRyEk.js → dist/web/_app/immutable/chunks/C20lZMGz.js} +1 -1
- package/dist/web/_app/immutable/chunks/C9lbZ-kT.js +1 -0
- package/dist/web/_app/immutable/chunks/CK9JZLaG.js +2 -0
- package/dist/web/_app/immutable/chunks/CME08kGM.js +1 -0
- package/dist/web/_app/immutable/chunks/{BPy8HLo7.js → Ck-be5J2.js} +1 -1
- package/dist/web/_app/immutable/chunks/Ck3rYNON.js +1 -0
- package/dist/web/_app/immutable/chunks/DMtIqaiV.js +2 -0
- package/dist/web/_app/immutable/chunks/{B8yYFADm.js → DhD271EB.js} +1 -1
- package/dist/web/_app/immutable/chunks/{DcrmIfTj.js → DpuLqk8d.js} +1 -1
- package/dist/web/_app/immutable/chunks/{ZkLyk0mE.js → Drm9vgeP.js} +1 -1
- package/dist/web/_app/immutable/chunks/DsIToJCP.js +1 -0
- package/dist/web/_app/immutable/chunks/{CyNaE55B.js → Zeh-C-mx.js} +1 -1
- package/{web/.svelte-kit/output/client/_app/immutable/entry/app.DO5eYwVz.js → dist/web/_app/immutable/entry/app.BgB5VkRU.js} +2 -2
- package/dist/web/_app/immutable/entry/start.DuxJo6av.js +1 -0
- package/dist/web/_app/immutable/nodes/0.C9oFZP9h.js +1 -0
- package/dist/web/_app/immutable/nodes/1.BON2Wk6k.js +1 -0
- package/dist/web/_app/immutable/nodes/{2.CK3CLC0f.js → 2.BnwnD1Ki.js} +1 -1
- package/dist/web/_app/immutable/nodes/{3.ncP0xLO6.js → 3.CIs4tjjw.js} +1 -1
- package/dist/web/_app/immutable/nodes/4.DLarELN4.js +60 -0
- package/dist/web/_app/immutable/nodes/{5.BpJUN6QH.js → 5.CE_QKy_3.js} +1 -1
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +12 -12
- package/dist/{workspace-DjoNjhW0.mjs → workspace-BJmJBfKi.mjs} +103 -11
- package/dist/workspace-BJmJBfKi.mjs.map +1 -0
- package/docs/14_google_chat_adapter/development_log.md +40 -0
- package/docs/14_google_chat_adapter/notes.md +28 -0
- package/docs/14_google_chat_adapter/prd.md +35 -0
- package/docs/14_google_chat_adapter/questions.md +9 -0
- package/docs/14_google_chat_adapter/tickets.md +117 -0
- package/docs/15_sandbox_policies/tickets.md +33 -0
- package/docs/16_session_timeout/development_log.md +20 -0
- package/docs/16_session_timeout/notes.md +44 -0
- package/docs/16_session_timeout/prd.md +106 -0
- package/docs/16_session_timeout/questions.md +10 -0
- package/docs/16_session_timeout/tickets.md +64 -0
- package/docs/17_auto_approve_policy/development_log.md +29 -0
- package/docs/17_auto_approve_policy/notes.md +25 -0
- package/docs/17_auto_approve_policy/prd.md +34 -0
- package/docs/17_auto_approve_policy/questions.md +10 -0
- package/docs/17_auto_approve_policy/tickets.md +11 -0
- package/docs/18_clawmini_skills/development_log.md +36 -0
- package/docs/18_clawmini_skills/notes.md +8 -0
- package/docs/18_clawmini_skills/prd.md +45 -0
- package/docs/18_clawmini_skills/questions.md +10 -0
- package/docs/18_clawmini_skills/tickets.md +55 -0
- package/docs/19_subagents/development_log.md +69 -0
- package/docs/19_subagents/notes.md +18 -0
- package/docs/19_subagents/prd.md +156 -0
- package/docs/19_subagents/questions.md +13 -0
- package/docs/19_subagents/tickets.md +113 -0
- package/docs/20_chat_logs_cleanup/development_log.md +50 -0
- package/docs/20_chat_logs_cleanup/notes.md +43 -0
- package/docs/20_chat_logs_cleanup/prd.md +232 -0
- package/docs/20_chat_logs_cleanup/questions.md +2 -0
- package/docs/20_chat_logs_cleanup/tickets.md +98 -0
- package/docs/20_webui_markdown/development_log.md +36 -0
- package/docs/20_webui_markdown/notes.md +23 -0
- package/docs/20_webui_markdown/prd.md +49 -0
- package/docs/20_webui_markdown/questions.md +10 -0
- package/docs/20_webui_markdown/tickets.md +55 -0
- package/docs/21_adapter_filtering/development_log.md +29 -0
- package/docs/21_adapter_filtering/notes.md +25 -0
- package/docs/21_adapter_filtering/prd.md +44 -0
- package/docs/21_adapter_filtering/questions.md +12 -0
- package/docs/21_adapter_filtering/tickets.md +38 -0
- package/docs/21_built_in_routers/development_log.md +17 -0
- package/docs/21_built_in_routers/notes.md +27 -0
- package/docs/21_built_in_routers/prd.md +34 -0
- package/docs/21_built_in_routers/questions.md +4 -0
- package/docs/21_built_in_routers/tickets.md +25 -0
- package/docs/21_fancy_policies/development_log.md +38 -0
- package/docs/21_fancy_policies/notes.md +27 -0
- package/docs/21_fancy_policies/prd.md +58 -0
- package/docs/21_fancy_policies/questions.md +6 -0
- package/docs/21_fancy_policies/tickets.md +48 -0
- package/docs/22_adapter_multi_chat/development_log.md +76 -0
- package/docs/22_adapter_multi_chat/notes.md +42 -0
- package/docs/22_adapter_multi_chat/prd.md +76 -0
- package/docs/22_adapter_multi_chat/questions.md +16 -0
- package/docs/22_adapter_multi_chat/tickets.md +164 -0
- package/docs/23_custom_token_env/development_log.md +31 -0
- package/docs/23_custom_token_env/notes.md +16 -0
- package/docs/23_custom_token_env/prd.md +42 -0
- package/docs/23_custom_token_env/questions.md +8 -0
- package/docs/23_custom_token_env/tickets.md +54 -0
- package/docs/guides/discord_adapter_setup.md +15 -2
- package/docs/guides/google_chat_adapter_setup.md +145 -0
- package/napkin.md +5 -0
- package/package.json +7 -2
- package/src/adapter-discord/config.test.ts +27 -8
- package/src/adapter-discord/config.ts +6 -8
- package/src/adapter-discord/forwarder.test.ts +307 -114
- package/src/adapter-discord/forwarder.ts +260 -75
- package/src/adapter-discord/index.test.ts +278 -0
- package/src/adapter-discord/index.ts +160 -30
- package/src/adapter-discord/interactions.test.ts +96 -0
- package/src/adapter-discord/interactions.ts +156 -0
- package/src/adapter-discord/state.test.ts +9 -8
- package/src/adapter-discord/state.ts +51 -8
- package/src/adapter-google-chat/auth.test.ts +87 -0
- package/src/adapter-google-chat/auth.ts +132 -0
- package/src/adapter-google-chat/cards.ts +71 -0
- package/src/adapter-google-chat/client.test.ts +561 -0
- package/src/adapter-google-chat/client.ts +430 -0
- package/src/adapter-google-chat/config.test.ts +187 -0
- package/src/adapter-google-chat/config.ts +82 -0
- package/src/adapter-google-chat/cron.test.ts +143 -0
- package/src/adapter-google-chat/cron.ts +81 -0
- package/src/adapter-google-chat/forwarder.test.ts +537 -0
- package/src/adapter-google-chat/forwarder.ts +349 -0
- package/src/adapter-google-chat/index.test.ts +62 -0
- package/src/adapter-google-chat/index.ts +61 -0
- package/src/adapter-google-chat/state.test.ts +96 -0
- package/src/adapter-google-chat/state.ts +85 -0
- package/src/adapter-google-chat/subscriptions.ts +124 -0
- package/src/adapter-google-chat/upload.ts +88 -0
- package/src/adapter-google-chat/utils.test.ts +111 -0
- package/src/adapter-google-chat/utils.ts +133 -0
- package/src/cli/commands/init.ts +0 -7
- package/src/cli/commands/messages.ts +18 -3
- package/src/cli/commands/policies.ts +70 -0
- package/src/cli/commands/skills.ts +71 -0
- package/src/cli/commands/web-api/chats.ts +5 -1
- package/src/cli/e2e/basic.test.ts +1 -1
- package/src/cli/e2e/cron.test.ts +1 -1
- package/src/cli/e2e/daemon.test.ts +132 -4
- package/src/cli/e2e/export-lite-func.test.ts +54 -31
- package/src/cli/e2e/fallbacks.test.ts +8 -6
- package/src/cli/e2e/init.test.ts +7 -0
- package/src/cli/e2e/messages.test.ts +90 -55
- package/src/cli/e2e/propose-policy.test.ts +203 -0
- package/src/cli/e2e/requests.test.ts +15 -0
- package/src/cli/e2e/session-timeout.test.ts +192 -0
- package/src/cli/e2e/skills.test.ts +55 -0
- package/src/cli/e2e/slash-new.test.ts +93 -0
- package/src/cli/e2e/subagents.test.ts +106 -0
- package/src/cli/index.ts +4 -0
- package/src/cli/lite.ts +51 -11
- package/src/cli/propose-policy.ts +91 -0
- package/src/cli/subagent-commands.ts +215 -0
- package/src/daemon/agent/agent-context.ts +89 -0
- package/src/daemon/agent/agent-extractors.ts +68 -0
- package/src/daemon/agent/agent-runner.ts +153 -0
- package/src/daemon/agent/agent-session.ts +261 -0
- package/src/daemon/agent/chat-logger.test.ts +158 -0
- package/src/daemon/agent/chat-logger.ts +188 -0
- package/src/daemon/agent/task-scheduler.test.ts +202 -0
- package/src/daemon/agent/task-scheduler.ts +276 -0
- package/src/daemon/agent/types.ts +84 -0
- package/src/daemon/agent/utils.ts +7 -0
- package/src/daemon/api/agent-router.ts +166 -18
- package/src/daemon/api/index.test.ts +50 -18
- package/src/daemon/api/policy-request.test.ts +39 -2
- package/src/daemon/api/subagent-router.test.ts +108 -0
- package/src/daemon/api/subagent-router.ts +296 -0
- package/src/daemon/api/subagent-utils.test.ts +56 -0
- package/src/daemon/api/subagent-utils.ts +130 -0
- package/src/daemon/api/user-router.ts +30 -13
- package/src/daemon/auth.ts +1 -0
- package/src/daemon/chats.ts +6 -0
- package/src/daemon/cron.test.ts +66 -1
- package/src/daemon/cron.ts +35 -8
- package/src/daemon/index.ts +23 -0
- package/src/daemon/message-agent.test.ts +11 -25
- package/src/daemon/message-extraction.test.ts +10 -27
- package/src/daemon/message-fallbacks.test.ts +13 -35
- package/src/daemon/message-interruption.test.ts +70 -53
- package/src/daemon/message-jobs.test.ts +138 -0
- package/src/daemon/message-queue.test.ts +30 -43
- package/src/daemon/message-router.test.ts +12 -11
- package/src/daemon/message-session.test.ts +41 -28
- package/src/daemon/message-typing.test.ts +19 -6
- package/src/daemon/message.ts +103 -515
- package/src/daemon/policy-request-service.ts +8 -3
- package/src/daemon/policy-utils.ts +19 -1
- package/src/daemon/queue.ts +16 -0
- package/src/daemon/request-store.test.ts +4 -0
- package/src/daemon/routers/session-timeout.test.ts +122 -0
- package/src/daemon/routers/session-timeout.ts +71 -0
- package/src/daemon/routers/slash-new.ts +3 -1
- package/src/daemon/routers/slash-policies.test.ts +26 -13
- package/src/daemon/routers/slash-policies.ts +39 -29
- package/src/daemon/routers/types.ts +8 -0
- package/src/daemon/routers.ts +64 -2
- package/src/daemon/utils/spawn.ts +6 -8
- package/src/shared/adapters/commands.test.ts +155 -0
- package/src/shared/adapters/commands.ts +125 -0
- package/src/shared/adapters/filtering.test.ts +111 -0
- package/src/shared/adapters/filtering.ts +57 -0
- package/src/shared/adapters/routing.test.ts +144 -0
- package/src/shared/adapters/routing.ts +109 -0
- package/src/shared/agent-utils.ts +10 -0
- package/src/shared/chats.test.ts +145 -3
- package/src/shared/chats.ts +215 -18
- package/src/shared/config.ts +67 -15
- package/src/shared/lite.ts +22 -18
- package/src/shared/policies.ts +7 -0
- package/src/shared/workspace.test.ts +45 -1
- package/src/shared/workspace.ts +119 -6
- package/templates/debug/settings.json +5 -2
- package/templates/environments/cladding/env.json +2 -2
- package/templates/gemini/.gemini/hooks/check-subagents.mjs +23 -0
- package/templates/gemini/.gemini/hooks/clawmini-logging.sh +17 -0
- package/templates/gemini/.gemini/hooks/insert-pending.sh +9 -0
- package/templates/gemini/.gemini/settings.json +50 -0
- package/templates/gemini/settings.json +22 -8
- package/templates/gemini-claw/.gemini/base-system.md +100 -0
- package/templates/gemini-claw/.gemini/hooks/check-subagents.mjs +23 -0
- package/templates/gemini-claw/.gemini/hooks/clawmini-logging.sh +1 -1
- package/templates/gemini-claw/.gemini/settings.json +13 -0
- package/templates/gemini-claw/.gemini/subagent-system.md +7 -0
- package/templates/gemini-claw/.gemini/system.md +3 -99
- package/templates/gemini-claw/settings.json +27 -22
- package/templates/skills/clawmini-requests/SKILL.md +92 -0
- package/templates/skills/clawmini-subagents/SKILL.md +79 -0
- package/templates/skills/skill-creator/SKILL.md +60 -0
- package/tsdown.config.ts +10 -1
- package/web/.svelte-kit/generated/server/internal.js +2 -1
- package/web/.svelte-kit/non-ambient.d.ts +2 -0
- package/web/.svelte-kit/output/client/.vite/manifest.json +141 -138
- package/web/.svelte-kit/output/client/_app/immutable/assets/0.C-4eziNy.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/assets/4.Cc_xwLNl.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{Dc-UOHw9.js → BmRlVmv6.js} +1 -1
- package/{dist/web/_app/immutable/chunks/8YNcRyEk.js → web/.svelte-kit/output/client/_app/immutable/chunks/C20lZMGz.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/C9lbZ-kT.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{BPy8HLo7.js → Ck-be5J2.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{B8yYFADm.js → DhD271EB.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{DcrmIfTj.js → DpuLqk8d.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{ZkLyk0mE.js → Drm9vgeP.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{CyNaE55B.js → Zeh-C-mx.js} +1 -1
- package/{dist/web/_app/immutable/entry/app.DO5eYwVz.js → web/.svelte-kit/output/client/_app/immutable/entry/app.BgB5VkRU.js} +2 -2
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.DuxJo6av.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/0.C9oFZP9h.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.BON2Wk6k.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.CK3CLC0f.js → 2.BnwnD1Ki.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{3.ncP0xLO6.js → 3.CIs4tjjw.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.DLarELN4.js +60 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.BpJUN6QH.js → 5.CE_QKy_3.js} +1 -1
- package/web/.svelte-kit/output/client/_app/version.json +1 -1
- package/web/.svelte-kit/output/server/.vite/manifest.json +12 -3
- package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.C-4eziNy.css +1 -0
- package/web/.svelte-kit/output/server/_app/immutable/assets/_page.Cc_xwLNl.css +1 -0
- package/web/.svelte-kit/output/server/chunks/app-state.svelte.js +5 -0
- package/web/.svelte-kit/output/server/chunks/bot.js +4 -4
- package/web/.svelte-kit/output/server/chunks/client.js +2 -1
- package/web/.svelte-kit/output/server/chunks/exports.js +0 -1
- package/web/.svelte-kit/output/server/chunks/internal.js +2 -1
- package/web/.svelte-kit/output/server/chunks/root.js +482 -392
- package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +57 -7
- package/web/.svelte-kit/output/server/entries/pages/chats/_id_/_page.svelte.js +234 -9
- package/web/.svelte-kit/output/server/index.js +82 -10
- package/web/.svelte-kit/output/server/manifest-full.js +1 -1
- package/web/.svelte-kit/output/server/manifest.js +1 -1
- package/web/.svelte-kit/output/server/nodes/0.js +2 -2
- package/web/.svelte-kit/output/server/nodes/1.js +1 -1
- package/web/.svelte-kit/output/server/nodes/2.js +1 -1
- package/web/.svelte-kit/output/server/nodes/3.js +1 -1
- package/web/.svelte-kit/output/server/nodes/4.js +2 -2
- package/web/.svelte-kit/output/server/nodes/5.js +1 -1
- package/web/.svelte-kit/types/src/routes/$types.d.ts +1 -2
- package/web/.svelte-kit/types/src/routes/agents/$types.d.ts +1 -2
- package/web/.svelte-kit/types/src/routes/chats/[id]/$types.d.ts +1 -2
- package/web/.svelte-kit/types/src/routes/chats/[id]/settings/$types.d.ts +1 -2
- package/web/package.json +8 -0
- package/web/src/lib/app-state.svelte.ts +5 -1
- package/web/src/lib/components/app/markdown-renderer.svelte +56 -0
- package/web/src/lib/components/app/markdown-renderer.svelte.spec.ts +44 -0
- package/web/src/lib/components/app/message-content.svelte +16 -0
- package/web/src/lib/types.ts +67 -3
- package/web/src/routes/+layout.svelte +31 -1
- package/web/src/routes/chats/[id]/+page.svelte +167 -18
- package/web/src/routes/chats/[id]/page.svelte.spec.ts +58 -7
- package/dist/lite-oSYSvaOr.mjs.map +0 -1
- package/dist/web/_app/immutable/assets/0.GI4C4dpV.css +0 -1
- package/dist/web/_app/immutable/chunks/B5abRDXp.js +0 -1
- package/dist/web/_app/immutable/chunks/Bi0jeV7Q.js +0 -1
- package/dist/web/_app/immutable/chunks/BmUXQ3wy.js +0 -2
- package/dist/web/_app/immutable/chunks/C3k55nDF.js +0 -1
- package/dist/web/_app/immutable/chunks/CpaGRn9L.js +0 -1
- package/dist/web/_app/immutable/chunks/DG5RZBw-.js +0 -2
- package/dist/web/_app/immutable/chunks/DQoygso7.js +0 -1
- package/dist/web/_app/immutable/entry/start.D48mVn1m.js +0 -1
- package/dist/web/_app/immutable/nodes/0.B-0CcADM.js +0 -1
- package/dist/web/_app/immutable/nodes/1.FixKgvRO.js +0 -1
- package/dist/web/_app/immutable/nodes/4.CQYJEgv8.js +0 -1
- package/dist/workspace-DjoNjhW0.mjs.map +0 -1
- package/src/daemon/message-verbosity.test.ts +0 -127
- package/web/.svelte-kit/output/client/_app/immutable/assets/0.GI4C4dpV.css +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B5abRDXp.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Bi0jeV7Q.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BmUXQ3wy.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/C3k55nDF.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CpaGRn9L.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DG5RZBw-.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DQoygso7.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.D48mVn1m.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/0.B-0CcADM.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.FixKgvRO.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CQYJEgv8.js +0 -1
- package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.GI4C4dpV.css +0 -1
- /package/templates/{gemini-claw/.gemini/skills → skills}/clawmini-jobs/SKILL.md +0 -0
|
@@ -20,7 +20,9 @@ export class PolicyRequestService {
|
|
|
20
20
|
args: string[],
|
|
21
21
|
fileMappings: Record<string, string>,
|
|
22
22
|
chatId: string,
|
|
23
|
-
agentId: string
|
|
23
|
+
agentId: string,
|
|
24
|
+
skipSave: boolean = false,
|
|
25
|
+
subagentId?: string
|
|
24
26
|
): Promise<PolicyRequest> {
|
|
25
27
|
const allRequests = await this.store.list();
|
|
26
28
|
const pendingCount = allRequests.filter((r) => r.state === 'Pending').length;
|
|
@@ -45,13 +47,16 @@ export class PolicyRequestService {
|
|
|
45
47
|
commandName,
|
|
46
48
|
args,
|
|
47
49
|
fileMappings: snapshotMappings,
|
|
48
|
-
state: 'Pending',
|
|
50
|
+
state: skipSave ? 'Approved' : 'Pending',
|
|
49
51
|
createdAt: Date.now(),
|
|
50
52
|
chatId,
|
|
51
53
|
agentId,
|
|
54
|
+
...(subagentId ? { subagentId } : {}),
|
|
52
55
|
};
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
if (!skipSave) {
|
|
58
|
+
await this.store.save(request);
|
|
59
|
+
}
|
|
55
60
|
|
|
56
61
|
return request;
|
|
57
62
|
}
|
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { randomBytes } from 'node:crypto';
|
|
5
5
|
import { spawn } from 'node:child_process';
|
|
6
6
|
import { pathIsInsideDir } from '../shared/utils/fs.js';
|
|
7
|
-
import type { PolicyRequest } from '../shared/policies.js';
|
|
7
|
+
import type { PolicyRequest, PolicyDefinition } from '../shared/policies.js';
|
|
8
8
|
|
|
9
9
|
export const MAX_SNAPSHOT_SIZE = 5 * 1024 * 1024;
|
|
10
10
|
|
|
@@ -127,6 +127,24 @@ export function executeSafe(
|
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
export async function executeRequest(
|
|
131
|
+
request: PolicyRequest,
|
|
132
|
+
policy: PolicyDefinition,
|
|
133
|
+
cwd?: string
|
|
134
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number; commandStr: string }> {
|
|
135
|
+
const fullArgs = [...(policy.args || []), ...request.args];
|
|
136
|
+
const interpolatedArgs = interpolateArgs(fullArgs, request.fileMappings);
|
|
137
|
+
|
|
138
|
+
const { stdout, stderr, exitCode } = await executeSafe(
|
|
139
|
+
policy.command,
|
|
140
|
+
interpolatedArgs,
|
|
141
|
+
cwd ? { cwd } : undefined
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const commandStr = `${policy.command} ${interpolatedArgs.join(' ')}`;
|
|
145
|
+
return { stdout, stderr, exitCode, commandStr };
|
|
146
|
+
}
|
|
147
|
+
|
|
130
148
|
export async function generateRequestPreview(request: PolicyRequest): Promise<string> {
|
|
131
149
|
let previewContent = `Sandbox Policy Request: ${request.commandName}\n`;
|
|
132
150
|
previewContent += `ID: ${request.id}\n`;
|
package/src/daemon/queue.ts
CHANGED
|
@@ -85,6 +85,22 @@ export class Queue<TPayload = string> {
|
|
|
85
85
|
|
|
86
86
|
return extracted;
|
|
87
87
|
}
|
|
88
|
+
|
|
89
|
+
interrupt(predicate?: (payload: TPayload) => boolean): TPayload[] {
|
|
90
|
+
const payloads: TPayload[] = [];
|
|
91
|
+
|
|
92
|
+
const currentMatches =
|
|
93
|
+
!predicate || (this.currentPayload !== undefined && predicate(this.currentPayload));
|
|
94
|
+
if (currentMatches && this.currentPayload !== undefined) {
|
|
95
|
+
payloads.push(this.currentPayload);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.abortCurrent(predicate);
|
|
99
|
+
|
|
100
|
+
payloads.push(...this.extractPending(predicate));
|
|
101
|
+
|
|
102
|
+
return payloads;
|
|
103
|
+
}
|
|
88
104
|
}
|
|
89
105
|
|
|
90
106
|
export interface MessageQueuePayload {
|
|
@@ -6,6 +6,10 @@ import path from 'path';
|
|
|
6
6
|
import * as workspace from '../shared/workspace.js';
|
|
7
7
|
|
|
8
8
|
vi.mock('../shared/workspace.js', () => ({
|
|
9
|
+
resolveAgentWorkDir: vi
|
|
10
|
+
.fn()
|
|
11
|
+
.mockImplementation((id, dir, root) => (dir ? `${root}/${dir}` : `${root}/${id}`)),
|
|
12
|
+
|
|
9
13
|
getClawminiDir: vi.fn(),
|
|
10
14
|
}));
|
|
11
15
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { createSessionTimeoutRouter } from './session-timeout.js';
|
|
3
|
+
import type { RouterState } from './types.js';
|
|
4
|
+
|
|
5
|
+
// Mock crypto.randomUUID to return a predictable value
|
|
6
|
+
vi.mock('node:crypto', () => ({
|
|
7
|
+
randomUUID: () => 'mock-uuid',
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
describe('sessionTimeoutRouter', () => {
|
|
11
|
+
it('refreshes the timeout job with default settings', () => {
|
|
12
|
+
const router = createSessionTimeoutRouter();
|
|
13
|
+
const initialState: RouterState = {
|
|
14
|
+
messageId: 'msg-1',
|
|
15
|
+
message: 'Hello!',
|
|
16
|
+
chatId: 'chat-1',
|
|
17
|
+
sessionId: 'session-123',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const nextState = router(initialState);
|
|
21
|
+
|
|
22
|
+
expect(nextState.nextSessionId).toBeUndefined(); // Should not modify current session
|
|
23
|
+
expect(nextState.jobs?.remove).toContain('__session_timeout__session-123');
|
|
24
|
+
expect(nextState.jobs?.add).toEqual(
|
|
25
|
+
expect.arrayContaining([
|
|
26
|
+
expect.objectContaining({
|
|
27
|
+
id: '__session_timeout__session-123',
|
|
28
|
+
schedule: { at: '60m' },
|
|
29
|
+
message:
|
|
30
|
+
'This chat session has ended. Save any important details from it to your memory. When finished, reply with NO_REPLY_NECESSARY.',
|
|
31
|
+
reply: '[@clawmini/session-timeout] Starting a fresh session...',
|
|
32
|
+
nextSessionId: 'mock-uuid',
|
|
33
|
+
session: { type: 'existing', id: 'session-123' },
|
|
34
|
+
jobs: {
|
|
35
|
+
remove: ['__session_timeout__session-123'],
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
])
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('works correctly when sessionId is undefined', () => {
|
|
43
|
+
const router = createSessionTimeoutRouter();
|
|
44
|
+
const initialState: RouterState = {
|
|
45
|
+
messageId: 'msg-1',
|
|
46
|
+
message: 'Hello!',
|
|
47
|
+
chatId: 'chat-1',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const nextState = router(initialState);
|
|
51
|
+
const generatedSessionId = nextState.sessionId;
|
|
52
|
+
|
|
53
|
+
expect(generatedSessionId).toBeDefined();
|
|
54
|
+
expect(nextState.jobs?.remove).toContain(`__session_timeout__${generatedSessionId}`);
|
|
55
|
+
expect(nextState.jobs?.add).toEqual(
|
|
56
|
+
expect.arrayContaining([
|
|
57
|
+
expect.objectContaining({
|
|
58
|
+
id: `__session_timeout__${generatedSessionId}`,
|
|
59
|
+
schedule: { at: '60m' },
|
|
60
|
+
message:
|
|
61
|
+
'This chat session has ended. Save any important details from it to your memory. When finished, reply with NO_REPLY_NECESSARY.',
|
|
62
|
+
reply: '[@clawmini/session-timeout] Starting a fresh session...',
|
|
63
|
+
nextSessionId: expect.any(String),
|
|
64
|
+
session: { type: 'existing', id: generatedSessionId },
|
|
65
|
+
env: { __SESSION_TIMEOUT__: 'true' },
|
|
66
|
+
jobs: {
|
|
67
|
+
remove: [`__session_timeout__${generatedSessionId}`],
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
])
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('respects custom timeout and prompt configuration', () => {
|
|
75
|
+
const router = createSessionTimeoutRouter({
|
|
76
|
+
timeout: '30m',
|
|
77
|
+
prompt: 'Custom prompt',
|
|
78
|
+
});
|
|
79
|
+
const initialState: RouterState = {
|
|
80
|
+
messageId: 'msg-2',
|
|
81
|
+
message: 'Hello again!',
|
|
82
|
+
chatId: 'chat-1',
|
|
83
|
+
sessionId: 'session-abc',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const nextState = router(initialState);
|
|
87
|
+
|
|
88
|
+
expect(nextState.jobs?.remove).toContain('__session_timeout__session-abc');
|
|
89
|
+
expect(nextState.jobs?.add).toEqual(
|
|
90
|
+
expect.arrayContaining([
|
|
91
|
+
expect.objectContaining({
|
|
92
|
+
id: '__session_timeout__session-abc',
|
|
93
|
+
schedule: { at: '30m' },
|
|
94
|
+
message: 'Custom prompt',
|
|
95
|
+
reply: '[@clawmini/session-timeout] Starting a fresh session...',
|
|
96
|
+
nextSessionId: 'mock-uuid',
|
|
97
|
+
session: { type: 'existing', id: 'session-abc' },
|
|
98
|
+
env: { __SESSION_TIMEOUT__: 'true' },
|
|
99
|
+
jobs: {
|
|
100
|
+
remove: ['__session_timeout__session-abc'],
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
])
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('bypasses timeout job creation if currently executing a timeout', () => {
|
|
108
|
+
const router = createSessionTimeoutRouter();
|
|
109
|
+
const initialState: RouterState = {
|
|
110
|
+
messageId: 'msg-3',
|
|
111
|
+
message: 'Timeout prompt',
|
|
112
|
+
chatId: 'chat-1',
|
|
113
|
+
sessionId: 'session-xyz',
|
|
114
|
+
env: { __SESSION_TIMEOUT__: 'true' },
|
|
115
|
+
jobs: { remove: ['__session_timeout__session-xyz'] },
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const nextState = router(initialState);
|
|
119
|
+
|
|
120
|
+
expect(nextState).toBe(initialState); // Returns exactly the same state without modifications
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { RouterState } from './types.js';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
|
|
4
|
+
export interface SessionTimeoutConfig {
|
|
5
|
+
timeout?: string;
|
|
6
|
+
prompt?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Router that automatically starts a new session after a period of inactivity.
|
|
11
|
+
*
|
|
12
|
+
* To register this router, add it to your `~/.gemini/settings.json`:
|
|
13
|
+
* ```json
|
|
14
|
+
* {
|
|
15
|
+
* "routers": [
|
|
16
|
+
* {
|
|
17
|
+
* "use": "session-timeout",
|
|
18
|
+
* "with": {
|
|
19
|
+
* "timeout": "60m",
|
|
20
|
+
* "prompt": "This chat session has ended. Save any important details from it to your memory. When finished, reply with NO_REPLY_NECESSARY."
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ]
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function createSessionTimeoutRouter(config: SessionTimeoutConfig = {}) {
|
|
28
|
+
const timeStr = config.timeout ?? '60m';
|
|
29
|
+
const prompt =
|
|
30
|
+
config.prompt ??
|
|
31
|
+
'This chat session has ended. Save any important details from it to your memory. When finished, reply with NO_REPLY_NECESSARY.';
|
|
32
|
+
|
|
33
|
+
return function (state: RouterState): RouterState {
|
|
34
|
+
if (state.env?.__SESSION_TIMEOUT__ === 'true') {
|
|
35
|
+
return state;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const sessionId = state.sessionId || crypto.randomUUID();
|
|
39
|
+
const jobId = `__session_timeout__${sessionId}`;
|
|
40
|
+
|
|
41
|
+
const jobs = {
|
|
42
|
+
...state.jobs,
|
|
43
|
+
remove: [...(state.jobs?.remove || []), jobId, '__session_timeout__'],
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
...state,
|
|
48
|
+
sessionId,
|
|
49
|
+
jobs: {
|
|
50
|
+
...jobs,
|
|
51
|
+
add: [
|
|
52
|
+
...(jobs.add || []),
|
|
53
|
+
// Add a job after the timeout that will send the prompt, reply to the user,
|
|
54
|
+
// start a fresh session, and delete the job
|
|
55
|
+
{
|
|
56
|
+
id: jobId,
|
|
57
|
+
schedule: { at: timeStr },
|
|
58
|
+
message: prompt,
|
|
59
|
+
reply: '[@clawmini/session-timeout] Starting a fresh session...',
|
|
60
|
+
nextSessionId: randomUUID(),
|
|
61
|
+
session: { type: 'existing', id: sessionId },
|
|
62
|
+
env: { __SESSION_TIMEOUT__: 'true' },
|
|
63
|
+
jobs: {
|
|
64
|
+
remove: [jobId],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -3,10 +3,12 @@ import type { RouterState } from './types.js';
|
|
|
3
3
|
export function slashNew(state: RouterState): RouterState {
|
|
4
4
|
if (/^\/new(\s|$)/.test(state.message)) {
|
|
5
5
|
const newMessage = state.message.replace(/^\/new(\s+|$)/, '').trim();
|
|
6
|
+
const id = crypto.randomUUID();
|
|
6
7
|
return {
|
|
7
8
|
...state,
|
|
8
9
|
message: newMessage,
|
|
9
|
-
sessionId:
|
|
10
|
+
sessionId: id,
|
|
11
|
+
nextSessionId: id,
|
|
10
12
|
reply: '[@clawmini/slash-new] Starting a new session...',
|
|
11
13
|
};
|
|
12
14
|
}
|
|
@@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
|
3
3
|
import { slashPolicies } from './slash-policies.js';
|
|
4
4
|
import { RequestStore } from '../request-store.js';
|
|
5
5
|
import { readPolicies } from '../../shared/workspace.js';
|
|
6
|
-
import {
|
|
6
|
+
import { executeRequest } from '../policy-utils.js';
|
|
7
7
|
import { appendMessage } from '../chats.js';
|
|
8
8
|
import type { PolicyRequest } from '../../shared/policies.js';
|
|
9
9
|
|
|
@@ -40,11 +40,11 @@ describe('slashPolicies', () => {
|
|
|
40
40
|
},
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
|
-
vi.mocked(
|
|
44
|
-
vi.mocked(executeSafe).mockResolvedValue({
|
|
43
|
+
vi.mocked(executeRequest).mockResolvedValue({
|
|
45
44
|
stdout: 'hello world',
|
|
46
45
|
stderr: '',
|
|
47
46
|
exitCode: 0,
|
|
47
|
+
commandStr: 'echo hello world',
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -97,16 +97,19 @@ describe('slashPolicies', () => {
|
|
|
97
97
|
const state = { message: '/approve req-1', messageId: 'mock-msg-id', chatId: 'chat-1' };
|
|
98
98
|
const result = await slashPolicies(state);
|
|
99
99
|
|
|
100
|
-
expect(mockStore.save).toHaveBeenCalledWith({
|
|
101
|
-
|
|
100
|
+
expect(mockStore.save).toHaveBeenCalledWith({
|
|
101
|
+
...pendingReq,
|
|
102
|
+
state: 'Approved',
|
|
103
|
+
executionResult: { stdout: 'hello world', stderr: '', exitCode: 0 },
|
|
104
|
+
});
|
|
105
|
+
expect(executeRequest).toHaveBeenCalledWith(pendingReq, expect.any(Object), undefined);
|
|
102
106
|
expect(appendMessage).toHaveBeenCalledWith(
|
|
103
107
|
'chat-1',
|
|
104
108
|
expect.objectContaining({
|
|
105
|
-
role: '
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
exitCode: 0,
|
|
109
|
+
role: 'system',
|
|
110
|
+
event: 'policy_approved',
|
|
111
|
+
displayRole: 'user',
|
|
112
|
+
content: expect.stringContaining('Request req-1 approved.'),
|
|
110
113
|
})
|
|
111
114
|
);
|
|
112
115
|
expect(result.action).toBeUndefined();
|
|
@@ -139,13 +142,23 @@ describe('slashPolicies', () => {
|
|
|
139
142
|
state: 'Rejected',
|
|
140
143
|
rejectionReason: 'Not allowed',
|
|
141
144
|
});
|
|
145
|
+
expect(appendMessage).toHaveBeenCalledTimes(2);
|
|
146
|
+
expect(appendMessage).toHaveBeenCalledWith(
|
|
147
|
+
'chat-1',
|
|
148
|
+
expect.objectContaining({
|
|
149
|
+
role: 'system',
|
|
150
|
+
event: 'policy_rejected',
|
|
151
|
+
displayRole: 'user',
|
|
152
|
+
content: 'Request req-1 rejected. Reason: Not allowed',
|
|
153
|
+
})
|
|
154
|
+
);
|
|
142
155
|
expect(appendMessage).toHaveBeenCalledWith(
|
|
143
156
|
'chat-1',
|
|
144
157
|
expect.objectContaining({
|
|
145
|
-
role: '
|
|
158
|
+
role: 'system',
|
|
159
|
+
event: 'policy_rejected',
|
|
160
|
+
displayRole: 'agent',
|
|
146
161
|
content: 'Request req-1 rejected. Reason: Not allowed',
|
|
147
|
-
command: 'policy-request-reject req-1',
|
|
148
|
-
exitCode: 1,
|
|
149
162
|
})
|
|
150
163
|
);
|
|
151
164
|
expect(result.action).toBeUndefined();
|
|
@@ -2,9 +2,9 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import type { RouterState } from './types.js';
|
|
3
3
|
import { RequestStore } from '../request-store.js';
|
|
4
4
|
import { readPolicies, getWorkspaceRoot } from '../../shared/workspace.js';
|
|
5
|
-
import {
|
|
5
|
+
import { executeRequest } from '../policy-utils.js';
|
|
6
6
|
import { appendMessage } from '../chats.js';
|
|
7
|
-
import type {
|
|
7
|
+
import type { SystemMessage } from '../../shared/chats.js';
|
|
8
8
|
|
|
9
9
|
async function loadAndValidateRequest(id: string, state: RouterState) {
|
|
10
10
|
const store = new RequestStore(getWorkspaceRoot());
|
|
@@ -54,37 +54,32 @@ export async function slashPolicies(state: RouterState): Promise<RouterState> {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
req.state = 'Approved';
|
|
57
|
-
await store.save(req);
|
|
58
57
|
|
|
59
|
-
const
|
|
60
|
-
const interpolatedArgs = interpolateArgs(fullArgs, req.fileMappings);
|
|
58
|
+
const { stdout, stderr, exitCode } = await executeRequest(req, policy, getWorkspaceRoot());
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
60
|
+
req.executionResult = { stdout, stderr, exitCode };
|
|
61
|
+
await store.save(req);
|
|
65
62
|
|
|
66
|
-
const
|
|
67
|
-
|
|
63
|
+
const agentMessage = `Request ${id} approved.\n\n${wrapInHtml('stdout', stdout)}\n\n${wrapInHtml('stderr', stderr)}\n\nExit Code: ${exitCode}`;
|
|
64
|
+
|
|
65
|
+
const logMsg: SystemMessage = {
|
|
68
66
|
id: randomUUID(),
|
|
69
67
|
messageId: state.messageId,
|
|
70
|
-
role: '
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
stdout,
|
|
68
|
+
role: 'system',
|
|
69
|
+
event: 'policy_approved',
|
|
70
|
+
displayRole: 'user',
|
|
71
|
+
content: agentMessage,
|
|
75
72
|
timestamp: new Date().toISOString(),
|
|
76
|
-
|
|
77
|
-
cwd: getWorkspaceRoot(),
|
|
78
|
-
exitCode,
|
|
73
|
+
...(req.subagentId ? { subagentId: req.subagentId } : {}),
|
|
79
74
|
};
|
|
80
75
|
|
|
81
76
|
await appendMessage(state.chatId, logMsg);
|
|
82
77
|
|
|
83
|
-
const agentMessage = `Request ${id} approved.\n\n${wrapInHtml('stdout', stdout)}\n\n${wrapInHtml('stderr', stderr)}\n\nExit Code: ${exitCode}`;
|
|
84
78
|
return {
|
|
85
79
|
...state,
|
|
86
80
|
message: agentMessage,
|
|
87
81
|
reply: `Approved request, running ${req.commandName}`,
|
|
82
|
+
...(req.subagentId ? { subagentId: req.subagentId } : {}),
|
|
88
83
|
};
|
|
89
84
|
}
|
|
90
85
|
|
|
@@ -101,23 +96,38 @@ export async function slashPolicies(state: RouterState): Promise<RouterState> {
|
|
|
101
96
|
req.rejectionReason = reason;
|
|
102
97
|
await store.save(req);
|
|
103
98
|
|
|
104
|
-
const
|
|
99
|
+
const agentMessage = `Request ${id} rejected. Reason: ${reason}`;
|
|
100
|
+
|
|
101
|
+
const logMsg: SystemMessage = {
|
|
105
102
|
id: randomUUID(),
|
|
106
103
|
messageId: state.messageId,
|
|
107
|
-
role: '
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
role: 'system',
|
|
105
|
+
event: 'policy_rejected',
|
|
106
|
+
displayRole: 'user',
|
|
107
|
+
content: agentMessage,
|
|
111
108
|
timestamp: new Date().toISOString(),
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
...(req.subagentId ? { subagentId: req.subagentId } : {}),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const userNotificationMsg: SystemMessage = {
|
|
113
|
+
id: randomUUID(),
|
|
114
|
+
messageId: state.messageId,
|
|
115
|
+
role: 'system',
|
|
116
|
+
event: 'policy_rejected',
|
|
117
|
+
displayRole: 'agent',
|
|
118
|
+
content: agentMessage,
|
|
119
|
+
timestamp: new Date().toISOString(),
|
|
120
|
+
...(req.subagentId ? { subagentId: req.subagentId } : {}),
|
|
115
121
|
};
|
|
116
122
|
|
|
117
123
|
await appendMessage(state.chatId, logMsg);
|
|
124
|
+
await appendMessage(state.chatId, userNotificationMsg);
|
|
118
125
|
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
return {
|
|
127
|
+
...state,
|
|
128
|
+
message: agentMessage,
|
|
129
|
+
...(req.subagentId ? { subagentId: req.subagentId } : {}),
|
|
130
|
+
};
|
|
121
131
|
}
|
|
122
132
|
|
|
123
133
|
return state;
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import type { CronJob } from '../../shared/config.js';
|
|
2
|
+
|
|
1
3
|
export interface RouterState {
|
|
2
4
|
messageId: string;
|
|
3
5
|
message: string;
|
|
4
6
|
chatId: string;
|
|
5
7
|
agentId?: string;
|
|
8
|
+
subagentId?: string;
|
|
6
9
|
sessionId?: string;
|
|
10
|
+
nextSessionId?: string;
|
|
7
11
|
env?: Record<string, string>;
|
|
8
12
|
reply?: string;
|
|
9
13
|
action?: 'stop' | 'interrupt' | 'continue';
|
|
14
|
+
jobs?: {
|
|
15
|
+
add?: CronJob[];
|
|
16
|
+
remove?: string[];
|
|
17
|
+
};
|
|
10
18
|
}
|
package/src/daemon/routers.ts
CHANGED
|
@@ -5,18 +5,78 @@ import { slashCommand } from './routers/slash-command.js';
|
|
|
5
5
|
import { slashStop } from './routers/slash-stop.js';
|
|
6
6
|
import { slashInterrupt } from './routers/slash-interrupt.js';
|
|
7
7
|
import { slashPolicies } from './routers/slash-policies.js';
|
|
8
|
+
import { createSessionTimeoutRouter } from './routers/session-timeout.js';
|
|
9
|
+
import type { RouterConfig } from '../shared/config.js';
|
|
10
|
+
|
|
11
|
+
export const GLOBAL_ROUTERS: RouterConfig[] = ['@clawmini/session-timeout'];
|
|
12
|
+
|
|
13
|
+
export const USER_ROUTERS: RouterConfig[] = [
|
|
14
|
+
'@clawmini/slash-new',
|
|
15
|
+
'@clawmini/slash-command',
|
|
16
|
+
'@clawmini/slash-stop',
|
|
17
|
+
'@clawmini/slash-interrupt',
|
|
18
|
+
'@clawmini/slash-policies',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export function resolveRouters(
|
|
22
|
+
userRouters: RouterConfig[],
|
|
23
|
+
isUserMessage: boolean
|
|
24
|
+
): RouterConfig[] {
|
|
25
|
+
const resolvedGlobals: RouterConfig[] = [];
|
|
26
|
+
const resolvedUsers: RouterConfig[] = [];
|
|
27
|
+
|
|
28
|
+
const userConfigMap = new Map<string, unknown>();
|
|
29
|
+
for (const r of userRouters) {
|
|
30
|
+
const name = typeof r === 'string' ? r : r.use;
|
|
31
|
+
const config = typeof r === 'string' ? {} : r.with || {};
|
|
32
|
+
|
|
33
|
+
if (name.startsWith('@clawmini/')) {
|
|
34
|
+
userConfigMap.set(name, config);
|
|
35
|
+
} else {
|
|
36
|
+
resolvedUsers.push(r);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (const globalRouter of GLOBAL_ROUTERS) {
|
|
41
|
+
const name = typeof globalRouter === 'string' ? globalRouter : globalRouter.use;
|
|
42
|
+
const baseConfig = typeof globalRouter === 'string' ? {} : globalRouter.with || {};
|
|
43
|
+
const userConfig = userConfigMap.get(name) || {};
|
|
44
|
+
const mergedConfig = { ...baseConfig, ...userConfig };
|
|
45
|
+
|
|
46
|
+
resolvedGlobals.push({ use: name, with: mergedConfig });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const defaultUserRouters: RouterConfig[] = [];
|
|
50
|
+
for (const defaultUserRouter of USER_ROUTERS) {
|
|
51
|
+
const name = typeof defaultUserRouter === 'string' ? defaultUserRouter : defaultUserRouter.use;
|
|
52
|
+
const baseConfig = typeof defaultUserRouter === 'string' ? {} : defaultUserRouter.with || {};
|
|
53
|
+
const userConfig = userConfigMap.get(name) || {};
|
|
54
|
+
const mergedConfig = { ...baseConfig, ...userConfig };
|
|
55
|
+
|
|
56
|
+
defaultUserRouters.push({ use: name, with: mergedConfig });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (isUserMessage) {
|
|
60
|
+
return [...resolvedGlobals, ...defaultUserRouters, ...resolvedUsers];
|
|
61
|
+
} else {
|
|
62
|
+
return resolvedGlobals;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
8
65
|
|
|
9
66
|
export async function executeRouterPipeline(
|
|
10
67
|
initialState: RouterState,
|
|
11
|
-
routers:
|
|
68
|
+
routers: RouterConfig[]
|
|
12
69
|
): Promise<RouterState> {
|
|
13
70
|
let state = { ...initialState };
|
|
14
71
|
|
|
15
|
-
for (const
|
|
72
|
+
for (const routerDef of routers) {
|
|
16
73
|
if (state.action === 'stop') {
|
|
17
74
|
break;
|
|
18
75
|
}
|
|
19
76
|
|
|
77
|
+
const router = typeof routerDef === 'string' ? routerDef : routerDef.use;
|
|
78
|
+
const config = typeof routerDef === 'string' ? {} : routerDef.with || {};
|
|
79
|
+
|
|
20
80
|
if (router === '@clawmini/slash-new') {
|
|
21
81
|
state = slashNew(state);
|
|
22
82
|
} else if (router === '@clawmini/slash-command') {
|
|
@@ -27,6 +87,8 @@ export async function executeRouterPipeline(
|
|
|
27
87
|
state = slashInterrupt(state);
|
|
28
88
|
} else if (router === '@clawmini/slash-policies') {
|
|
29
89
|
state = await slashPolicies(state);
|
|
90
|
+
} else if (router === '@clawmini/session-timeout') {
|
|
91
|
+
state = createSessionTimeoutRouter(config)(state);
|
|
30
92
|
} else {
|
|
31
93
|
// Execute as custom shell command
|
|
32
94
|
try {
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import type { RunCommandFn } from '../
|
|
2
|
+
import type { RunCommandFn } from '../agent/types.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
) => ReturnType<RunCommandFn>) = async ({
|
|
4
|
+
const LOG_TO_TERMINAL = true;
|
|
5
|
+
|
|
6
|
+
export const runCommand: RunCommandFn = async ({
|
|
8
7
|
command,
|
|
9
8
|
cwd,
|
|
10
9
|
env,
|
|
11
10
|
stdin,
|
|
12
11
|
signal,
|
|
13
|
-
logToTerminal,
|
|
14
12
|
}: Parameters<RunCommandFn>[0] & { logToTerminal?: boolean }) => {
|
|
15
13
|
return new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve, reject) => {
|
|
16
14
|
const p = spawn(command, { shell: true, cwd, env, signal });
|
|
@@ -31,7 +29,7 @@ export const runCommand: RunCommandFn &
|
|
|
31
29
|
if (p.stdout) {
|
|
32
30
|
p.stdout.on('data', (data) => {
|
|
33
31
|
stdout += data.toString();
|
|
34
|
-
if (
|
|
32
|
+
if (LOG_TO_TERMINAL && !stdin) {
|
|
35
33
|
process.stdout.write(data);
|
|
36
34
|
}
|
|
37
35
|
});
|
|
@@ -40,7 +38,7 @@ export const runCommand: RunCommandFn &
|
|
|
40
38
|
if (p.stderr) {
|
|
41
39
|
p.stderr.on('data', (data) => {
|
|
42
40
|
stderr += data.toString();
|
|
43
|
-
if (
|
|
41
|
+
if (LOG_TO_TERMINAL && !stdin) {
|
|
44
42
|
process.stderr.write(data);
|
|
45
43
|
}
|
|
46
44
|
});
|