synabun 2.0.10 → 2.1.0

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 (517) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +22 -0
  4. package/bin/synabun.js +71 -24
  5. package/docs/whatsapp.md +2 -2
  6. package/hooks/claude-code/pre-websearch.mjs +12 -1
  7. package/hooks/claude-code/shared.mjs +5 -0
  8. package/hooks/claude-code/stop.mjs +1 -1
  9. package/lib/claude-hooks.js +172 -18
  10. package/lib/client-config-repair.js +17 -8
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +1 -1
  13. package/lib/first-launch-protection.js +57 -12
  14. package/lib/mcp-dist.js +176 -0
  15. package/lib/release-npm-ci.mjs +138 -0
  16. package/lib/release-publish.mjs +91 -0
  17. package/lib/release-scan.mjs +50 -0
  18. package/lib/server-crash-record.js +123 -0
  19. package/lib/server-exit.js +318 -0
  20. package/lib/server-supervisor.js +508 -0
  21. package/lib/start-launcher.js +37 -4
  22. package/lib/tools-cli.js +45 -0
  23. package/lib/update-snapshot.js +228 -0
  24. package/lib/virustotal.mjs +192 -0
  25. package/lib/windows-crash-event.js +269 -0
  26. package/mcp-server/dist/http.d.ts +20 -1
  27. package/mcp-server/dist/http.d.ts.map +1 -1
  28. package/mcp-server/dist/http.js +59 -12
  29. package/mcp-server/dist/http.js.map +1 -1
  30. package/mcp-server/dist/index.d.ts +33 -27
  31. package/mcp-server/dist/index.d.ts.map +1 -1
  32. package/mcp-server/dist/index.js +128 -143
  33. package/mcp-server/dist/index.js.map +1 -1
  34. package/mcp-server/dist/preload.js +1 -1
  35. package/mcp-server/dist/preload.js.map +1 -1
  36. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  37. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  38. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  39. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  40. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  41. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  42. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  43. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  44. package/mcp-server/dist/services/neural-interface.d.ts +16 -10
  45. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  46. package/mcp-server/dist/services/neural-interface.js +67 -11
  47. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  48. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  49. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  50. package/mcp-server/dist/services/server-instructions.js +20 -62
  51. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  52. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  53. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  54. package/mcp-server/dist/services/tool-catalog.js +339 -0
  55. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  56. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  57. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  58. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  59. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  60. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  61. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  62. package/mcp-server/dist/services/tool-list.js +334 -0
  63. package/mcp-server/dist/services/tool-list.js.map +1 -0
  64. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  65. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  66. package/mcp-server/dist/services/tool-runtime.js +400 -0
  67. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  68. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  69. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  70. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  71. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  72. package/mcp-server/dist/tools/agents.d.ts +10 -10
  73. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  74. package/mcp-server/dist/tools/agents.js +22 -13
  75. package/mcp-server/dist/tools/agents.js.map +1 -1
  76. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  77. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  78. package/mcp-server/dist/tools/image-tools.js +1 -1
  79. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  80. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  81. package/mcp-server/dist/tools/skill-tools.js +639 -0
  82. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  83. package/mcp-server/dist/tools/skill.d.ts +7 -0
  84. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  85. package/mcp-server/dist/tools/skill.js +11 -0
  86. package/mcp-server/dist/tools/skill.js.map +1 -0
  87. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  88. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  89. package/mcp-server/dist/tools/tool-groups.js +147 -0
  90. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  91. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  92. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  93. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  94. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  95. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  96. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  97. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  98. package/mcp-server/package-lock.json +2 -2
  99. package/mcp-server/package.json +1 -1
  100. package/mcp-server/src/http.ts +75 -12
  101. package/mcp-server/src/index.ts +147 -154
  102. package/mcp-server/src/preload.ts +12 -12
  103. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  104. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  105. package/mcp-server/src/services/neural-interface.ts +79 -20
  106. package/mcp-server/src/services/server-instructions.ts +27 -63
  107. package/mcp-server/src/services/tool-catalog.ts +403 -0
  108. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  109. package/mcp-server/src/services/tool-list.ts +410 -0
  110. package/mcp-server/src/services/tool-runtime.ts +457 -0
  111. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  112. package/mcp-server/src/tools/agents.ts +22 -14
  113. package/mcp-server/src/tools/image-tools.ts +1 -1
  114. package/mcp-server/src/tools/skill-tools.ts +589 -0
  115. package/mcp-server/src/tools/skill.ts +13 -0
  116. package/mcp-server/src/tools/tool-groups.ts +164 -0
  117. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  118. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  119. package/neural-interface/i18n/en.json +3463 -200
  120. package/neural-interface/i18n/pt-BR.json +3411 -151
  121. package/neural-interface/lib/assistant-api.js +127 -28
  122. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  123. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  124. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  125. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  126. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  127. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  128. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  129. package/neural-interface/lib/assistant-catalog.js +6 -7
  130. package/neural-interface/lib/assistant-dispatch.js +871 -156
  131. package/neural-interface/lib/assistant-envelope.js +3 -1
  132. package/neural-interface/lib/assistant-persona.js +80 -11
  133. package/neural-interface/lib/assistant-plan-permissions.js +10 -9
  134. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  135. package/neural-interface/lib/assistant-route-gate.js +6 -4
  136. package/neural-interface/lib/assistant-router.js +13 -8
  137. package/neural-interface/lib/assistant-runtime.js +56 -18
  138. package/neural-interface/lib/assistant-task-prompt.js +78 -14
  139. package/neural-interface/lib/assistant-tools.js +51 -0
  140. package/neural-interface/lib/backup-service.js +620 -3
  141. package/neural-interface/lib/backup-zip-reader.js +10 -5
  142. package/neural-interface/lib/backup-zip-writer.js +257 -0
  143. package/neural-interface/lib/browser-execution.js +10 -2
  144. package/neural-interface/lib/browser-guard-cdp.js +83 -0
  145. package/neural-interface/lib/browser-network-guard.js +284 -0
  146. package/neural-interface/lib/browser-policy-roots.js +64 -0
  147. package/neural-interface/lib/browser-tool-policy.js +186 -31
  148. package/neural-interface/lib/claude-agent-bridge.js +4 -2
  149. package/neural-interface/lib/claude-hooks-status.js +103 -0
  150. package/neural-interface/lib/claude-temporary.js +5 -11
  151. package/neural-interface/lib/cli-install.js +18 -138
  152. package/neural-interface/lib/cli-resolver.js +4 -1
  153. package/neural-interface/lib/cli-update-planner.js +32 -31
  154. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  155. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  156. package/neural-interface/lib/codex-worker-app-server.js +172 -0
  157. package/neural-interface/lib/confined-fs.js +30 -3
  158. package/neural-interface/lib/crash-notice-api.js +98 -0
  159. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  160. package/neural-interface/lib/exec-loop-command.js +4 -8
  161. package/neural-interface/lib/http-guards.js +8 -2
  162. package/neural-interface/lib/install-details.js +4 -1
  163. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  164. package/neural-interface/lib/mcp-client-config.js +0 -29
  165. package/neural-interface/lib/mcp-external-servers.js +323 -0
  166. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  167. package/neural-interface/lib/morelogin.js +30 -0
  168. package/neural-interface/lib/native-loop-providers.js +547 -47
  169. package/neural-interface/lib/native-loop-runtime.js +268 -41
  170. package/neural-interface/lib/opencode-config.js +557 -0
  171. package/neural-interface/lib/opencode-db-schema.js +17 -34
  172. package/neural-interface/lib/opencode-history.js +48 -218
  173. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  174. package/neural-interface/lib/opencode-native-boundary.js +44 -0
  175. package/neural-interface/lib/opencode-protocol.js +249 -112
  176. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  177. package/neural-interface/lib/opencode-serve-records.js +39 -21
  178. package/neural-interface/lib/opencode-v2-client.js +48 -153
  179. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  180. package/neural-interface/lib/opencode-worker-data.js +27 -0
  181. package/neural-interface/lib/opencode2-client.js +73 -37
  182. package/neural-interface/lib/opencode2-proxy.js +23 -63
  183. package/neural-interface/lib/opencode2-translate.js +51 -2
  184. package/neural-interface/lib/owner-authority.js +249 -0
  185. package/neural-interface/lib/page-session.js +275 -0
  186. package/neural-interface/lib/peer-identity.js +763 -0
  187. package/neural-interface/lib/request-gate.js +17 -2
  188. package/neural-interface/lib/rulesets/api.js +1 -1
  189. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  190. package/neural-interface/lib/rulesets/installer.js +92 -27
  191. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  192. package/neural-interface/lib/session-cache-builder.js +17 -30
  193. package/neural-interface/lib/session-title-generator.js +58 -36
  194. package/neural-interface/lib/skills/api-v2.js +495 -0
  195. package/neural-interface/lib/skills/bundle.js +418 -0
  196. package/neural-interface/lib/skills/catalog.js +294 -0
  197. package/neural-interface/lib/skills/creation-api.js +191 -0
  198. package/neural-interface/lib/skills/creation-brief.js +247 -0
  199. package/neural-interface/lib/skills/creation-sources.js +267 -0
  200. package/neural-interface/lib/skills/creation.js +843 -0
  201. package/neural-interface/lib/skills/deploy.js +564 -0
  202. package/neural-interface/lib/skills/digest.js +119 -0
  203. package/neural-interface/lib/skills/discover.js +111 -0
  204. package/neural-interface/lib/skills/draft-confinement.js +214 -0
  205. package/neural-interface/lib/skills/eval-confinement.js +397 -0
  206. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  207. package/neural-interface/lib/skills/eval-trace.js +119 -0
  208. package/neural-interface/lib/skills/evals-api.js +212 -0
  209. package/neural-interface/lib/skills/evals.js +1573 -0
  210. package/neural-interface/lib/skills/export.js +200 -0
  211. package/neural-interface/lib/skills/frontmatter.js +64 -0
  212. package/neural-interface/lib/skills/health.js +75 -0
  213. package/neural-interface/lib/skills/json-edit.js +165 -0
  214. package/neural-interface/lib/skills/known-bridge-digests.json +387 -0
  215. package/neural-interface/lib/skills/known-bridges.js +96 -0
  216. package/neural-interface/lib/skills/library.js +823 -0
  217. package/neural-interface/lib/skills/local-store.js +21 -0
  218. package/neural-interface/lib/skills/migration.js +433 -0
  219. package/neural-interface/lib/skills/operations.js +45 -0
  220. package/neural-interface/lib/skills/ownership.js +427 -0
  221. package/neural-interface/lib/skills/packages.js +88 -0
  222. package/neural-interface/lib/skills/reviews.js +212 -0
  223. package/neural-interface/lib/skills/revision.js +80 -0
  224. package/neural-interface/lib/skills/roots.js +262 -0
  225. package/neural-interface/lib/skills/runtime-checks.js +355 -0
  226. package/neural-interface/lib/skills/scan-assets.js +252 -0
  227. package/neural-interface/lib/skills/scan-context.js +26 -0
  228. package/neural-interface/lib/skills/scan-shell.js +324 -0
  229. package/neural-interface/lib/skills/scan.js +364 -0
  230. package/neural-interface/lib/skills/scanners.js +54 -0
  231. package/neural-interface/lib/skills/service.js +522 -0
  232. package/neural-interface/lib/skills/telemetry.js +113 -0
  233. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  234. package/neural-interface/lib/tool-lists.js +124 -0
  235. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  236. package/neural-interface/lib/worker-confinement.js +1192 -0
  237. package/neural-interface/lib/worker-guard-setting.js +56 -0
  238. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  239. package/neural-interface/lib/worker-relay-ports.js +227 -0
  240. package/neural-interface/lib/worker-resume.js +229 -0
  241. package/neural-interface/lib/worker-sandbox.js +299 -0
  242. package/neural-interface/package-lock.json +18 -12
  243. package/neural-interface/package.json +2 -2
  244. package/neural-interface/public/index.html +3 -1
  245. package/neural-interface/public/index2d.html +19 -11
  246. package/neural-interface/public/onboarding.html +2 -2
  247. package/neural-interface/public/shared/account-menu.js +8 -5
  248. package/neural-interface/public/shared/agent-runtime-options.js +35 -19
  249. package/neural-interface/public/shared/api.js +1527 -1336
  250. package/neural-interface/public/shared/app-frame.js +192 -0
  251. package/neural-interface/public/shared/assistant/asst-agents-dock.js +33 -2
  252. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  253. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  254. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  255. package/neural-interface/public/shared/assistant/asst-brain-picker.js +49 -35
  256. package/neural-interface/public/shared/assistant/asst-control.js +157 -26
  257. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  258. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  259. package/neural-interface/public/shared/assistant/asst-limit-dock.js +40 -0
  260. package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -0
  261. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  262. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  263. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  264. package/neural-interface/public/shared/assistant/asst-panel.js +106 -11
  265. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  266. package/neural-interface/public/shared/assistant/asst-render.js +401 -77
  267. package/neural-interface/public/shared/assistant/asst-route.js +83 -12
  268. package/neural-interface/public/shared/assistant/asst-scenes.js +2 -0
  269. package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
  270. package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
  271. package/neural-interface/public/shared/assistant/asst-state.js +11 -15
  272. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  273. package/neural-interface/public/shared/assistant/asst-styles.js +59 -21
  274. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +156 -16
  275. package/neural-interface/public/shared/automation-context.js +5 -2
  276. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  277. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  278. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  279. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  280. package/neural-interface/public/shared/cdx/cdx-output.js +8 -7
  281. package/neural-interface/public/shared/cdx/cdx-panel.js +45 -149
  282. package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
  283. package/neural-interface/public/shared/cdx/cdx-render.js +47 -29
  284. package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
  285. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  286. package/neural-interface/public/shared/cdx/cdx-styles.js +11 -3
  287. package/neural-interface/public/shared/cdx/cdx-tabs.js +52 -39
  288. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  289. package/neural-interface/public/shared/cli-install-view.js +4 -8
  290. package/neural-interface/public/shared/cli-status.js +2 -2
  291. package/neural-interface/public/shared/constants.js +2 -2
  292. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  293. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  294. package/neural-interface/public/shared/context-menu-model.js +366 -0
  295. package/neural-interface/public/shared/context-menu.js +372 -0
  296. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  297. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  298. package/neural-interface/public/shared/desktop-update-view.js +20 -0
  299. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  300. package/neural-interface/public/shared/html-shell.js +9 -11
  301. package/neural-interface/public/shared/i18n.js +2 -0
  302. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  303. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  304. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  305. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  306. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  307. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  308. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  309. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  310. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  311. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  312. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  313. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +47 -252
  314. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  315. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  316. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +6 -21
  317. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  318. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  319. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  320. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  321. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  322. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  323. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  324. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +0 -21
  325. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  326. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +14 -47
  327. package/neural-interface/public/shared/page-session.js +96 -0
  328. package/neural-interface/public/shared/registry.js +5 -3
  329. package/neural-interface/public/shared/retired-2d.js +3 -0
  330. package/neural-interface/public/shared/schedules-view.js +195 -61
  331. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  332. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  333. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  334. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  335. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  336. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  337. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  338. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  339. package/neural-interface/public/shared/skills/ss-creation.js +219 -0
  340. package/neural-interface/public/shared/skills/ss-dialog.js +130 -0
  341. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  342. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  343. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  344. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  345. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  346. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  347. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  348. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  349. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  350. package/neural-interface/public/shared/skills/ss-lint.js +141 -0
  351. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  352. package/neural-interface/public/shared/skills/ss-profiles.js +475 -0
  353. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  354. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  355. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  356. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  357. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  358. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  359. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  360. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +236 -0
  361. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  362. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  363. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  364. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  365. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  366. package/neural-interface/public/shared/skills/studio/sx-dom.js +229 -0
  367. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  368. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  369. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  370. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  371. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  372. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  373. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +279 -0
  374. package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
  375. package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
  376. package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
  377. package/neural-interface/public/shared/skills/studio/sx-main.js +681 -0
  378. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  379. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  380. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  381. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  382. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  383. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  384. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  385. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  386. package/neural-interface/public/shared/skills/studio/sx-subject.js +248 -0
  387. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  388. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  389. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  390. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +425 -0
  391. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  392. package/neural-interface/public/shared/styles.css +1525 -1779
  393. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  394. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  395. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  396. package/neural-interface/public/shared/tool-list-view.js +112 -0
  397. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  398. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  399. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  400. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  401. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  402. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  403. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  404. package/neural-interface/public/shared/tour/tour.css +144 -0
  405. package/neural-interface/public/shared/ui-automation-studio.js +91 -128
  406. package/neural-interface/public/shared/ui-claude-panel.js +77 -5
  407. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  408. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  409. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  410. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  411. package/neural-interface/public/shared/ui-detail.js +15 -3
  412. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  413. package/neural-interface/public/shared/ui-keybinds.js +26 -1
  414. package/neural-interface/public/shared/ui-menubar.js +8 -18
  415. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  416. package/neural-interface/public/shared/ui-native-loop-router.js +7 -1
  417. package/neural-interface/public/shared/ui-navbar.js +4 -24
  418. package/neural-interface/public/shared/ui-panels.js +96 -65
  419. package/neural-interface/public/shared/ui-schedules-studio.js +507 -423
  420. package/neural-interface/public/shared/ui-sessions.js +5 -3
  421. package/neural-interface/public/shared/ui-settings.js +594 -462
  422. package/neural-interface/public/shared/ui-sidepanel-sessions.js +1 -1
  423. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  424. package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
  425. package/neural-interface/public/shared/ui-skills.js +33 -2830
  426. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  427. package/neural-interface/public/shared/ui-sync.js +15 -5
  428. package/neural-interface/public/shared/ui-terminal.js +124 -180
  429. package/neural-interface/public/shared/ui-tool-updates.js +3 -1
  430. package/neural-interface/public/shared/ui-tooltip.js +10 -5
  431. package/neural-interface/public/shared/ui-trash.js +6 -4
  432. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  433. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  434. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  435. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  436. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  437. package/neural-interface/public/shared/ui-update.js +38 -2
  438. package/neural-interface/public/shared/ui-whiteboard.js +311 -58
  439. package/neural-interface/public/shared/ui-worker-end.js +4 -0
  440. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  441. package/neural-interface/public/shared/view-variant.js +66 -0
  442. package/neural-interface/public/shared/whatsapp/wa-view.js +1 -1
  443. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  444. package/neural-interface/public/shared/worker-end.js +10 -3
  445. package/neural-interface/public/shared/worker-restart.js +12 -0
  446. package/neural-interface/public/sidepanel-session.html +1 -1
  447. package/neural-interface/public/variant/2d/background.js +2 -1
  448. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  449. package/neural-interface/public/variant/2d/graph.js +42 -20
  450. package/neural-interface/public/variant/2d/hulls.js +14 -9
  451. package/neural-interface/public/variant/2d/lasso.js +11 -7
  452. package/neural-interface/public/variant/2d/main.js +32 -1
  453. package/neural-interface/public/variant/2d/minimap.js +11 -13
  454. package/neural-interface/public/variant/3d/main.js +69 -6
  455. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  456. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  457. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  458. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  459. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  460. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  461. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  462. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  463. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  464. package/neural-interface/scripts/build-vendor.mjs +32 -0
  465. package/neural-interface/server.js +3934 -2454
  466. package/neural-interface/templates/rulesets/core.md +1 -1
  467. package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
  468. package/neural-interface/templates/rulesets/manifest.json +8 -8
  469. package/npm-shrinkwrap.json +18 -12
  470. package/package.json +16 -3
  471. package/postinstall.js +9 -4
  472. package/preuninstall.js +1 -1
  473. package/setup.js +97 -322
  474. package/skills/skill-forge/SKILL.md +177 -0
  475. package/skills/skill-forge/evals/evals.json +54 -0
  476. package/skills/skill-forge/references/package.md +105 -0
  477. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  478. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  479. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  480. package/skills/synabun/SKILL.md +10 -7
  481. package/skills/synabun/modules/audit.md +1 -5
  482. package/skills/synabun/modules/changelog.md +1 -5
  483. package/skills/synabun/modules/idea.md +1 -1
  484. package/skills/synabun/modules/memorize.md +6 -9
  485. package/skills/synabun/modules/schedule.md +4 -4
  486. package/mcp-server/dist/services/profiles.d.ts +0 -120
  487. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  488. package/mcp-server/dist/services/profiles.js +0 -387
  489. package/mcp-server/dist/services/profiles.js.map +0 -1
  490. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  491. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  492. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  493. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  494. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  495. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  496. package/mcp-server/dist/tools/leonardo.js +0 -21
  497. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  498. package/mcp-server/dist/tools/profile.d.ts +0 -17
  499. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  500. package/mcp-server/dist/tools/profile.js +0 -114
  501. package/mcp-server/dist/tools/profile.js.map +0 -1
  502. package/mcp-server/src/services/profiles.ts +0 -428
  503. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  504. package/mcp-server/src/tools/leonardo.ts +0 -30
  505. package/mcp-server/src/tools/profile.ts +0 -122
  506. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  507. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  508. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  509. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  510. package/skills/leonardo/SKILL.md +0 -168
  511. package/skills/leonardo/icon.svg +0 -1
  512. package/skills/leonardo/modules/browser-guide.md +0 -378
  513. package/skills/leonardo/modules/image-prompter.md +0 -283
  514. package/skills/leonardo/modules/model-advisor.md +0 -100
  515. package/skills/leonardo/modules/prompt-library.md +0 -110
  516. package/skills/leonardo/modules/style-guide.md +0 -186
  517. package/skills/leonardo/modules/video-prompter.md +0 -317
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Tool lists: what a run names out of the catalog (docs/design/mcp-tool-lists/PLAN.md §3.2-3.4).
3
+ *
4
+ * A list is an array of group ids, `all` and `mcp:` items. parseToolList reads one, or converts a name an older
5
+ * SynaBun stored (a preset, a comma list); resolveToolList applies the defaults and the groups a run gets by itself.
6
+ * Both refuse what the catalog does not have, with suggestions. Pure: the Neural Interface (dispatch, launches) and
7
+ * the MCP child (its runtime file, its environment, a header) call the same code.
8
+ */
9
+ import {
10
+ ALWAYS_ON_TOOLS,
11
+ DEFAULT_TOOLS,
12
+ HOST_EFFECT,
13
+ LEGACY_PRESETS,
14
+ LEGACY_PRESET_PLATFORMS,
15
+ RETIRED_GROUPS,
16
+ RETIRED_PRESETS,
17
+ SELECTABLE_GROUP_IDS,
18
+ TOOL_GROUPS,
19
+ TOOL_LIST_LIMITS,
20
+ countTools,
21
+ groupOfTool,
22
+ isAlwaysOnId,
23
+ isBrowserGroup,
24
+ isGatedGroup,
25
+ isSelectableGroup,
26
+ sortGroups,
27
+ toolGroup,
28
+ type ToolListEffect,
29
+ } from './tool-catalog.js';
30
+
31
+ export type ToolListProblemReason = 'unknown' | 'gated' | 'too-long' | 'too-many' | 'not-a-string' | 'unknown-server' | 'non-selectable' | 'absent-for-provider' | 'blocked' | 'unavailable';
32
+
33
+ export interface ToolListProblem {
34
+ item: string;
35
+ reason: ToolListProblemReason;
36
+ /** Ids to name instead (group ids, `all`, `mcp:*`); empty when nothing fits. */
37
+ suggestions: string[];
38
+ /** One sentence for the person or agent that wrote the item. */
39
+ hint: string | null;
40
+ }
41
+
42
+ export type ToolListErrorCode = 'TOOLS_INVALID' | 'TOOLS_TOO_MANY';
43
+
44
+ export interface ToolListFailure {
45
+ ok: false;
46
+ code: ToolListErrorCode;
47
+ problems: ToolListProblem[];
48
+ message: string;
49
+ }
50
+
51
+ export interface ParsedToolList {
52
+ ok: true;
53
+ /** Normalized items, each once, in the order given. */
54
+ items: string[];
55
+ /** The stored preset name this was converted from, or null. */
56
+ preset: string | null;
57
+ /** The platform that preset implied (`twitter`, `facebook`), or null. */
58
+ platform: string | null;
59
+ }
60
+
61
+ export type ToolListParse = ParsedToolList | ToolListFailure;
62
+
63
+ /** Registry presets by name (`profiles.<name>.groups` of data/mcp-registry.json): read only to convert a stored name. */
64
+ export type CustomPresets = Readonly<Record<string, { groups?: unknown } | readonly unknown[] | null | undefined>>;
65
+
66
+ export type ToolListSource = 'dispatch' | 'launch' | 'runtime';
67
+ export type AddedReason = 'browser-group' | 'uses-browser' | 'design';
68
+ export interface AddedGroup { id: string; why: AddedReason }
69
+
70
+ export interface ResolveToolListContext {
71
+ /** dispatch: the Assistant's run; launch: a stored automation; runtime: an MCP child reading its own list. */
72
+ source: ToolListSource;
73
+ usesBrowser?: boolean | null;
74
+ taskClass?: string | null;
75
+ /** claude-code, codex, opencode, gemini: decides the effect. */
76
+ provider?: string | null;
77
+ /** launch: the record's own list, already converted (§3.10). */
78
+ stored?: readonly string[] | null;
79
+ /** The owner's Default tools (launch and runtime, when nothing else names a list). */
80
+ defaultTools?: readonly string[] | null;
81
+ browserV2?: boolean;
82
+ }
83
+
84
+ export interface ToolListResolution {
85
+ ok: true;
86
+ /** The items asked for, normalized; null when the run named nothing (a default applied). */
87
+ requested: string[] | null;
88
+ /** The list in its stored form: `all` or groups in catalog order, then the `mcp:` items. */
89
+ items: string[];
90
+ /** Every selectable group the run gets, in catalog order: `all` expanded, added groups included. */
91
+ groups: string[];
92
+ /** External refs; availability is checked at the provider launch boundary. */
93
+ servers: string[];
94
+ /** Groups the run gets without naming them, and why. */
95
+ added: AddedGroup[];
96
+ /** Always-on ids and tool names that were named: accepted and dropped. */
97
+ dropped: string[];
98
+ effect: ToolListEffect;
99
+ /** Tools the run loads (strict) or focuses on (focus), before its role and grants. */
100
+ count: number;
101
+ }
102
+
103
+ export type ToolListResult = ToolListResolution | ToolListFailure;
104
+
105
+ const MCP_PREFIX = /^mcp:/i;
106
+
107
+ /** Trimmed; group ids and literals lower-cased; an `mcp:` server name keeps its case. */
108
+ export function normalizeToolItem(item: string): string {
109
+ const trimmed = item.trim();
110
+ if (MCP_PREFIX.test(trimmed)) return `mcp:${trimmed.slice(4).trim()}`;
111
+ return trimmed.toLowerCase();
112
+ }
113
+
114
+ function splitList(value: string): string[] {
115
+ return value.split(',').map(normalizeToolItem).filter(Boolean);
116
+ }
117
+
118
+ function unique(items: Iterable<string>): string[] {
119
+ return [...new Set(items)];
120
+ }
121
+
122
+ function clip(value: string, max = 80): string {
123
+ return value.length > max ? `${value.slice(0, max)}…` : value;
124
+ }
125
+
126
+ function describeValue(value: unknown): string {
127
+ if (value === null) return 'null';
128
+ if (Array.isArray(value)) return 'an array';
129
+ return typeof value === 'object' ? 'an object' : clip(String(value));
130
+ }
131
+
132
+ function failure(code: ToolListErrorCode, problems: ToolListProblem[]): ToolListFailure {
133
+ return { ok: false, code, problems, message: describeToolListProblems(code, problems) };
134
+ }
135
+
136
+ /** One sentence per problem, for an API error, a tool answer or the MCP child's log. */
137
+ export function describeToolListProblems(code: ToolListErrorCode, problems: readonly ToolListProblem[]): string {
138
+ const parts = problems.map((problem) => (problem.hint ? `${problem.item} (${problem.hint})` : problem.item));
139
+ if (code === 'TOOLS_TOO_MANY') {
140
+ return `A tool list holds at most ${TOOL_LIST_LIMITS.maxItems} items of at most ${TOOL_LIST_LIMITS.maxGroupItemLength} characters (${TOOL_LIST_LIMITS.maxServerItemLength} for an mcp: item): ${parts.join('; ')}`;
141
+ }
142
+ return `${problems.some(problem => problem.item.startsWith('mcp:')) ? 'Invalid tool selection' : 'Not SynaBun tool groups'}: ${parts.join('; ')}`;
143
+ }
144
+
145
+ /** A registry preset's groups that a list may name, or null when the registry has no preset of that name. */
146
+ function customPresetGroups(customPresets: CustomPresets | null | undefined, name: string): string[] | null {
147
+ if (!customPresets) return null;
148
+ for (const [key, preset] of Object.entries(customPresets)) {
149
+ if (String(key).trim().toLowerCase() !== name) continue;
150
+ const groups = Array.isArray(preset) ? preset : (preset && typeof preset === 'object' ? (preset as { groups?: unknown }).groups : null);
151
+ if (!Array.isArray(groups)) return [];
152
+ return sortGroups(groups.filter((group): group is string => typeof group === 'string').map((group) => group.trim().toLowerCase()).filter(isSelectableGroup));
153
+ }
154
+ return null;
155
+ }
156
+
157
+ /**
158
+ * A profile name an older SynaBun stored (SYNABUN_PROFILE, a runtime file's `profile`, a record's `mcpProfile`,
159
+ * active-profile.json): a preset becomes its groups (with the registry's own groups of that name), `full` and a
160
+ * retired preset become `all`, anything else is read as a comma list. In a comma list the retired groups and the
161
+ * gated ones are left out (the role and the grant decide those); what is left is checked like any list.
162
+ */
163
+ function convertLegacyProfile(value: string, customPresets: CustomPresets | null | undefined): ParsedToolList {
164
+ const name = value.trim().toLowerCase();
165
+ const platform = LEGACY_PRESET_PLATFORMS[name] ?? null;
166
+ if (name === 'full' || RETIRED_PRESETS.includes(name)) return { ok: true, items: ['all'], preset: name, platform: null };
167
+ const custom = customPresetGroups(customPresets, name);
168
+ if (Object.prototype.hasOwnProperty.call(LEGACY_PRESETS, name)) {
169
+ return { ok: true, items: sortGroups([...LEGACY_PRESETS[name], ...(custom || [])]), preset: name, platform };
170
+ }
171
+ if (custom) return { ok: true, items: custom, preset: name, platform: null };
172
+ const tokens = splitList(value);
173
+ const kept = tokens.filter((token) => !RETIRED_GROUPS.includes(token) && !isGatedGroup(token));
174
+ // A list that named only retired groups launched as every group before; it still does.
175
+ if (tokens.length && !kept.length && tokens.every((token) => RETIRED_GROUPS.includes(token))) {
176
+ return { ok: true, items: ['all'], preset: null, platform: null };
177
+ }
178
+ return { ok: true, items: unique(kept), preset: null, platform: null };
179
+ }
180
+
181
+ /**
182
+ * Read a list. An array (or a comma-joined string) is read as written: preset names are refused later, with
183
+ * suggestions. With `legacy`, a string is a stored profile value and is converted (presets, comma lists).
184
+ * A blank string is an empty list; a caller that means "no list" checks for blank first.
185
+ */
186
+ export function parseToolList(
187
+ value: unknown,
188
+ { legacy = false, customPresets = null }: { legacy?: boolean; customPresets?: CustomPresets | null } = {},
189
+ ): ToolListParse {
190
+ if (Array.isArray(value)) {
191
+ const problems: ToolListProblem[] = [];
192
+ const items: string[] = [];
193
+ for (const raw of value) {
194
+ if (typeof raw !== 'string') {
195
+ problems.push({ item: describeValue(raw), reason: 'not-a-string', suggestions: [], hint: 'every item of a tool list is a string' });
196
+ continue;
197
+ }
198
+ const item = normalizeToolItem(raw);
199
+ if (item) items.push(item);
200
+ }
201
+ if (problems.length) return failure('TOOLS_INVALID', problems);
202
+ return { ok: true, items: unique(items), preset: null, platform: null };
203
+ }
204
+ if (typeof value !== 'string') {
205
+ return failure('TOOLS_INVALID', [{ item: describeValue(value), reason: 'not-a-string', suggestions: [], hint: 'a tool list is an array of group ids' }]);
206
+ }
207
+ if (legacy) return convertLegacyProfile(value, customPresets);
208
+ return { ok: true, items: unique(splitList(value)), preset: null, platform: null };
209
+ }
210
+
211
+ function levenshtein(a: string, b: string): number {
212
+ if (a === b) return 0;
213
+ const previous = Array.from({ length: b.length + 1 }, (_, index) => index);
214
+ for (let i = 1; i <= a.length; i += 1) {
215
+ let diagonal = previous[0];
216
+ previous[0] = i;
217
+ for (let j = 1; j <= b.length; j += 1) {
218
+ const above = previous[j];
219
+ previous[j] = Math.min(previous[j] + 1, previous[j - 1] + 1, diagonal + (a[i - 1] === b[j - 1] ? 0 : 1));
220
+ diagonal = above;
221
+ }
222
+ }
223
+ return previous[b.length];
224
+ }
225
+
226
+ /**
227
+ * Group ids an unknown item probably meant, best first (at most `limit`): an id, a label or a word of a label that
228
+ * equals it (`whatsapp`, `x`), one that contains it or that it contains (`googlesearch` → gsc, `discord_bot`),
229
+ * then one within two edits (`whatsap`). Selectable groups only.
230
+ */
231
+ export function suggestToolIds(item: string, limit = 3): string[] {
232
+ const key = String(item ?? '').toLowerCase().replace(/[^a-z0-9]/g, '');
233
+ if (!key) return [];
234
+ const scored: Array<{ id: string; score: number; order: number }> = [];
235
+ TOOL_GROUPS.forEach((group, order) => {
236
+ if (group.gate) return;
237
+ const id = group.id.replace(/_/g, '');
238
+ const short = group.id.replace(/^browser_/, '').replace(/_/g, '');
239
+ const label = group.label.toLowerCase().replace(/[^a-z0-9]/g, '');
240
+ const words = group.label.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
241
+ let score = 0;
242
+ if (key === id || key === short || key === label || words.includes(key)) score = 3;
243
+ else if (key.length >= 3 && (label.includes(key) || id.includes(key) || (short.length >= 3 && key.includes(short)))) score = 2;
244
+ else if (key.length >= 3 && Math.min(levenshtein(key, short), levenshtein(key, id), levenshtein(key, label)) <= 2) score = 1;
245
+ if (score) scored.push({ id: group.id, score, order });
246
+ });
247
+ return scored.sort((a, b) => b.score - a.score || a.order - b.order).slice(0, limit).map((entry) => entry.id);
248
+ }
249
+
250
+ /** What a retired preset name stands for now: the groups that set it apart from the default. */
251
+ function presetProblem(item: string): ToolListProblem | null {
252
+ if (!Object.prototype.hasOwnProperty.call(LEGACY_PRESETS, item)) return null;
253
+ if (item === 'full' || RETIRED_PRESETS.includes(item)) {
254
+ return { item, reason: 'unknown', suggestions: ['all'], hint: `${item} was a preset; name all` };
255
+ }
256
+ const groups = LEGACY_PRESETS[item];
257
+ const browserComesWith = groups.some((id) => id !== 'browser' && isBrowserGroup(id));
258
+ const distinct = sortGroups(groups.filter((id) => !DEFAULT_TOOLS.includes(id) && !(id === 'browser' && browserComesWith)));
259
+ if (!distinct.length) {
260
+ return { item, reason: 'unknown', suggestions: [...DEFAULT_TOOLS], hint: `${item} was a preset: it is the default (${DEFAULT_TOOLS.join(', ')}), so leave tools out` };
261
+ }
262
+ return { item, reason: 'unknown', suggestions: distinct, hint: `${item} was a preset; name ${distinct.join(', ')}` };
263
+ }
264
+
265
+ function gatedProblem(item: string, group: string): ToolListProblem {
266
+ if (toolGroup(group)?.gate === 'grant:computer') {
267
+ return { item, reason: 'gated', suggestions: [], hint: `${group} is never named in a list: pass uses_computer: true for a desktop grant` };
268
+ }
269
+ return { item, reason: 'gated', suggestions: [], hint: `${group} is the Assistant's own, never a worker's: its role decides` };
270
+ }
271
+
272
+ function unknownProblem(item: string): ToolListProblem {
273
+ const preset = presetProblem(item);
274
+ if (preset) return preset;
275
+ const owner = groupOfTool(item);
276
+ if (owner && isSelectableGroup(owner)) {
277
+ return { item, reason: 'unknown', suggestions: [owner], hint: `${item} is a tool of the ${owner} group; name ${owner}` };
278
+ }
279
+ const suggestions = suggestToolIds(item);
280
+ return { item, reason: 'unknown', suggestions, hint: suggestions.length ? `did you mean ${suggestions.join(' or ')}?` : null };
281
+ }
282
+
283
+ interface CheckedItems {
284
+ ok: true;
285
+ groups: string[];
286
+ servers: string[];
287
+ dropped: string[];
288
+ items: string[];
289
+ }
290
+
291
+ /** Every item checked against the catalog and the limits. */
292
+ function checkItems(items: readonly string[]): CheckedItems | ToolListFailure {
293
+ const problems: ToolListProblem[] = [];
294
+ if (items.length > TOOL_LIST_LIMITS.maxItems) {
295
+ problems.push({ item: `${items.length} items`, reason: 'too-many', suggestions: [], hint: `at most ${TOOL_LIST_LIMITS.maxItems}` });
296
+ }
297
+ const serializedBytes = new TextEncoder().encode(items.join(',')).length;
298
+ if (serializedBytes > TOOL_LIST_LIMITS.maxSerializedBytes) problems.push({ item: `${serializedBytes} bytes`, reason: 'too-long', suggestions: [], hint: `at most ${TOOL_LIST_LIMITS.maxSerializedBytes} serialized bytes` });
299
+ const groups = new Set<string>();
300
+ const servers: string[] = [];
301
+ const dropped: string[] = [];
302
+ let all = false;
303
+ for (const item of items) {
304
+ const server = item.startsWith('mcp:');
305
+ const limit = server ? TOOL_LIST_LIMITS.maxServerItemLength : TOOL_LIST_LIMITS.maxGroupItemLength;
306
+ if (item.length > limit) {
307
+ problems.push({ item: clip(item), reason: 'too-long', suggestions: [], hint: `at most ${limit} characters` });
308
+ continue;
309
+ }
310
+ if (item === 'all') { all = true; continue; }
311
+ if (isAlwaysOnId(item) || (ALWAYS_ON_TOOLS as readonly string[]).includes(item)) { dropped.push(item); continue; }
312
+ if (isSelectableGroup(item)) { groups.add(item); continue; }
313
+ if (isGatedGroup(item)) { problems.push(gatedProblem(item, item)); continue; }
314
+ if (item === 'mcp:*') { servers.push(item); continue; }
315
+ if (server) {
316
+ if (/^mcp:[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/.test(item) && item !== 'mcp:SynaBun') servers.push(item);
317
+ else problems.push({ item, reason: 'non-selectable', suggestions: [], hint: item === 'mcp:SynaBun'
318
+ ? 'SynaBun is managed through tool groups, not an external server reference'
319
+ : 'this name cannot be selected individually: use 1-64 letters, digits, dots, underscores, colons or hyphens, starting with a letter or digit; mcp:* selects configured, permitted servers' });
320
+ continue;
321
+ }
322
+ const owner = groupOfTool(item);
323
+ if (owner && isGatedGroup(owner)) { problems.push(gatedProblem(item, owner)); continue; }
324
+ problems.push(unknownProblem(item));
325
+ }
326
+ if (problems.length) {
327
+ const tooMany = problems.some((problem) => problem.reason === 'too-many' || problem.reason === 'too-long');
328
+ return failure(tooMany ? 'TOOLS_TOO_MANY' : 'TOOLS_INVALID', problems);
329
+ }
330
+ const sorted = sortGroups(groups);
331
+ return {
332
+ ok: true,
333
+ groups: all ? [...SELECTABLE_GROUP_IDS] : sorted,
334
+ servers: unique(servers).sort(),
335
+ dropped,
336
+ items: all ? ['all', ...unique(servers).sort()] : [...sorted, ...unique(servers).sort()],
337
+ };
338
+ }
339
+
340
+ function defaultItems(context: ResolveToolListContext): readonly string[] {
341
+ if (context.source === 'dispatch') return DEFAULT_TOOLS;
342
+ if (context.source === 'launch' && context.stored) return context.stored;
343
+ return context.defaultTools ?? ['all'];
344
+ }
345
+
346
+ /** strict for a provider that loads its list exactly, focus for one that reaches every SynaBun tool anyway. */
347
+ export function toolListEffect(provider: string | null | undefined): ToolListEffect {
348
+ return (provider && HOST_EFFECT[provider]) || 'strict';
349
+ }
350
+
351
+ /**
352
+ * The groups a run gets (§3.3). No list means the default of its source: core for a dispatch, the record's own
353
+ * list or the owner's Default tools for a launch, the owner's Default tools for a runtime (else `all`). `all` is
354
+ * every selectable group, always-on ids are dropped, unknown and gated ids are refused. A browser group, or
355
+ * usesBrowser, adds `browser`; a design run adds browser (unless usesBrowser is false), styleguide and image.
356
+ */
357
+ export function resolveToolList(requested: readonly string[] | string | null | undefined, context: ResolveToolListContext): ToolListResult {
358
+ let asked: string[] | null = null;
359
+ if (requested !== undefined && requested !== null) {
360
+ const parsed = parseToolList(requested);
361
+ if (!parsed.ok) return parsed;
362
+ asked = parsed.items;
363
+ }
364
+ let base = asked;
365
+ if (!base) {
366
+ const fallback = parseToolList([...defaultItems(context)]);
367
+ if (!fallback.ok) return fallback;
368
+ base = fallback.items;
369
+ }
370
+ const checked = checkItems(base);
371
+ if (!checked.ok) return checked;
372
+
373
+ const groups = new Set(checked.groups);
374
+ const added: AddedGroup[] = [];
375
+ const add = (id: string, why: AddedReason) => {
376
+ if (groups.has(id)) return;
377
+ groups.add(id);
378
+ added.push({ id, why });
379
+ };
380
+ if ([...groups].some((id) => id !== 'browser' && isBrowserGroup(id))) add('browser', 'browser-group');
381
+ if (context.usesBrowser === true) add('browser', 'uses-browser');
382
+ const design = context.taskClass === 'design';
383
+ if (design && context.usesBrowser !== false) add('browser', 'design');
384
+ if (design) {
385
+ add('styleguide', 'design');
386
+ add('image', 'design');
387
+ }
388
+ const resolved = sortGroups(groups);
389
+ return {
390
+ ok: true,
391
+ requested: asked,
392
+ items: checked.items,
393
+ groups: resolved,
394
+ servers: checked.servers,
395
+ added,
396
+ dropped: checked.dropped,
397
+ effect: toolListEffect(context.provider),
398
+ count: countTools(resolved, { browserV2: context.browserV2 }),
399
+ };
400
+ }
401
+
402
+ /** A list joined for an environment variable or a header (SYNABUN_TOOLS, X-Synabun-Tools): at most 2048 bytes. */
403
+ export function serializeToolList(items: readonly string[]): string {
404
+ const value = unique(items.map(normalizeToolItem).filter(Boolean)).join(',');
405
+ const bytes = new TextEncoder().encode(value).length;
406
+ if (bytes > TOOL_LIST_LIMITS.maxSerializedBytes) {
407
+ throw new RangeError(`A tool list joined for an environment variable or a header is at most ${TOOL_LIST_LIMITS.maxSerializedBytes} bytes; this one is ${bytes}.`);
408
+ }
409
+ return value;
410
+ }