synabun 2.0.5 → 2.0.9

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 (527) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +2 -1
  3. package/THIRD-PARTY-LICENSES.md +13 -0
  4. package/docs/whatsapp.md +151 -16
  5. package/hooks/claude-code/post-plan.mjs +6 -30
  6. package/hooks/claude-code/session-start.mjs +1 -4
  7. package/hooks/claude-code/shared.mjs +112 -75
  8. package/lib/child-path.js +303 -0
  9. package/lib/claude-hooks.js +2 -1
  10. package/lib/data-home-migration.js +2 -0
  11. package/lib/desktop-app.js +265 -0
  12. package/lib/external-tools.js +7 -3
  13. package/lib/log-redact.js +102 -0
  14. package/lib/package-processes.js +670 -0
  15. package/lib/packaged-runtime.js +138 -11
  16. package/lib/runtime-dependencies.js +225 -0
  17. package/mcp-server/dist/http.d.ts +3 -1
  18. package/mcp-server/dist/http.d.ts.map +1 -1
  19. package/mcp-server/dist/http.js +15 -4
  20. package/mcp-server/dist/http.js.map +1 -1
  21. package/mcp-server/dist/index.d.ts.map +1 -1
  22. package/mcp-server/dist/index.js +9 -6
  23. package/mcp-server/dist/index.js.map +1 -1
  24. package/mcp-server/dist/services/browser-bench.d.ts +1 -1
  25. package/mcp-server/dist/services/browser-bench.d.ts.map +1 -1
  26. package/mcp-server/dist/services/browser-bench.js +1 -1
  27. package/mcp-server/dist/services/browser-bench.js.map +1 -1
  28. package/mcp-server/dist/services/budget-judgments.d.ts +108 -0
  29. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -0
  30. package/mcp-server/dist/services/budget-judgments.js +153 -0
  31. package/mcp-server/dist/services/budget-judgments.js.map +1 -0
  32. package/mcp-server/dist/services/categories.d.ts +35 -2
  33. package/mcp-server/dist/services/categories.d.ts.map +1 -1
  34. package/mcp-server/dist/services/categories.js +77 -33
  35. package/mcp-server/dist/services/categories.js.map +1 -1
  36. package/mcp-server/dist/services/codex-config-heal.d.ts +5 -1
  37. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  38. package/mcp-server/dist/services/codex-config-heal.js +41 -4
  39. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  40. package/mcp-server/dist/services/desktop-bench.d.ts +7 -7
  41. package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -1
  42. package/mcp-server/dist/services/desktop-bench.js +1 -1
  43. package/mcp-server/dist/services/desktop-bench.js.map +1 -1
  44. package/mcp-server/dist/services/identity.d.ts +11 -0
  45. package/mcp-server/dist/services/identity.d.ts.map +1 -1
  46. package/mcp-server/dist/services/identity.js +24 -0
  47. package/mcp-server/dist/services/identity.js.map +1 -1
  48. package/mcp-server/dist/services/neural-interface.d.ts +13 -0
  49. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  50. package/mcp-server/dist/services/neural-interface.js +34 -2
  51. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  52. package/mcp-server/dist/services/typesafe-config.d.ts +1 -1
  53. package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -1
  54. package/mcp-server/dist/services/typesafe-config.js +4 -1
  55. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  56. package/mcp-server/dist/tools/agents.d.ts +11 -8
  57. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  58. package/mcp-server/dist/tools/agents.js +35 -14
  59. package/mcp-server/dist/tools/agents.js.map +1 -1
  60. package/mcp-server/dist/tools/bluesky.js +1 -1
  61. package/mcp-server/dist/tools/bluesky.js.map +1 -1
  62. package/mcp-server/dist/tools/browser-advanced.d.ts +1 -1
  63. package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -1
  64. package/mcp-server/dist/tools/browser-advanced.js +1 -1
  65. package/mcp-server/dist/tools/browser-advanced.js.map +1 -1
  66. package/mcp-server/dist/tools/browser-batch.d.ts +1 -1
  67. package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -1
  68. package/mcp-server/dist/tools/browser-batch.js +1 -1
  69. package/mcp-server/dist/tools/browser-batch.js.map +1 -1
  70. package/mcp-server/dist/tools/browser-cheatsheet.d.ts +1 -1
  71. package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -1
  72. package/mcp-server/dist/tools/browser-cheatsheet.js +1 -1
  73. package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -1
  74. package/mcp-server/dist/tools/browser-interact.d.ts +1 -1
  75. package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -1
  76. package/mcp-server/dist/tools/browser-interact.js +1 -1
  77. package/mcp-server/dist/tools/browser-interact.js.map +1 -1
  78. package/mcp-server/dist/tools/browser-navigate.d.ts +1 -1
  79. package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -1
  80. package/mcp-server/dist/tools/browser-navigate.js +1 -1
  81. package/mcp-server/dist/tools/browser-navigate.js.map +1 -1
  82. package/mcp-server/dist/tools/browser-observe.d.ts +1 -1
  83. package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -1
  84. package/mcp-server/dist/tools/browser-observe.js +1 -1
  85. package/mcp-server/dist/tools/browser-observe.js.map +1 -1
  86. package/mcp-server/dist/tools/card-tools.d.ts +1 -1
  87. package/mcp-server/dist/tools/card-tools.d.ts.map +1 -1
  88. package/mcp-server/dist/tools/card-tools.js +1 -1
  89. package/mcp-server/dist/tools/card-tools.js.map +1 -1
  90. package/mcp-server/dist/tools/category.d.ts +1 -1
  91. package/mcp-server/dist/tools/category.d.ts.map +1 -1
  92. package/mcp-server/dist/tools/category.js +5 -1
  93. package/mcp-server/dist/tools/category.js.map +1 -1
  94. package/mcp-server/dist/tools/choice.d.ts +1 -1
  95. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  96. package/mcp-server/dist/tools/choice.js +1 -1
  97. package/mcp-server/dist/tools/choice.js.map +1 -1
  98. package/mcp-server/dist/tools/computer.d.ts +1 -1
  99. package/mcp-server/dist/tools/computer.d.ts.map +1 -1
  100. package/mcp-server/dist/tools/computer.js +1 -1
  101. package/mcp-server/dist/tools/computer.js.map +1 -1
  102. package/mcp-server/dist/tools/discord-channel.d.ts +1 -1
  103. package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -1
  104. package/mcp-server/dist/tools/discord-channel.js +1 -1
  105. package/mcp-server/dist/tools/discord-channel.js.map +1 -1
  106. package/mcp-server/dist/tools/discord-guild.d.ts +1 -1
  107. package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -1
  108. package/mcp-server/dist/tools/discord-guild.js +1 -1
  109. package/mcp-server/dist/tools/discord-guild.js.map +1 -1
  110. package/mcp-server/dist/tools/discord-member.d.ts +1 -1
  111. package/mcp-server/dist/tools/discord-member.d.ts.map +1 -1
  112. package/mcp-server/dist/tools/discord-member.js +1 -1
  113. package/mcp-server/dist/tools/discord-member.js.map +1 -1
  114. package/mcp-server/dist/tools/discord-message.d.ts +1 -1
  115. package/mcp-server/dist/tools/discord-message.d.ts.map +1 -1
  116. package/mcp-server/dist/tools/discord-message.js +1 -1
  117. package/mcp-server/dist/tools/discord-message.js.map +1 -1
  118. package/mcp-server/dist/tools/discord-onboarding.d.ts +1 -1
  119. package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -1
  120. package/mcp-server/dist/tools/discord-onboarding.js +1 -1
  121. package/mcp-server/dist/tools/discord-onboarding.js.map +1 -1
  122. package/mcp-server/dist/tools/discord-role.d.ts +1 -1
  123. package/mcp-server/dist/tools/discord-role.d.ts.map +1 -1
  124. package/mcp-server/dist/tools/discord-role.js +1 -1
  125. package/mcp-server/dist/tools/discord-role.js.map +1 -1
  126. package/mcp-server/dist/tools/discord-thread.d.ts +1 -1
  127. package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -1
  128. package/mcp-server/dist/tools/discord-thread.js +1 -1
  129. package/mcp-server/dist/tools/discord-thread.js.map +1 -1
  130. package/mcp-server/dist/tools/discord-webhook.d.ts +1 -1
  131. package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -1
  132. package/mcp-server/dist/tools/discord-webhook.js +1 -1
  133. package/mcp-server/dist/tools/discord-webhook.js.map +1 -1
  134. package/mcp-server/dist/tools/fb-groups.d.ts +1 -1
  135. package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -1
  136. package/mcp-server/dist/tools/fb-groups.js +1 -1
  137. package/mcp-server/dist/tools/fb-groups.js.map +1 -1
  138. package/mcp-server/dist/tools/forget.d.ts +1 -1
  139. package/mcp-server/dist/tools/forget.d.ts.map +1 -1
  140. package/mcp-server/dist/tools/forget.js +1 -1
  141. package/mcp-server/dist/tools/forget.js.map +1 -1
  142. package/mcp-server/dist/tools/git-tools.d.ts +1 -1
  143. package/mcp-server/dist/tools/git-tools.d.ts.map +1 -1
  144. package/mcp-server/dist/tools/git-tools.js +1 -1
  145. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  146. package/mcp-server/dist/tools/gsc/experience.d.ts +1 -1
  147. package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -1
  148. package/mcp-server/dist/tools/gsc/experience.js +1 -1
  149. package/mcp-server/dist/tools/gsc/experience.js.map +1 -1
  150. package/mcp-server/dist/tools/gsc/indexing.d.ts +1 -1
  151. package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -1
  152. package/mcp-server/dist/tools/gsc/indexing.js +1 -1
  153. package/mcp-server/dist/tools/gsc/indexing.js.map +1 -1
  154. package/mcp-server/dist/tools/gsc/inspect.d.ts +1 -1
  155. package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -1
  156. package/mcp-server/dist/tools/gsc/inspect.js +1 -1
  157. package/mcp-server/dist/tools/gsc/inspect.js.map +1 -1
  158. package/mcp-server/dist/tools/gsc/navigate.d.ts +1 -1
  159. package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -1
  160. package/mcp-server/dist/tools/gsc/navigate.js +1 -1
  161. package/mcp-server/dist/tools/gsc/navigate.js.map +1 -1
  162. package/mcp-server/dist/tools/gsc/performance.d.ts +1 -1
  163. package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -1
  164. package/mcp-server/dist/tools/gsc/performance.js +1 -1
  165. package/mcp-server/dist/tools/gsc/performance.js.map +1 -1
  166. package/mcp-server/dist/tools/gsc/settings.d.ts +1 -1
  167. package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -1
  168. package/mcp-server/dist/tools/gsc/settings.js +1 -1
  169. package/mcp-server/dist/tools/gsc/settings.js.map +1 -1
  170. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  171. package/mcp-server/dist/tools/image-tools.d.ts.map +1 -1
  172. package/mcp-server/dist/tools/image-tools.js +1 -1
  173. package/mcp-server/dist/tools/image-tools.js.map +1 -1
  174. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +1 -1
  175. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -1
  176. package/mcp-server/dist/tools/leonardo-browser-tools.js +1 -1
  177. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -1
  178. package/mcp-server/dist/tools/loop.d.ts +1 -1
  179. package/mcp-server/dist/tools/loop.d.ts.map +1 -1
  180. package/mcp-server/dist/tools/loop.js +1 -1
  181. package/mcp-server/dist/tools/loop.js.map +1 -1
  182. package/mcp-server/dist/tools/memories.d.ts +1 -1
  183. package/mcp-server/dist/tools/memories.d.ts.map +1 -1
  184. package/mcp-server/dist/tools/memories.js +1 -1
  185. package/mcp-server/dist/tools/memories.js.map +1 -1
  186. package/mcp-server/dist/tools/morelogin.d.ts +1 -1
  187. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  188. package/mcp-server/dist/tools/morelogin.js +1 -1
  189. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  190. package/mcp-server/dist/tools/profile.d.ts +1 -1
  191. package/mcp-server/dist/tools/profile.d.ts.map +1 -1
  192. package/mcp-server/dist/tools/profile.js +1 -1
  193. package/mcp-server/dist/tools/profile.js.map +1 -1
  194. package/mcp-server/dist/tools/recall.d.ts +1 -1
  195. package/mcp-server/dist/tools/recall.d.ts.map +1 -1
  196. package/mcp-server/dist/tools/recall.js +1 -1
  197. package/mcp-server/dist/tools/recall.js.map +1 -1
  198. package/mcp-server/dist/tools/reflect.d.ts +1 -1
  199. package/mcp-server/dist/tools/reflect.d.ts.map +1 -1
  200. package/mcp-server/dist/tools/reflect.js +1 -1
  201. package/mcp-server/dist/tools/reflect.js.map +1 -1
  202. package/mcp-server/dist/tools/remember.d.ts +1 -1
  203. package/mcp-server/dist/tools/remember.d.ts.map +1 -1
  204. package/mcp-server/dist/tools/remember.js +13 -11
  205. package/mcp-server/dist/tools/remember.js.map +1 -1
  206. package/mcp-server/dist/tools/restore.d.ts +1 -1
  207. package/mcp-server/dist/tools/restore.d.ts.map +1 -1
  208. package/mcp-server/dist/tools/restore.js +1 -1
  209. package/mcp-server/dist/tools/restore.js.map +1 -1
  210. package/mcp-server/dist/tools/style-guide-tools.d.ts +1 -1
  211. package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -1
  212. package/mcp-server/dist/tools/style-guide-tools.js +1 -1
  213. package/mcp-server/dist/tools/style-guide-tools.js.map +1 -1
  214. package/mcp-server/dist/tools/sync.d.ts +1 -1
  215. package/mcp-server/dist/tools/sync.d.ts.map +1 -1
  216. package/mcp-server/dist/tools/sync.js +1 -1
  217. package/mcp-server/dist/tools/sync.js.map +1 -1
  218. package/mcp-server/dist/tools/tictactoe-tools.d.ts +1 -1
  219. package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -1
  220. package/mcp-server/dist/tools/tictactoe-tools.js +1 -1
  221. package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -1
  222. package/mcp-server/dist/tools/utils.d.ts +1 -1
  223. package/mcp-server/dist/tools/utils.d.ts.map +1 -1
  224. package/mcp-server/dist/tools/utils.js +1 -1
  225. package/mcp-server/dist/tools/utils.js.map +1 -1
  226. package/mcp-server/dist/tools/whatsapp-send-file.d.ts +17 -0
  227. package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -0
  228. package/mcp-server/dist/tools/whatsapp-send-file.js +44 -0
  229. package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -0
  230. package/mcp-server/dist/tools/whiteboard-tools.d.ts +3 -3
  231. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  232. package/mcp-server/dist/tools/whiteboard-tools.js +1 -1
  233. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  234. package/mcp-server/dist/tools/youtube/analytics.d.ts +1 -1
  235. package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -1
  236. package/mcp-server/dist/tools/youtube/analytics.js +1 -1
  237. package/mcp-server/dist/tools/youtube/analytics.js.map +1 -1
  238. package/mcp-server/dist/tools/youtube/download.d.ts +1 -1
  239. package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -1
  240. package/mcp-server/dist/tools/youtube/download.js +1 -1
  241. package/mcp-server/dist/tools/youtube/download.js.map +1 -1
  242. package/mcp-server/dist/tools/youtube/media.d.ts +1 -1
  243. package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -1
  244. package/mcp-server/dist/tools/youtube/media.js +1 -1
  245. package/mcp-server/dist/tools/youtube/media.js.map +1 -1
  246. package/mcp-server/dist/tools/youtube/metadata.d.ts +1 -1
  247. package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -1
  248. package/mcp-server/dist/tools/youtube/metadata.js +1 -1
  249. package/mcp-server/dist/tools/youtube/metadata.js.map +1 -1
  250. package/mcp-server/dist/tools/youtube/navigate.d.ts +1 -1
  251. package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -1
  252. package/mcp-server/dist/tools/youtube/navigate.js +1 -1
  253. package/mcp-server/dist/tools/youtube/navigate.js.map +1 -1
  254. package/mcp-server/dist/tools/youtube/playlist.d.ts +1 -1
  255. package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -1
  256. package/mcp-server/dist/tools/youtube/playlist.js +1 -1
  257. package/mcp-server/dist/tools/youtube/playlist.js.map +1 -1
  258. package/mcp-server/dist/tools/youtube/schedule.d.ts +1 -1
  259. package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -1
  260. package/mcp-server/dist/tools/youtube/schedule.js +1 -1
  261. package/mcp-server/dist/tools/youtube/schedule.js.map +1 -1
  262. package/mcp-server/dist/tools/youtube/source.d.ts +1 -1
  263. package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -1
  264. package/mcp-server/dist/tools/youtube/source.js +1 -1
  265. package/mcp-server/dist/tools/youtube/source.js.map +1 -1
  266. package/mcp-server/dist/tools/youtube/upload.d.ts +1 -1
  267. package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -1
  268. package/mcp-server/dist/tools/youtube/upload.js +4 -9
  269. package/mcp-server/dist/tools/youtube/upload.js.map +1 -1
  270. package/mcp-server/dist/tui.js +18 -5
  271. package/mcp-server/dist/tui.js.map +1 -1
  272. package/mcp-server/dist/version.d.ts +5 -0
  273. package/mcp-server/dist/version.d.ts.map +1 -0
  274. package/mcp-server/dist/version.js +21 -0
  275. package/mcp-server/dist/version.js.map +1 -0
  276. package/mcp-server/package-lock.json +3 -3
  277. package/mcp-server/package.json +3 -3
  278. package/mcp-server/run.mjs +15 -9
  279. package/mcp-server/src/http.ts +18 -3
  280. package/mcp-server/src/index.ts +9 -6
  281. package/mcp-server/src/services/browser-bench.ts +1 -1
  282. package/mcp-server/src/services/budget-judgments.ts +183 -0
  283. package/mcp-server/src/services/categories.ts +77 -32
  284. package/mcp-server/src/services/codex-config-heal.ts +35 -4
  285. package/mcp-server/src/services/desktop-bench.ts +1 -1
  286. package/mcp-server/src/services/identity.ts +27 -0
  287. package/mcp-server/src/services/neural-interface.ts +34 -2
  288. package/mcp-server/src/services/typesafe-config.ts +4 -1
  289. package/mcp-server/src/tools/agents.ts +34 -15
  290. package/mcp-server/src/tools/bluesky.ts +1 -1
  291. package/mcp-server/src/tools/browser-advanced.ts +1 -1
  292. package/mcp-server/src/tools/browser-batch.ts +1 -1
  293. package/mcp-server/src/tools/browser-cheatsheet.ts +1 -1
  294. package/mcp-server/src/tools/browser-interact.ts +1 -1
  295. package/mcp-server/src/tools/browser-navigate.ts +1 -1
  296. package/mcp-server/src/tools/browser-observe.ts +1 -1
  297. package/mcp-server/src/tools/card-tools.ts +1 -1
  298. package/mcp-server/src/tools/category.ts +6 -1
  299. package/mcp-server/src/tools/choice.ts +1 -1
  300. package/mcp-server/src/tools/computer.ts +1 -1
  301. package/mcp-server/src/tools/discord-channel.ts +1 -1
  302. package/mcp-server/src/tools/discord-guild.ts +1 -1
  303. package/mcp-server/src/tools/discord-member.ts +1 -1
  304. package/mcp-server/src/tools/discord-message.ts +1 -1
  305. package/mcp-server/src/tools/discord-onboarding.ts +1 -1
  306. package/mcp-server/src/tools/discord-role.ts +1 -1
  307. package/mcp-server/src/tools/discord-thread.ts +1 -1
  308. package/mcp-server/src/tools/discord-webhook.ts +1 -1
  309. package/mcp-server/src/tools/fb-groups.ts +1 -1
  310. package/mcp-server/src/tools/forget.ts +1 -1
  311. package/mcp-server/src/tools/git-tools.ts +1 -1
  312. package/mcp-server/src/tools/gsc/experience.ts +1 -1
  313. package/mcp-server/src/tools/gsc/indexing.ts +1 -1
  314. package/mcp-server/src/tools/gsc/inspect.ts +1 -1
  315. package/mcp-server/src/tools/gsc/navigate.ts +1 -1
  316. package/mcp-server/src/tools/gsc/performance.ts +1 -1
  317. package/mcp-server/src/tools/gsc/settings.ts +1 -1
  318. package/mcp-server/src/tools/image-tools.ts +1 -1
  319. package/mcp-server/src/tools/leonardo-browser-tools.ts +1 -1
  320. package/mcp-server/src/tools/loop.ts +1 -1
  321. package/mcp-server/src/tools/memories.ts +1 -1
  322. package/mcp-server/src/tools/morelogin.ts +1 -1
  323. package/mcp-server/src/tools/profile.ts +1 -1
  324. package/mcp-server/src/tools/recall.ts +1 -1
  325. package/mcp-server/src/tools/reflect.ts +1 -1
  326. package/mcp-server/src/tools/remember.ts +13 -12
  327. package/mcp-server/src/tools/restore.ts +1 -1
  328. package/mcp-server/src/tools/style-guide-tools.ts +1 -1
  329. package/mcp-server/src/tools/sync.ts +1 -1
  330. package/mcp-server/src/tools/tictactoe-tools.ts +1 -1
  331. package/mcp-server/src/tools/utils.ts +1 -1
  332. package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
  333. package/mcp-server/src/tools/whiteboard-tools.ts +1 -1
  334. package/mcp-server/src/tools/youtube/analytics.ts +1 -1
  335. package/mcp-server/src/tools/youtube/download.ts +1 -1
  336. package/mcp-server/src/tools/youtube/media.ts +1 -1
  337. package/mcp-server/src/tools/youtube/metadata.ts +1 -1
  338. package/mcp-server/src/tools/youtube/navigate.ts +1 -1
  339. package/mcp-server/src/tools/youtube/playlist.ts +1 -1
  340. package/mcp-server/src/tools/youtube/schedule.ts +1 -1
  341. package/mcp-server/src/tools/youtube/source.ts +1 -1
  342. package/mcp-server/src/tools/youtube/upload.ts +4 -12
  343. package/mcp-server/src/tui.ts +24 -10
  344. package/mcp-server/src/version.ts +22 -0
  345. package/neural-interface/i18n/en.json +645 -57
  346. package/neural-interface/i18n/pt-BR.json +644 -56
  347. package/neural-interface/lib/account-usage.js +163 -0
  348. package/neural-interface/lib/agent-sandbox-elevation.js +102 -0
  349. package/neural-interface/lib/agent-sandbox-setting.js +57 -0
  350. package/neural-interface/lib/assistant-api.js +274 -52
  351. package/neural-interface/lib/assistant-brains/claude.js +15 -2
  352. package/neural-interface/lib/assistant-brains/codex.js +3 -0
  353. package/neural-interface/lib/assistant-brains/opencode.js +17 -4
  354. package/neural-interface/lib/assistant-budget-planner.js +390 -0
  355. package/neural-interface/lib/assistant-budget-split.js +408 -0
  356. package/neural-interface/lib/assistant-budget.js +94 -95
  357. package/neural-interface/lib/assistant-config.js +62 -14
  358. package/neural-interface/lib/assistant-dispatch.js +432 -125
  359. package/neural-interface/lib/assistant-jev.js +26 -3
  360. package/neural-interface/lib/assistant-persona.js +68 -11
  361. package/neural-interface/lib/assistant-plan-permissions.js +8 -1
  362. package/neural-interface/lib/assistant-route-accounts.js +14 -0
  363. package/neural-interface/lib/assistant-route-gate-codex.js +3 -1
  364. package/neural-interface/lib/assistant-route-gate.js +19 -3
  365. package/neural-interface/lib/assistant-router.js +373 -42
  366. package/neural-interface/lib/assistant-runtime.js +312 -48
  367. package/neural-interface/lib/assistant-user-writer.js +4 -2
  368. package/neural-interface/lib/augmented-path.js +317 -53
  369. package/neural-interface/lib/claude-accounts.js +342 -31
  370. package/neural-interface/lib/claude-agent-bridge.js +90 -3
  371. package/neural-interface/lib/claude-executable.js +6 -1
  372. package/neural-interface/lib/claude-model-catalog.js +3 -3
  373. package/neural-interface/lib/claude-panel-auth.js +221 -0
  374. package/neural-interface/lib/claude-profile-api-key.js +62 -0
  375. package/neural-interface/lib/cli-install-api.js +137 -0
  376. package/neural-interface/lib/cli-install.js +797 -0
  377. package/neural-interface/lib/cli-path.js +130 -0
  378. package/neural-interface/lib/cli-resolver.js +744 -0
  379. package/neural-interface/lib/cli-update-planner.js +143 -7
  380. package/neural-interface/lib/codex-account-auth.js +180 -0
  381. package/neural-interface/lib/codex-accounts.js +502 -0
  382. package/neural-interface/lib/codex-capabilities.js +2 -1
  383. package/neural-interface/lib/codex-compat-rpc.js +8 -2
  384. package/neural-interface/lib/codex-mcp-approvals.js +5 -1
  385. package/neural-interface/lib/codex-panel-auth.js +62 -0
  386. package/neural-interface/lib/codex-session-settings.js +1 -1
  387. package/neural-interface/lib/codex-settings-schema.js +122 -0
  388. package/neural-interface/lib/desktop/config.js +3 -0
  389. package/neural-interface/lib/exec-loop-command.js +3 -1
  390. package/neural-interface/lib/git-bash/bzip2.js +339 -0
  391. package/neural-interface/lib/git-bash/claude-settings.js +73 -0
  392. package/neural-interface/lib/git-bash/extract-worker.js +34 -0
  393. package/neural-interface/lib/git-bash/install.js +529 -0
  394. package/neural-interface/lib/git-bash/licenses/COPYING +360 -0
  395. package/neural-interface/lib/git-bash/licenses/LGPL-2.1 +511 -0
  396. package/neural-interface/lib/git-bash/manager.js +268 -0
  397. package/neural-interface/lib/git-bash/pins.js +206 -0
  398. package/neural-interface/lib/git-bash/pins.json +34 -0
  399. package/neural-interface/lib/git-bash/resolver.js +194 -0
  400. package/neural-interface/lib/git-read.js +34 -2
  401. package/neural-interface/lib/install-details.js +163 -0
  402. package/neural-interface/lib/mcp-installer.js +14 -2
  403. package/neural-interface/lib/native-loop-providers.js +22 -4
  404. package/neural-interface/lib/native-loop-runtime.js +9 -4
  405. package/neural-interface/lib/os-path.js +319 -0
  406. package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
  407. package/neural-interface/lib/provider-panel-terminal-auth.js +96 -0
  408. package/neural-interface/lib/pty-host/core.js +2 -1
  409. package/neural-interface/lib/pty-host/manager.js +27 -2
  410. package/neural-interface/lib/remote-policy.js +20 -11
  411. package/neural-interface/lib/session-indexer.js +3 -1
  412. package/neural-interface/lib/session-title-generator.js +6 -3
  413. package/neural-interface/lib/system-about.js +340 -0
  414. package/neural-interface/lib/system-activity.js +66 -0
  415. package/neural-interface/lib/terminal-env.js +11 -3
  416. package/neural-interface/lib/terminal-path.js +55 -0
  417. package/neural-interface/lib/virtual-socket.js +12 -1
  418. package/neural-interface/lib/whatsapp/baileys-adapter.js +165 -45
  419. package/neural-interface/lib/whatsapp/bridge.js +78 -34
  420. package/neural-interface/lib/whatsapp/commands.js +13 -14
  421. package/neural-interface/lib/whatsapp/config.js +134 -20
  422. package/neural-interface/lib/whatsapp/fake-baileys.js +99 -14
  423. package/neural-interface/lib/whatsapp/host-core.js +168 -35
  424. package/neural-interface/lib/whatsapp/inbound.js +5 -3
  425. package/neural-interface/lib/whatsapp/local-file.js +524 -0
  426. package/neural-interface/lib/whatsapp/manager.js +92 -32
  427. package/neural-interface/lib/whatsapp/paths.js +11 -1
  428. package/neural-interface/lib/whatsapp/protocol.js +65 -5
  429. package/neural-interface/lib/whatsapp/redact.js +63 -0
  430. package/neural-interface/lib/whatsapp/service.js +343 -91
  431. package/neural-interface/lib/whatsapp/transcription.js +463 -0
  432. package/neural-interface/package-lock.json +2 -2
  433. package/neural-interface/package.json +1 -1
  434. package/neural-interface/public/index.html +2 -0
  435. package/neural-interface/public/index2d.html +2 -0
  436. package/neural-interface/public/offline.html +16 -1
  437. package/neural-interface/public/onboarding.html +96 -2
  438. package/neural-interface/public/shared/account-i18n.js +7 -0
  439. package/neural-interface/public/shared/account-menu.js +542 -0
  440. package/neural-interface/public/shared/account-usage.js +79 -0
  441. package/neural-interface/public/shared/account-view.js +336 -0
  442. package/neural-interface/public/shared/agent-runtime-options.js +28 -8
  443. package/neural-interface/public/shared/assistant/asst-account-menu.js +298 -0
  444. package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
  445. package/neural-interface/public/shared/assistant/asst-api.js +39 -2
  446. package/neural-interface/public/shared/assistant/asst-brain-picker.js +288 -32
  447. package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
  448. package/neural-interface/public/shared/assistant/asst-mascot.js +126 -7
  449. package/neural-interface/public/shared/assistant/asst-menu.js +219 -80
  450. package/neural-interface/public/shared/assistant/asst-model-chip.js +135 -0
  451. package/neural-interface/public/shared/assistant/asst-panel.js +87 -16
  452. package/neural-interface/public/shared/assistant/asst-render.js +38 -7
  453. package/neural-interface/public/shared/assistant/asst-route.js +72 -14
  454. package/neural-interface/public/shared/assistant/asst-routes-editor.js +45 -6
  455. package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
  456. package/neural-interface/public/shared/assistant/asst-state.js +1 -1
  457. package/neural-interface/public/shared/assistant/asst-styles.js +160 -29
  458. package/neural-interface/public/shared/cdx/cdx-commands.js +4 -1
  459. package/neural-interface/public/shared/cdx/cdx-features.js +22 -14
  460. package/neural-interface/public/shared/cdx/cdx-icons.js +2 -0
  461. package/neural-interface/public/shared/cdx/cdx-panel.js +49 -108
  462. package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
  463. package/neural-interface/public/shared/cdx/cdx-styles.js +172 -111
  464. package/neural-interface/public/shared/cdx/cdx-tabs.js +264 -664
  465. package/neural-interface/public/shared/cdx/cdx-ws.js +2 -0
  466. package/neural-interface/public/shared/claude-account-view.js +3 -0
  467. package/neural-interface/public/shared/cli-install-view.js +392 -0
  468. package/neural-interface/public/shared/cli-status.js +282 -22
  469. package/neural-interface/public/shared/cp/cp-events.js +2 -1
  470. package/neural-interface/public/shared/cp/cp-styles.js +46 -0
  471. package/neural-interface/public/shared/desktop-bridge.js +39 -0
  472. package/neural-interface/public/shared/desktop-titlebar-page.js +59 -0
  473. package/neural-interface/public/shared/desktop-titlebar-view.js +122 -0
  474. package/neural-interface/public/shared/desktop-titlebar.js +153 -0
  475. package/neural-interface/public/shared/desktop-update-view.js +462 -0
  476. package/neural-interface/public/shared/editor/editor-panel.js +1 -1
  477. package/neural-interface/public/shared/explorer/fx-main.js +1 -1
  478. package/neural-interface/public/shared/git-bash-view.js +145 -0
  479. package/neural-interface/public/shared/html-shell.js +1 -0
  480. package/neural-interface/public/shared/i18n.js +19 -1
  481. package/neural-interface/public/shared/install-details-view.js +86 -0
  482. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -1
  483. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +36 -1
  484. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +17 -0
  485. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +169 -2
  486. package/neural-interface/public/shared/pwa-install-page.js +3 -1
  487. package/neural-interface/public/shared/settings/settings-about-pane.js +271 -0
  488. package/neural-interface/public/shared/settings/settings-about.js +254 -0
  489. package/neural-interface/public/shared/settings/settings-ia.js +15 -0
  490. package/neural-interface/public/shared/showcase-privacy.js +490 -0
  491. package/neural-interface/public/shared/storage.js +30 -3
  492. package/neural-interface/public/shared/styles.css +281 -32
  493. package/neural-interface/public/shared/synabun-mascot.js +48 -2
  494. package/neural-interface/public/shared/ui-claude-panel.js +262 -217
  495. package/neural-interface/public/shared/ui-cli-banner.js +355 -0
  496. package/neural-interface/public/shared/ui-explorer.js +2 -0
  497. package/neural-interface/public/shared/ui-git-bash.js +124 -0
  498. package/neural-interface/public/shared/ui-judgments.js +10 -1
  499. package/neural-interface/public/shared/ui-loading.js +30 -6
  500. package/neural-interface/public/shared/ui-menubar.js +13 -3
  501. package/neural-interface/public/shared/ui-navbar.js +3 -1
  502. package/neural-interface/public/shared/ui-provider-auth.js +104 -0
  503. package/neural-interface/public/shared/ui-provider-terminal-auth.js +223 -0
  504. package/neural-interface/public/shared/ui-sessions.js +9 -3
  505. package/neural-interface/public/shared/ui-settings.js +55 -3
  506. package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
  507. package/neural-interface/public/shared/ui-sync.js +8 -0
  508. package/neural-interface/public/shared/ui-terminal.js +17 -0
  509. package/neural-interface/public/shared/ui-tool-updates.js +5 -0
  510. package/neural-interface/public/shared/ui-update.js +598 -7
  511. package/neural-interface/public/shared/ui-whatsapp.js +21 -6
  512. package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
  513. package/neural-interface/public/shared/worker-end.js +2 -0
  514. package/neural-interface/public/sw.js +1 -1
  515. package/neural-interface/public/variant/2d/main.js +10 -1
  516. package/neural-interface/public/variant/3d/main.js +10 -1
  517. package/neural-interface/scripts/rebuild-pty.js +14 -2
  518. package/neural-interface/server.js +1384 -679
  519. package/npm-shrinkwrap.json +4424 -0
  520. package/package.json +57 -2
  521. package/postinstall.js +61 -47
  522. package/preuninstall.js +8 -35
  523. package/setup.js +80 -47
  524. package/skills/synabun/modules/idea.md +1 -1
  525. package/skills/synabun/modules/schedule.md +1 -1
  526. package/updater.cmd +2 -2
  527. package/updater.mjs +97 -3
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import * as ni from '../services/neural-interface.js';
4
4
  import { callerRole } from '../services/identity.js';
@@ -54,6 +54,7 @@ export const agentRouteSchema = {
54
54
  provider: z.enum(PROVIDERS).optional().describe('Worker provider for "dispatch" (ignored for "direct").'),
55
55
  model: z.string().max(200).optional().describe('Model id from the routing sheet / agent_catalog. Omit for the provider default (or a remembered route).'),
56
56
  effort: z.string().max(40).optional().describe('Reasoning effort for that model, per agent_catalog (e.g. low…max/ultra; OpenCode uses the model\'s variant names). Unsupported values are corrected to the nearest level the model runs.'),
57
+ account_id: z.string().max(64).optional().describe('Claude Code or Codex account id, or "auto" to choose the signed-in subscription with most usage left. API-key accounts are excluded from Auto. A limited pinned/default account falls back within the provider; corrections explain the selection. Another account runs on a worker when the proposal was direct.'),
57
58
  reason: z.string().max(240).optional().describe('Why this model (one short clause, shown on the card).'),
58
59
  })).min(1).max(3).describe('1-3 candidate routes, best first. The first is your pick.'),
59
60
  independent: z.boolean().optional().describe(
@@ -120,7 +121,7 @@ export const agentDispatchSchema = {
120
121
  'SynaBun MCP profile preset for the worker (agent_catalog mcpPresets): "core" for memory-only work, "standard" for coding, a platform preset for browser/social jobs (design runs default to "browser" unless uses_browser is false).'
121
122
  ),
122
123
  account_id: z.string().max(200).optional().describe(
123
- 'Account profile id: a Codex account for provider "codex" or a Claude account for provider "claude-code" (ignored for opencode). Omit for the default account.'
124
+ 'Account profile id, or "auto" for the signed-in subscription with most usage left (API keys excluded; limited pinned/default accounts fall back within the provider, with corrections). An approved route binds its resolved account unless it becomes limited before dispatch. A Codex account for provider "codex" or a Claude account for provider "claude-code" (ignored for opencode), an id from agent_catalog accounts["codex"] / accounts["claude-code"]. The worker uses that account\'s own mode (its ChatGPT or Claude subscription, or its API key). Omit to use the user\'s worker account for that provider (agent_catalog codexWorkerAccount / claudeWorkerAccount; Default when null). A signed-out account is refused with ACCOUNT_SIGNED_OUT.'
124
125
  ),
125
126
  permission_policy: z.enum(['auto', 'ask', 'restricted']).optional().describe(
126
127
  '"auto" (default): fully autonomous. "ask": tool permissions and questions are relayed to you — collect them with agent_wait until="event" and answer with agent_send reply. "restricted": workspace-write sandbox without prompts (the Codex alternative to ask).'
@@ -129,10 +130,10 @@ export const agentDispatchSchema = {
129
130
  '"full" (default; "workspace" for design runs), "workspace" (edits limited to cwd) or "read-only" (reviews, research). Browser jobs with "full" require the tag "user-authorized-full".'
130
131
  ),
131
132
  max_minutes: z.number().int().min(1).max(240).optional().describe(
132
- 'Wall-clock cap in minutes (1-240, default 45; 60 for design runs); the run is stopped when exceeded.'
133
+ 'Work-time cap in minutes (at most 240, default 45; 60 for design runs; values under 20 are raised to 20, never refused): only the time the worker is working a turn counts, not time queued, idle between turns or waiting on a permission or question, and a turn still working when it is used up is stopped. The run view shows workMs (used) and workLeftMs (left).'
133
134
  ),
134
- budget_usd: z.number().min(0.1).max(50).optional().describe(
135
- 'Spend cap in USD (0.1-50; the user\'s Budget settings set the default and may lower the ceiling). Every provider is held to it: Claude between model calls, OpenCode per step, Codex after each turn (priced at list price). It is lowered to what the session hard cap (brain + all runs) has left.'
135
+ budget_usd: z.number().min(0.01).max(1000).optional().describe(
136
+ 'Optional ceiling in USD for this one run (0.01-1000), inside its provider\'s share of the session budget. Omit it: the run may use what its provider\'s share has left (nothing is reserved; idle runs hold no money). Every provider is held to it: Claude between model calls, OpenCode per step, Codex per rollout record or turn (at list price). Ignored, with a correction, when the user chose No limit.'
136
137
  ),
137
138
  uses_browser: z.boolean().optional().describe(
138
139
  'true when the worker drives the SynaBun browser: it gets a loop browser tab and the browser enforcement block; page content is treated as untrusted data. Design runs default to true; false keeps one off the browser (no tab, no browser profile).'
@@ -231,28 +232,28 @@ export const agentUsageSchema = {
231
232
  // ── Descriptions (routing instructions) ──
232
233
 
233
234
  export const agentCatalogDescription =
234
- 'Discover what you can route to: providers (claude-code, codex, opencode) with models (tier, price per 1M tokens, vision, context, efforts), accounts, registered projects (cwd candidates), MCP profile presets, rails/limits and active runs. Without arguments it returns a compact routing view (OpenCode sampled); pass provider and/or search to list more models. Call it when the routing sheet in your instructions lacks a model, or after a MODEL_UNKNOWN rejection. Returns JSON.';
235
+ 'Discover what you can route to: providers (claude-code, codex, opencode) with models (tier, price per 1M tokens, vision, context, efforts), accounts with subscription usage remaining (or usage unknown; API keys are n/a), registered projects (cwd candidates), MCP profile presets, rails/limits and active runs. Without arguments it returns a compact routing view (OpenCode sampled); pass provider and/or search to list more models. Call it when the routing sheet in your instructions lacks a model, or after a MODEL_UNKNOWN rejection. Returns JSON.';
235
236
 
236
237
  export const agentRouteDescription =
237
- 'Route an actionable task BEFORE starting it (you are the planner). Give task_class, a one-line summary, your honest confidence (0-1) and 1-3 proposals (direct = here on your model; dispatch = a worker provider/model). The server applies the session\'s route mode (always ask / ask when unsure / never ask): it approves at once, or shows the user a route card and waits briefly. Follow the returned status and next: approved+dispatch → agent_dispatch with route_id; approved+direct → do it yourself; continuation → end your turn (SynaBun continues on the chosen model); pending → end your turn, the choice arrives as a [SynaBun Mailbox] route_decided event; declined → do not start (reason no_capable_model: no model can make the image or video, or see for design; tell the user which Model routes row needs one); clarifying → end your turn, the user has not answered your agent_clarify questions yet (independent:true for a task that does not depend on them). image_gen / video_gen always route to a worker whose model generates the medium, design to a worker whose model can see. Never use it for conversation or bookkeeping. Returns JSON.';
238
+ 'Route an actionable task BEFORE starting it (you are the planner). Give task_class, a one-line summary, your honest confidence (0-1) and 1-3 proposals (direct = here on your model; dispatch = a worker provider/model). proposals.account_id accepts an account id or "auto" (most subscription usage left); limited pinned/default accounts fall back within the provider. The returned target.account includes usage and corrections explain the choice. The server applies the session\'s route mode (always ask / ask when unsure / never ask): it approves at once, or shows the user a route card and waits briefly. Follow the returned status and next: approved+dispatch → agent_dispatch with route_id; approved+direct → do it yourself; continuation → end your turn (SynaBun continues on the chosen model); pending → end your turn, the choice arrives as a [SynaBun Mailbox] route_decided event; declined → do not start (reason no_capable_model: no model can make the image or video, or see for design; tell the user which Model routes row needs one); clarifying → end your turn, the user has not answered your agent_clarify questions yet (independent:true for a task that does not depend on them). image_gen / video_gen always route to a worker whose model generates the medium, design to a worker whose model can see. With a session budget, a provider whose share is used up cannot take the task: SynaBun first divides the unspent budget again, then moves the task to the next capable provider with money left (your next proposal, the same tier on another provider, then a free model) and says so in corrections (reason budget_share, "budget: codex share used up -> claude-code/sonnet"); the saved routes yield to this. When no provider can pay it declines with reason budget_exhausted and names the dry providers (dry). The result carries budget: each provider\'s share, spent and left. Never use it for conversation or bookkeeping. Returns JSON.';
238
239
 
239
240
  export const agentClarifyDescription =
240
241
  'Ask the user 1-3 targeted questions BEFORE routing a new request that is materially ambiguous: two plausible readings with different results, an unclear target (project, feature, files, audience), destructive or irreversible scope, spend, or memories that conflict with it. Not for clear requests, details a sensible default covers, anything the request, memory or the project answers, or the model (agent_route asks that). Each question gets 2-4 options (recommended first; the user can always type their own); add constraints (what the request fixes) and assumptions (what you will assume for the rest). The card waits briefly. Follow the returned status and next: answered → route, then agent_dispatch with the brief_id (SynaBun adds the user\'s original words, their answers, the constraints and assumptions to the worker\'s context); declined → proceed on your assumptions; pending → end your turn, the answers arrive as a [SynaBun Mailbox] clarify_answered event or as the user\'s next message, and dependent routes and dispatches wait until then. Returns JSON.';
241
242
 
242
243
  export const agentListDescription =
243
- 'List dispatched worker runs with status, provider/model, title, elapsed time and cost. Use it before dispatching more work, to recover run ids, or after a mailbox event. Filter with active_only, assistant_session_id (your own session) or workflow_id. Returns JSON.';
244
+ 'List dispatched worker runs with status, provider/model, title, elapsed time, work time left (workLeftMs) and cost. Use it before dispatching more work, to recover run ids, or after a mailbox event. Filter with active_only, assistant_session_id (your own session) or workflow_id. Returns JSON.';
244
245
 
245
246
  export const agentDispatchDescription =
246
- 'Dispatch a task to a worker agent (Claude Code, Codex or OpenCode). Route it first with agent_route and pass the approved route_id (the server applies that provider/model/effort); without one, the dispatch may be held until the user picks a model (awaitingRoute:true — do not dispatch it again). After agent_clarify, pass its brief_id: the worker gets the user\'s own words and answers; while its questions are open a dependent dispatch is refused (CLARIFICATION_PENDING). The run attaches as a live automation tab in the matching sidepanel without stealing focus. Write a self-contained task that ends with a ## Result block, pass the absolute cwd and your assistant_session_id. Defaults: permission_policy "auto", capability "full", 45 minutes, $5. Use "ask" only for sensitive scopes (Codex cannot ask: use "restricted"). uses_computer:true for desktop work (one at a time, vision model). An image_gen / video_gen run makes the asset with its model\'s own generation tool; SynaBun collects the files into the run\'s result (media: path + url); with no model that generates the medium an un-routed dispatch is refused (NO_CAPABLE_MODEL), and a route_id approved for other work is refused for image_gen / video_gen / design (and the other way round: ROUTE_CLASS_MISMATCH; route the task again with its own class). A design run gets SynaBun\'s design rules and the project\'s style guide, defaults to capability "workspace", uses_browser true, mcp_profile "browser" and 60 minutes (explicit values win), runs only on a model confirmed to see (MODEL_CANNOT_SEE otherwise), and its screenshots land in the result\'s media. Group fan-outs with workflow_id, chain with parent_run_id, retry safely with idempotency_key. Over-limit dispatches are queued (queued:true, position). After dispatching, block with agent_wait rather than polling. Returns JSON.';
247
+ 'Dispatch a task to a worker agent (Claude Code, Codex or OpenCode). Route it first with agent_route and pass the approved route_id (the server applies that provider/model/effort); without one, the dispatch may be held until the user picks a model (awaitingRoute:true — do not dispatch it again). After agent_clarify, pass its brief_id: the worker gets the user\'s own words and answers; while its questions are open a dependent dispatch is refused (CLARIFICATION_PENDING). The run attaches as a live automation tab in the matching sidepanel without stealing focus. Write a self-contained task that ends with a ## Result block, pass the absolute cwd and your assistant_session_id. Defaults: permission_policy "auto", capability "full", 45 minutes of work time (max_minutes, at least 20), no per-run dollar ceiling (with a budget the run draws from its provider\'s share; a provider whose share is used up and cannot get more is refused with BUDGET_SHARE_EXHAUSTED: route again). Use "ask" only for sensitive scopes (Codex cannot ask: use "restricted"). uses_computer:true for desktop work (one at a time, vision model). An image_gen / video_gen run makes the asset with its model\'s own generation tool; SynaBun collects the files into the run\'s result (media: path + url); with no model that generates the medium an un-routed dispatch is refused (NO_CAPABLE_MODEL), and a route_id approved for other work is refused for image_gen / video_gen / design (and the other way round: ROUTE_CLASS_MISMATCH; route the task again with its own class). A design run gets SynaBun\'s design rules and the project\'s style guide, defaults to capability "workspace", uses_browser true, mcp_profile "browser" and 60 minutes of work time (explicit values win), runs only on a model confirmed to see (MODEL_CANNOT_SEE otherwise), and its screenshots land in the result\'s media. Group fan-outs with workflow_id, chain with parent_run_id, retry safely with idempotency_key. Over-limit dispatches are queued (queued:true, position). After dispatching, block with agent_wait rather than polling. Returns JSON.';
247
248
 
248
249
  export const agentStatusDescription =
249
- 'Get one run\'s current descriptor: status (queued, running, completed, failed, stopped, interrupted), turnState (running, idle, awaiting_permission), provider/model/account, elapsed time, cost, the last parsed result summary and any pending permission or question requests. Cheap; use it between agent_wait calls or before agent_send / agent_stop. Returns JSON.';
250
+ 'Get one run\'s current descriptor: status (queued, running, completed, failed, stopped, interrupted), turnState (running, idle, awaiting_permission), provider/model/account, elapsed time (elapsedMs, wall clock), work time used and left of max_minutes (workMs, workLeftMs), cost, the last parsed result summary and any pending permission or question requests. Cheap; use it between agent_wait calls or before agent_send / agent_stop. Returns JSON.';
250
251
 
251
252
  export const agentReadDescription =
252
253
  'Read a run\'s output. format "result" (default) returns the parsed ## Result contract (status, summary, changes, follow_ups, question, json, and media: the images / videos an image_gen or video_gen run generated or a design run captured, each { kind, path, url, mime, bytes } — show one with ![](url) plus its path); "tail" returns the last transcript events; "text" the worker\'s assistant text; "files" the files it reported. Call after agent_wait reports idle or terminal; keep max_chars small and read again if truncated. Returns JSON.';
253
254
 
254
255
  export const agentSendDescription =
255
- 'Continue a worker\'s conversation. text sends a follow-up turn (queue:true enqueues it while the worker is still running). reply answers a pending permission or question request: decision allow/deny for tools, answer (with answers) for questions, note as an optional message. Obtain request ids from agent_status or agent_wait until="event". Returns JSON.';
256
+ 'Continue a worker\'s conversation. text sends a follow-up turn (queue:true enqueues it while the worker is still running). reply answers a pending permission or question request: decision allow/deny for tools, answer (with answers) for questions, note as an optional message. Obtain request ids from agent_status or agent_wait until="event". A follow-up to a run whose work time (max_minutes) is used up is refused with TIME_CAP: dispatch a new run with its result as context. Returns JSON.';
256
257
 
257
258
  export const agentWaitDescription =
258
259
  'Blocking barrier for orchestration. Waits up to timeout_seconds (max 120) for one run (run_id), several runs (run_ids with mode all/any) or a whole workflow to reach until="idle" (turn finished; default), "terminal" (completed, failed, stopped) or "event" (next mailbox event: result, needs_input, permission_request, failed). Returns the run descriptors and whether the wait timed out; call again to keep waiting. Prefer this over polling agent_status. Returns JSON.';
@@ -264,7 +265,7 @@ export const agentFocusDescription =
264
265
  'Bring a run\'s sidepanel automation tab to the front (focus:false releases it). Use when the user asks to watch a worker; dispatches never steal focus by themselves. Returns JSON.';
265
266
 
266
267
  export const agentUsageDescription =
267
- 'Get token usage for a task, run, or entire Assistant session. Returns compact JSON. `session` is the headline the panel shows: every task of this session added up (it only grows, and survives a restart), with a per-model breakdown (models: inputTotal, outputTotal, total, costUsd, costBasis). Below it the task asked for: tokens, USD cost, fidelity, unsynced (rows not on disk yet, normally 0), and each agent\'s key, title, provider, model, total, sub-agents total, fidelity and state (partialReason when a count is partial; calls on the Jev judgments row). Every tokens object has the five additive classes (input = uncached input, cacheWrite, cacheRead, output = visible output, reasoning), total, inputTotal (input + cacheWrite + cacheRead: everything sent to the model) and outputTotal (output + reasoning): the same meaning for every provider, nothing counted twice. costUsd is at API list prices; costBasis says how it is known: reported (the provider reported it), estimated (tokens at list price: Codex and other plan-billed work, where it is the list-price equivalent, not a charge), free, or unpriced (no list price: tokens counted, no dollars). Counts are exact provider counts when fidelity is exact; live marks provisional counts and partial marks incomplete counts. metered:false means this server keeps no usage ledger. No routing is needed.';
268
+ 'Get token usage for a task, run, or entire Assistant session. Returns compact JSON. `session` is the headline the panel shows: every task of this session added up (it only grows, and survives a restart), with a per-model breakdown (models: inputTotal, outputTotal, total, costUsd, costBasis). Below it the task asked for: tokens, USD cost, fidelity, unsynced (rows not on disk yet, normally 0), and each agent\'s key, title, provider, model, total, sub-agents total, fidelity and state (partialReason when a count is partial; calls on the Jev judgments row). `budget` is the session budget: mode (limited / unlimited: the user chose No limit), the amount, spent and left, warned / exceeded, how the split was made (source jev | fallback, updatedAt) and each provider\'s share, spent and left (brain marks your own provider; leftUsd is what its workers may still spend), and dry: the providers whose share is used up. Every tokens object has the five additive classes (input = uncached input, cacheWrite, cacheRead, output = visible output, reasoning), total, inputTotal (input + cacheWrite + cacheRead: everything sent to the model) and outputTotal (output + reasoning): the same meaning for every provider, nothing counted twice. costUsd is at API list prices; costBasis says how it is known: reported (the provider reported it), estimated (tokens at list price: Codex and other plan-billed work, where it is the list-price equivalent, not a charge), free, or unpriced (no list price: tokens counted, no dollars). Counts are exact provider counts when fidelity is exact; live marks provisional counts and partial marks incomplete counts. metered:false means this server keeps no usage ledger. No routing is needed.';
268
269
 
269
270
  // ── Handlers ──
270
271
 
@@ -473,6 +474,23 @@ export function handleAgentUsage(args: AgentUsageArgs): Promise<ToolResult> {
473
474
  tasks: Array.isArray(session.tasks) ? session.tasks.length : session.tasks ?? 0,
474
475
  models: (Array.isArray(session.models) ? session.models : []).map(compactModel),
475
476
  });
477
+ /** The session budget: the mode, the total, and each provider's share / spent / left. */
478
+ const compactBudget = (b: any) => {
479
+ if (!b || typeof b !== 'object') return null;
480
+ if (b.unlimited) return { mode: 'unlimited', spentUsd: b.spentUsd ?? 0 };
481
+ return {
482
+ mode: 'limited', amountUsd: b.amountUsd ?? null, spentUsd: b.spentUsd ?? 0, leftUsd: b.leftUsd ?? null,
483
+ warnAtUsd: b.warnAtUsd ?? null, warned: !!b.warned, exceeded: !!b.exceeded,
484
+ split: b.split ? { source: b.split.source ?? null, reason: b.split.reason ?? null, updatedAt: b.split.updatedAt ?? null } : null,
485
+ providers: (Array.isArray(b.providers) ? b.providers : []).map((row: any) => ({
486
+ provider: row.provider, ...(row.isBrain ? { brain: true } : {}), eligible: row.eligible !== false,
487
+ shareUsd: row.shareUsd ?? null, spentUsd: row.spentUsd ?? 0, leftUsd: row.workerLeftUsd ?? row.leftUsd ?? null,
488
+ ...(row.isBrain ? { brainLeftUsd: row.leftUsd ?? null } : {}),
489
+ })),
490
+ dry: Array.isArray(b.dry) ? b.dry : [],
491
+ };
492
+ };
493
+ const budget = compactBudget((answer as any).budget);
476
494
  const compactAgent = (agent: any) => ({
477
495
  key: agent.key, title: agent.title ?? null, provider: agent.provider, model: agent.model,
478
496
  tokens: agent.tokens, total: agent.tokens?.total ?? 0, subagents: { total: agent.subagents?.total ?? 0 },
@@ -484,9 +502,9 @@ export function handleAgentUsage(args: AgentUsageArgs): Promise<ToolResult> {
484
502
  if (task === 'all') {
485
503
  const session = answer.session as any;
486
504
  // The server has no usage ledger: say so, never fail on the missing view.
487
- if (!session) return text(JSON.stringify({ sessionId: args.assistant_session_id, metered: false, tokens: null, costUsd: 0, tasks: [] }));
505
+ if (!session) return text(JSON.stringify({ sessionId: args.assistant_session_id, metered: false, tokens: null, costUsd: 0, tasks: [], budget }));
488
506
  const { tasks: _taskCount, ...totals } = sessionHead(session);
489
- const head = { sessionId: session.sessionId, ...totals, unsynced: session.unsynced ?? 0 };
507
+ const head = { sessionId: session.sessionId, ...totals, unsynced: session.unsynced ?? 0, budget };
490
508
  if (args.run_id) {
491
509
  const run = answer.run as any;
492
510
  const worked = new Set<string>(Array.isArray(run?.taskIds) ? run.taskIds : []);
@@ -500,7 +518,7 @@ export function handleAgentUsage(args: AgentUsageArgs): Promise<ToolResult> {
500
518
  return text(JSON.stringify({ ...head, tasks: session.tasks }));
501
519
  }
502
520
  const view = answer.usage as any;
503
- if (!view) return text(JSON.stringify({ sessionId: args.assistant_session_id, metered: false, task: null, tokens: null, costUsd: 0, fidelity: null, agents: [] }));
521
+ if (!view) return text(JSON.stringify({ sessionId: args.assistant_session_id, metered: false, task: null, tokens: null, costUsd: 0, fidelity: null, agents: [], budget }));
504
522
  const detail = view.task;
505
523
  return text(JSON.stringify({
506
524
  sessionId: view.sessionId,
@@ -511,6 +529,7 @@ export function handleAgentUsage(args: AgentUsageArgs): Promise<ToolResult> {
511
529
  // Rows the ledger has not written to disk yet (normally 0).
512
530
  unsynced: view.session?.unsynced ?? 0,
513
531
  agents: (detail?.agents || []).filter((agent: any) => !args.run_id || agent.key === args.run_id || agent.runId === args.run_id).map(compactAgent),
532
+ budget,
514
533
  }));
515
534
  });
516
535
  }
@@ -21,7 +21,7 @@
21
21
  * reloading the tab once) and only then reports "not logged in" — when the page
22
22
  * really holds no session.
23
23
  */
24
- import { z } from 'zod';
24
+ import { z } from 'zod/v3';
25
25
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
26
26
  import * as ni from '../services/neural-interface.js';
27
27
  import { text } from './response.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import * as navigate from './browser-navigate.js';
4
4
  import * as interact from './browser-interact.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { text } from './response.js';
3
3
 
4
4
  const PLATFORMS = ['twitter', 'facebook', 'tiktok', 'whatsapp', 'instagram', 'linkedin', 'bluesky'] as const;
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import { text } from './response.js';
4
4
  import { formatInlineSnapshot, formatAiSnapshotBody } from './browser-observe.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import { text } from './response.js';
4
4
  import { formatInlineSnapshot, formatAiSnapshotBody } from './browser-observe.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import { getMemory } from '../services/sqlite.js';
4
4
  import { cleanName, parseSeedQueue, regionForSeed, resolveClassification } from '../services/fb-regions.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import { text, image } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import {
3
3
  validateCategoryName,
4
4
  addCategory,
@@ -86,6 +86,11 @@ async function handleCreate(args: {
86
86
  return text('Invalid color format. Use hex format: #rrggbb (e.g., #3b82f6)');
87
87
  }
88
88
 
89
+ // A child under a parent that does not exist would be dangling (a fresh install has no categories at all).
90
+ if (args.parent && !categoryExists(args.parent)) {
91
+ return text(`Parent category "${args.parent}" does not exist. Create "${args.name}" with no parent, or create the parent first. Available: ${getAllCategories().join(', ') || '(none)'}`);
92
+ }
93
+
89
94
  addCategory(args.name, args.description.trim(), args.parent, args.color, args.is_parent);
90
95
  refreshCategorySchemas();
91
96
 
@@ -1,6 +1,6 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import type { ElicitRequestFormParams } from '@modelcontextprotocol/sdk/types.js';
3
- import { z } from 'zod';
3
+ import { z } from 'zod/v3';
4
4
 
5
5
  import { text } from './response.js';
6
6
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { callerDesktopGrant } from '../services/identity.js';
4
4
  import { desktopAct, desktopApps, desktopAx, desktopStatus, type DesktopResponse } from '../services/desktop-client.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as discord from '../services/discord.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as discord from '../services/discord.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as discord from '../services/discord.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as discord from '../services/discord.js';
3
3
  import { coerceStringArray } from './utils.js';
4
4
  import { text } from './response.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as discord from '../services/discord.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as discord from '../services/discord.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as discord from '../services/discord.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as discord from '../services/discord.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { text } from './response.js';
3
3
  import {
4
4
  getMemory, scrollMemories,
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { softDeleteMemory, getMemory } from '../services/sqlite.js';
3
3
  import type { MemoryPayload } from '../types.js';
4
4
  import { invalidateCache } from '../services/neural-interface.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -4,7 +4,7 @@
4
4
  * gsc_manual_actions, gsc_enhancements, gsc_links_report, gsc_links_export
5
5
  */
6
6
 
7
- import { z } from 'zod';
7
+ import { z } from 'zod/v3';
8
8
  import * as ni from '../../services/neural-interface.js';
9
9
  import { text } from '../response.js';
10
10
  import { GSC_BASE, encodeProperty, currentProperty, ensureAuth, resolve, wait, pollFor, safeNavigate, TABLE_EXTRACTOR_SCRIPT, readMetricTileScript } from './helpers.js';
@@ -4,7 +4,7 @@
4
4
  * gsc_sitemap, gsc_removals, gsc_removals_cancel
5
5
  */
6
6
 
7
- import { z } from 'zod';
7
+ import { z } from 'zod/v3';
8
8
  import * as ni from '../../services/neural-interface.js';
9
9
  import { text } from '../response.js';
10
10
  import { GSC_BASE, encodeProperty, currentProperty, ensureAuth, resolve, wait, pollFor, safeNavigate, TABLE_EXTRACTOR_SCRIPT, readMetricTileScript } from './helpers.js';
@@ -3,7 +3,7 @@
3
3
  * gsc_inspect_url, gsc_inspect_test_live, gsc_inspect_request_indexing, gsc_inspect_view_crawled
4
4
  */
5
5
 
6
- import { z } from 'zod';
6
+ import { z } from 'zod/v3';
7
7
  import * as ni from '../../services/neural-interface.js';
8
8
  import { text } from '../response.js';
9
9
  import { GSC_BASE, encodeProperty, currentProperty, ensureAuth, resolve, wait, pollFor, safeNavigate } from './helpers.js';
@@ -3,7 +3,7 @@
3
3
  * Tools: gsc_navigate, gsc_property
4
4
  */
5
5
 
6
- import { z } from 'zod';
6
+ import { z } from 'zod/v3';
7
7
  import * as ni from '../../services/neural-interface.js';
8
8
  import { text } from '../response.js';
9
9
  import { GSC_BASE, encodeProperty, currentProperty, ensureAuth, resolve, wait, pollFor, safeNavigate } from './helpers.js';
@@ -3,7 +3,7 @@
3
3
  * gsc_performance_query, gsc_performance_export, gsc_performance_chart_screenshot
4
4
  */
5
5
 
6
- import { z } from 'zod';
6
+ import { z } from 'zod/v3';
7
7
  import * as ni from '../../services/neural-interface.js';
8
8
  import { text } from '../response.js';
9
9
  import { GSC_BASE, encodeProperty, currentProperty, ensureAuth, resolve, wait, pollFor, safeNavigate, TABLE_EXTRACTOR_SCRIPT, readMetricTileScript } from './helpers.js';
@@ -4,7 +4,7 @@
4
4
  * gsc_disavow, gsc_shopping, gsc_extract_table, gsc_screenshot
5
5
  */
6
6
 
7
- import { z } from 'zod';
7
+ import { z } from 'zod/v3';
8
8
  import * as ni from '../../services/neural-interface.js';
9
9
  import { text } from '../response.js';
10
10
  import { GSC_BASE, encodeProperty, currentProperty, ensureAuth, resolve, wait, pollFor, safeNavigate, TABLE_EXTRACTOR_SCRIPT, readMetricTileScript } from './helpers.js';
@@ -5,7 +5,7 @@
5
5
  * Any skill or tool can use staged images (Leonardo references, social posts, etc.).
6
6
  */
7
7
 
8
- import { z } from 'zod';
8
+ import { z } from 'zod/v3';
9
9
  import * as ni from '../services/neural-interface.js';
10
10
  import { text } from './response.js';
11
11
 
@@ -6,7 +6,7 @@
6
6
  * Tools: leonardo_browser_navigate, leonardo_browser_generate, leonardo_browser_library, leonardo_browser_download, leonardo_browser_reference
7
7
  */
8
8
 
9
- import { z } from 'zod';
9
+ import { z } from 'zod/v3';
10
10
  import * as ni from '../services/neural-interface.js';
11
11
  import { text } from './response.js';
12
12
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { readFileSync, writeFileSync, existsSync, unlinkSync, mkdirSync, readdirSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import { text } from './response.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { scrollMemories, getMemoryStats, getMemory, rowToSessionChunkPayload } from '../services/sqlite.js';
3
3
  import { validateCategory } from '../services/categories.js';
4
4
  import type { MemoryPayload } from '../types.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import * as ni from '../services/neural-interface.js';
4
4
  import { text } from './response.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { text } from './response.js';
3
3
  import { VALID_GROUPS, getProfilePresets, persistRuntimeProfile, type ProfileRuntime } from '../services/profiles.js';
4
4
  import { reportRuntimeMcpProfile, type RuntimeMcpProfileReport } from '../services/neural-interface.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { readFileSync } from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { retrieveMemory, compactRecall } from '../services/memory-retrieval.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { getMemory, updatePayload, upsertMemory, getDb, memoryVectors } from '../services/sqlite.js';
3
3
  import { generateEmbedding } from '../services/local-embeddings.js';
4
4
  import { validateCategory } from '../services/categories.js';
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { writeMemory, IdempotencyConflict, type WriteMemoryResult } from '../services/memory-writer.js';
3
- import { z } from 'zod';
4
- import { categoryExists, getAllCategories, getCategories } from '../services/categories.js';
3
+ import { z } from 'zod/v3';
4
+ import { categoryExists, ensureCategory, ensureFeatureCategory, getCategories, projectCategoryLabel } from '../services/categories.js';
5
5
  import { coerceStringArray } from './utils.js';
6
6
  import type { MemoryPayload, MemorySource } from '../types.js';
7
7
  import { detectProject, projectRoot } from '../config.js';
@@ -112,22 +112,23 @@ export const rememberDescription =
112
112
 
113
113
  /**
114
114
  * Resolve the category to store under. If the caller supplied a valid category,
115
- * use it verbatim. Otherwise fall back to a project default so a memory is never
116
- * lost just because the required field was omitted or misspelled.
115
+ * use it verbatim. A feature's category (conversations, communication-style, …)
116
+ * is created the first time it is asked for: a fresh install has none. Anything
117
+ * else falls back to the project's default child, created if it is missing, so a
118
+ * memory is never lost just because the required field was omitted or misspelled.
117
119
  * Returns the chosen category and whether a fallback was applied.
118
120
  */
119
121
  function resolveCategory(requested: string | undefined, project: string): { category: string; fallback: boolean } {
120
122
  if (requested && categoryExists(requested)) {
121
123
  return { category: requested, fallback: false };
122
124
  }
123
- const all = getAllCategories();
124
- const projectDefault = `${project}-project`;
125
- const chosen =
126
- (all.includes(projectDefault) && projectDefault) ||
127
- (all.includes('conversations') && 'conversations') ||
128
- all[0] ||
129
- 'conversations';
130
- return { category: chosen, fallback: true };
125
+ if (requested && ensureFeatureCategory(requested)) {
126
+ return { category: requested, fallback: false };
127
+ }
128
+ const label = projectCategoryLabel(project);
129
+ const projectDefault = `${label}-project`;
130
+ ensureCategory(projectDefault, `General project knowledge, decisions, and milestones for ${project}`, { parent: label });
131
+ return { category: projectDefault, fallback: true };
131
132
  }
132
133
 
133
134
  export async function handleRemember(args: {
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { restoreMemory, getMemory } from '../services/sqlite.js';
3
3
  import type { MemoryPayload } from '../types.js';
4
4
  import { text } from './response.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { resolve } from 'path';
3
3
  import { existsSync, lstatSync, readFileSync } from 'fs';
4
4
  import * as ni from '../services/neural-interface.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import { scrollMemories } from '../services/sqlite.js';
3
3
  import { hashFile, resolveStoredPath } from '../services/file-checksums.js';
4
4
  import { fileExcerpt } from '../services/file-excerpt.js';
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import { text } from './response.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
 
3
3
  /**
4
4
  * A boolean argument as a model sends it: true / false, "true" / "false"
@@ -0,0 +1,51 @@
1
+ import { z } from 'zod/v3';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import * as ni from '../services/neural-interface.js';
4
+ import { callerBrainCredential, callerRole } from '../services/identity.js';
5
+ import { text } from './response.js';
6
+
7
+ // ═══════════════════════════════════════════
8
+ // whatsapp_send_file — a local file to the owner, in the WhatsApp conversation
9
+ // ═══════════════════════════════════════════
10
+ //
11
+ // In the role-gated `agents` group (profiles.ts ROLE_GATED_GROUPS): advertised
12
+ // to assistant brains only, and the handler refuses any other caller. One
13
+ // POST to /api/assistant/whatsapp/send-file (neural-interface/lib/assistant-api.js)
14
+ // carrying the brain's own credential (identity.ts callerBrainCredential), which
15
+ // the server resolves to the WhatsApp conversation; the WhatsApp host checks and
16
+ // reads the file (neural-interface/lib/whatsapp/local-file.js). Never retried:
17
+ // a timeout may come after WhatsApp took the file. No recipient, no session id.
18
+
19
+ export const WHATSAPP_SEND_FILE_DENIED = 'whatsapp_send_file is only available to the SynaBun assistant runtime.';
20
+
21
+ export const WHATSAPP_SEND_AS = ['auto', 'document', 'image', 'video', 'audio'] as const;
22
+
23
+ export const whatsappSendFileSchema = {
24
+ path: z.string().min(1).max(2048).describe('Absolute path of an existing regular file on this computer. No URL or network share.'),
25
+ caption: z.string().max(1024).optional().describe('Text shown under the file (at most 1024 characters). Audio has none: leave it out, or choose as "document".'),
26
+ as: z.enum(WHATSAPP_SEND_AS).optional().describe(
27
+ 'Default "auto": JPEG/PNG/WebP as a photo, MP4 as a video, OGG/Opus/MP3/M4A as audio, everything else as a document. "document" sends the original file as it is. Photos, videos and audio over 16 MiB go as documents; nothing over 100 MiB is sent. A native form that does not match the extension is refused.'
28
+ ),
29
+ };
30
+
31
+ export const whatsappSendFileDescription = 'Send a file already on this computer as a real WhatsApp attachment to the owner, in THIS WhatsApp conversation. Use it only when the user asked you to send a file (a generated image or video they asked for included: take its local path from the worker result\'s media). Only the active WhatsApp conversation\'s own Assistant can use it: never workers, desktop chats or other contacts; there is no recipient or session parameter. Sensitive places (keys, credentials, browser and app data, SynaBun\'s own data) are refused, and links are resolved and checked too. Returns the delivery id, type, mimetype, size, file name and canonical path, or a clear error code. An answer with uncertain: true (a timeout, a lost answer), or a call of yours that times out, means delivery is uncertain: never retry it on your own.';
32
+
33
+ export type WhatsAppSendFileArgs = z.infer<z.ZodObject<typeof whatsappSendFileSchema>>;
34
+
35
+ /** Role guard, one request, never throws: every failure reaches the brain as data. */
36
+ export async function handleWhatsAppSendFile(args: WhatsAppSendFileArgs): Promise<ReturnType<typeof text>> {
37
+ if (callerRole() !== 'assistant') return text(WHATSAPP_SEND_FILE_DENIED);
38
+ try {
39
+ const body: { path: string; caption?: string; as?: string } = { path: args.path };
40
+ if (typeof args.caption === 'string') body.caption = args.caption;
41
+ if (typeof args.as === 'string') body.as = args.as;
42
+ return text(JSON.stringify(await ni.whatsappSendFile(body, callerBrainCredential()), null, 2));
43
+ } catch (err) {
44
+ return text(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err), code: 'WHATSAPP_SEND_FILE_ERROR' }));
45
+ }
46
+ }
47
+
48
+ /** Registered into the `agents` group (index.ts): the returned handle is gated on the caller role. */
49
+ export function registerWhatsAppSendFileTool(server: McpServer) {
50
+ return server.tool('whatsapp_send_file', whatsappSendFileDescription, whatsappSendFileSchema, (args) => handleWhatsAppSendFile(args));
51
+ }
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
  import * as ni from '../services/neural-interface.js';
3
3
  import { text, image } from './response.js';
4
4
  import { SHAPE_TYPES, SECTION_TYPE_NAMES, ELEMENT_TYPES, DEFAULT_VIEWPORT, type WbElement, type WbViewport } from '../services/whiteboard-geometry.js';