nodal-agents 0.7.8 → 0.7.95

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 (226) hide show
  1. package/README.md +7 -6
  2. package/cli.js +73 -17
  3. package/migrations/0066_schedule_notify_channel.sql +19 -0
  4. package/migrations/0067_webhook_notify_channel.sql +12 -0
  5. package/migrations/meta/_journal.json +14 -0
  6. package/package.json +1 -1
  7. package/runner.js +407 -178
  8. package/web/.next/BUILD_ID +1 -1
  9. package/web/.next/app-path-routes-manifest.json +8 -8
  10. package/web/.next/build-manifest.json +2 -2
  11. package/web/.next/prerender-manifest.json +3 -3
  12. package/web/.next/required-server-files.json +1 -0
  13. package/web/.next/server/app/(dashboard)/agents/[id]/channels/page.js +2 -2
  14. package/web/.next/server/app/(dashboard)/agents/[id]/channels/page.js.nft.json +1 -1
  15. package/web/.next/server/app/(dashboard)/agents/[id]/channels/page_client-reference-manifest.js +1 -1
  16. package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js +5 -5
  17. package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js.nft.json +1 -1
  18. package/web/.next/server/app/(dashboard)/agents/[id]/edit/page_client-reference-manifest.js +1 -1
  19. package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js +1 -1
  20. package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js.nft.json +1 -1
  21. package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page_client-reference-manifest.js +1 -1
  22. package/web/.next/server/app/(dashboard)/agents/page.js +2 -2
  23. package/web/.next/server/app/(dashboard)/agents/page.js.nft.json +1 -1
  24. package/web/.next/server/app/(dashboard)/agents/page_client-reference-manifest.js +1 -1
  25. package/web/.next/server/app/(dashboard)/approvals/page.js +2 -2
  26. package/web/.next/server/app/(dashboard)/approvals/page.js.nft.json +1 -1
  27. package/web/.next/server/app/(dashboard)/approvals/page_client-reference-manifest.js +1 -1
  28. package/web/.next/server/app/(dashboard)/automations/page.js +2 -2
  29. package/web/.next/server/app/(dashboard)/automations/page.js.nft.json +1 -1
  30. package/web/.next/server/app/(dashboard)/automations/page_client-reference-manifest.js +1 -1
  31. package/web/.next/server/app/(dashboard)/chat/page.js +2 -2
  32. package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
  33. package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
  34. package/web/.next/server/app/(dashboard)/connectors/page.js +2 -2
  35. package/web/.next/server/app/(dashboard)/connectors/page.js.nft.json +1 -1
  36. package/web/.next/server/app/(dashboard)/connectors/page_client-reference-manifest.js +1 -1
  37. package/web/.next/server/app/(dashboard)/credentials/page.js +2 -2
  38. package/web/.next/server/app/(dashboard)/credentials/page.js.nft.json +1 -1
  39. package/web/.next/server/app/(dashboard)/credentials/page_client-reference-manifest.js +1 -1
  40. package/web/.next/server/app/(dashboard)/jobs/[id]/page.js +2 -2
  41. package/web/.next/server/app/(dashboard)/jobs/[id]/page.js.nft.json +1 -1
  42. package/web/.next/server/app/(dashboard)/jobs/[id]/page_client-reference-manifest.js +1 -1
  43. package/web/.next/server/app/(dashboard)/jobs/page.js +2 -2
  44. package/web/.next/server/app/(dashboard)/jobs/page.js.nft.json +1 -1
  45. package/web/.next/server/app/(dashboard)/jobs/page_client-reference-manifest.js +1 -1
  46. package/web/.next/server/app/(dashboard)/learned-skills/page.js +2 -2
  47. package/web/.next/server/app/(dashboard)/learned-skills/page.js.nft.json +1 -1
  48. package/web/.next/server/app/(dashboard)/learned-skills/page_client-reference-manifest.js +1 -1
  49. package/web/.next/server/app/(dashboard)/llm-providers/page.js +2 -2
  50. package/web/.next/server/app/(dashboard)/llm-providers/page.js.nft.json +1 -1
  51. package/web/.next/server/app/(dashboard)/llm-providers/page_client-reference-manifest.js +1 -1
  52. package/web/.next/server/app/(dashboard)/logs/page.js +2 -2
  53. package/web/.next/server/app/(dashboard)/logs/page.js.nft.json +1 -1
  54. package/web/.next/server/app/(dashboard)/logs/page_client-reference-manifest.js +1 -1
  55. package/web/.next/server/app/(dashboard)/mcp/page.js +2 -2
  56. package/web/.next/server/app/(dashboard)/mcp/page.js.nft.json +1 -1
  57. package/web/.next/server/app/(dashboard)/mcp/page_client-reference-manifest.js +1 -1
  58. package/web/.next/server/app/(dashboard)/memories/page.js +2 -2
  59. package/web/.next/server/app/(dashboard)/memories/page.js.nft.json +1 -1
  60. package/web/.next/server/app/(dashboard)/memories/page_client-reference-manifest.js +1 -1
  61. package/web/.next/server/app/(dashboard)/page.js +4 -4
  62. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  63. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  64. package/web/.next/server/app/(dashboard)/settings/page.js +2 -2
  65. package/web/.next/server/app/(dashboard)/settings/page.js.nft.json +1 -1
  66. package/web/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
  67. package/web/.next/server/app/(dashboard)/settings/root-context/page.js +2 -2
  68. package/web/.next/server/app/(dashboard)/settings/root-context/page.js.nft.json +1 -1
  69. package/web/.next/server/app/(dashboard)/settings/root-context/page_client-reference-manifest.js +1 -1
  70. package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js +2 -2
  71. package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js.nft.json +1 -1
  72. package/web/.next/server/app/(dashboard)/skills/[id]/edit/page_client-reference-manifest.js +1 -1
  73. package/web/.next/server/app/(dashboard)/skills/new/page.js +1 -1
  74. package/web/.next/server/app/(dashboard)/skills/new/page.js.nft.json +1 -1
  75. package/web/.next/server/app/(dashboard)/skills/new/page_client-reference-manifest.js +1 -1
  76. package/web/.next/server/app/(dashboard)/skills/page.js +2 -2
  77. package/web/.next/server/app/(dashboard)/skills/page.js.nft.json +1 -1
  78. package/web/.next/server/app/(dashboard)/skills/page_client-reference-manifest.js +1 -1
  79. package/web/.next/server/app/_global-error/page.js +2 -2
  80. package/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  81. package/web/.next/server/app/_global-error.html +1 -1
  82. package/web/.next/server/app/_global-error.rsc +3 -3
  83. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +3 -3
  84. package/web/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  85. package/web/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  86. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  87. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  88. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  89. package/web/.next/server/app/_not-found/page.js +1 -1
  90. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/app/_not-found.html +1 -1
  92. package/web/.next/server/app/_not-found.rsc +4 -4
  93. package/web/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  94. package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  95. package/web/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  96. package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  97. package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  98. package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  99. package/web/.next/server/app/login/page.js +2 -2
  100. package/web/.next/server/app/login/page_client-reference-manifest.js +1 -1
  101. package/web/.next/server/app/onboarding/page.js +192 -192
  102. package/web/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
  103. package/web/.next/server/app-paths-manifest.json +8 -8
  104. package/web/.next/server/chunks/1466.js +1 -0
  105. package/web/.next/server/chunks/1767.js +1 -0
  106. package/web/.next/server/chunks/3308.js +1 -0
  107. package/web/.next/server/chunks/4162.js +1 -1
  108. package/web/.next/server/chunks/4574.js +1 -1
  109. package/web/.next/server/chunks/5300.js +1 -0
  110. package/web/.next/server/chunks/6184.js +1 -0
  111. package/web/.next/server/chunks/6539.js +1 -0
  112. package/web/.next/server/chunks/7124.js +20 -20
  113. package/web/.next/server/chunks/8380.js +1 -0
  114. package/web/.next/server/chunks/9000.js +1 -0
  115. package/web/.next/server/chunks/9137.js +1 -0
  116. package/web/.next/server/chunks/{3847.js → 9507.js} +4 -4
  117. package/web/.next/server/chunks/9982.js +1 -0
  118. package/web/.next/server/middleware-build-manifest.js +1 -1
  119. package/web/.next/server/pages/404.html +1 -1
  120. package/web/.next/server/pages/500.html +1 -1
  121. package/web/.next/server/server-reference-manifest.js +1 -1
  122. package/web/.next/server/server-reference-manifest.json +1 -1
  123. package/web/.next/static/chunks/1498-d0d434749bb18cd2.js +1 -0
  124. package/web/.next/static/chunks/2406-66d8aa55b97d75c3.js +1 -0
  125. package/web/.next/static/chunks/{2491-cc8dee1fc55e1e38.js → 2491-b14243a2db419dd9.js} +1 -1
  126. package/web/.next/static/chunks/3966-679a4c07d6db8ee6.js +1 -0
  127. package/web/.next/static/chunks/4095-f76de40c53ae3d47.js +1 -0
  128. package/web/.next/static/chunks/4766-d80c537321cca448.js +1 -0
  129. package/web/.next/static/chunks/5876-4423499f49214575.js +1 -0
  130. package/web/.next/static/chunks/5953-54a29fc1e2d84c0c.js +1 -0
  131. package/web/.next/static/chunks/7829-78f753c50b408cde.js +1 -0
  132. package/web/.next/static/chunks/8542-ba178b7c68e14cf3.js +1 -0
  133. package/web/.next/static/chunks/8719-8ab59c5faa49c9ab.js +1 -0
  134. package/web/.next/static/chunks/9387-f5283e69fe4d4e83.js +1 -0
  135. package/web/.next/static/chunks/9567-db1512a42580d07c.js +1 -0
  136. package/web/.next/static/chunks/{8097-bad68cd78aa59a10.js → 9583-f93faba69d4c1f57.js} +1 -1
  137. package/web/.next/static/chunks/app/(dashboard)/agents/[id]/channels/page-d40d5db150472c4f.js +1 -0
  138. package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-74934ff99c3b1261.js +6 -0
  139. package/web/.next/static/chunks/app/(dashboard)/agents/[id]/telegram/page-d40d5db150472c4f.js +1 -0
  140. package/web/.next/static/chunks/app/(dashboard)/agents/page-8ec50d6f48425813.js +1 -0
  141. package/web/.next/static/chunks/app/(dashboard)/approvals/page-d907a7c12917ab8a.js +1 -0
  142. package/web/.next/static/chunks/app/(dashboard)/automations/page-dd20cb7f04d22cca.js +1 -0
  143. package/web/.next/static/chunks/app/(dashboard)/chat/page-e9ffd3d09a46ad38.js +1 -0
  144. package/web/.next/static/chunks/app/(dashboard)/connectors/page-52828e317e7a63e6.js +1 -0
  145. package/web/.next/static/chunks/app/(dashboard)/credentials/page-f84a3f991cf69228.js +1 -0
  146. package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-a0866da7952de417.js +1 -0
  147. package/web/.next/static/chunks/app/(dashboard)/jobs/page-aade90b389efb824.js +1 -0
  148. package/web/.next/static/chunks/app/(dashboard)/layout-10486dd8640fb6a0.js +1 -0
  149. package/web/.next/static/chunks/app/(dashboard)/learned-skills/page-e22d1e586ac8579c.js +1 -0
  150. package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-46858f7d737ee49b.js +1 -0
  151. package/web/.next/static/chunks/app/(dashboard)/logs/page-17dd2080f6196b01.js +1 -0
  152. package/web/.next/static/chunks/app/(dashboard)/mcp/page-81e83a08c7b65719.js +1 -0
  153. package/web/.next/static/chunks/app/(dashboard)/memories/page-0336ba541b5ab006.js +1 -0
  154. package/web/.next/static/chunks/app/(dashboard)/page-3bf3a72ec95863d8.js +1 -0
  155. package/web/.next/static/chunks/app/(dashboard)/settings/page-0ee25e256bc3097f.js +1 -0
  156. package/web/.next/static/chunks/app/(dashboard)/settings/root-context/page-76653439bca06d8c.js +1 -0
  157. package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-de1bf934a2c5e8b2.js +1 -0
  158. package/web/.next/static/chunks/app/(dashboard)/skills/new/page-a9640274b845190a.js +1 -0
  159. package/web/.next/static/chunks/app/(dashboard)/skills/page-928b6f005ba4dafb.js +1 -0
  160. package/web/.next/static/chunks/app/_global-error/page-d40d5db150472c4f.js +1 -0
  161. package/web/.next/static/chunks/app/_not-found/page-d40d5db150472c4f.js +1 -0
  162. package/web/.next/static/chunks/app/api/auth/[...all]/route-d40d5db150472c4f.js +1 -0
  163. package/web/.next/static/chunks/app/api/health/route-d40d5db150472c4f.js +1 -0
  164. package/web/.next/static/chunks/app/api/oauth/[provider]/callback/route-d40d5db150472c4f.js +1 -0
  165. package/web/.next/static/chunks/app/api/oauth/[provider]/start/route-d40d5db150472c4f.js +1 -0
  166. package/web/.next/static/chunks/app/auth/callback/route-d40d5db150472c4f.js +1 -0
  167. package/web/.next/static/chunks/app/error-ec052ef28a67f9b0.js +1 -0
  168. package/web/.next/static/chunks/app/login/page-97a658fa01e36c3f.js +1 -0
  169. package/web/.next/static/chunks/app/onboarding/page-d7c5a220f9244b45.js +26 -0
  170. package/web/.next/static/chunks/next/dist/client/components/builtin/app-error-d40d5db150472c4f.js +1 -0
  171. package/web/.next/static/chunks/next/dist/client/components/builtin/forbidden-d40d5db150472c4f.js +1 -0
  172. package/web/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d40d5db150472c4f.js +1 -0
  173. package/web/.next/static/css/0f40c037c3aa9ff2.css +3 -0
  174. package/web/server.js +1 -1
  175. package/web/.next/server/chunks/6823.js +0 -1
  176. package/web/.next/server/chunks/715.js +0 -1
  177. package/web/.next/server/chunks/8308.js +0 -1
  178. package/web/.next/server/chunks/8430.js +0 -1
  179. package/web/.next/static/chunks/1361-5bc59efe9312f6ad.js +0 -1
  180. package/web/.next/static/chunks/2716-55970bc6e3910ccf.js +0 -1
  181. package/web/.next/static/chunks/3114-d846062bc8434b58.js +0 -1
  182. package/web/.next/static/chunks/370-554f47928c2648ee.js +0 -1
  183. package/web/.next/static/chunks/3763-2fa54c0e83122050.js +0 -1
  184. package/web/.next/static/chunks/3865-9aa6dedee678d08f.js +0 -1
  185. package/web/.next/static/chunks/8447-ec639f4e1d42d912.js +0 -1
  186. package/web/.next/static/chunks/9775-dad785c12d658539.js +0 -1
  187. package/web/.next/static/chunks/9836-5beba80ab70ed698.js +0 -1
  188. package/web/.next/static/chunks/app/(dashboard)/agents/[id]/channels/page-f2413d131f4e0bdf.js +0 -1
  189. package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-5ab1dcbc58720645.js +0 -6
  190. package/web/.next/static/chunks/app/(dashboard)/agents/[id]/telegram/page-9397b9b7fccbb444.js +0 -1
  191. package/web/.next/static/chunks/app/(dashboard)/agents/page-6ac1ebd6598d7da7.js +0 -1
  192. package/web/.next/static/chunks/app/(dashboard)/approvals/page-76247d88c06bf203.js +0 -1
  193. package/web/.next/static/chunks/app/(dashboard)/automations/page-901227b6d047b2b7.js +0 -1
  194. package/web/.next/static/chunks/app/(dashboard)/chat/page-72f0688180411e7e.js +0 -1
  195. package/web/.next/static/chunks/app/(dashboard)/connectors/page-59b11d68fd1107c3.js +0 -1
  196. package/web/.next/static/chunks/app/(dashboard)/credentials/page-445228b74058e9c2.js +0 -1
  197. package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-d7153b1b30dc6b78.js +0 -1
  198. package/web/.next/static/chunks/app/(dashboard)/jobs/page-65cb4b9970d04210.js +0 -1
  199. package/web/.next/static/chunks/app/(dashboard)/layout-16531dffd6974eb5.js +0 -1
  200. package/web/.next/static/chunks/app/(dashboard)/learned-skills/page-0211eb7caae5531d.js +0 -1
  201. package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-c06f48cf0fbe5d63.js +0 -1
  202. package/web/.next/static/chunks/app/(dashboard)/logs/page-5080105f905f2d05.js +0 -1
  203. package/web/.next/static/chunks/app/(dashboard)/mcp/page-1aed0a1ab4459e69.js +0 -1
  204. package/web/.next/static/chunks/app/(dashboard)/memories/page-addb7eb81a34188b.js +0 -1
  205. package/web/.next/static/chunks/app/(dashboard)/page-5e99a1628397f82c.js +0 -1
  206. package/web/.next/static/chunks/app/(dashboard)/settings/page-ffff6582f6a33a65.js +0 -1
  207. package/web/.next/static/chunks/app/(dashboard)/settings/root-context/page-f42cc0aff627bd35.js +0 -1
  208. package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-6022f41d61c64f4f.js +0 -1
  209. package/web/.next/static/chunks/app/(dashboard)/skills/new/page-a421b5020aa53715.js +0 -1
  210. package/web/.next/static/chunks/app/(dashboard)/skills/page-e8f83c423960e91d.js +0 -1
  211. package/web/.next/static/chunks/app/_global-error/page-9397b9b7fccbb444.js +0 -1
  212. package/web/.next/static/chunks/app/_not-found/page-9397b9b7fccbb444.js +0 -1
  213. package/web/.next/static/chunks/app/api/auth/[...all]/route-9397b9b7fccbb444.js +0 -1
  214. package/web/.next/static/chunks/app/api/health/route-9397b9b7fccbb444.js +0 -1
  215. package/web/.next/static/chunks/app/api/oauth/[provider]/callback/route-9397b9b7fccbb444.js +0 -1
  216. package/web/.next/static/chunks/app/api/oauth/[provider]/start/route-9397b9b7fccbb444.js +0 -1
  217. package/web/.next/static/chunks/app/auth/callback/route-9397b9b7fccbb444.js +0 -1
  218. package/web/.next/static/chunks/app/error-dc3b2db3bdb5b34e.js +0 -1
  219. package/web/.next/static/chunks/app/login/page-a6993d175f94d322.js +0 -1
  220. package/web/.next/static/chunks/app/onboarding/page-9619ad033b220394.js +0 -26
  221. package/web/.next/static/chunks/next/dist/client/components/builtin/app-error-9397b9b7fccbb444.js +0 -1
  222. package/web/.next/static/chunks/next/dist/client/components/builtin/forbidden-9397b9b7fccbb444.js +0 -1
  223. package/web/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9397b9b7fccbb444.js +0 -1
  224. package/web/.next/static/css/637b48680bc0d57a.css +0 -3
  225. /package/web/.next/static/{29LavAHsyomtNE9YjHNlk → TWzSfBwiIIU81SgNxXcIw}/_buildManifest.js +0 -0
  226. /package/web/.next/static/{29LavAHsyomtNE9YjHNlk → TWzSfBwiIIU81SgNxXcIw}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Your AI agents. Your data. Your machine.**
4
4
 
5
- A self-hosted platform for building and orchestrating a **team of AI agents** on your own hardware — each with its own personality, tools, memory, and model. Talk to them in the dashboard or on Telegram; they research, write files, call your connectors, and delegate to each other to get the job done.
5
+ A self-hosted platform for building and orchestrating a **team of AI agents** on your own hardware — each with its own personality, tools, memory, and model. Talk to them in the dashboard, or on Telegram, Discord, Slack, and WhatsApp; they research, write files, call your connectors, and delegate to each other to get the job done.
6
6
 
7
7
  **No SaaS lock-in. No per-token markup. No cloud roundtrip.** Two commands to install, runs on any machine with Node 22+ (Mac, Windows, Linux), and works with **any LLM** — frontier or local, paid or free.
8
8
 
@@ -10,7 +10,7 @@ A self-hosted platform for building and orchestrating a **team of AI agents** on
10
10
  [![Node](https://img.shields.io/badge/node-22%2B-339933?logo=node.js&logoColor=white)](https://nodejs.org)
11
11
  [![TypeScript](https://img.shields.io/badge/typescript-strict-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org)
12
12
  [![Docs](https://img.shields.io/badge/docs-online-3565ff)](https://kwintspiracy.github.io/nodal-agents/)
13
- [![Changelog](https://img.shields.io/badge/changelog-v0.6.8-d4ff2e)](CHANGELOG.md)
13
+ [![Changelog](https://img.shields.io/npm/v/nodal-agents?label=changelog&color=d4ff2e)](CHANGELOG.md)
14
14
 
15
15
  | Home dashboard — light theme | Agent detail — dark theme |
16
16
  | :---: | :---: |
@@ -70,18 +70,20 @@ Every agent runs on the model **you** choose, with the tools **you** grant, in a
70
70
 
71
71
  ## Available now
72
72
 
73
- **Models** — Anthropic · OpenAI · Google · Groq · Mistral · OpenRouter · **native DeepSeek** (`api.deepseek.com`) · **native MiniMax** (`api.minimax.io`) · any local model (LM Studio, Ollama). One key per provider; each agent picks its own model.
73
+ **Models** — Anthropic · OpenAI · Google · Groq · Mistral · OpenRouter · **native DeepSeek** (`api.deepseek.com`) · **native MiniMax** (`api.minimax.io`) · **native Moonshot / Kimi** (`api.moonshot.ai`) · any local model (LM Studio, Ollama). One key per provider; each agent picks its own model.
74
74
 
75
75
  **Connectors** — multi-instance (Gmail perso *and* boulot on one install), managed from the dashboard:
76
76
  - *OAuth* — Airtable · Calendar · Docs · Gmail · Google Drive · Notion · Sheets
77
- - *API key* — Airtable · Apify · Firecrawl · Notion · Tavily
77
+ - *API key* — Airtable · Apify · Firecrawl · Notion · Poyo · Tavily
78
78
 
79
79
  **MCP servers** — over Streamable HTTP *and* stdio, plus add/edit your own:
80
80
  Apify · Blender · Cogni Cortex · Composio · Fetch · Filesystem · Git · GitHub · KeyShot · Linear · n8n · Notion · Perplexity · Photoshop · Playwright · PostgreSQL · Sentry · Stripe · Supabase · Unity · Unreal Engine
81
81
 
82
82
  **Skills** — built-in: office editing (Excel/Word/PowerPoint), shell execution, Obsidian, Telegram etiquette, task planning, markdown output, citation discipline, research methodology, results delivery, language mirroring, HTML design. Plus **install any community `SKILL.md`** from GitHub / skills.sh / ClawHub — and agents can **write their own**.
83
83
 
84
- **Channels** — Telegram (long-poll, multi-agent routing via `/ask <slug>`, group-chat filters, conversation continuity) and the dashboard chat.
84
+ **Channels** — Telegram (long-poll, multi-agent routing via `/ask <slug>`, group-chat filters, conversation continuity) · Discord (bot gateway) · Slack (Socket Mode) · WhatsApp (QR pairing) — and the dashboard chat. Approvals, images, and files flow over every channel, with graceful fallbacks where a channel lacks buttons.
85
+
86
+ **Event triggers** — inbound **webhooks** (`POST /webhooks/<slug>/<secret>` starts a job from any external service) and **watchers** (recurring polls with a capped daily budget and overlap protection).
85
87
 
86
88
  **Other** — shell execution (`run_command`, approval-gated), per-agent sandboxed filesystem folders, cron automations, tool-call audit log, full job transcripts.
87
89
 
@@ -172,7 +174,6 @@ Used daily by the maintainer; stable enough for personal production. **Pre-1.0**
172
174
  - **MCP OAuth** → unlocks Linear, Notion remote, GitHub remote, Atlassian, Sentry, and the rest of the SaaS-as-MCP ecosystem.
173
175
  - **Dry-run + test-workflow meta-tool** → preview what the ROOT would do before it runs.
174
176
  - **Bundled pgvector** → semantic memory search out of the box (today: keyword fallback).
175
- - **More channels** → Discord, Slack, and beyond Telegram.
176
177
 
177
178
  ---
178
179
 
package/cli.js CHANGED
@@ -12216,17 +12216,30 @@ var init_model_catalog = __esm({
12216
12216
  contextWindow: 4e5
12217
12217
  }
12218
12218
  ],
12219
+ // ─── Native Google (generativelanguage.googleapis.com) ──────────────────────
12220
+ // gemini-2.0-flash and gemini-2.5-pro were verified live (2026-07-12, real
12221
+ // key) to 404 / be shut down — dropped per product decision (family 3.x
12222
+ // only in the native catalog; gemini-2.5-flash deliberately NOT added).
12223
+ // Both entries below confirmed alive via ai.google.dev/gemini-api/docs/models
12224
+ // and openrouter.ai/google/… (2026-07-12): 1M-token context window, native
12225
+ // reasoning ("thinking") models, multimodal (text/image/video/audio/PDF).
12226
+ // forcedToolChoice:false — matches this file's reasoning-model convention
12227
+ // (MiniMax M3, Moonshot, GLM 5.2): don't force tool_choice on a thinking
12228
+ // model, let the runtime completion floor relax it to 'auto'. google.ts's
12229
+ // fetch shim injects generationConfig.thinkingConfig for these two entries
12230
+ // (reasoning:true gates it) so the API returns the chain-of-thought the
12231
+ // execute.ts round-trip needs across tool-call turns.
12219
12232
  google: [
12220
12233
  {
12221
- modelId: "gemini-2.0-flash",
12222
- label: "Gemini 2.0 Flash",
12223
- capabilities: { tools: true, forcedToolChoice: true },
12234
+ modelId: "gemini-3.5-flash",
12235
+ label: "Gemini 3.5 Flash",
12236
+ capabilities: { tools: true, forcedToolChoice: false, reasoning: true },
12224
12237
  contextWindow: 1048576
12225
12238
  },
12226
12239
  {
12227
- modelId: "gemini-2.5-pro",
12228
- label: "Gemini 2.5 Pro",
12229
- capabilities: { tools: true, forcedToolChoice: true },
12240
+ modelId: "gemini-3.1-pro-preview",
12241
+ label: "Gemini 3.1 Pro (preview)",
12242
+ capabilities: { tools: true, forcedToolChoice: false, reasoning: true },
12230
12243
  contextWindow: 1048576
12231
12244
  }
12232
12245
  ],
@@ -12314,23 +12327,30 @@ var init_model_catalog = __esm({
12314
12327
  contextWindow: 1048576,
12315
12328
  providerOrder: ["deepseek"]
12316
12329
  },
12317
- // Google
12330
+ // Google — all three are thinking models on OpenRouter (supported_parameters
12331
+ // includes "reasoning", verified via openrouter.ai/google/… 2026-07-12).
12332
+ // reasoning:true makes the OpenRouter provider enable reasoning + round-trip
12333
+ // reasoning_details across tool-call turns. Unlike the M-series/Kimi/GLM
12334
+ // reasoning entries above, forcedToolChoice stays true here — no evidence
12335
+ // (live or documented) that OpenRouter's Gemini routes reject a forced
12336
+ // tool_choice, matching how deepseek/deepseek-v4-flash (also reasoning:true)
12337
+ // keeps forcedToolChoice:true in this file.
12318
12338
  {
12319
12339
  modelId: "google/gemini-3.1-flash-lite-preview",
12320
12340
  label: "Gemini 3.1 Flash Lite (preview)",
12321
- capabilities: { tools: true, forcedToolChoice: true },
12341
+ capabilities: { tools: true, forcedToolChoice: true, reasoning: true },
12322
12342
  contextWindow: 1048576
12323
12343
  },
12324
12344
  {
12325
12345
  modelId: "google/gemini-3.1-pro-preview",
12326
12346
  label: "Gemini 3.1 Pro (preview)",
12327
- capabilities: { tools: true, forcedToolChoice: true },
12347
+ capabilities: { tools: true, forcedToolChoice: true, reasoning: true },
12328
12348
  contextWindow: 1048576
12329
12349
  },
12330
12350
  {
12331
12351
  modelId: "google/gemini-3.5-flash",
12332
12352
  label: "Gemini 3.5 Flash",
12333
- capabilities: { tools: true, forcedToolChoice: true },
12353
+ capabilities: { tools: true, forcedToolChoice: true, reasoning: true },
12334
12354
  contextWindow: 1048576
12335
12355
  },
12336
12356
  {
@@ -12408,8 +12428,8 @@ var init_model_catalog = __esm({
12408
12428
  "claude-haiku-4-5-20251001",
12409
12429
  "gpt-5",
12410
12430
  "gpt-5-mini",
12411
- "gemini-2.0-flash",
12412
- "gemini-2.5-pro",
12431
+ "gemini-3.5-flash",
12432
+ "gemini-3.1-pro-preview",
12413
12433
  "mistral-large-latest",
12414
12434
  "MiniMax-M3",
12415
12435
  "kimi-k2.6",
@@ -12844,6 +12864,17 @@ var init_schedules = __esm({
12844
12864
  // forces the agent to send the user a success confirmation before finishing.
12845
12865
  // Default false → the cron runs silently (the user must opt in per schedule).
12846
12866
  notifyOnSuccess: boolean("notify_on_success").notNull().default(false),
12867
+ // Explicit notify channel choice (B1, notify-channel-choice plan). One of
12868
+ // 'telegram'|'discord'|'slack'|'whatsapp', or NULL = auto (the historical
12869
+ // behavior: first active channel by CHANNEL_PRIORITY — see run-schedules.ts).
12870
+ // Choosing a channel here LINKS chatId resolution to it: the owner
12871
+ // conversation resolved at fire time is the owner's conversation ON THIS
12872
+ // CHANNEL, not whichever channel happened to win priority. 'whatsapp' is
12873
+ // accepted at the DB layer for forward-compat but the UI does not offer it
12874
+ // yet — no outbound send tool exists for whatsapp (TOOL_ONLY_DELIVERY_CHANNELS,
12875
+ // execute.ts), so a whatsapp notify would only ever reach the user through
12876
+ // deliver-results.ts's adapter-direct path, never a mid-run agent send.
12877
+ notifyChannel: text("notify_channel"),
12847
12878
  // Per-schedule daily cost ceiling in USD (Event Triggers, Brique 3). Rolled
12848
12879
  // up against agent_jobs.total_cost_usd for this schedule since the start
12849
12880
  // of its local day — see runScheduleTick (apps/runner/src/cron/run-schedules.ts).
@@ -12859,7 +12890,11 @@ var init_schedules = __esm({
12859
12890
  check("agent_schedules_type_check", sql`${table.type} IN ('cron','heartbeat')`),
12860
12891
  check(
12861
12892
  "agent_schedules_last_status_check",
12862
- sql`${table.lastStatus} IN ('success','failed','no_action','budget_exhausted') OR ${table.lastStatus} IS NULL`
12893
+ sql`${table.lastStatus} IN ('success','failed','no_action','budget_exhausted','notify_unreachable') OR ${table.lastStatus} IS NULL`
12894
+ ),
12895
+ check(
12896
+ "agent_schedules_notify_channel_check",
12897
+ sql`${table.notifyChannel} IN ('telegram','discord','slack','whatsapp') OR ${table.notifyChannel} IS NULL`
12863
12898
  )
12864
12899
  ]
12865
12900
  );
@@ -13365,6 +13400,7 @@ var init_webhooks = __esm({
13365
13400
  "../../packages/db/src/schema/webhooks.ts"() {
13366
13401
  "use strict";
13367
13402
  init_pg_core();
13403
+ init_drizzle_orm();
13368
13404
  init_entities();
13369
13405
  init_agents();
13370
13406
  webhookTriggers = pgTable(
@@ -13381,10 +13417,30 @@ var init_webhooks = __esm({
13381
13417
  secret: text("secret"),
13382
13418
  lastTriggeredAt: timestamp("last_triggered_at", { withTimezone: true }),
13383
13419
  triggerCount: integer("trigger_count").default(0),
13420
+ // B2 (notify-channel-choice plan): same pair of columns as
13421
+ // agent_schedules (see schedules.ts), same mechanic — the schedules
13422
+ // brique (B1) established the pattern, this just closes the gap the plan
13423
+ // identified: webhooks had no notify at all, not by design, just because
13424
+ // the original webhooks brique scoped delivery to the HTTP caller (202 +
13425
+ // jobId) and never to the owner. Default false → firing stays silent
13426
+ // unless opted in per trigger.
13427
+ notifyOnSuccess: boolean("notify_on_success").notNull().default(false),
13428
+ // Explicit notify channel choice, NULL = auto (first active channel by
13429
+ // CHANNEL_PRIORITY — see routes/webhook.ts). Unlike agent_schedules,
13430
+ // there is no legacy webhook-notify behavior to preserve, so "auto" here
13431
+ // is a plain first-active-channel resolution from the start (no
13432
+ // telegram-only wrapper).
13433
+ notifyChannel: text("notify_channel"),
13384
13434
  createdAt: timestamp("created_at", { withTimezone: true }).defaultNow(),
13385
13435
  updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow()
13386
13436
  },
13387
- (table) => [index("idx_webhook_triggers_entity_id").on(table.entityId)]
13437
+ (table) => [
13438
+ index("idx_webhook_triggers_entity_id").on(table.entityId),
13439
+ check(
13440
+ "webhook_triggers_notify_channel_check",
13441
+ sql`${table.notifyChannel} IN ('telegram','discord','slack','whatsapp') OR ${table.notifyChannel} IS NULL`
13442
+ )
13443
+ ]
13388
13444
  );
13389
13445
  }
13390
13446
  });
@@ -14753,13 +14809,13 @@ async function waitForHealth(url, timeoutMs = 3e4) {
14753
14809
  }
14754
14810
  throw new Error(`Service at ${url} did not become healthy within ${timeoutMs}ms`);
14755
14811
  }
14756
- async function assertWebRenders(url, timeoutMs = 6e4) {
14812
+ async function assertWebRenders(url, timeoutMs = 3e5) {
14757
14813
  const deadline = Date.now() + timeoutMs;
14758
14814
  let lastStatus = 0;
14759
14815
  while (Date.now() < deadline) {
14760
14816
  try {
14761
14817
  const controller = new AbortController();
14762
- const t = setTimeout(() => controller.abort(), 5e3);
14818
+ const t = setTimeout(() => controller.abort(), 6e4);
14763
14819
  const res = await fetch(`${url}/`, { signal: controller.signal });
14764
14820
  clearTimeout(t);
14765
14821
  lastStatus = res.status;
@@ -14984,7 +15040,7 @@ async function runUp(opts = {}) {
14984
15040
  waitForHealth(runnerUrl, runnerHealthMs),
14985
15041
  waitForHealth(webUrl, webHealthMs)
14986
15042
  ]);
14987
- await assertWebRenders(webUrl);
15043
+ await assertWebRenders(webUrl, webHealthMs);
14988
15044
  healthSpinner.succeed(chalk.green("All services healthy"));
14989
15045
  } catch (err) {
14990
15046
  healthSpinner.fail("Health check timed out");
@@ -0,0 +1,19 @@
1
+ -- Notify multi-canal pour les automations (B1). Today a schedule's success
2
+ -- confirmation always resolves the OWNER'S TELEGRAM chat (resolveOwnerChatId,
3
+ -- a hardcoded 'telegram' wrapper) and lets delivery-guard/deliver-results pick
4
+ -- whichever channel wins CHANNEL_PRIORITY — an agent bound to telegram+slack
5
+ -- notifies telegram today by priority coincidence, not by design.
6
+ --
7
+ -- notify_channel: explicit choice, NULL = auto (unchanged behavior: first
8
+ -- active channel by priority). Choosing a channel LINKS chatId resolution to
9
+ -- it — see run-schedules.ts's runScheduleTick.
10
+ ALTER TABLE "agent_schedules" ADD COLUMN "notify_channel" text;--> statement-breakpoint
11
+ ALTER TABLE "agent_schedules" ADD CONSTRAINT "agent_schedules_notify_channel_check" CHECK ("notify_channel" IN ('telegram','discord','slack','whatsapp') OR "notify_channel" IS NULL);--> statement-breakpoint
12
+
13
+ -- 'notify_unreachable' — fail-loud (invariant #4) status for when the chosen
14
+ -- channel has no owner conversation yet (never DMed the bot there): the cron
15
+ -- still fires the job (no silent fallback to another channel), just without
16
+ -- a chatId, and this status surfaces the problem in the UI instead of reading
17
+ -- as an ordinary 'failed'.
18
+ ALTER TABLE "agent_schedules" DROP CONSTRAINT IF EXISTS "agent_schedules_last_status_check";--> statement-breakpoint
19
+ ALTER TABLE "agent_schedules" ADD CONSTRAINT "agent_schedules_last_status_check" CHECK ("last_status" IN ('success','failed','no_action','budget_exhausted','notify_unreachable') OR "last_status" IS NULL);
@@ -0,0 +1,12 @@
1
+ -- Notify multi-canal pour les webhooks (B2, same plan as 0066's schedule
2
+ -- notify_channel). Webhooks never had a notify option at all — the original
3
+ -- webhooks brique scoped delivery to the HTTP caller (202 + jobId) and never
4
+ -- to the owner. Same pair of columns, same mechanic as agent_schedules.
5
+ --
6
+ -- notify_channel: explicit choice, NULL = auto (first active channel by
7
+ -- priority — no legacy telegram-only behavior to preserve here, unlike
8
+ -- schedules). Choosing a channel LINKS chatId resolution to it — see
9
+ -- routes/webhook.ts.
10
+ ALTER TABLE "webhook_triggers" ADD COLUMN "notify_on_success" boolean NOT NULL DEFAULT false;--> statement-breakpoint
11
+ ALTER TABLE "webhook_triggers" ADD COLUMN "notify_channel" text;--> statement-breakpoint
12
+ ALTER TABLE "webhook_triggers" ADD CONSTRAINT "webhook_triggers_notify_channel_check" CHECK ("notify_channel" IN ('telegram','discord','slack','whatsapp') OR "notify_channel" IS NULL);
@@ -456,6 +456,20 @@
456
456
  "when": 1784500000000,
457
457
  "tag": "0065_conversations_origin",
458
458
  "breakpoints": true
459
+ },
460
+ {
461
+ "idx": 66,
462
+ "version": "7",
463
+ "when": 1784600000000,
464
+ "tag": "0066_schedule_notify_channel",
465
+ "breakpoints": true
466
+ },
467
+ {
468
+ "idx": 67,
469
+ "version": "7",
470
+ "when": 1784700000000,
471
+ "tag": "0067_webhook_notify_channel",
472
+ "breakpoints": true
459
473
  }
460
474
  ]
461
475
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodal-agents",
3
- "version": "0.7.8",
3
+ "version": "0.7.95",
4
4
  "description": "Local-first AI agent platform with a web dashboard — install in one command.",
5
5
  "license": "MIT",
6
6
  "repository": {