@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
@@ -0,0 +1,149 @@
1
+ import assert from 'node:assert/strict'
2
+ import fs from 'node:fs'
3
+ import os from 'node:os'
4
+ import path from 'node:path'
5
+ import { after, before, describe, it } from 'node:test'
6
+
7
+ const originalEnv = {
8
+ DATA_DIR: process.env.DATA_DIR,
9
+ WORKSPACE_DIR: process.env.WORKSPACE_DIR,
10
+ SWARMCLAW_BUILD_MODE: process.env.SWARMCLAW_BUILD_MODE,
11
+ }
12
+
13
+ let tempDir = ''
14
+ let integrityMonitor: typeof import('./integrity-monitor')
15
+
16
+ before(async () => {
17
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmclaw-integrity-'))
18
+ process.env.DATA_DIR = path.join(tempDir, 'data')
19
+ process.env.WORKSPACE_DIR = path.join(tempDir, 'workspace')
20
+ process.env.SWARMCLAW_BUILD_MODE = '1'
21
+ integrityMonitor = await import('./integrity-monitor')
22
+ })
23
+
24
+ after(() => {
25
+ if (originalEnv.DATA_DIR === undefined) delete process.env.DATA_DIR
26
+ else process.env.DATA_DIR = originalEnv.DATA_DIR
27
+ if (originalEnv.WORKSPACE_DIR === undefined) delete process.env.WORKSPACE_DIR
28
+ else process.env.WORKSPACE_DIR = originalEnv.WORKSPACE_DIR
29
+ if (originalEnv.SWARMCLAW_BUILD_MODE === undefined) delete process.env.SWARMCLAW_BUILD_MODE
30
+ else process.env.SWARMCLAW_BUILD_MODE = originalEnv.SWARMCLAW_BUILD_MODE
31
+ fs.rmSync(tempDir, { recursive: true, force: true })
32
+ })
33
+
34
+ describe('integrity-monitor', () => {
35
+ it('returns disabled result when integrityMonitorEnabled is false', () => {
36
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: false })
37
+ assert.equal(result.enabled, false)
38
+ assert.equal(result.checkedFiles, 0)
39
+ assert.equal(result.drifts.length, 0)
40
+ assert.ok(result.checkedAt > 0)
41
+ })
42
+
43
+ it('returns disabled for string "false"', () => {
44
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: 'false' })
45
+ assert.equal(result.enabled, false)
46
+ })
47
+
48
+ it('returns disabled for string "0"', () => {
49
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: '0' })
50
+ assert.equal(result.enabled, false)
51
+ })
52
+
53
+ it('returns disabled for string "off"', () => {
54
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: 'off' })
55
+ assert.equal(result.enabled, false)
56
+ })
57
+
58
+ it('defaults to enabled when setting is null', () => {
59
+ const result = integrityMonitor.runIntegrityMonitor(null)
60
+ assert.equal(result.enabled, true)
61
+ assert.ok(result.checkedAt > 0)
62
+ })
63
+
64
+ it('defaults to enabled when setting is undefined', () => {
65
+ const result = integrityMonitor.runIntegrityMonitor()
66
+ assert.equal(result.enabled, true)
67
+ })
68
+
69
+ it('enabled with string "true"', () => {
70
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: 'true' })
71
+ assert.equal(result.enabled, true)
72
+ })
73
+
74
+ it('enabled with string "1"', () => {
75
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: '1' })
76
+ assert.equal(result.enabled, true)
77
+ })
78
+
79
+ it('enabled run returns result with checkedFiles and drifts array', () => {
80
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: true })
81
+ assert.equal(result.enabled, true)
82
+ assert.ok(typeof result.checkedFiles === 'number')
83
+ assert.ok(Array.isArray(result.drifts))
84
+ assert.ok(result.checkedAt > 0)
85
+ })
86
+
87
+ it('second run with no changes produces zero drifts', () => {
88
+ // First run establishes baselines
89
+ integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: true })
90
+ // Second run with no changes
91
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: true })
92
+ assert.equal(result.drifts.length, 0)
93
+ })
94
+
95
+ it('detects file modification as drift', () => {
96
+ // Create a plugin file in the data/plugins dir
97
+ const pluginDir = path.join(process.env.DATA_DIR!, 'plugins')
98
+ fs.mkdirSync(pluginDir, { recursive: true })
99
+ const pluginFile = path.join(pluginDir, 'test-integrity-plugin.js')
100
+ fs.writeFileSync(pluginFile, 'module.exports = { name: "test" }')
101
+
102
+ // First run: baseline
103
+ integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: true })
104
+
105
+ // Modify the file
106
+ fs.writeFileSync(pluginFile, 'module.exports = { name: "modified" }')
107
+
108
+ // Second run: should detect drift
109
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: true })
110
+ const drift = result.drifts.find((d) => d.filePath === path.resolve(pluginFile))
111
+ assert.ok(drift, 'should detect modified plugin file')
112
+ assert.equal(drift!.type, 'modified')
113
+ assert.ok(drift!.previousHash)
114
+ assert.ok(drift!.nextHash)
115
+ assert.notEqual(drift!.previousHash, drift!.nextHash)
116
+ })
117
+
118
+ it('deleted plugin file is no longer in watch targets (no drift)', () => {
119
+ // pushIfExists skips non-existent files, so deletion means the file
120
+ // simply drops out of the watch targets — no drift is generated.
121
+ const pluginDir = path.join(process.env.DATA_DIR!, 'plugins')
122
+ fs.mkdirSync(pluginDir, { recursive: true })
123
+ const pluginFile = path.join(pluginDir, 'test-delete-plugin.js')
124
+ fs.writeFileSync(pluginFile, 'module.exports = {}')
125
+
126
+ // Baseline
127
+ integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: true })
128
+
129
+ // Delete
130
+ fs.unlinkSync(pluginFile)
131
+
132
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: true })
133
+ const drift = result.drifts.find((d) => d.filePath === path.resolve(pluginFile))
134
+ assert.equal(drift, undefined, 'deleted file should not appear as drift')
135
+ })
136
+
137
+ it('new plugin file is baselined without drift on first run', () => {
138
+ const pluginDir = path.join(process.env.DATA_DIR!, 'plugins')
139
+ fs.mkdirSync(pluginDir, { recursive: true })
140
+ const pluginFile = path.join(pluginDir, 'brand-new-plugin.js')
141
+ fs.writeFileSync(pluginFile, 'module.exports = { name: "new" }')
142
+
143
+ const result = integrityMonitor.runIntegrityMonitor({ integrityMonitorEnabled: true })
144
+ // First time seeing the file — establishes baseline, no drift
145
+ const drift = result.drifts.find((d) => d.filePath === path.resolve(pluginFile))
146
+ assert.equal(drift, undefined, 'new file on first run should not produce drift')
147
+ assert.ok(result.checkedFiles > 0)
148
+ })
149
+ })
@@ -0,0 +1,22 @@
1
+ export function safeJsonParse<T>(raw: unknown, fallback: T): T {
2
+ if (typeof raw !== 'string') return fallback
3
+ const trimmed = raw.trim()
4
+ if (!trimmed) return fallback
5
+ try {
6
+ return JSON.parse(trimmed) as T
7
+ } catch {
8
+ return fallback
9
+ }
10
+ }
11
+
12
+ export function safeJsonParseObject<T extends object = Record<string, unknown>>(raw: unknown): T | null {
13
+ const parsed = safeJsonParse<unknown>(raw, null)
14
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
15
+ ? parsed as T
16
+ : null
17
+ }
18
+
19
+ export function safeJsonParseArray<T = unknown>(raw: unknown): T[] | null {
20
+ const parsed = safeJsonParse<unknown>(raw, null)
21
+ return Array.isArray(parsed) ? parsed as T[] : null
22
+ }
@@ -117,17 +117,17 @@ function addRawMemory(data: {
117
117
  }): MemoryEntry {
118
118
  const id = crypto.randomBytes(6).toString('hex')
119
119
  const now = Date.now()
120
- stmts.insert.run(
121
- id,
122
- data.agentId || null,
123
- data.sessionId || null,
124
- data.category,
125
- data.title,
126
- data.content,
127
- data.metadata ? JSON.stringify(data.metadata) : null,
128
- now,
129
- now,
130
- )
120
+ stmts.insert.run({
121
+ id: data.id || 'mem-1',
122
+ agentId: data.agentId || null,
123
+ sessionId: data.sessionId || null,
124
+ taskId: data.taskId || null,
125
+ url: data.url || null,
126
+ category: data.category,
127
+ textContent: data.textContent || null,
128
+ createdAt: now,
129
+ updatedAt: now
130
+ })
131
131
  return {
132
132
  id,
133
133
  agentId: data.agentId || null,
@@ -392,7 +392,7 @@ describe('isolation between knowledge and agent memory', () => {
392
392
  })
393
393
 
394
394
  it('knowledge entries do not appear in agent-scoped memory list', () => {
395
- const agentMemories = (stmts.listByAgent.all('agent-xyz', 500) as Record<string, unknown>[]).map(rowToEntry)
395
+ const agentMemories = (stmts.listByAgent.all('agent-xyz') as Record<string, unknown>[]).map(rowToEntry)
396
396
  for (const e of agentMemories) {
397
397
  assert.notEqual(e.category, 'knowledge')
398
398
  assert.equal(e.agentId, 'agent-xyz')
@@ -402,7 +402,7 @@ describe('isolation between knowledge and agent memory', () => {
402
402
  it('knowledge entries do not appear in agent-scoped search', () => {
403
403
  const ftsQuery = buildFtsQuery('quantum entanglement')
404
404
  if (!ftsQuery) return
405
- const agentResults = (stmts.searchByAgent.all(ftsQuery, 'agent-xyz') as Record<string, unknown>[]).map(rowToEntry)
405
+ const agentResults = (stmts.searchByAgent.all(ftsQuery) as Record<string, unknown>[]).map(rowToEntry)
406
406
  for (const e of agentResults) {
407
407
  assert.equal(e.agentId, 'agent-xyz')
408
408
  }
@@ -1,4 +1,5 @@
1
1
  import * as cheerio from 'cheerio'
2
+ import { dedup } from '@/lib/shared-utils'
2
3
  import { truncate } from './session-tools/context'
3
4
 
4
5
  const BARE_LINK_RE = /https?:\/\/\S+/gi
@@ -11,7 +12,7 @@ export async function runLinkUnderstanding(message: string): Promise<string[]> {
11
12
  const links = message.match(BARE_LINK_RE)
12
13
  if (!links || links.length === 0) return []
13
14
 
14
- const uniqueLinks = Array.from(new Set(links)).slice(0, 3) // Limit to first 3 links
15
+ const uniqueLinks = dedup(links).slice(0, 3) // Limit to first 3 links
15
16
  const results: string[] = []
16
17
 
17
18
  for (const url of uniqueLinks) {
@@ -7,7 +7,7 @@ import {
7
7
  getCachedLlmResponse,
8
8
  resolveLlmResponseCacheConfig,
9
9
  setCachedLlmResponse,
10
- } from './llm-response-cache.ts'
10
+ } from './llm-response-cache'
11
11
 
12
12
  const HISTORY: Message[] = [
13
13
  { role: 'user', text: 'Plan a release.', time: 1 },
@@ -5,7 +5,7 @@ import path from 'node:path'
5
5
  import { spawnSync } from 'node:child_process'
6
6
  import { describe, it } from 'node:test'
7
7
 
8
- import { stripMainLoopMetaForPersistence } from './main-agent-loop.ts'
8
+ import { stripMainLoopMetaForPersistence } from './main-agent-loop'
9
9
 
10
10
  const repoRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '../../..')
11
11
 
@@ -43,9 +43,9 @@ function runWithTempDataDir(script: string) {
43
43
  /** Shared setup script that creates one agent and one heartbeat-enabled main session */
44
44
  function sessionSetupScript(sessionOverrides?: string, extraSessions?: string): string {
45
45
  return `
46
- const storageMod = await import('./src/lib/server/storage.ts')
46
+ const storageMod = await import('./src/lib/server/storage')
47
47
  const storage = storageMod.default || storageMod['module.exports'] || storageMod
48
- const mainLoopMod = await import('./src/lib/server/main-agent-loop.ts')
48
+ const mainLoopMod = await import('./src/lib/server/main-agent-loop')
49
49
  const mainLoop = mainLoopMod.default || mainLoopMod['module.exports'] || mainLoopMod
50
50
 
51
51
  storage.saveAgents({
@@ -195,6 +195,68 @@ describe('main-agent-loop advanced', () => {
195
195
  assert.equal(output.followupOk, null, 'no followup on terminal ack')
196
196
  })
197
197
 
198
+ it('resets metadata miss count when structured metadata returns and keeps terminal acks at zero', () => {
199
+ const meta = heartbeatMetaLine('progress', 'deploy', 'continue')
200
+ const output = runWithTempDataDir(`
201
+ ${sessionSetupScript()}
202
+
203
+ const miss1 = mainLoop.handleMainLoopRunResult({
204
+ sessionId: 'main',
205
+ message: 'Continue objective.',
206
+ internal: true,
207
+ source: 'heartbeat',
208
+ resultText: 'Still working without structured metadata.',
209
+ })
210
+ const state1 = mainLoop.getMainLoopStateForSession('main')
211
+
212
+ const miss2 = mainLoop.handleMainLoopRunResult({
213
+ sessionId: 'main',
214
+ message: 'Continue objective.',
215
+ internal: true,
216
+ source: 'heartbeat',
217
+ resultText: 'Another plain-text update without metadata.',
218
+ })
219
+ const state2 = mainLoop.getMainLoopStateForSession('main')
220
+
221
+ const withMeta = mainLoop.handleMainLoopRunResult({
222
+ sessionId: 'main',
223
+ message: 'Continue objective.',
224
+ internal: true,
225
+ source: 'heartbeat',
226
+ resultText: \`Metadata restored.\\n${meta}\`,
227
+ })
228
+ const state3 = mainLoop.getMainLoopStateForSession('main')
229
+
230
+ const terminalAck = mainLoop.handleMainLoopRunResult({
231
+ sessionId: 'main',
232
+ message: 'Continue objective.',
233
+ internal: true,
234
+ source: 'heartbeat',
235
+ resultText: 'HEARTBEAT_OK',
236
+ })
237
+ const state4 = mainLoop.getMainLoopStateForSession('main')
238
+
239
+ console.log(JSON.stringify({
240
+ followupMiss1: miss1,
241
+ followupMiss2: miss2,
242
+ followupWithMeta: withMeta,
243
+ followupTerminalAck: terminalAck,
244
+ missCount1: state1?.metaMissCount ?? -1,
245
+ missCount2: state2?.metaMissCount ?? -1,
246
+ missCount3: state3?.metaMissCount ?? -1,
247
+ missCount4: state4?.metaMissCount ?? -1,
248
+ statusAfterAck: state4?.status ?? null,
249
+ }))
250
+ `)
251
+
252
+ assert.equal(output.missCount1, 1)
253
+ assert.equal(output.missCount2, 2)
254
+ assert.equal(output.missCount3, 0, 'structured metadata resets the miss counter')
255
+ assert.equal(output.missCount4, 0, 'terminal ack should not count as a metadata miss')
256
+ assert.equal(output.statusAfterAck, 'ok')
257
+ assert.equal(output.followupTerminalAck, null)
258
+ })
259
+
198
260
  // ─────────────────────────────────────────────────────────────────────
199
261
  // 3. Chain reset on error
200
262
  // ─────────────────────────────────────────────────────────────────────
@@ -35,9 +35,9 @@ function runWithTempDataDir(script: string) {
35
35
  describe('main-agent-loop', () => {
36
36
  it('fans out events to durable main sessions and shapes heartbeat prompts', () => {
37
37
  const output = runWithTempDataDir(`
38
- const storageMod = await import('./src/lib/server/storage.ts')
38
+ const storageMod = await import('./src/lib/server/storage')
39
39
  const storage = storageMod.default || storageMod['module.exports'] || storageMod
40
- const mainLoopMod = await import('./src/lib/server/main-agent-loop.ts')
40
+ const mainLoopMod = await import('./src/lib/server/main-agent-loop')
41
41
  const mainLoop = mainLoopMod.default || mainLoopMod['module.exports'] || mainLoopMod
42
42
 
43
43
  storage.saveAgents({
@@ -113,9 +113,9 @@ describe('main-agent-loop', () => {
113
113
 
114
114
  it('updates state from heartbeat metadata and returns a bounded follow-up', () => {
115
115
  const output = runWithTempDataDir(`
116
- const storageMod = await import('./src/lib/server/storage.ts')
116
+ const storageMod = await import('./src/lib/server/storage')
117
117
  const storage = storageMod.default || storageMod['module.exports'] || storageMod
118
- const mainLoopMod = await import('./src/lib/server/main-agent-loop.ts')
118
+ const mainLoopMod = await import('./src/lib/server/main-agent-loop')
119
119
  const mainLoop = mainLoopMod.default || mainLoopMod['module.exports'] || mainLoopMod
120
120
 
121
121
  storage.saveAgents({
@@ -195,9 +195,9 @@ describe('main-agent-loop', () => {
195
195
 
196
196
  it('does not keep chaining when the heartbeat explicitly reports ok', () => {
197
197
  const output = runWithTempDataDir(`
198
- const storageMod = await import('./src/lib/server/storage.ts')
198
+ const storageMod = await import('./src/lib/server/storage')
199
199
  const storage = storageMod.default || storageMod['module.exports'] || storageMod
200
- const mainLoopMod = await import('./src/lib/server/main-agent-loop.ts')
200
+ const mainLoopMod = await import('./src/lib/server/main-agent-loop')
201
201
  const mainLoop = mainLoopMod.default || mainLoopMod['module.exports'] || mainLoopMod
202
202
 
203
203
  storage.saveAgents({
@@ -1,3 +1,4 @@
1
+ import { hmrSingleton } from '@/lib/shared-utils'
1
2
  import type { GoalContract, Message, MessageToolEvent, Session } from '@/types'
2
3
  import { mergeGoalContracts, parseGoalContractFromText, parseMainLoopPlan, parseMainLoopReview } from './autonomy-contract'
3
4
  import { enqueueSystemEvent } from './system-events'
@@ -77,9 +78,7 @@ export interface HandleMainLoopRunResultInput {
77
78
 
78
79
  type MainSessionLike = Partial<Session> & Record<string, unknown>
79
80
 
80
- const globalKey = '__swarmclaw_main_loop_state__' as const
81
- const globalScope = globalThis as typeof globalThis & { [globalKey]?: Map<string, MainLoopState> }
82
- const stateMap = globalScope[globalKey] ?? (globalScope[globalKey] = new Map<string, MainLoopState>())
81
+ const stateMap = hmrSingleton('__swarmclaw_main_loop_state__', () => new Map<string, MainLoopState>())
83
82
 
84
83
  function now(): number {
85
84
  return Date.now()
@@ -506,6 +505,21 @@ export function getMainLoopStateForSession(sessionId: string): MainLoopState | n
506
505
  return state ? normalizeState(state) : null
507
506
  }
508
507
 
508
+ /**
509
+ * Remove stateMap entries for sessions that no longer exist.
510
+ * Called periodically by the daemon health sweep.
511
+ */
512
+ export function pruneMainLoopState(liveSessionIds: Set<string>): number {
513
+ let removed = 0
514
+ for (const sessionId of stateMap.keys()) {
515
+ if (!liveSessionIds.has(sessionId)) {
516
+ stateMap.delete(sessionId)
517
+ removed++
518
+ }
519
+ }
520
+ return removed
521
+ }
522
+
509
523
  export function setMainLoopStateForSession(sessionId: string, patch: Partial<MainLoopState>): MainLoopState | null {
510
524
  const current = getOrCreateState(sessionId)
511
525
  if (!current) return null
@@ -608,15 +622,15 @@ export function handleMainLoopRunResult(input: HandleMainLoopRunResultInput): Ma
608
622
  state.updatedAt = nowTs
609
623
  state.missionTokens += Math.max(0, Math.trunc((input.inputTokens || 0) + (input.outputTokens || 0)))
610
624
  state.missionCostUsd += Math.max(0, Number(input.estimatedCost || 0))
611
- state.metaMissCount = heartbeat || plan || review ? 0 : state.metaMissCount + 1
625
+ const cleanedResult = persistedText.trim()
626
+ const waitingForExternal = extractWaitSignal(resultText, toolEvents)
627
+ const gotTerminalAck = /^HEARTBEAT_OK$/i.test(cleanedResult) || /^NO_MESSAGE$/i.test(cleanedResult)
628
+ state.metaMissCount = heartbeat || plan || review || gotTerminalAck ? 0 : state.metaMissCount + 1
612
629
 
613
630
  if (input.internal) {
614
631
  state.pendingEvents = []
615
632
  }
616
633
 
617
- const cleanedResult = persistedText.trim()
618
- const waitingForExternal = extractWaitSignal(resultText, toolEvents)
619
- const gotTerminalAck = /^HEARTBEAT_OK$/i.test(cleanedResult) || /^NO_MESSAGE$/i.test(cleanedResult)
620
634
  const needsReplan = review?.needs_replan === true || ((review?.confidence ?? 1) < 0.45)
621
635
  const limit = followupLimit()
622
636
 
@@ -7,7 +7,7 @@ import {
7
7
  mcpToolsToLangChain,
8
8
  disconnectMcpServer,
9
9
  connectMcpServer,
10
- } from './mcp-client.ts'
10
+ } from './mcp-client'
11
11
 
12
12
  /* ============================================================
13
13
  * 1. sanitizeName
@@ -1,6 +1,6 @@
1
1
  import assert from 'node:assert/strict'
2
2
  import { test } from 'node:test'
3
- import { runMcpConformanceCheck } from './mcp-conformance.ts'
3
+ import { runMcpConformanceCheck } from './mcp-conformance'
4
4
 
5
5
  test('runMcpConformanceCheck reports connect/list failure for unsupported transport', async () => {
6
6
  const result = await runMcpConformanceCheck({
@@ -1,5 +1,6 @@
1
1
  import type { McpServerConfig } from '@/types'
2
2
  import { connectMcpServer, disconnectMcpServer } from './mcp-client'
3
+ import { errorMessage } from '@/lib/shared-utils'
3
4
 
4
5
  export interface McpConformanceIssue {
5
6
  level: 'error' | 'warning'
@@ -209,7 +210,7 @@ export async function runMcpConformanceCheck(
209
210
  issues.push({
210
211
  level: 'error',
211
212
  code: 'smoke_tool_failed',
212
- message: err instanceof Error ? err.message : String(err),
213
+ message: errorMessage(err),
213
214
  toolName: smokeToolName,
214
215
  })
215
216
  } finally {
@@ -220,7 +221,7 @@ export async function runMcpConformanceCheck(
220
221
  issues.push({
221
222
  level: 'error',
222
223
  code: 'connect_or_list_failed',
223
- message: err instanceof Error ? err.message : String(err),
224
+ message: errorMessage(err),
224
225
  })
225
226
  } finally {
226
227
  if (client && transport) {
@@ -1,5 +1,6 @@
1
1
  import { getMemoryDb } from './memory-db'
2
2
  import { HumanMessage } from '@langchain/core/messages'
3
+ import { errorMessage } from '@/lib/shared-utils'
3
4
 
4
5
  /**
5
6
  * Produce daily digests per agent and prune stale entries.
@@ -89,7 +90,7 @@ export async function runDailyConsolidation(): Promise<{
89
90
 
90
91
  digestsCreated++
91
92
  } catch (err: unknown) {
92
- errors.push(`Agent ${agentId}: ${err instanceof Error ? err.message : String(err)}`)
93
+ errors.push(`Agent ${agentId}: ${errorMessage(err)}`)
93
94
  }
94
95
  }
95
96