@swarmclawai/swarmclaw 0.8.4 → 0.8.7

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 (394) hide show
  1. package/README.md +9 -9
  2. package/bin/swarmclaw.js +5 -1
  3. package/bin/worker-cmd.js +73 -0
  4. package/package.json +2 -1
  5. package/src/app/api/agents/[id]/route.ts +17 -7
  6. package/src/app/api/agents/route.ts +21 -8
  7. package/src/app/api/approvals/route.test.ts +6 -6
  8. package/src/app/api/approvals/route.ts +2 -1
  9. package/src/app/api/auth/route.ts +2 -3
  10. package/src/app/api/chatrooms/[id]/chat/route.test.ts +299 -0
  11. package/src/app/api/chatrooms/[id]/chat/route.ts +3 -2
  12. package/src/app/api/chatrooms/[id]/route.ts +7 -6
  13. package/src/app/api/chats/[id]/chat/route.test.ts +496 -0
  14. package/src/app/api/chats/[id]/chat/route.ts +7 -3
  15. package/src/app/api/chats/[id]/clear/route.ts +9 -9
  16. package/src/app/api/chats/[id]/devserver/route.ts +2 -1
  17. package/src/app/api/chats/[id]/edit-resend/route.ts +3 -4
  18. package/src/app/api/chats/[id]/fork/route.ts +3 -5
  19. package/src/app/api/chats/[id]/restore/route.ts +6 -7
  20. package/src/app/api/chats/[id]/retry/route.ts +3 -4
  21. package/src/app/api/chats/[id]/route.ts +61 -62
  22. package/src/app/api/chats/route.ts +7 -1
  23. package/src/app/api/connectors/[id]/route.ts +7 -8
  24. package/src/app/api/connectors/route.ts +5 -4
  25. package/src/app/api/eval/run/route.ts +2 -1
  26. package/src/app/api/eval/suite/route.ts +2 -1
  27. package/src/app/api/external-agents/route.test.ts +1 -1
  28. package/src/app/api/external-agents/route.ts +2 -2
  29. package/src/app/api/files/serve/route.ts +1 -1
  30. package/src/app/api/gateways/[id]/route.ts +7 -5
  31. package/src/app/api/gateways/route.ts +1 -1
  32. package/src/app/api/knowledge/upload/route.ts +1 -1
  33. package/src/app/api/logs/route.ts +5 -7
  34. package/src/app/api/memory-images/[filename]/route.ts +2 -3
  35. package/src/app/api/openclaw/agent-files/route.ts +4 -3
  36. package/src/app/api/openclaw/approvals/route.ts +3 -4
  37. package/src/app/api/openclaw/config-sync/route.ts +3 -2
  38. package/src/app/api/openclaw/cron/route.ts +3 -2
  39. package/src/app/api/openclaw/dotenv-keys/route.ts +2 -1
  40. package/src/app/api/openclaw/exec-config/route.ts +3 -2
  41. package/src/app/api/openclaw/gateway/route.ts +5 -4
  42. package/src/app/api/openclaw/history/route.ts +3 -2
  43. package/src/app/api/openclaw/media/route.ts +2 -1
  44. package/src/app/api/openclaw/permissions/route.ts +3 -2
  45. package/src/app/api/openclaw/sandbox-env/route.ts +3 -2
  46. package/src/app/api/openclaw/skills/install/route.ts +2 -1
  47. package/src/app/api/openclaw/skills/remove/route.ts +2 -1
  48. package/src/app/api/openclaw/skills/route.ts +3 -2
  49. package/src/app/api/orchestrator/run/route.ts +5 -14
  50. package/src/app/api/perf/route.ts +43 -0
  51. package/src/app/api/plugins/dependencies/route.ts +2 -1
  52. package/src/app/api/plugins/install/route.ts +2 -1
  53. package/src/app/api/plugins/marketplace/route.ts +3 -2
  54. package/src/app/api/plugins/settings/route.ts +2 -1
  55. package/src/app/api/preview-server/route.ts +11 -10
  56. package/src/app/api/projects/[id]/route.ts +1 -1
  57. package/src/app/api/schedules/[id]/route.test.ts +128 -0
  58. package/src/app/api/schedules/[id]/route.ts +43 -43
  59. package/src/app/api/schedules/[id]/run/route.ts +11 -62
  60. package/src/app/api/schedules/route.ts +21 -87
  61. package/src/app/api/settings/route.ts +2 -0
  62. package/src/app/api/setup/doctor/route.ts +9 -8
  63. package/src/app/api/tasks/[id]/approve/route.ts +33 -30
  64. package/src/app/api/tasks/[id]/route.ts +12 -35
  65. package/src/app/api/tasks/import/github/route.ts +2 -1
  66. package/src/app/api/tasks/route.ts +79 -91
  67. package/src/app/api/wallets/[id]/approve/route.ts +2 -1
  68. package/src/app/api/wallets/[id]/route.ts +13 -19
  69. package/src/app/api/wallets/[id]/send/route.ts +2 -1
  70. package/src/app/api/wallets/route.ts +2 -1
  71. package/src/app/api/webhooks/[id]/route.ts +2 -1
  72. package/src/app/api/webhooks/route.test.ts +3 -1
  73. package/src/app/page.tsx +23 -331
  74. package/src/cli/index.js +19 -0
  75. package/src/cli/index.ts +38 -7
  76. package/src/cli/spec.js +9 -0
  77. package/src/components/activity/activity-feed.tsx +7 -4
  78. package/src/components/agents/agent-card.tsx +32 -6
  79. package/src/components/agents/agent-chat-list.tsx +55 -22
  80. package/src/components/agents/agent-files-editor.tsx +3 -2
  81. package/src/components/agents/agent-sheet.tsx +123 -22
  82. package/src/components/agents/inspector-panel.tsx +1 -1
  83. package/src/components/agents/openclaw-skills-panel.tsx +2 -1
  84. package/src/components/agents/trash-list.tsx +1 -1
  85. package/src/components/auth/access-key-gate.tsx +8 -2
  86. package/src/components/auth/setup-wizard.tsx +10 -9
  87. package/src/components/auth/user-picker.tsx +3 -2
  88. package/src/components/chat/chat-area.tsx +20 -1
  89. package/src/components/chat/chat-card.tsx +18 -3
  90. package/src/components/chat/chat-header.tsx +24 -4
  91. package/src/components/chat/chat-list.tsx +2 -11
  92. package/src/components/chat/heartbeat-history-panel.tsx +2 -1
  93. package/src/components/chat/message-bubble.tsx +45 -6
  94. package/src/components/chat/message-list.tsx +280 -145
  95. package/src/components/chat/streaming-bubble.tsx +217 -60
  96. package/src/components/chat/swarm-panel.test.ts +274 -0
  97. package/src/components/chat/swarm-panel.tsx +410 -0
  98. package/src/components/chat/swarm-status-card.tsx +346 -0
  99. package/src/components/chat/tool-call-bubble.tsx +48 -23
  100. package/src/components/chatrooms/chatroom-list.tsx +8 -5
  101. package/src/components/chatrooms/chatroom-message.tsx +10 -7
  102. package/src/components/chatrooms/chatroom-view.tsx +12 -9
  103. package/src/components/connectors/connector-health.tsx +6 -4
  104. package/src/components/connectors/connector-list.tsx +16 -11
  105. package/src/components/connectors/connector-sheet.tsx +12 -6
  106. package/src/components/home/home-view.tsx +38 -24
  107. package/src/components/input/chat-input.tsx +10 -1
  108. package/src/components/layout/app-layout.tsx +2 -38
  109. package/src/components/layout/sheet-layer.tsx +50 -0
  110. package/src/components/mcp-servers/mcp-server-list.tsx +37 -5
  111. package/src/components/mcp-servers/mcp-server-sheet.tsx +12 -2
  112. package/src/components/plugins/plugin-list.tsx +8 -4
  113. package/src/components/plugins/plugin-sheet.tsx +2 -1
  114. package/src/components/providers/provider-list.tsx +3 -2
  115. package/src/components/providers/provider-sheet.tsx +2 -1
  116. package/src/components/runs/run-list.tsx +11 -7
  117. package/src/components/schedules/schedule-card.tsx +5 -3
  118. package/src/components/shared/agent-switch-dialog.tsx +1 -1
  119. package/src/components/shared/attachment-chip.tsx +19 -3
  120. package/src/components/shared/notification-center.tsx +6 -3
  121. package/src/components/shared/settings/plugin-manager.tsx +3 -2
  122. package/src/components/shared/settings/section-embedding.tsx +2 -1
  123. package/src/components/shared/settings/section-orchestrator.tsx +2 -1
  124. package/src/components/shared/settings/section-user-preferences.tsx +107 -0
  125. package/src/components/shared/settings/settings-page.tsx +13 -9
  126. package/src/components/skills/clawhub-browser.tsx +15 -4
  127. package/src/components/skills/skill-list.tsx +15 -4
  128. package/src/components/tasks/approvals-panel.tsx +2 -1
  129. package/src/components/tasks/task-board.tsx +35 -37
  130. package/src/components/tasks/task-sheet.tsx +4 -3
  131. package/src/components/ui/full-screen-loader.tsx +164 -0
  132. package/src/components/wallets/wallet-approval-dialog.tsx +2 -1
  133. package/src/components/wallets/wallet-panel.tsx +6 -5
  134. package/src/components/wallets/wallet-section.tsx +3 -2
  135. package/src/components/webhooks/webhook-list.tsx +4 -5
  136. package/src/components/webhooks/webhook-sheet.tsx +6 -6
  137. package/src/hooks/use-app-bootstrap.ts +202 -0
  138. package/src/hooks/use-mounted-ref.ts +14 -0
  139. package/src/hooks/use-now.ts +31 -0
  140. package/src/hooks/use-openclaw-gateway.ts +2 -1
  141. package/src/instrumentation.ts +20 -8
  142. package/src/lib/agent-default-tools.test.ts +52 -0
  143. package/src/lib/agent-default-tools.ts +40 -0
  144. package/src/lib/api-client.test.ts +21 -0
  145. package/src/lib/api-client.ts +6 -11
  146. package/src/lib/canvas-content.test.ts +360 -0
  147. package/src/lib/chat-streaming-state.test.ts +49 -2
  148. package/src/lib/chat-streaming-state.ts +26 -10
  149. package/src/lib/fetch-timeout.test.ts +54 -0
  150. package/src/lib/fetch-timeout.ts +60 -3
  151. package/src/lib/live-tool-events.test.ts +77 -0
  152. package/src/lib/live-tool-events.ts +73 -0
  153. package/src/lib/local-observability.test.ts +2 -2
  154. package/src/lib/openclaw-endpoint.test.ts +1 -1
  155. package/src/lib/providers/anthropic.ts +12 -16
  156. package/src/lib/providers/index.ts +4 -2
  157. package/src/lib/providers/ollama.ts +9 -6
  158. package/src/lib/providers/openai.ts +11 -14
  159. package/src/lib/runtime-env.test.ts +8 -8
  160. package/src/lib/schedule-dedupe-advanced.test.ts +2 -2
  161. package/src/lib/schedule-dedupe.test.ts +1 -1
  162. package/src/lib/schedule-dedupe.ts +3 -2
  163. package/src/lib/server/agent-thread-session.test.ts +6 -6
  164. package/src/lib/server/agent-thread-session.ts +6 -9
  165. package/src/lib/server/alert-dispatch.ts +2 -1
  166. package/src/lib/server/api-routes.test.ts +6 -6
  167. package/src/lib/server/approval-connector-notify.test.ts +4 -4
  168. package/src/lib/server/approvals-auto-approve.test.ts +29 -29
  169. package/src/lib/server/approvals.test.ts +317 -0
  170. package/src/lib/server/approvals.ts +5 -4
  171. package/src/lib/server/autonomy-runtime.test.ts +11 -11
  172. package/src/lib/server/browser-state.ts +2 -2
  173. package/src/lib/server/capability-router.test.ts +1 -1
  174. package/src/lib/server/capability-router.ts +3 -2
  175. package/src/lib/server/chat-execution-advanced.test.ts +15 -2
  176. package/src/lib/server/chat-execution-connector-delivery.ts +67 -0
  177. package/src/lib/server/chat-execution-disabled.test.ts +3 -3
  178. package/src/lib/server/chat-execution-eval-history.test.ts +3 -3
  179. package/src/lib/server/chat-execution-heartbeat.test.ts +42 -1
  180. package/src/lib/server/chat-execution-session-sync.test.ts +119 -0
  181. package/src/lib/server/chat-execution-tool-events.ts +116 -0
  182. package/src/lib/server/chat-execution-utils.test.ts +479 -0
  183. package/src/lib/server/chat-execution-utils.ts +533 -0
  184. package/src/lib/server/chat-execution.ts +153 -748
  185. package/src/lib/server/chat-streaming-utils.ts +174 -0
  186. package/src/lib/server/chat-turn-tool-routing.ts +310 -0
  187. package/src/lib/server/chatroom-session-persistence.test.ts +2 -2
  188. package/src/lib/server/clawhub-client.ts +2 -1
  189. package/src/lib/server/collection-helpers.test.ts +92 -0
  190. package/src/lib/server/collection-helpers.ts +25 -3
  191. package/src/lib/server/connectors/access.ts +146 -0
  192. package/src/lib/server/connectors/bluebubbles.test.ts +1 -1
  193. package/src/lib/server/connectors/bluebubbles.ts +4 -4
  194. package/src/lib/server/connectors/commands.ts +367 -0
  195. package/src/lib/server/connectors/connector-routing.test.ts +4 -4
  196. package/src/lib/server/connectors/delivery.ts +142 -0
  197. package/src/lib/server/connectors/discord.ts +37 -40
  198. package/src/lib/server/connectors/email.ts +11 -10
  199. package/src/lib/server/connectors/googlechat.ts +4 -4
  200. package/src/lib/server/connectors/inbound-audio-transcription.ts +2 -1
  201. package/src/lib/server/connectors/ingress-delivery.ts +23 -0
  202. package/src/lib/server/connectors/manager-roundtrip.test.ts +300 -0
  203. package/src/lib/server/connectors/manager.test.ts +352 -77
  204. package/src/lib/server/connectors/manager.ts +134 -673
  205. package/src/lib/server/connectors/matrix.ts +4 -4
  206. package/src/lib/server/connectors/message-sentinel.ts +7 -0
  207. package/src/lib/server/connectors/openclaw.test.ts +1 -1
  208. package/src/lib/server/connectors/openclaw.ts +8 -10
  209. package/src/lib/server/connectors/outbox.test.ts +192 -0
  210. package/src/lib/server/connectors/outbox.ts +369 -0
  211. package/src/lib/server/connectors/pairing.test.ts +18 -1
  212. package/src/lib/server/connectors/pairing.ts +49 -4
  213. package/src/lib/server/connectors/policy.ts +9 -3
  214. package/src/lib/server/connectors/reconnect-state.ts +71 -0
  215. package/src/lib/server/connectors/response-media.ts +256 -0
  216. package/src/lib/server/connectors/runtime-state.ts +67 -0
  217. package/src/lib/server/connectors/session.test.ts +357 -0
  218. package/src/lib/server/connectors/session.ts +422 -0
  219. package/src/lib/server/connectors/signal.ts +7 -7
  220. package/src/lib/server/connectors/slack.ts +43 -43
  221. package/src/lib/server/connectors/teams.ts +4 -4
  222. package/src/lib/server/connectors/telegram.ts +37 -43
  223. package/src/lib/server/connectors/types.ts +31 -1
  224. package/src/lib/server/connectors/whatsapp.test.ts +108 -0
  225. package/src/lib/server/connectors/whatsapp.ts +106 -34
  226. package/src/lib/server/context-manager.test.ts +409 -0
  227. package/src/lib/server/cost.test.ts +1 -1
  228. package/src/lib/server/daemon-policy.ts +78 -0
  229. package/src/lib/server/daemon-state-connectors.test.ts +167 -0
  230. package/src/lib/server/daemon-state.test.ts +283 -55
  231. package/src/lib/server/daemon-state.ts +106 -109
  232. package/src/lib/server/data-dir.test.ts +5 -5
  233. package/src/lib/server/data-dir.ts +4 -0
  234. package/src/lib/server/delegation-jobs-advanced.test.ts +1 -1
  235. package/src/lib/server/delegation-jobs.test.ts +87 -0
  236. package/src/lib/server/delegation-jobs.ts +42 -48
  237. package/src/lib/server/devserver-launch.ts +1 -1
  238. package/src/lib/server/document-utils.ts +7 -9
  239. package/src/lib/server/elevenlabs.ts +2 -1
  240. package/src/lib/server/embeddings.test.ts +105 -0
  241. package/src/lib/server/ethereum.ts +3 -2
  242. package/src/lib/server/eval/agent-regression.ts +3 -2
  243. package/src/lib/server/eval/runner.ts +2 -1
  244. package/src/lib/server/eval/scorer.ts +2 -1
  245. package/src/lib/server/evm-swap.ts +2 -1
  246. package/src/lib/server/gateway/protocol.test.ts +1 -1
  247. package/src/lib/server/guardian.ts +2 -1
  248. package/src/lib/server/heartbeat-blocked-suppression.test.ts +151 -0
  249. package/src/lib/server/heartbeat-service-timer.test.ts +6 -6
  250. package/src/lib/server/heartbeat-service.test.ts +406 -0
  251. package/src/lib/server/heartbeat-service.ts +54 -7
  252. package/src/lib/server/heartbeat-wake.test.ts +19 -0
  253. package/src/lib/server/heartbeat-wake.ts +17 -16
  254. package/src/lib/server/integrity-monitor.test.ts +149 -0
  255. package/src/lib/server/json-utils.ts +22 -0
  256. package/src/lib/server/knowledge-db.test.ts +13 -13
  257. package/src/lib/server/link-understanding.ts +2 -1
  258. package/src/lib/server/llm-response-cache.test.ts +1 -1
  259. package/src/lib/server/main-agent-loop-advanced.test.ts +65 -3
  260. package/src/lib/server/main-agent-loop.test.ts +6 -6
  261. package/src/lib/server/main-agent-loop.ts +21 -7
  262. package/src/lib/server/mcp-client.test.ts +1 -1
  263. package/src/lib/server/mcp-conformance.test.ts +1 -1
  264. package/src/lib/server/mcp-conformance.ts +3 -2
  265. package/src/lib/server/memory-consolidation.ts +2 -1
  266. package/src/lib/server/memory-db.test.ts +485 -0
  267. package/src/lib/server/memory-db.ts +39 -26
  268. package/src/lib/server/memory-graph.test.ts +2 -2
  269. package/src/lib/server/memory-policy.test.ts +7 -7
  270. package/src/lib/server/memory-retrieval.test.ts +1 -1
  271. package/src/lib/server/openclaw-config-sync.ts +2 -1
  272. package/src/lib/server/openclaw-deploy.test.ts +1 -1
  273. package/src/lib/server/openclaw-deploy.ts +8 -12
  274. package/src/lib/server/openclaw-exec-config.ts +2 -1
  275. package/src/lib/server/openclaw-gateway.ts +6 -7
  276. package/src/lib/server/openclaw-skills-normalize.ts +2 -1
  277. package/src/lib/server/openclaw-sync.ts +7 -5
  278. package/src/lib/server/orchestrator-lg-structure.test.ts +17 -0
  279. package/src/lib/server/orchestrator-lg.ts +199 -327
  280. package/src/lib/server/path-utils.ts +31 -0
  281. package/src/lib/server/perf.ts +161 -0
  282. package/src/lib/server/plugins-approval-guidance.ts +115 -0
  283. package/src/lib/server/plugins.test.ts +1 -1
  284. package/src/lib/server/plugins.ts +22 -132
  285. package/src/lib/server/process-manager.ts +5 -8
  286. package/src/lib/server/provider-health.test.ts +137 -0
  287. package/src/lib/server/provider-health.ts +3 -3
  288. package/src/lib/server/provider-model-discovery.ts +3 -12
  289. package/src/lib/server/queue-followups.test.ts +9 -9
  290. package/src/lib/server/queue-reconcile.test.ts +2 -2
  291. package/src/lib/server/queue-recovery.test.ts +269 -0
  292. package/src/lib/server/queue.test.ts +570 -0
  293. package/src/lib/server/queue.ts +62 -455
  294. package/src/lib/server/resolve-image.ts +30 -0
  295. package/src/lib/server/runtime-settings.test.ts +4 -4
  296. package/src/lib/server/runtime-storage-write-paths.test.ts +60 -0
  297. package/src/lib/server/schedule-normalization.test.ts +279 -0
  298. package/src/lib/server/schedule-service.ts +263 -0
  299. package/src/lib/server/scheduler.ts +17 -74
  300. package/src/lib/server/session-mailbox.test.ts +191 -0
  301. package/src/lib/server/session-run-manager.test.ts +640 -0
  302. package/src/lib/server/session-run-manager.ts +59 -15
  303. package/src/lib/server/session-tools/autonomy-tools.test.ts +20 -20
  304. package/src/lib/server/session-tools/calendar.ts +2 -1
  305. package/src/lib/server/session-tools/canvas.ts +2 -1
  306. package/src/lib/server/session-tools/chatroom.ts +2 -1
  307. package/src/lib/server/session-tools/connector.ts +26 -28
  308. package/src/lib/server/session-tools/context-mgmt.ts +3 -2
  309. package/src/lib/server/session-tools/crawl.ts +4 -3
  310. package/src/lib/server/session-tools/crud.ts +105 -324
  311. package/src/lib/server/session-tools/delegate-fallback.test.ts +9 -9
  312. package/src/lib/server/session-tools/delegate.ts +6 -8
  313. package/src/lib/server/session-tools/discovery-approvals.test.ts +15 -15
  314. package/src/lib/server/session-tools/discovery.ts +4 -3
  315. package/src/lib/server/session-tools/document.ts +2 -1
  316. package/src/lib/server/session-tools/email.ts +2 -1
  317. package/src/lib/server/session-tools/extract.ts +2 -1
  318. package/src/lib/server/session-tools/file.ts +4 -3
  319. package/src/lib/server/session-tools/http.ts +2 -1
  320. package/src/lib/server/session-tools/human-loop.ts +2 -1
  321. package/src/lib/server/session-tools/image-gen.ts +4 -3
  322. package/src/lib/server/session-tools/index.ts +26 -30
  323. package/src/lib/server/session-tools/mailbox.ts +2 -1
  324. package/src/lib/server/session-tools/manage-connectors.test.ts +4 -4
  325. package/src/lib/server/session-tools/manage-schedules.test.ts +12 -12
  326. package/src/lib/server/session-tools/manage-tasks-advanced.test.ts +5 -5
  327. package/src/lib/server/session-tools/manage-tasks.test.ts +2 -2
  328. package/src/lib/server/session-tools/monitor.ts +2 -1
  329. package/src/lib/server/session-tools/platform.ts +2 -1
  330. package/src/lib/server/session-tools/plugin-creator.ts +2 -1
  331. package/src/lib/server/session-tools/replicate.ts +3 -2
  332. package/src/lib/server/session-tools/session-tools-wiring.test.ts +6 -6
  333. package/src/lib/server/session-tools/shell.ts +4 -9
  334. package/src/lib/server/session-tools/subagent.ts +322 -170
  335. package/src/lib/server/session-tools/table.ts +6 -5
  336. package/src/lib/server/session-tools/wallet-tool.test.ts +3 -3
  337. package/src/lib/server/session-tools/wallet.ts +7 -6
  338. package/src/lib/server/session-tools/web-browser-config.test.ts +1 -0
  339. package/src/lib/server/session-tools/web-utils.ts +317 -0
  340. package/src/lib/server/session-tools/web.ts +62 -328
  341. package/src/lib/server/skill-prompt-budget.test.ts +1 -1
  342. package/src/lib/server/skills-normalize.ts +2 -1
  343. package/src/lib/server/storage-item-access.test.ts +302 -0
  344. package/src/lib/server/storage.ts +366 -314
  345. package/src/lib/server/stream-agent-chat.test.ts +82 -3
  346. package/src/lib/server/stream-agent-chat.ts +146 -510
  347. package/src/lib/server/stream-continuation.ts +412 -0
  348. package/src/lib/server/subagent-lineage.test.ts +647 -0
  349. package/src/lib/server/subagent-lineage.ts +435 -0
  350. package/src/lib/server/subagent-runtime.test.ts +484 -0
  351. package/src/lib/server/subagent-runtime.ts +419 -0
  352. package/src/lib/server/subagent-swarm.test.ts +391 -0
  353. package/src/lib/server/subagent-swarm.ts +564 -0
  354. package/src/lib/server/system-events.ts +3 -3
  355. package/src/lib/server/task-followups.test.ts +491 -0
  356. package/src/lib/server/task-followups.ts +391 -0
  357. package/src/lib/server/task-lifecycle.test.ts +205 -0
  358. package/src/lib/server/task-lifecycle.ts +200 -0
  359. package/src/lib/server/task-quality-gate.test.ts +1 -1
  360. package/src/lib/server/task-resume.ts +208 -0
  361. package/src/lib/server/task-service.test.ts +108 -0
  362. package/src/lib/server/task-service.ts +264 -0
  363. package/src/lib/server/task-validation.test.ts +1 -1
  364. package/src/lib/server/test-utils/run-with-temp-data-dir.ts +42 -0
  365. package/src/lib/server/tool-capability-policy.test.ts +2 -2
  366. package/src/lib/server/tool-capability-policy.ts +3 -2
  367. package/src/lib/server/tool-planning.ts +2 -1
  368. package/src/lib/server/tool-retry.ts +2 -3
  369. package/src/lib/server/wake-dispatcher.test.ts +303 -0
  370. package/src/lib/server/wake-dispatcher.ts +318 -0
  371. package/src/lib/server/wake-mode.test.ts +161 -0
  372. package/src/lib/server/wake-mode.ts +174 -0
  373. package/src/lib/server/wallet-service.ts +8 -9
  374. package/src/lib/server/watch-jobs.ts +2 -1
  375. package/src/lib/server/workspace-context.ts +2 -2
  376. package/src/lib/shared-utils.test.ts +142 -0
  377. package/src/lib/shared-utils.ts +62 -0
  378. package/src/lib/tool-event-summary.ts +2 -1
  379. package/src/lib/view-routes.test.ts +100 -0
  380. package/src/lib/wallet.test.ts +322 -6
  381. package/src/proxy.test.ts +4 -4
  382. package/src/proxy.ts +2 -3
  383. package/src/stores/set-if-changed.ts +40 -0
  384. package/src/stores/slices/agent-slice.ts +111 -0
  385. package/src/stores/slices/auth-slice.ts +25 -0
  386. package/src/stores/slices/data-slice.ts +301 -0
  387. package/src/stores/slices/index.ts +7 -0
  388. package/src/stores/slices/session-slice.ts +112 -0
  389. package/src/stores/slices/task-slice.ts +63 -0
  390. package/src/stores/slices/ui-slice.ts +192 -0
  391. package/src/stores/use-app-store.ts +17 -822
  392. package/src/stores/use-approval-store.ts +2 -1
  393. package/src/stores/use-chat-store.ts +8 -1
  394. package/src/types/index.ts +10 -0
@@ -8,6 +8,7 @@ import { enqueueSystemEvent } from './system-events'
8
8
  import { loadApprovals, loadTasks, loadWatchJobs, upsertWatchJob, upsertWatchJobs } from './storage'
9
9
  import { notify } from './ws-hub'
10
10
  import { fetchMailboxMessages, getMailboxHighwaterUid } from './mailbox-utils'
11
+ import { errorMessage } from '@/lib/shared-utils'
11
12
 
12
13
  export interface CreateWatchJobInput {
13
14
  type: WatchJob['type']
@@ -408,7 +409,7 @@ export async function processDueWatchJobs(timestamp = now()): Promise<{ checked:
408
409
  updates.push([job.id, scheduleNextCheck({
409
410
  ...job,
410
411
  lastCheckedAt: timestamp,
411
- lastError: err instanceof Error ? err.message : String(err),
412
+ lastError: errorMessage(err),
412
413
  }, timestamp)])
413
414
  }
414
415
  }
@@ -9,8 +9,8 @@
9
9
  */
10
10
 
11
11
  import fs from 'fs'
12
- import path from 'path'
13
12
  import { WORKSPACE_DIR } from './data-dir'
13
+ import { resolvePathWithinBaseDir } from './path-utils'
14
14
 
15
15
  /**
16
16
  * Workspace files to inject, in priority order.
@@ -87,7 +87,7 @@ export function buildWorkspaceContext(opts: WorkspaceContextOptions = {}): Works
87
87
  for (const spec of WORKSPACE_FILES) {
88
88
  if (totalChars >= maxTotal) break
89
89
 
90
- const filePath = path.join(workspaceDir, spec.name)
90
+ const filePath = resolvePathWithinBaseDir(workspaceDir, spec.name)
91
91
  const content = readFileSafe(filePath)
92
92
  if (!content || isEffectivelyEmpty(content)) continue
93
93
 
@@ -0,0 +1,142 @@
1
+ import assert from 'node:assert/strict'
2
+ import { describe, it } from 'node:test'
3
+
4
+ import {
5
+ errorMessage,
6
+ safeJsonParse,
7
+ truncate,
8
+ hmrSingleton,
9
+ dedup,
10
+ dedupBy,
11
+ sleep,
12
+ } from './shared-utils'
13
+
14
+ describe('errorMessage', () => {
15
+ it('extracts message from Error', () => {
16
+ assert.equal(errorMessage(new Error('boom')), 'boom')
17
+ })
18
+ it('converts string to string', () => {
19
+ assert.equal(errorMessage('fail'), 'fail')
20
+ })
21
+ it('converts number to string', () => {
22
+ assert.equal(errorMessage(42), '42')
23
+ })
24
+ it('converts null to string', () => {
25
+ assert.equal(errorMessage(null), 'null')
26
+ })
27
+ it('converts undefined to string', () => {
28
+ assert.equal(errorMessage(undefined), 'undefined')
29
+ })
30
+ it('handles TypeError subclass', () => {
31
+ assert.equal(errorMessage(new TypeError('bad type')), 'bad type')
32
+ })
33
+ })
34
+
35
+ describe('safeJsonParse', () => {
36
+ it('parses valid JSON', () => {
37
+ assert.deepEqual(safeJsonParse('{"a":1}', null), { a: 1 })
38
+ })
39
+ it('returns fallback for invalid JSON', () => {
40
+ assert.equal(safeJsonParse('not json', 'default'), 'default')
41
+ })
42
+ it('returns fallback for empty string', () => {
43
+ assert.deepEqual(safeJsonParse('', []), [])
44
+ })
45
+ it('parses arrays', () => {
46
+ assert.deepEqual(safeJsonParse('[1,2,3]', []), [1, 2, 3])
47
+ })
48
+ it('parses null literal', () => {
49
+ assert.equal(safeJsonParse('null', 'fallback'), null)
50
+ })
51
+ })
52
+
53
+ describe('truncate', () => {
54
+ it('returns short strings unchanged', () => {
55
+ assert.equal(truncate('hello', 10), 'hello')
56
+ })
57
+ it('truncates long strings', () => {
58
+ assert.equal(truncate('hello world', 5), 'hello')
59
+ })
60
+ it('truncates with suffix', () => {
61
+ assert.equal(truncate('hello world', 8, '…'), 'hello w…')
62
+ })
63
+ it('handles exact limit', () => {
64
+ assert.equal(truncate('hello', 5), 'hello')
65
+ })
66
+ it('handles zero limit', () => {
67
+ assert.equal(truncate('hello', 0), '')
68
+ })
69
+ it('handles suffix longer than limit gracefully', () => {
70
+ assert.equal(truncate('hello world', 2, '...'), '...')
71
+ })
72
+ it('empty string unchanged', () => {
73
+ assert.equal(truncate('', 10), '')
74
+ })
75
+ })
76
+
77
+ describe('hmrSingleton', () => {
78
+ it('creates and returns a value', () => {
79
+ const val = hmrSingleton('__test_hmr_1__', () => ({ count: 0 }))
80
+ assert.deepEqual(val, { count: 0 })
81
+ })
82
+ it('returns same instance on second call', () => {
83
+ const a = hmrSingleton('__test_hmr_2__', () => ({ id: Math.random() }))
84
+ const b = hmrSingleton('__test_hmr_2__', () => ({ id: Math.random() }))
85
+ assert.equal(a, b)
86
+ assert.equal(a.id, b.id)
87
+ })
88
+ it('creates different instances for different keys', () => {
89
+ const a = hmrSingleton('__test_hmr_3a__', () => 'a')
90
+ const b = hmrSingleton('__test_hmr_3b__', () => 'b')
91
+ assert.notEqual(a, b)
92
+ })
93
+ })
94
+
95
+ describe('dedup', () => {
96
+ it('removes duplicates', () => {
97
+ assert.deepEqual(dedup([1, 2, 2, 3, 1]), [1, 2, 3])
98
+ })
99
+ it('preserves order', () => {
100
+ assert.deepEqual(dedup(['b', 'a', 'b', 'c']), ['b', 'a', 'c'])
101
+ })
102
+ it('handles empty array', () => {
103
+ assert.deepEqual(dedup([]), [])
104
+ })
105
+ it('handles all unique', () => {
106
+ assert.deepEqual(dedup([1, 2, 3]), [1, 2, 3])
107
+ })
108
+ })
109
+
110
+ describe('dedupBy', () => {
111
+ it('deduplicates by key function', () => {
112
+ const items = [
113
+ { id: '1', name: 'a' },
114
+ { id: '2', name: 'b' },
115
+ { id: '1', name: 'c' },
116
+ ]
117
+ const result = dedupBy(items, (i) => i.id)
118
+ assert.equal(result.length, 2)
119
+ assert.equal(result[0].name, 'a')
120
+ assert.equal(result[1].name, 'b')
121
+ })
122
+ it('keeps first occurrence', () => {
123
+ const result = dedupBy(['hello', 'HELLO', 'world'], (s) => s.toLowerCase())
124
+ assert.deepEqual(result, ['hello', 'world'])
125
+ })
126
+ it('handles empty array', () => {
127
+ assert.deepEqual(dedupBy([], (x) => String(x)), [])
128
+ })
129
+ })
130
+
131
+ describe('sleep', () => {
132
+ it('resolves after delay', async () => {
133
+ const start = Date.now()
134
+ await sleep(50)
135
+ const elapsed = Date.now() - start
136
+ assert.ok(elapsed >= 40, `Expected ≥40ms, got ${elapsed}ms`)
137
+ })
138
+ it('resolves with undefined', async () => {
139
+ const result = await sleep(1)
140
+ assert.equal(result, undefined)
141
+ })
142
+ })
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Shared utility functions used across the codebase.
3
+ *
4
+ * These replace ad-hoc patterns that were duplicated in 100+ files:
5
+ * - errorMessage: 231 occurrences across 112 files
6
+ * - safeJsonParse: 137 occurrences across 82 files
7
+ * - truncate: 62+ occurrences across 20+ files
8
+ * - hmrSingleton: 77 occurrences across 38 files
9
+ * - dedup/dedupBy: 40 occurrences across 28 files
10
+ * - sleep: 25 occurrences across 17 files
11
+ */
12
+
13
+ /** Extract a human-readable error message from an unknown catch value. */
14
+ export function errorMessage(err: unknown): string {
15
+ return err instanceof Error ? err.message : String(err)
16
+ }
17
+
18
+ /** Parse JSON with a fallback value instead of throwing. */
19
+ export function safeJsonParse<T>(json: string, fallback: T): T {
20
+ try {
21
+ return JSON.parse(json) as T
22
+ } catch {
23
+ return fallback
24
+ }
25
+ }
26
+
27
+ /** Truncate a string to `limit` characters, optionally appending a suffix. */
28
+ export function truncate(s: string, limit: number, suffix = ''): string {
29
+ if (s.length <= limit) return s
30
+ const cutoff = Math.max(0, limit - suffix.length)
31
+ return s.slice(0, cutoff) + suffix
32
+ }
33
+
34
+ /**
35
+ * HMR-safe singleton on globalThis. Survives Next.js hot module reloads.
36
+ * Replaces the ad-hoc `__swarmclaw_*` pattern scattered across 38 files.
37
+ */
38
+ export function hmrSingleton<T>(key: string, init: () => T): T {
39
+ const g = globalThis as Record<string, unknown>
40
+ return (g[key] ??= init()) as T
41
+ }
42
+
43
+ /** Deduplicate an array preserving insertion order. */
44
+ export function dedup<T>(arr: T[]): T[] {
45
+ return [...new Set(arr)]
46
+ }
47
+
48
+ /** Deduplicate an array by a key function, keeping the first occurrence. */
49
+ export function dedupBy<T>(arr: T[], key: (item: T) => string): T[] {
50
+ const seen = new Set<string>()
51
+ return arr.filter((item) => {
52
+ const k = key(item)
53
+ if (seen.has(k)) return false
54
+ seen.add(k)
55
+ return true
56
+ })
57
+ }
58
+
59
+ /** Promise-based sleep. Replaces `await new Promise(r => setTimeout(r, ms))`. */
60
+ export function sleep(ms: number): Promise<void> {
61
+ return new Promise((resolve) => setTimeout(resolve, ms))
62
+ }
@@ -1,4 +1,5 @@
1
1
  import type { MessageToolEvent } from '@/types'
2
+ import { dedup } from '@/lib/shared-utils'
2
3
 
3
4
  interface ToolEventAssistantSummaryOptions {
4
5
  interrupted?: boolean
@@ -13,7 +14,7 @@ export function buildToolEventAssistantSummary(
13
14
  : []
14
15
  if (events.length === 0) return ''
15
16
 
16
- const uniqueNames = [...new Set(events.map((event) => event.name.trim()))]
17
+ const uniqueNames = dedup(events.map((event) => event.name.trim()))
17
18
  const visibleNames = uniqueNames.slice(0, 4).map((name) => `\`${name}\``).join(', ')
18
19
  const hiddenCount = Math.max(0, uniqueNames.length - 4)
19
20
  const pendingCount = events.filter((event) => !event.output).length
@@ -0,0 +1,100 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { parsePath, buildPath, DEFAULT_VIEW, VIEW_TO_PATH, PATH_TO_VIEW } from './view-routes'
4
+
5
+ describe('DEFAULT_VIEW', () => {
6
+ it('is home', () => {
7
+ assert.equal(DEFAULT_VIEW, 'home')
8
+ })
9
+ })
10
+
11
+ describe('VIEW_TO_PATH / PATH_TO_VIEW', () => {
12
+ it('has matching forward and reverse mappings', () => {
13
+ for (const [view, path] of Object.entries(VIEW_TO_PATH)) {
14
+ assert.equal(PATH_TO_VIEW[path], view, `PATH_TO_VIEW['${path}'] should be '${view}'`)
15
+ }
16
+ })
17
+
18
+ it('maps known views', () => {
19
+ assert.equal(VIEW_TO_PATH.home, '/')
20
+ assert.equal(VIEW_TO_PATH.agents, '/agents')
21
+ assert.equal(VIEW_TO_PATH.settings, '/settings')
22
+ assert.equal(VIEW_TO_PATH.mcp_servers, '/mcp-servers')
23
+ })
24
+ })
25
+
26
+ describe('parsePath', () => {
27
+ it('matches exact routes', () => {
28
+ assert.deepEqual(parsePath('/'), { view: 'home', id: null })
29
+ assert.deepEqual(parsePath('/agents'), { view: 'agents', id: null })
30
+ assert.deepEqual(parsePath('/settings'), { view: 'settings', id: null })
31
+ assert.deepEqual(parsePath('/mcp-servers'), { view: 'mcp_servers', id: null })
32
+ })
33
+
34
+ it('parses agents deep link with ID', () => {
35
+ assert.deepEqual(parsePath('/agents/abc123'), { view: 'agents', id: 'abc123' })
36
+ })
37
+
38
+ it('parses chatrooms deep link with ID', () => {
39
+ assert.deepEqual(parsePath('/chatrooms/room-1'), { view: 'chatrooms', id: 'room-1' })
40
+ })
41
+
42
+ it('decodes URI components in IDs', () => {
43
+ assert.deepEqual(
44
+ parsePath('/agents/hello%20world'),
45
+ { view: 'agents', id: 'hello world' },
46
+ )
47
+ })
48
+
49
+ it('returns null for malformed URI encoding', () => {
50
+ assert.equal(parsePath('/agents/%ZZ'), null)
51
+ })
52
+
53
+ it('rejects deep link for views that do not support IDs', () => {
54
+ assert.equal(parsePath('/settings/something'), null)
55
+ assert.equal(parsePath('/wallets/abc'), null)
56
+ assert.equal(parsePath('/tasks/123'), null)
57
+ })
58
+
59
+ it('rejects nested paths beyond one level', () => {
60
+ assert.equal(parsePath('/agents/abc/def'), null)
61
+ })
62
+
63
+ it('returns null for unknown paths', () => {
64
+ assert.equal(parsePath('/unknown'), null)
65
+ assert.equal(parsePath('/foo/bar'), null)
66
+ })
67
+
68
+ it('longest-path-first matching prevents prefix collisions', () => {
69
+ // /mcp-servers should not be matched as /m... prefix of something else
70
+ assert.deepEqual(parsePath('/mcp-servers'), { view: 'mcp_servers', id: null })
71
+ })
72
+ })
73
+
74
+ describe('buildPath', () => {
75
+ it('builds basic view paths', () => {
76
+ assert.equal(buildPath('home'), '/')
77
+ assert.equal(buildPath('agents'), '/agents')
78
+ assert.equal(buildPath('settings'), '/settings')
79
+ })
80
+
81
+ it('appends encoded ID for views that support it', () => {
82
+ assert.equal(buildPath('agents', 'abc123'), '/agents/abc123')
83
+ assert.equal(buildPath('chatrooms', 'room-1'), '/chatrooms/room-1')
84
+ })
85
+
86
+ it('encodes special characters in ID', () => {
87
+ assert.equal(buildPath('agents', 'hello world'), '/agents/hello%20world')
88
+ assert.equal(buildPath('agents', 'a/b'), '/agents/a%2Fb')
89
+ })
90
+
91
+ it('ignores ID for views that do not support it', () => {
92
+ assert.equal(buildPath('settings', 'ignored'), '/settings')
93
+ assert.equal(buildPath('wallets', 'ignored'), '/wallets')
94
+ })
95
+
96
+ it('ignores null/empty ID', () => {
97
+ assert.equal(buildPath('agents', null), '/agents')
98
+ assert.equal(buildPath('agents', ''), '/agents')
99
+ })
100
+ })