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.
Files changed (333) hide show
  1. package/README.md +19 -0
  2. package/dist/adapter-discord/index.d.mts.map +1 -1
  3. package/dist/adapter-discord/index.mjs +398 -193
  4. package/dist/adapter-discord/index.mjs.map +1 -1
  5. package/dist/adapter-google-chat/index.d.mts +5 -0
  6. package/dist/adapter-google-chat/index.d.mts.map +1 -0
  7. package/dist/adapter-google-chat/index.mjs +1077 -0
  8. package/dist/adapter-google-chat/index.mjs.map +1 -0
  9. package/dist/cli/index.mjs +107 -14
  10. package/dist/cli/index.mjs.map +1 -1
  11. package/dist/cli/lite.mjs +175 -16
  12. package/dist/cli/lite.mjs.map +1 -1
  13. package/dist/cli/propose-policy.d.mts +1 -0
  14. package/dist/cli/propose-policy.mjs +7159 -0
  15. package/dist/cli/propose-policy.mjs.map +1 -0
  16. package/dist/daemon/index.d.mts.map +1 -1
  17. package/dist/daemon/index.mjs +1427 -513
  18. package/dist/daemon/index.mjs.map +1 -1
  19. package/dist/{lite-oSYSvaOr.mjs → lite-CBxOT1y5.mjs} +101 -24
  20. package/dist/lite-CBxOT1y5.mjs.map +1 -0
  21. package/dist/routing-D8rTxtaV.mjs +245 -0
  22. package/dist/routing-D8rTxtaV.mjs.map +1 -0
  23. package/dist/web/_app/immutable/assets/0.C-4eziNy.css +1 -0
  24. package/dist/web/_app/immutable/assets/4.Cc_xwLNl.css +1 -0
  25. package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +1 -0
  26. package/dist/web/_app/immutable/chunks/{Dc-UOHw9.js → BmRlVmv6.js} +1 -1
  27. package/{web/.svelte-kit/output/client/_app/immutable/chunks/8YNcRyEk.js → dist/web/_app/immutable/chunks/C20lZMGz.js} +1 -1
  28. package/dist/web/_app/immutable/chunks/C9lbZ-kT.js +1 -0
  29. package/dist/web/_app/immutable/chunks/CK9JZLaG.js +2 -0
  30. package/dist/web/_app/immutable/chunks/CME08kGM.js +1 -0
  31. package/dist/web/_app/immutable/chunks/{BPy8HLo7.js → Ck-be5J2.js} +1 -1
  32. package/dist/web/_app/immutable/chunks/Ck3rYNON.js +1 -0
  33. package/dist/web/_app/immutable/chunks/DMtIqaiV.js +2 -0
  34. package/dist/web/_app/immutable/chunks/{B8yYFADm.js → DhD271EB.js} +1 -1
  35. package/dist/web/_app/immutable/chunks/{DcrmIfTj.js → DpuLqk8d.js} +1 -1
  36. package/dist/web/_app/immutable/chunks/{ZkLyk0mE.js → Drm9vgeP.js} +1 -1
  37. package/dist/web/_app/immutable/chunks/DsIToJCP.js +1 -0
  38. package/dist/web/_app/immutable/chunks/{CyNaE55B.js → Zeh-C-mx.js} +1 -1
  39. package/{web/.svelte-kit/output/client/_app/immutable/entry/app.DO5eYwVz.js → dist/web/_app/immutable/entry/app.BgB5VkRU.js} +2 -2
  40. package/dist/web/_app/immutable/entry/start.DuxJo6av.js +1 -0
  41. package/dist/web/_app/immutable/nodes/0.C9oFZP9h.js +1 -0
  42. package/dist/web/_app/immutable/nodes/1.BON2Wk6k.js +1 -0
  43. package/dist/web/_app/immutable/nodes/{2.CK3CLC0f.js → 2.BnwnD1Ki.js} +1 -1
  44. package/dist/web/_app/immutable/nodes/{3.ncP0xLO6.js → 3.CIs4tjjw.js} +1 -1
  45. package/dist/web/_app/immutable/nodes/4.DLarELN4.js +60 -0
  46. package/dist/web/_app/immutable/nodes/{5.BpJUN6QH.js → 5.CE_QKy_3.js} +1 -1
  47. package/dist/web/_app/version.json +1 -1
  48. package/dist/web/index.html +12 -12
  49. package/dist/{workspace-DjoNjhW0.mjs → workspace-BJmJBfKi.mjs} +103 -11
  50. package/dist/workspace-BJmJBfKi.mjs.map +1 -0
  51. package/docs/14_google_chat_adapter/development_log.md +40 -0
  52. package/docs/14_google_chat_adapter/notes.md +28 -0
  53. package/docs/14_google_chat_adapter/prd.md +35 -0
  54. package/docs/14_google_chat_adapter/questions.md +9 -0
  55. package/docs/14_google_chat_adapter/tickets.md +117 -0
  56. package/docs/15_sandbox_policies/tickets.md +33 -0
  57. package/docs/16_session_timeout/development_log.md +20 -0
  58. package/docs/16_session_timeout/notes.md +44 -0
  59. package/docs/16_session_timeout/prd.md +106 -0
  60. package/docs/16_session_timeout/questions.md +10 -0
  61. package/docs/16_session_timeout/tickets.md +64 -0
  62. package/docs/17_auto_approve_policy/development_log.md +29 -0
  63. package/docs/17_auto_approve_policy/notes.md +25 -0
  64. package/docs/17_auto_approve_policy/prd.md +34 -0
  65. package/docs/17_auto_approve_policy/questions.md +10 -0
  66. package/docs/17_auto_approve_policy/tickets.md +11 -0
  67. package/docs/18_clawmini_skills/development_log.md +36 -0
  68. package/docs/18_clawmini_skills/notes.md +8 -0
  69. package/docs/18_clawmini_skills/prd.md +45 -0
  70. package/docs/18_clawmini_skills/questions.md +10 -0
  71. package/docs/18_clawmini_skills/tickets.md +55 -0
  72. package/docs/19_subagents/development_log.md +69 -0
  73. package/docs/19_subagents/notes.md +18 -0
  74. package/docs/19_subagents/prd.md +156 -0
  75. package/docs/19_subagents/questions.md +13 -0
  76. package/docs/19_subagents/tickets.md +113 -0
  77. package/docs/20_chat_logs_cleanup/development_log.md +50 -0
  78. package/docs/20_chat_logs_cleanup/notes.md +43 -0
  79. package/docs/20_chat_logs_cleanup/prd.md +232 -0
  80. package/docs/20_chat_logs_cleanup/questions.md +2 -0
  81. package/docs/20_chat_logs_cleanup/tickets.md +98 -0
  82. package/docs/20_webui_markdown/development_log.md +36 -0
  83. package/docs/20_webui_markdown/notes.md +23 -0
  84. package/docs/20_webui_markdown/prd.md +49 -0
  85. package/docs/20_webui_markdown/questions.md +10 -0
  86. package/docs/20_webui_markdown/tickets.md +55 -0
  87. package/docs/21_adapter_filtering/development_log.md +29 -0
  88. package/docs/21_adapter_filtering/notes.md +25 -0
  89. package/docs/21_adapter_filtering/prd.md +44 -0
  90. package/docs/21_adapter_filtering/questions.md +12 -0
  91. package/docs/21_adapter_filtering/tickets.md +38 -0
  92. package/docs/21_built_in_routers/development_log.md +17 -0
  93. package/docs/21_built_in_routers/notes.md +27 -0
  94. package/docs/21_built_in_routers/prd.md +34 -0
  95. package/docs/21_built_in_routers/questions.md +4 -0
  96. package/docs/21_built_in_routers/tickets.md +25 -0
  97. package/docs/21_fancy_policies/development_log.md +38 -0
  98. package/docs/21_fancy_policies/notes.md +27 -0
  99. package/docs/21_fancy_policies/prd.md +58 -0
  100. package/docs/21_fancy_policies/questions.md +6 -0
  101. package/docs/21_fancy_policies/tickets.md +48 -0
  102. package/docs/22_adapter_multi_chat/development_log.md +76 -0
  103. package/docs/22_adapter_multi_chat/notes.md +42 -0
  104. package/docs/22_adapter_multi_chat/prd.md +76 -0
  105. package/docs/22_adapter_multi_chat/questions.md +16 -0
  106. package/docs/22_adapter_multi_chat/tickets.md +164 -0
  107. package/docs/23_custom_token_env/development_log.md +31 -0
  108. package/docs/23_custom_token_env/notes.md +16 -0
  109. package/docs/23_custom_token_env/prd.md +42 -0
  110. package/docs/23_custom_token_env/questions.md +8 -0
  111. package/docs/23_custom_token_env/tickets.md +54 -0
  112. package/docs/guides/discord_adapter_setup.md +15 -2
  113. package/docs/guides/google_chat_adapter_setup.md +145 -0
  114. package/napkin.md +5 -0
  115. package/package.json +7 -2
  116. package/src/adapter-discord/config.test.ts +27 -8
  117. package/src/adapter-discord/config.ts +6 -8
  118. package/src/adapter-discord/forwarder.test.ts +307 -114
  119. package/src/adapter-discord/forwarder.ts +260 -75
  120. package/src/adapter-discord/index.test.ts +278 -0
  121. package/src/adapter-discord/index.ts +160 -30
  122. package/src/adapter-discord/interactions.test.ts +96 -0
  123. package/src/adapter-discord/interactions.ts +156 -0
  124. package/src/adapter-discord/state.test.ts +9 -8
  125. package/src/adapter-discord/state.ts +51 -8
  126. package/src/adapter-google-chat/auth.test.ts +87 -0
  127. package/src/adapter-google-chat/auth.ts +132 -0
  128. package/src/adapter-google-chat/cards.ts +71 -0
  129. package/src/adapter-google-chat/client.test.ts +561 -0
  130. package/src/adapter-google-chat/client.ts +430 -0
  131. package/src/adapter-google-chat/config.test.ts +187 -0
  132. package/src/adapter-google-chat/config.ts +82 -0
  133. package/src/adapter-google-chat/cron.test.ts +143 -0
  134. package/src/adapter-google-chat/cron.ts +81 -0
  135. package/src/adapter-google-chat/forwarder.test.ts +537 -0
  136. package/src/adapter-google-chat/forwarder.ts +349 -0
  137. package/src/adapter-google-chat/index.test.ts +62 -0
  138. package/src/adapter-google-chat/index.ts +61 -0
  139. package/src/adapter-google-chat/state.test.ts +96 -0
  140. package/src/adapter-google-chat/state.ts +85 -0
  141. package/src/adapter-google-chat/subscriptions.ts +124 -0
  142. package/src/adapter-google-chat/upload.ts +88 -0
  143. package/src/adapter-google-chat/utils.test.ts +111 -0
  144. package/src/adapter-google-chat/utils.ts +133 -0
  145. package/src/cli/commands/init.ts +0 -7
  146. package/src/cli/commands/messages.ts +18 -3
  147. package/src/cli/commands/policies.ts +70 -0
  148. package/src/cli/commands/skills.ts +71 -0
  149. package/src/cli/commands/web-api/chats.ts +5 -1
  150. package/src/cli/e2e/basic.test.ts +1 -1
  151. package/src/cli/e2e/cron.test.ts +1 -1
  152. package/src/cli/e2e/daemon.test.ts +132 -4
  153. package/src/cli/e2e/export-lite-func.test.ts +54 -31
  154. package/src/cli/e2e/fallbacks.test.ts +8 -6
  155. package/src/cli/e2e/init.test.ts +7 -0
  156. package/src/cli/e2e/messages.test.ts +90 -55
  157. package/src/cli/e2e/propose-policy.test.ts +203 -0
  158. package/src/cli/e2e/requests.test.ts +15 -0
  159. package/src/cli/e2e/session-timeout.test.ts +192 -0
  160. package/src/cli/e2e/skills.test.ts +55 -0
  161. package/src/cli/e2e/slash-new.test.ts +93 -0
  162. package/src/cli/e2e/subagents.test.ts +106 -0
  163. package/src/cli/index.ts +4 -0
  164. package/src/cli/lite.ts +51 -11
  165. package/src/cli/propose-policy.ts +91 -0
  166. package/src/cli/subagent-commands.ts +215 -0
  167. package/src/daemon/agent/agent-context.ts +89 -0
  168. package/src/daemon/agent/agent-extractors.ts +68 -0
  169. package/src/daemon/agent/agent-runner.ts +153 -0
  170. package/src/daemon/agent/agent-session.ts +261 -0
  171. package/src/daemon/agent/chat-logger.test.ts +158 -0
  172. package/src/daemon/agent/chat-logger.ts +188 -0
  173. package/src/daemon/agent/task-scheduler.test.ts +202 -0
  174. package/src/daemon/agent/task-scheduler.ts +276 -0
  175. package/src/daemon/agent/types.ts +84 -0
  176. package/src/daemon/agent/utils.ts +7 -0
  177. package/src/daemon/api/agent-router.ts +166 -18
  178. package/src/daemon/api/index.test.ts +50 -18
  179. package/src/daemon/api/policy-request.test.ts +39 -2
  180. package/src/daemon/api/subagent-router.test.ts +108 -0
  181. package/src/daemon/api/subagent-router.ts +296 -0
  182. package/src/daemon/api/subagent-utils.test.ts +56 -0
  183. package/src/daemon/api/subagent-utils.ts +130 -0
  184. package/src/daemon/api/user-router.ts +30 -13
  185. package/src/daemon/auth.ts +1 -0
  186. package/src/daemon/chats.ts +6 -0
  187. package/src/daemon/cron.test.ts +66 -1
  188. package/src/daemon/cron.ts +35 -8
  189. package/src/daemon/index.ts +23 -0
  190. package/src/daemon/message-agent.test.ts +11 -25
  191. package/src/daemon/message-extraction.test.ts +10 -27
  192. package/src/daemon/message-fallbacks.test.ts +13 -35
  193. package/src/daemon/message-interruption.test.ts +70 -53
  194. package/src/daemon/message-jobs.test.ts +138 -0
  195. package/src/daemon/message-queue.test.ts +30 -43
  196. package/src/daemon/message-router.test.ts +12 -11
  197. package/src/daemon/message-session.test.ts +41 -28
  198. package/src/daemon/message-typing.test.ts +19 -6
  199. package/src/daemon/message.ts +103 -515
  200. package/src/daemon/policy-request-service.ts +8 -3
  201. package/src/daemon/policy-utils.ts +19 -1
  202. package/src/daemon/queue.ts +16 -0
  203. package/src/daemon/request-store.test.ts +4 -0
  204. package/src/daemon/routers/session-timeout.test.ts +122 -0
  205. package/src/daemon/routers/session-timeout.ts +71 -0
  206. package/src/daemon/routers/slash-new.ts +3 -1
  207. package/src/daemon/routers/slash-policies.test.ts +26 -13
  208. package/src/daemon/routers/slash-policies.ts +39 -29
  209. package/src/daemon/routers/types.ts +8 -0
  210. package/src/daemon/routers.ts +64 -2
  211. package/src/daemon/utils/spawn.ts +6 -8
  212. package/src/shared/adapters/commands.test.ts +155 -0
  213. package/src/shared/adapters/commands.ts +125 -0
  214. package/src/shared/adapters/filtering.test.ts +111 -0
  215. package/src/shared/adapters/filtering.ts +57 -0
  216. package/src/shared/adapters/routing.test.ts +144 -0
  217. package/src/shared/adapters/routing.ts +109 -0
  218. package/src/shared/agent-utils.ts +10 -0
  219. package/src/shared/chats.test.ts +145 -3
  220. package/src/shared/chats.ts +215 -18
  221. package/src/shared/config.ts +67 -15
  222. package/src/shared/lite.ts +22 -18
  223. package/src/shared/policies.ts +7 -0
  224. package/src/shared/workspace.test.ts +45 -1
  225. package/src/shared/workspace.ts +119 -6
  226. package/templates/debug/settings.json +5 -2
  227. package/templates/environments/cladding/env.json +2 -2
  228. package/templates/gemini/.gemini/hooks/check-subagents.mjs +23 -0
  229. package/templates/gemini/.gemini/hooks/clawmini-logging.sh +17 -0
  230. package/templates/gemini/.gemini/hooks/insert-pending.sh +9 -0
  231. package/templates/gemini/.gemini/settings.json +50 -0
  232. package/templates/gemini/settings.json +22 -8
  233. package/templates/gemini-claw/.gemini/base-system.md +100 -0
  234. package/templates/gemini-claw/.gemini/hooks/check-subagents.mjs +23 -0
  235. package/templates/gemini-claw/.gemini/hooks/clawmini-logging.sh +1 -1
  236. package/templates/gemini-claw/.gemini/settings.json +13 -0
  237. package/templates/gemini-claw/.gemini/subagent-system.md +7 -0
  238. package/templates/gemini-claw/.gemini/system.md +3 -99
  239. package/templates/gemini-claw/settings.json +27 -22
  240. package/templates/skills/clawmini-requests/SKILL.md +92 -0
  241. package/templates/skills/clawmini-subagents/SKILL.md +79 -0
  242. package/templates/skills/skill-creator/SKILL.md +60 -0
  243. package/tsdown.config.ts +10 -1
  244. package/web/.svelte-kit/generated/server/internal.js +2 -1
  245. package/web/.svelte-kit/non-ambient.d.ts +2 -0
  246. package/web/.svelte-kit/output/client/.vite/manifest.json +141 -138
  247. package/web/.svelte-kit/output/client/_app/immutable/assets/0.C-4eziNy.css +1 -0
  248. package/web/.svelte-kit/output/client/_app/immutable/assets/4.Cc_xwLNl.css +1 -0
  249. package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +1 -0
  250. package/web/.svelte-kit/output/client/_app/immutable/chunks/{Dc-UOHw9.js → BmRlVmv6.js} +1 -1
  251. package/{dist/web/_app/immutable/chunks/8YNcRyEk.js → web/.svelte-kit/output/client/_app/immutable/chunks/C20lZMGz.js} +1 -1
  252. package/web/.svelte-kit/output/client/_app/immutable/chunks/C9lbZ-kT.js +1 -0
  253. package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +2 -0
  254. package/web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js +1 -0
  255. package/web/.svelte-kit/output/client/_app/immutable/chunks/{BPy8HLo7.js → Ck-be5J2.js} +1 -1
  256. package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +1 -0
  257. package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +2 -0
  258. package/web/.svelte-kit/output/client/_app/immutable/chunks/{B8yYFADm.js → DhD271EB.js} +1 -1
  259. package/web/.svelte-kit/output/client/_app/immutable/chunks/{DcrmIfTj.js → DpuLqk8d.js} +1 -1
  260. package/web/.svelte-kit/output/client/_app/immutable/chunks/{ZkLyk0mE.js → Drm9vgeP.js} +1 -1
  261. package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +1 -0
  262. package/web/.svelte-kit/output/client/_app/immutable/chunks/{CyNaE55B.js → Zeh-C-mx.js} +1 -1
  263. package/{dist/web/_app/immutable/entry/app.DO5eYwVz.js → web/.svelte-kit/output/client/_app/immutable/entry/app.BgB5VkRU.js} +2 -2
  264. package/web/.svelte-kit/output/client/_app/immutable/entry/start.DuxJo6av.js +1 -0
  265. package/web/.svelte-kit/output/client/_app/immutable/nodes/0.C9oFZP9h.js +1 -0
  266. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.BON2Wk6k.js +1 -0
  267. package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.CK3CLC0f.js → 2.BnwnD1Ki.js} +1 -1
  268. package/web/.svelte-kit/output/client/_app/immutable/nodes/{3.ncP0xLO6.js → 3.CIs4tjjw.js} +1 -1
  269. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.DLarELN4.js +60 -0
  270. package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.BpJUN6QH.js → 5.CE_QKy_3.js} +1 -1
  271. package/web/.svelte-kit/output/client/_app/version.json +1 -1
  272. package/web/.svelte-kit/output/server/.vite/manifest.json +12 -3
  273. package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.C-4eziNy.css +1 -0
  274. package/web/.svelte-kit/output/server/_app/immutable/assets/_page.Cc_xwLNl.css +1 -0
  275. package/web/.svelte-kit/output/server/chunks/app-state.svelte.js +5 -0
  276. package/web/.svelte-kit/output/server/chunks/bot.js +4 -4
  277. package/web/.svelte-kit/output/server/chunks/client.js +2 -1
  278. package/web/.svelte-kit/output/server/chunks/exports.js +0 -1
  279. package/web/.svelte-kit/output/server/chunks/internal.js +2 -1
  280. package/web/.svelte-kit/output/server/chunks/root.js +482 -392
  281. package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +57 -7
  282. package/web/.svelte-kit/output/server/entries/pages/chats/_id_/_page.svelte.js +234 -9
  283. package/web/.svelte-kit/output/server/index.js +82 -10
  284. package/web/.svelte-kit/output/server/manifest-full.js +1 -1
  285. package/web/.svelte-kit/output/server/manifest.js +1 -1
  286. package/web/.svelte-kit/output/server/nodes/0.js +2 -2
  287. package/web/.svelte-kit/output/server/nodes/1.js +1 -1
  288. package/web/.svelte-kit/output/server/nodes/2.js +1 -1
  289. package/web/.svelte-kit/output/server/nodes/3.js +1 -1
  290. package/web/.svelte-kit/output/server/nodes/4.js +2 -2
  291. package/web/.svelte-kit/output/server/nodes/5.js +1 -1
  292. package/web/.svelte-kit/types/src/routes/$types.d.ts +1 -2
  293. package/web/.svelte-kit/types/src/routes/agents/$types.d.ts +1 -2
  294. package/web/.svelte-kit/types/src/routes/chats/[id]/$types.d.ts +1 -2
  295. package/web/.svelte-kit/types/src/routes/chats/[id]/settings/$types.d.ts +1 -2
  296. package/web/package.json +8 -0
  297. package/web/src/lib/app-state.svelte.ts +5 -1
  298. package/web/src/lib/components/app/markdown-renderer.svelte +56 -0
  299. package/web/src/lib/components/app/markdown-renderer.svelte.spec.ts +44 -0
  300. package/web/src/lib/components/app/message-content.svelte +16 -0
  301. package/web/src/lib/types.ts +67 -3
  302. package/web/src/routes/+layout.svelte +31 -1
  303. package/web/src/routes/chats/[id]/+page.svelte +167 -18
  304. package/web/src/routes/chats/[id]/page.svelte.spec.ts +58 -7
  305. package/dist/lite-oSYSvaOr.mjs.map +0 -1
  306. package/dist/web/_app/immutable/assets/0.GI4C4dpV.css +0 -1
  307. package/dist/web/_app/immutable/chunks/B5abRDXp.js +0 -1
  308. package/dist/web/_app/immutable/chunks/Bi0jeV7Q.js +0 -1
  309. package/dist/web/_app/immutable/chunks/BmUXQ3wy.js +0 -2
  310. package/dist/web/_app/immutable/chunks/C3k55nDF.js +0 -1
  311. package/dist/web/_app/immutable/chunks/CpaGRn9L.js +0 -1
  312. package/dist/web/_app/immutable/chunks/DG5RZBw-.js +0 -2
  313. package/dist/web/_app/immutable/chunks/DQoygso7.js +0 -1
  314. package/dist/web/_app/immutable/entry/start.D48mVn1m.js +0 -1
  315. package/dist/web/_app/immutable/nodes/0.B-0CcADM.js +0 -1
  316. package/dist/web/_app/immutable/nodes/1.FixKgvRO.js +0 -1
  317. package/dist/web/_app/immutable/nodes/4.CQYJEgv8.js +0 -1
  318. package/dist/workspace-DjoNjhW0.mjs.map +0 -1
  319. package/src/daemon/message-verbosity.test.ts +0 -127
  320. package/web/.svelte-kit/output/client/_app/immutable/assets/0.GI4C4dpV.css +0 -1
  321. package/web/.svelte-kit/output/client/_app/immutable/chunks/B5abRDXp.js +0 -1
  322. package/web/.svelte-kit/output/client/_app/immutable/chunks/Bi0jeV7Q.js +0 -1
  323. package/web/.svelte-kit/output/client/_app/immutable/chunks/BmUXQ3wy.js +0 -2
  324. package/web/.svelte-kit/output/client/_app/immutable/chunks/C3k55nDF.js +0 -1
  325. package/web/.svelte-kit/output/client/_app/immutable/chunks/CpaGRn9L.js +0 -1
  326. package/web/.svelte-kit/output/client/_app/immutable/chunks/DG5RZBw-.js +0 -2
  327. package/web/.svelte-kit/output/client/_app/immutable/chunks/DQoygso7.js +0 -1
  328. package/web/.svelte-kit/output/client/_app/immutable/entry/start.D48mVn1m.js +0 -1
  329. package/web/.svelte-kit/output/client/_app/immutable/nodes/0.B-0CcADM.js +0 -1
  330. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.FixKgvRO.js +0 -1
  331. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CQYJEgv8.js +0 -1
  332. package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.GI4C4dpV.css +0 -1
  333. /package/templates/{gemini-claw/.gemini/skills → skills}/clawmini-jobs/SKILL.md +0 -0
@@ -0,0 +1,296 @@
1
+ import { z } from 'zod';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { TRPCError } from '@trpc/server';
4
+ import { getWorkspaceRoot, readChatSettings, updateChatSettings } from '../../shared/workspace.js';
5
+ import { apiProcedure } from './trpc.js';
6
+ import { createChatLogger } from '../agent/chat-logger.js';
7
+ import { on } from 'node:events';
8
+ import { daemonEvents, DAEMON_EVENT_MESSAGE_APPENDED } from '../events.js';
9
+ import { createAgentSession } from '../agent/agent-session.js';
10
+ import { executeSubagent, getSubagentDepth } from './subagent-utils.js';
11
+ import type { SubagentTracker } from '../../shared/config.js';
12
+
13
+ const MAX_SUBAGENT_DEPTH = 2;
14
+
15
+ export const subagentSpawn = apiProcedure
16
+ .input(
17
+ z.object({
18
+ subagentId: z.string().optional(),
19
+ targetAgentId: z.string().optional(),
20
+ prompt: z.string(),
21
+ async: z.boolean().optional(),
22
+ })
23
+ )
24
+ .mutation(async ({ input, ctx }) => {
25
+ if (!ctx.tokenPayload) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Missing token' });
26
+ const chatId = ctx.tokenPayload.chatId;
27
+ const parentAgentId = ctx.tokenPayload.agentId;
28
+ const parentId = ctx.tokenPayload.subagentId;
29
+
30
+ const id = input.subagentId || randomUUID();
31
+ const sessionId = randomUUID();
32
+ const agentId = input.targetAgentId || parentAgentId;
33
+ let depth = 0;
34
+
35
+ await updateChatSettings(chatId, (settings) => {
36
+ settings.subagents = settings.subagents || {};
37
+
38
+ depth = getSubagentDepth(settings, parentId);
39
+ if (depth >= MAX_SUBAGENT_DEPTH) {
40
+ throw new TRPCError({ code: 'BAD_REQUEST', message: 'Max subagent depth reached' });
41
+ }
42
+
43
+ // Make sure the id does not already exist
44
+ if (settings.subagents[id]) {
45
+ throw new TRPCError({ code: 'BAD_REQUEST', message: 'Subagent ID already exists' });
46
+ }
47
+
48
+ settings.subagents[id] = {
49
+ id,
50
+ agentId,
51
+ sessionId,
52
+ createdAt: new Date().toISOString(),
53
+ status: 'active',
54
+ parentId,
55
+ };
56
+
57
+ return settings;
58
+ });
59
+
60
+ const workspaceRoot = getWorkspaceRoot(process.cwd());
61
+
62
+ const isAsync = input.async ?? depth === 0;
63
+
64
+ // Execute asynchronously
65
+ executeSubagent(
66
+ chatId,
67
+ id,
68
+ agentId,
69
+ sessionId,
70
+ input.prompt,
71
+ isAsync,
72
+ ctx.tokenPayload,
73
+ workspaceRoot
74
+ );
75
+
76
+ return { id, depth, isAsync };
77
+ });
78
+
79
+ export const subagentSend = apiProcedure
80
+ .input(
81
+ z.object({
82
+ subagentId: z.string(),
83
+ prompt: z.string(),
84
+ async: z.boolean().optional(),
85
+ })
86
+ )
87
+ .mutation(async ({ input, ctx }) => {
88
+ if (!ctx.tokenPayload) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Missing token' });
89
+ const chatId = ctx.tokenPayload.chatId;
90
+
91
+ let sub: SubagentTracker | undefined;
92
+
93
+ await updateChatSettings(chatId, (settings) => {
94
+ if (!settings.subagents?.[input.subagentId]) {
95
+ throw new TRPCError({ code: 'NOT_FOUND', message: 'Subagent not found' });
96
+ }
97
+
98
+ sub = settings.subagents[input.subagentId];
99
+ sub!.status = 'active';
100
+ return settings;
101
+ });
102
+
103
+ const workspaceRoot = getWorkspaceRoot(process.cwd());
104
+
105
+ // Execute asynchronously
106
+ executeSubagent(
107
+ chatId,
108
+ sub!.id,
109
+ sub!.agentId || 'default',
110
+ sub!.sessionId || 'default',
111
+ input.prompt,
112
+ input.async,
113
+ ctx.tokenPayload,
114
+ workspaceRoot
115
+ );
116
+
117
+ return { success: true };
118
+ });
119
+
120
+ async function checkSubagentStatus(chatId: string, subagentId: string) {
121
+ const settings = await readChatSettings(chatId);
122
+ const sub = settings?.subagents?.[subagentId];
123
+ if (!sub) throw new TRPCError({ code: 'NOT_FOUND', message: 'Subagent not found' });
124
+
125
+ if (sub.status === 'completed' || sub.status === 'failed') {
126
+ let outputContent: string | undefined;
127
+ if (sub.status === 'completed') {
128
+ const logger = createChatLogger(chatId, subagentId);
129
+ const lastLogMessage = await logger.findLastMessage((m) => m.role === 'agent');
130
+ if (lastLogMessage && 'content' in lastLogMessage) {
131
+ outputContent = lastLogMessage.content;
132
+ }
133
+ }
134
+ return { status: sub.status, output: outputContent };
135
+ }
136
+ return null;
137
+ }
138
+
139
+ export const subagentWait = apiProcedure
140
+ .input(z.object({ subagentId: z.string() }))
141
+ .mutation(async ({ input, ctx, signal }) => {
142
+ if (!ctx.tokenPayload) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Missing token' });
143
+ const chatId = ctx.tokenPayload.chatId;
144
+
145
+ const ac = new AbortController();
146
+ const timeout = setTimeout(() => ac.abort(), 60000);
147
+
148
+ // Bind to the TRPC request abort signal to clean up listeners if client disconnects
149
+ const onAbort = () => {
150
+ clearTimeout(timeout);
151
+ ac.abort();
152
+ };
153
+ if (signal) {
154
+ signal.addEventListener('abort', onAbort);
155
+ }
156
+
157
+ const eventIterator = on(daemonEvents, DAEMON_EVENT_MESSAGE_APPENDED, {
158
+ signal: ac.signal,
159
+ });
160
+
161
+ try {
162
+ // Check status immediately before listening, but after event iterator is buffering
163
+ const initialStatus = await checkSubagentStatus(chatId, input.subagentId);
164
+ if (initialStatus) {
165
+ clearTimeout(timeout);
166
+ if (signal) signal.removeEventListener('abort', onAbort);
167
+ return initialStatus;
168
+ }
169
+
170
+ for await (const [event] of eventIterator) {
171
+ if (event.chatId === chatId && event.message?.subagentId === input.subagentId) {
172
+ const msg = event.message;
173
+ if (msg.role === 'subagent_status') {
174
+ const status = await checkSubagentStatus(chatId, input.subagentId);
175
+ if (status) {
176
+ clearTimeout(timeout);
177
+ if (signal) signal.removeEventListener('abort', onAbort);
178
+ return status;
179
+ }
180
+ }
181
+ }
182
+ }
183
+ } catch (err: unknown) {
184
+ if (err && typeof err === 'object' && 'name' in err && err.name === 'AbortError') {
185
+ return { status: 'active' as const, output: undefined };
186
+ }
187
+ throw err;
188
+ } finally {
189
+ clearTimeout(timeout);
190
+ if (signal) signal.removeEventListener('abort', onAbort);
191
+ ac.abort();
192
+ }
193
+
194
+ return { status: 'active' as const, output: undefined };
195
+ });
196
+
197
+ export const subagentStop = apiProcedure
198
+ .input(z.object({ subagentId: z.string() }))
199
+ .mutation(async ({ input, ctx }) => {
200
+ if (!ctx.tokenPayload) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Missing token' });
201
+ const chatId = ctx.tokenPayload.chatId;
202
+
203
+ let subToStop: SubagentTracker | undefined;
204
+
205
+ await updateChatSettings(chatId, (settings) => {
206
+ if (settings.subagents) {
207
+ const sub = settings.subagents[input.subagentId];
208
+ if (sub) {
209
+ sub.status = 'failed';
210
+ subToStop = sub;
211
+ }
212
+ }
213
+ return settings;
214
+ });
215
+
216
+ if (subToStop) {
217
+ const session = await createAgentSession({
218
+ chatId,
219
+ agentId: subToStop.agentId || 'default',
220
+ sessionId: subToStop.sessionId || 'default',
221
+ subagentId: input.subagentId,
222
+ cwd: process.cwd(),
223
+ });
224
+ session.stop();
225
+ }
226
+
227
+ return { success: true };
228
+ });
229
+
230
+ export const subagentDelete = apiProcedure
231
+ .input(z.object({ subagentId: z.string() }))
232
+ .mutation(async ({ input, ctx }) => {
233
+ if (!ctx.tokenPayload) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Missing token' });
234
+ const chatId = ctx.tokenPayload.chatId;
235
+
236
+ let subToDelete: SubagentTracker | undefined;
237
+
238
+ await updateChatSettings(chatId, (settings) => {
239
+ if (settings.subagents && settings.subagents[input.subagentId]) {
240
+ subToDelete = settings.subagents[input.subagentId]!;
241
+ delete settings.subagents[input.subagentId];
242
+ }
243
+ return settings;
244
+ });
245
+
246
+ if (subToDelete) {
247
+ const session = await createAgentSession({
248
+ chatId,
249
+ agentId: subToDelete.agentId || 'default',
250
+ sessionId: subToDelete.sessionId || 'default',
251
+ subagentId: input.subagentId,
252
+ cwd: process.cwd(),
253
+ });
254
+ session.stop();
255
+
256
+ return { success: true, deleted: true };
257
+ }
258
+
259
+ return { success: true, deleted: false };
260
+ });
261
+
262
+ export const subagentList = apiProcedure
263
+ .input(z.object({ blocking: z.boolean().optional() }).optional())
264
+ .query(async ({ input, ctx }) => {
265
+ if (!ctx.tokenPayload) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Missing token' });
266
+ const chatId = ctx.tokenPayload.chatId;
267
+ const settings = await readChatSettings(chatId);
268
+
269
+ let subagents = Object.values(settings?.subagents || {});
270
+
271
+ const isSubagent = !!ctx.tokenPayload.subagentId;
272
+ const myId = ctx.tokenPayload.subagentId;
273
+
274
+ subagents = subagents.filter((s) => s.parentId === myId);
275
+
276
+ if (input?.blocking) {
277
+ if (!isSubagent) {
278
+ subagents = [];
279
+ } else {
280
+ subagents = subagents.filter((s) => s.status === 'active');
281
+ }
282
+ }
283
+ return { subagents };
284
+ });
285
+
286
+ export const subagentTail = apiProcedure
287
+ .input(z.object({ subagentId: z.string(), limit: z.number().optional() }))
288
+ .query(async ({ input, ctx }) => {
289
+ if (!ctx.tokenPayload) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Missing token' });
290
+ const chatId = ctx.tokenPayload.chatId;
291
+
292
+ const logger = createChatLogger(chatId, input.subagentId);
293
+ const messages = await logger.getMessages(input.limit);
294
+
295
+ return { messages };
296
+ });
@@ -0,0 +1,56 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { executeSubagent } from './subagent-utils.js';
3
+ import * as workspace from '../../shared/workspace.js';
4
+ import { taskScheduler } from '../agent/task-scheduler.js';
5
+
6
+ vi.mock('../../shared/workspace.js', () => ({
7
+ updateChatSettings: vi.fn(),
8
+ readChatSettings: vi.fn().mockResolvedValue({}),
9
+ }));
10
+
11
+ vi.mock('../routers.js', () => ({
12
+ executeRouterPipeline: vi.fn().mockImplementation((state) => Promise.resolve(state)),
13
+ resolveRouters: vi.fn((routers) => routers),
14
+ }));
15
+
16
+ vi.mock('../message.js', () => ({
17
+ executeDirectMessage: vi.fn(),
18
+ applyRouterStateUpdates: vi.fn(),
19
+ }));
20
+
21
+ vi.mock('../agent/chat-logger.js', () => ({
22
+ createChatLogger: vi.fn(() => ({
23
+ findLastMessage: vi.fn().mockResolvedValue(null),
24
+ logSystemEvent: vi.fn(),
25
+ })),
26
+ }));
27
+
28
+ vi.mock('../agent/task-scheduler.js', () => ({
29
+ taskScheduler: {
30
+ hasTasks: vi.fn(),
31
+ },
32
+ }));
33
+
34
+ describe('executeSubagent', () => {
35
+ beforeEach(() => {
36
+ vi.clearAllMocks();
37
+ });
38
+
39
+ it('should not mark subagent as completed if there are still pending tasks in the queue', async () => {
40
+ vi.mocked(taskScheduler.hasTasks).mockReturnValue(true);
41
+
42
+ await executeSubagent(
43
+ 'chat-1',
44
+ 'sub-1',
45
+ 'agent-1',
46
+ 'session-1',
47
+ 'hello',
48
+ false,
49
+ { agentId: 'parent-agent' },
50
+ '/workspace'
51
+ );
52
+
53
+ // Should NOT call updateChatSettings to set status to completed
54
+ expect(workspace.updateChatSettings).not.toHaveBeenCalled();
55
+ });
56
+ });
@@ -0,0 +1,130 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { updateChatSettings, readChatSettings } from '../../shared/workspace.js';
3
+ import { executeDirectMessage, applyRouterStateUpdates } from '../message.js';
4
+ import { executeRouterPipeline, resolveRouters } from '../routers.js';
5
+ import type { RouterState } from '../routers/types.js';
6
+ import { createChatLogger } from '../agent/chat-logger.js';
7
+ import type { ChatSettings } from '../../shared/config.js';
8
+ import { taskScheduler } from '../agent/task-scheduler.js';
9
+
10
+ export function getSubagentDepth(settings: ChatSettings, parentId: string | undefined): number {
11
+ let depth = 0;
12
+ let currentParentId = parentId;
13
+ while (currentParentId && settings.subagents?.[currentParentId]) {
14
+ depth++;
15
+ currentParentId = settings.subagents[currentParentId]?.parentId;
16
+ }
17
+ return depth;
18
+ }
19
+
20
+ export async function executeSubagent(
21
+ chatId: string,
22
+ subagentId: string,
23
+ agentId: string,
24
+ sessionId: string,
25
+ prompt: string,
26
+ isAsync: boolean | undefined,
27
+ parentTokenPayload: { agentId?: string; subagentId?: string; sessionId?: string },
28
+ workspaceRoot: string
29
+ ) {
30
+ try {
31
+ const settings = (await readChatSettings(chatId)) || {};
32
+ const routers = settings.routers ?? [];
33
+ const resolvedRouters = resolveRouters(routers, false);
34
+
35
+ let routerState: RouterState = {
36
+ messageId: randomUUID(),
37
+ message: prompt,
38
+ chatId,
39
+ agentId,
40
+ sessionId,
41
+ env: {},
42
+ };
43
+
44
+ const initialState = { ...routerState };
45
+ routerState = await executeRouterPipeline(routerState, resolvedRouters);
46
+
47
+ await applyRouterStateUpdates(
48
+ chatId,
49
+ workspaceRoot,
50
+ routerState,
51
+ settings,
52
+ initialState.agentId
53
+ );
54
+
55
+ await executeDirectMessage(
56
+ chatId,
57
+ routerState,
58
+ undefined, // settings
59
+ workspaceRoot,
60
+ false, // noWait
61
+ undefined, // userMessageContent
62
+ subagentId // subagentId
63
+ );
64
+
65
+ if (taskScheduler.hasTasks(sessionId)) {
66
+ return;
67
+ }
68
+
69
+ // Update status
70
+ await updateChatSettings(chatId, (finalSettings) => {
71
+ if (finalSettings.subagents?.[subagentId]) {
72
+ finalSettings.subagents[subagentId]!.status = 'completed';
73
+ }
74
+ return finalSettings;
75
+ });
76
+
77
+ const logger = createChatLogger(chatId, subagentId);
78
+
79
+ // Emit debug message to wake up waiters
80
+ await logger.logSubagentStatus({ subagentId, status: 'completed' });
81
+
82
+ if (isAsync) {
83
+ const lastLogMessage = await logger.findLastMessage(
84
+ (m) => m.role === 'agent' || m.displayRole === 'agent'
85
+ );
86
+ let outputContent = '';
87
+ if (lastLogMessage && 'content' in lastLogMessage) {
88
+ outputContent = `\n\n<subagent_output>\n${lastLogMessage.content}\n</subagent_output>`;
89
+ }
90
+
91
+ console.log(
92
+ 'Notifying parent',
93
+ chatId,
94
+ parentTokenPayload?.agentId,
95
+ parentTokenPayload?.subagentId
96
+ );
97
+ // TODO: We need to overhaul the log system in general, and should not try to do it in this PR.
98
+ // Currently, if the parent is the root agent, this notification is logged as a normal user message
99
+ // and appears in the chat UI, violating the PRD requirement to hide orchestration.
100
+ await executeDirectMessage(
101
+ chatId,
102
+ {
103
+ messageId: randomUUID(),
104
+ message: `<notification>Subagent ${subagentId} completed.</notification>${outputContent}`,
105
+ chatId,
106
+ agentId: parentTokenPayload?.agentId || 'default',
107
+ ...(parentTokenPayload?.subagentId ? { subagentId: parentTokenPayload.subagentId } : {}),
108
+ sessionId: parentTokenPayload?.sessionId || 'default',
109
+ env: {},
110
+ },
111
+ undefined,
112
+ workspaceRoot,
113
+ true,
114
+ undefined,
115
+ parentTokenPayload?.subagentId,
116
+ 'subagent_update'
117
+ );
118
+ }
119
+ } catch {
120
+ // TODO: Wrap this in a safe try-catch to prevent unhandled promise rejections crashing the daemon if disk errors occur
121
+ await updateChatSettings(chatId, (errSettings) => {
122
+ if (errSettings.subagents?.[subagentId]) {
123
+ errSettings.subagents[subagentId]!.status = 'failed';
124
+ }
125
+ return errSettings;
126
+ });
127
+ const logger = createChatLogger(chatId, subagentId);
128
+ await logger.logSubagentStatus({ subagentId, status: 'failed' });
129
+ }
130
+ }
@@ -5,11 +5,16 @@ import { TRPCError } from '@trpc/server';
5
5
  import { pathIsInsideDir } from '../../shared/utils/fs.js';
6
6
  import { on } from 'node:events';
7
7
  import { daemonEvents, DAEMON_EVENT_MESSAGE_APPENDED, DAEMON_EVENT_TYPING } from '../events.js';
8
- import { getSettingsPath, readChatSettings, getWorkspaceRoot } from '../../shared/workspace.js';
8
+ import {
9
+ getSettingsPath,
10
+ readChatSettings,
11
+ writeChatSettings,
12
+ getWorkspaceRoot,
13
+ listAgents,
14
+ } from '../../shared/workspace.js';
9
15
  import { CronJobSchema } from '../../shared/config.js';
10
16
  import { handleUserMessage } from '../message.js';
11
- import { getDefaultChatId, getMessages as fetchMessages } from '../chats.js';
12
- import { runCommand } from '../utils/spawn.js';
17
+ import { getDefaultChatId, getMessages as fetchMessages, listChats, createChat } from '../chats.js';
13
18
  import { apiProcedure, publicProcedure, router } from './trpc.js';
14
19
  import {
15
20
  getUniquePath,
@@ -94,16 +99,7 @@ export const sendMessage = apiProcedure
94
99
  message = message ? `${message}\n\n${fileList}` : fileList;
95
100
  }
96
101
 
97
- await handleUserMessage(
98
- chatId,
99
- message,
100
- settings,
101
- undefined,
102
- noWait,
103
- (args) => runCommand({ ...args, logToTerminal: true }),
104
- sessionId,
105
- agentId
106
- );
102
+ await handleUserMessage(chatId, message, settings, undefined, noWait, sessionId, agentId);
107
103
 
108
104
  return { success: true };
109
105
  });
@@ -192,6 +188,24 @@ export const userListCronJobs = apiProcedure
192
188
  return listCronJobsShared(chatId);
193
189
  });
194
190
 
191
+ export const getChats = apiProcedure.query(async () => {
192
+ return listChats();
193
+ });
194
+
195
+ export const getAgents = apiProcedure.query(async () => {
196
+ return listAgents();
197
+ });
198
+
199
+ export const userCreateChat = apiProcedure
200
+ .input(z.object({ chatId: z.string(), agent: z.string().optional() }))
201
+ .mutation(async ({ input }) => {
202
+ await createChat(input.chatId);
203
+ if (input.agent) {
204
+ await writeChatSettings(input.chatId, { defaultAgent: input.agent });
205
+ }
206
+ return { success: true, chatId: input.chatId };
207
+ });
208
+
195
209
  export const userAddCronJob = apiProcedure
196
210
  .input(z.object({ chatId: z.string().optional(), job: CronJobSchema }))
197
211
  .mutation(async ({ input }) => {
@@ -216,6 +230,9 @@ export const userRouter = router({
216
230
  listCronJobs: userListCronJobs,
217
231
  addCronJob: userAddCronJob,
218
232
  deleteCronJob: userDeleteCronJob,
233
+ getChats,
234
+ getAgents,
235
+ createChat: userCreateChat,
219
236
  });
220
237
 
221
238
  export type UserRouter = typeof userRouter;
@@ -9,6 +9,7 @@ export interface TokenPayload {
9
9
  chatId: string;
10
10
  agentId: string;
11
11
  sessionId: string;
12
+ subagentId?: string;
12
13
  timestamp: number;
13
14
  }
14
15
 
@@ -14,12 +14,18 @@ export {
14
14
  type ChatMessage,
15
15
  type UserMessage,
16
16
  type CommandLogMessage,
17
+ type SystemMessage,
18
+ type AgentReplyMessage,
19
+ type ToolMessage,
20
+ type PolicyRequestMessage,
21
+ type SubagentStatusMessage,
17
22
  getChatsDir,
18
23
  isValidChatId,
19
24
  createChat,
20
25
  listChats,
21
26
  deleteChat,
22
27
  getMessages,
28
+ findLastMessage,
23
29
  getDefaultChatId,
24
30
  setDefaultChatId,
25
31
  DEFAULT_CHAT_ID,
@@ -1,7 +1,42 @@
1
- import { describe, it, expect } from 'vitest';
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
3
  import { CronManager } from './cron.js';
4
+ // @ts-expect-error - node-schedule types are missing
5
+ import schedule from 'node-schedule';
6
+ import { getInitialRouterState } from './message.js';
7
+
8
+ vi.mock('node-schedule', () => ({
9
+ default: {
10
+ scheduleJob: vi.fn(),
11
+ },
12
+ }));
13
+
14
+ vi.mock('./message.js', () => ({
15
+ getInitialRouterState: vi.fn().mockResolvedValue({}),
16
+ applyRouterStateUpdates: vi.fn(),
17
+ executeDirectMessage: vi.fn(),
18
+ }));
19
+
20
+ vi.mock('../shared/workspace.js', () => ({
21
+ readChatSettings: vi.fn().mockResolvedValue({}),
22
+ getSettingsPath: vi.fn().mockReturnValue('/mock/settings.json'),
23
+ }));
24
+
25
+ vi.mock('../shared/chats.js', () => ({
26
+ listChats: vi.fn().mockResolvedValue([]),
27
+ }));
28
+
29
+ vi.mock('node:fs/promises', () => ({
30
+ default: {
31
+ readFile: vi.fn().mockResolvedValue('{}'),
32
+ },
33
+ }));
3
34
 
4
35
  describe('CronManager', () => {
36
+ beforeEach(() => {
37
+ vi.clearAllMocks();
38
+ });
39
+
5
40
  it('throws on invalid date in "at" schedule', () => {
6
41
  const cronManager = new CronManager();
7
42
  expect(() => {
@@ -25,4 +60,34 @@ describe('CronManager', () => {
25
60
  });
26
61
  }).not.toThrow();
27
62
  });
63
+
64
+ it('passes job.session.id to getInitialRouterState when session type is existing', async () => {
65
+ const cronManager = new CronManager();
66
+ let scheduledCallback: any = null;
67
+ vi.mocked(schedule.scheduleJob as any).mockImplementation((rule: any, cb: any) => {
68
+ scheduledCallback = cb;
69
+ return { cancel: vi.fn() } as any;
70
+ });
71
+
72
+ cronManager.scheduleJob('chat3', {
73
+ id: 'job3',
74
+ createdAt: new Date().toISOString(),
75
+ message: 'test existing session',
76
+ schedule: { at: '1m' },
77
+ session: { type: 'existing', id: 'my-old-session-id' },
78
+ });
79
+
80
+ expect(scheduledCallback).toBeTruthy();
81
+
82
+ // Execute the cron job callback
83
+ await scheduledCallback();
84
+
85
+ expect(getInitialRouterState).toHaveBeenCalledWith(
86
+ 'chat3',
87
+ 'test existing session',
88
+ expect.any(Object),
89
+ undefined,
90
+ 'my-old-session-id'
91
+ );
92
+ });
28
93
  });