synabun 2.0.9 → 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 (679) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +68 -4
  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/launcher.mjs +9 -3
  10. package/lib/claude-hooks.js +172 -18
  11. package/lib/client-config-repair.js +17 -8
  12. package/lib/desktop-app.js +7 -1
  13. package/lib/external-tools.js +1 -1
  14. package/lib/first-launch-protection.js +57 -12
  15. package/lib/mcp-dist.js +176 -0
  16. package/lib/release-npm-ci.mjs +138 -0
  17. package/lib/release-publish.mjs +91 -0
  18. package/lib/release-scan.mjs +50 -0
  19. package/lib/server-crash-record.js +123 -0
  20. package/lib/server-exit.js +318 -0
  21. package/lib/server-supervisor.js +508 -0
  22. package/lib/start-launcher.js +43 -5
  23. package/lib/tools-cli.js +45 -0
  24. package/lib/update-snapshot.js +228 -0
  25. package/lib/virustotal.mjs +192 -0
  26. package/lib/windows-crash-event.js +269 -0
  27. package/mcp-server/dist/http.d.ts +20 -1
  28. package/mcp-server/dist/http.d.ts.map +1 -1
  29. package/mcp-server/dist/http.js +59 -12
  30. package/mcp-server/dist/http.js.map +1 -1
  31. package/mcp-server/dist/index.d.ts +33 -27
  32. package/mcp-server/dist/index.d.ts.map +1 -1
  33. package/mcp-server/dist/index.js +128 -143
  34. package/mcp-server/dist/index.js.map +1 -1
  35. package/mcp-server/dist/preload.js +1 -1
  36. package/mcp-server/dist/preload.js.map +1 -1
  37. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  38. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  39. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  40. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  41. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  42. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  43. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  44. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  45. package/mcp-server/dist/services/neural-interface.d.ts +16 -10
  46. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  47. package/mcp-server/dist/services/neural-interface.js +67 -11
  48. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  49. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  50. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  51. package/mcp-server/dist/services/server-instructions.js +20 -62
  52. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  53. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  54. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  55. package/mcp-server/dist/services/tool-catalog.js +339 -0
  56. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  57. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  58. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  59. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  60. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  61. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  62. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  63. package/mcp-server/dist/services/tool-list.js +334 -0
  64. package/mcp-server/dist/services/tool-list.js.map +1 -0
  65. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  66. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  67. package/mcp-server/dist/services/tool-runtime.js +400 -0
  68. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  69. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  70. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  71. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  72. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  73. package/mcp-server/dist/tools/agents.d.ts +10 -10
  74. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  75. package/mcp-server/dist/tools/agents.js +22 -13
  76. package/mcp-server/dist/tools/agents.js.map +1 -1
  77. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  78. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  79. package/mcp-server/dist/tools/image-tools.js +1 -1
  80. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  81. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  82. package/mcp-server/dist/tools/skill-tools.js +639 -0
  83. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  84. package/mcp-server/dist/tools/skill.d.ts +7 -0
  85. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  86. package/mcp-server/dist/tools/skill.js +11 -0
  87. package/mcp-server/dist/tools/skill.js.map +1 -0
  88. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  89. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  90. package/mcp-server/dist/tools/tool-groups.js +147 -0
  91. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  92. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  93. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  94. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  95. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  96. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  97. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  98. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  99. package/mcp-server/package-lock.json +2 -2
  100. package/mcp-server/package.json +1 -1
  101. package/mcp-server/src/http.ts +75 -12
  102. package/mcp-server/src/index.ts +147 -154
  103. package/mcp-server/src/preload.ts +12 -12
  104. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  105. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  106. package/mcp-server/src/services/neural-interface.ts +79 -20
  107. package/mcp-server/src/services/server-instructions.ts +27 -63
  108. package/mcp-server/src/services/tool-catalog.ts +403 -0
  109. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  110. package/mcp-server/src/services/tool-list.ts +410 -0
  111. package/mcp-server/src/services/tool-runtime.ts +457 -0
  112. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  113. package/mcp-server/src/tools/agents.ts +22 -14
  114. package/mcp-server/src/tools/image-tools.ts +1 -1
  115. package/mcp-server/src/tools/skill-tools.ts +589 -0
  116. package/mcp-server/src/tools/skill.ts +13 -0
  117. package/mcp-server/src/tools/tool-groups.ts +164 -0
  118. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  119. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  120. package/neural-interface/i18n/en.json +3680 -206
  121. package/neural-interface/i18n/pt-BR.json +3628 -157
  122. package/neural-interface/lib/account-usage.js +5 -3
  123. package/neural-interface/lib/app-controls-api.js +161 -0
  124. package/neural-interface/lib/assistant-api.js +148 -35
  125. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  126. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  127. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  128. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  129. package/neural-interface/lib/assistant-brains/opencode.js +122 -44
  130. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +59 -0
  131. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +97 -0
  132. package/neural-interface/lib/assistant-catalog.js +23 -9
  133. package/neural-interface/lib/assistant-dispatch.js +874 -156
  134. package/neural-interface/lib/assistant-envelope.js +22 -2
  135. package/neural-interface/lib/assistant-persona.js +80 -11
  136. package/neural-interface/lib/assistant-plan-permissions.js +10 -9
  137. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  138. package/neural-interface/lib/assistant-route-gate.js +6 -4
  139. package/neural-interface/lib/assistant-router.js +13 -8
  140. package/neural-interface/lib/assistant-runtime.js +183 -26
  141. package/neural-interface/lib/assistant-task-prompt.js +78 -14
  142. package/neural-interface/lib/assistant-tools.js +51 -0
  143. package/neural-interface/lib/backup-service.js +620 -3
  144. package/neural-interface/lib/backup-zip-reader.js +10 -5
  145. package/neural-interface/lib/backup-zip-writer.js +257 -0
  146. package/neural-interface/lib/browser-execution.js +10 -2
  147. package/neural-interface/lib/browser-guard-cdp.js +83 -0
  148. package/neural-interface/lib/browser-network-guard.js +284 -0
  149. package/neural-interface/lib/browser-policy-roots.js +64 -0
  150. package/neural-interface/lib/browser-tool-policy.js +186 -31
  151. package/neural-interface/lib/claude-agent-bridge.js +4 -2
  152. package/neural-interface/lib/claude-hooks-status.js +103 -0
  153. package/neural-interface/lib/claude-model-catalog.js +64 -14
  154. package/neural-interface/lib/claude-temporary.js +5 -11
  155. package/neural-interface/lib/cli-install.js +18 -138
  156. package/neural-interface/lib/cli-resolver.js +4 -1
  157. package/neural-interface/lib/cli-update-planner.js +32 -31
  158. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  159. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  160. package/neural-interface/lib/codex-settings-schema.js +109 -47
  161. package/neural-interface/lib/codex-worker-app-server.js +172 -0
  162. package/neural-interface/lib/confined-fs.js +30 -3
  163. package/neural-interface/lib/crash-notice-api.js +98 -0
  164. package/neural-interface/lib/editor-completion-opencode.js +164 -67
  165. package/neural-interface/lib/exec-loop-command.js +4 -1
  166. package/neural-interface/lib/http-guards.js +8 -2
  167. package/neural-interface/lib/install-details.js +4 -1
  168. package/neural-interface/lib/launch-cache.js +293 -0
  169. package/neural-interface/lib/login-start.js +524 -0
  170. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  171. package/neural-interface/lib/mcp-client-config.js +0 -29
  172. package/neural-interface/lib/mcp-external-servers.js +323 -0
  173. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  174. package/neural-interface/lib/morelogin.js +30 -0
  175. package/neural-interface/lib/native-loop-providers.js +565 -50
  176. package/neural-interface/lib/native-loop-runtime.js +287 -41
  177. package/neural-interface/lib/opencode-config.js +557 -0
  178. package/neural-interface/lib/opencode-db-schema.js +58 -0
  179. package/neural-interface/lib/opencode-history.js +49 -204
  180. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  181. package/neural-interface/lib/opencode-native-boundary.js +44 -0
  182. package/neural-interface/lib/opencode-protocol.js +310 -0
  183. package/neural-interface/lib/opencode-provider-view.js +81 -0
  184. package/neural-interface/lib/opencode-runtime-config.js +32 -15
  185. package/neural-interface/lib/opencode-serve-records.js +624 -0
  186. package/neural-interface/lib/opencode-v2-client.js +53 -131
  187. package/neural-interface/lib/opencode-v2-ws-requests.js +35 -195
  188. package/neural-interface/lib/opencode-worker-activity.js +229 -0
  189. package/neural-interface/lib/opencode-worker-data.js +27 -0
  190. package/neural-interface/lib/opencode2-client.js +796 -0
  191. package/neural-interface/lib/opencode2-proxy.js +76 -0
  192. package/neural-interface/lib/opencode2-translate.js +1057 -0
  193. package/neural-interface/lib/owner-authority.js +249 -0
  194. package/neural-interface/lib/page-session.js +275 -0
  195. package/neural-interface/lib/peer-identity.js +763 -0
  196. package/neural-interface/lib/process-identity.js +361 -0
  197. package/neural-interface/lib/request-gate.js +17 -2
  198. package/neural-interface/lib/rulesets/api.js +1 -1
  199. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  200. package/neural-interface/lib/rulesets/installer.js +92 -27
  201. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  202. package/neural-interface/lib/session-cache-builder.js +18 -10
  203. package/neural-interface/lib/session-title-generator.js +58 -18
  204. package/neural-interface/lib/skills/api-v2.js +495 -0
  205. package/neural-interface/lib/skills/bundle.js +418 -0
  206. package/neural-interface/lib/skills/catalog.js +294 -0
  207. package/neural-interface/lib/skills/creation-api.js +191 -0
  208. package/neural-interface/lib/skills/creation-brief.js +247 -0
  209. package/neural-interface/lib/skills/creation-sources.js +267 -0
  210. package/neural-interface/lib/skills/creation.js +843 -0
  211. package/neural-interface/lib/skills/deploy.js +564 -0
  212. package/neural-interface/lib/skills/digest.js +119 -0
  213. package/neural-interface/lib/skills/discover.js +111 -0
  214. package/neural-interface/lib/skills/draft-confinement.js +214 -0
  215. package/neural-interface/lib/skills/eval-confinement.js +397 -0
  216. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  217. package/neural-interface/lib/skills/eval-trace.js +119 -0
  218. package/neural-interface/lib/skills/evals-api.js +212 -0
  219. package/neural-interface/lib/skills/evals.js +1573 -0
  220. package/neural-interface/lib/skills/export.js +200 -0
  221. package/neural-interface/lib/skills/frontmatter.js +64 -0
  222. package/neural-interface/lib/skills/health.js +75 -0
  223. package/neural-interface/lib/skills/json-edit.js +165 -0
  224. package/neural-interface/lib/skills/known-bridge-digests.json +387 -0
  225. package/neural-interface/lib/skills/known-bridges.js +96 -0
  226. package/neural-interface/lib/skills/library.js +823 -0
  227. package/neural-interface/lib/skills/local-store.js +21 -0
  228. package/neural-interface/lib/skills/migration.js +433 -0
  229. package/neural-interface/lib/skills/operations.js +45 -0
  230. package/neural-interface/lib/skills/ownership.js +427 -0
  231. package/neural-interface/lib/skills/packages.js +88 -0
  232. package/neural-interface/lib/skills/reviews.js +212 -0
  233. package/neural-interface/lib/skills/revision.js +80 -0
  234. package/neural-interface/lib/skills/roots.js +262 -0
  235. package/neural-interface/lib/skills/runtime-checks.js +355 -0
  236. package/neural-interface/lib/skills/scan-assets.js +252 -0
  237. package/neural-interface/lib/skills/scan-context.js +26 -0
  238. package/neural-interface/lib/skills/scan-shell.js +324 -0
  239. package/neural-interface/lib/skills/scan.js +364 -0
  240. package/neural-interface/lib/skills/scanners.js +54 -0
  241. package/neural-interface/lib/skills/service.js +522 -0
  242. package/neural-interface/lib/skills/telemetry.js +113 -0
  243. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  244. package/neural-interface/lib/style-guide/api.js +4 -3
  245. package/neural-interface/lib/tool-lists.js +124 -0
  246. package/neural-interface/lib/untrusted-file-headers.js +27 -0
  247. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  248. package/neural-interface/lib/worker-confinement.js +1192 -0
  249. package/neural-interface/lib/worker-guard-setting.js +56 -0
  250. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  251. package/neural-interface/lib/worker-relay-ports.js +227 -0
  252. package/neural-interface/lib/worker-resume.js +229 -0
  253. package/neural-interface/lib/worker-sandbox.js +299 -0
  254. package/neural-interface/package-lock.json +1354 -50
  255. package/neural-interface/package.json +6 -2
  256. package/neural-interface/public/index.html +5 -3
  257. package/neural-interface/public/index2d.html +19 -11
  258. package/neural-interface/public/onboarding.html +2 -2
  259. package/neural-interface/public/shared/account-menu.js +8 -5
  260. package/neural-interface/public/shared/agent-runtime-options.js +76 -16
  261. package/neural-interface/public/shared/api.js +1527 -1336
  262. package/neural-interface/public/shared/app-frame.js +192 -0
  263. package/neural-interface/public/shared/assistant/asst-agents-dock.js +205 -19
  264. package/neural-interface/public/shared/assistant/asst-api.js +11 -3
  265. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  266. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  267. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  268. package/neural-interface/public/shared/assistant/asst-brain-picker.js +241 -112
  269. package/neural-interface/public/shared/assistant/asst-composer.js +1 -1
  270. package/neural-interface/public/shared/assistant/asst-control.js +157 -26
  271. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  272. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  273. package/neural-interface/public/shared/assistant/asst-hosts.js +49 -2
  274. package/neural-interface/public/shared/assistant/asst-limit-dock.js +40 -0
  275. package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -0
  276. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  277. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  278. package/neural-interface/public/shared/assistant/asst-menu.js +84 -12
  279. package/neural-interface/public/shared/assistant/asst-panel.js +303 -44
  280. package/neural-interface/public/shared/assistant/asst-rack-styles.js +93 -58
  281. package/neural-interface/public/shared/assistant/asst-redact.js +186 -0
  282. package/neural-interface/public/shared/assistant/asst-render.js +770 -100
  283. package/neural-interface/public/shared/assistant/asst-route.js +83 -12
  284. package/neural-interface/public/shared/assistant/asst-run-stage.js +231 -0
  285. package/neural-interface/public/shared/assistant/asst-sanitize.js +193 -3
  286. package/neural-interface/public/shared/assistant/asst-scene-styles.js +273 -0
  287. package/neural-interface/public/shared/assistant/asst-scenes.js +530 -0
  288. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +3 -15
  289. package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
  290. package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
  291. package/neural-interface/public/shared/assistant/asst-state.js +25 -15
  292. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  293. package/neural-interface/public/shared/assistant/asst-styles.js +102 -21
  294. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +165 -13
  295. package/neural-interface/public/shared/automation-context.js +5 -2
  296. package/neural-interface/public/shared/cc-dropdown.js +550 -0
  297. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  298. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  299. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  300. package/neural-interface/public/shared/cdx/cdx-output.js +8 -7
  301. package/neural-interface/public/shared/cdx/cdx-panel.js +58 -150
  302. package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
  303. package/neural-interface/public/shared/cdx/cdx-render.js +62 -32
  304. package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
  305. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  306. package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
  307. package/neural-interface/public/shared/cdx/cdx-tabs.js +201 -74
  308. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  309. package/neural-interface/public/shared/cli-install-view.js +4 -8
  310. package/neural-interface/public/shared/cli-status.js +2 -2
  311. package/neural-interface/public/shared/constants.js +2 -2
  312. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  313. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  314. package/neural-interface/public/shared/context-menu-model.js +366 -0
  315. package/neural-interface/public/shared/context-menu.js +372 -0
  316. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  317. package/neural-interface/public/shared/cp/cp-markdown.js +4 -57
  318. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  319. package/neural-interface/public/shared/data-cache.js +223 -0
  320. package/neural-interface/public/shared/desktop-bridge.js +11 -0
  321. package/neural-interface/public/shared/desktop-titlebar-view.js +78 -1
  322. package/neural-interface/public/shared/desktop-titlebar.js +214 -28
  323. package/neural-interface/public/shared/desktop-update-view.js +35 -5
  324. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  325. package/neural-interface/public/shared/file-links.js +73 -8
  326. package/neural-interface/public/shared/html-shell.js +78 -86
  327. package/neural-interface/public/shared/i18n.js +2 -0
  328. package/neural-interface/public/shared/launch-prefetch.js +59 -0
  329. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  330. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  331. package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +3 -2
  332. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  333. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +9 -2
  334. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  335. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  336. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  337. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  338. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  339. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  340. package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +54 -17
  341. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  342. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +140 -254
  343. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  344. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +97 -203
  345. package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +11 -9
  346. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +15 -4
  347. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -22
  348. package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +401 -0
  349. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +20 -13
  350. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  351. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +53 -82
  352. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  353. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  354. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  355. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  356. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +48 -40
  357. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  358. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +205 -62
  359. package/neural-interface/public/shared/opencode-providers.js +39 -0
  360. package/neural-interface/public/shared/page-session.js +96 -0
  361. package/neural-interface/public/shared/registry.js +5 -3
  362. package/neural-interface/public/shared/retired-2d.js +3 -0
  363. package/neural-interface/public/shared/schedules-view.js +452 -0
  364. package/neural-interface/public/shared/settings/settings-app-pane.js +335 -0
  365. package/neural-interface/public/shared/settings/settings-app.js +243 -0
  366. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  367. package/neural-interface/public/shared/settings/settings-data.js +90 -0
  368. package/neural-interface/public/shared/settings/settings-ia.js +23 -6
  369. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  370. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  371. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  372. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  373. package/neural-interface/public/shared/sidepanel-session-status.js +49 -0
  374. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  375. package/neural-interface/public/shared/skills/ss-creation.js +219 -0
  376. package/neural-interface/public/shared/skills/ss-dialog.js +130 -0
  377. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  378. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  379. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  380. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  381. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  382. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  383. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  384. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  385. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  386. package/neural-interface/public/shared/skills/ss-lint.js +141 -0
  387. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  388. package/neural-interface/public/shared/skills/ss-profiles.js +475 -0
  389. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  390. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  391. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  392. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  393. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  394. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  395. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  396. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +236 -0
  397. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  398. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  399. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  400. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  401. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  402. package/neural-interface/public/shared/skills/studio/sx-dom.js +229 -0
  403. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  404. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  405. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  406. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  407. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  408. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  409. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +279 -0
  410. package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
  411. package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
  412. package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
  413. package/neural-interface/public/shared/skills/studio/sx-main.js +681 -0
  414. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  415. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  416. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  417. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  418. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  419. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  420. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  421. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  422. package/neural-interface/public/shared/skills/studio/sx-subject.js +248 -0
  423. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  424. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  425. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  426. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +425 -0
  427. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  428. package/neural-interface/public/shared/styles.css +2065 -2150
  429. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  430. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  431. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  432. package/neural-interface/public/shared/tool-list-view.js +112 -0
  433. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  434. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  435. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  436. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  437. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  438. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  439. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  440. package/neural-interface/public/shared/tour/tour.css +144 -0
  441. package/neural-interface/public/shared/ui-assistant.js +27 -5
  442. package/neural-interface/public/shared/ui-automation-studio.js +155 -152
  443. package/neural-interface/public/shared/ui-bookmarks.js +2 -1
  444. package/neural-interface/public/shared/ui-claude-panel.js +153 -13
  445. package/neural-interface/public/shared/ui-codex-panel.js +1 -0
  446. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  447. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  448. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  449. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  450. package/neural-interface/public/shared/ui-detail.js +21 -9
  451. package/neural-interface/public/shared/ui-file-links.js +1 -0
  452. package/neural-interface/public/shared/ui-image-gallery.js +56 -52
  453. package/neural-interface/public/shared/ui-invite.js +18 -2
  454. package/neural-interface/public/shared/ui-keybinds.js +26 -1
  455. package/neural-interface/public/shared/ui-link.js +9 -9
  456. package/neural-interface/public/shared/ui-menubar.js +229 -40
  457. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  458. package/neural-interface/public/shared/ui-native-loop-router.js +9 -1
  459. package/neural-interface/public/shared/ui-navbar.js +4 -24
  460. package/neural-interface/public/shared/ui-opencode-panel-v2.js +1 -0
  461. package/neural-interface/public/shared/ui-panels.js +96 -65
  462. package/neural-interface/public/shared/ui-schedules-studio.js +2267 -953
  463. package/neural-interface/public/shared/ui-sessions.js +20 -7
  464. package/neural-interface/public/shared/ui-settings.js +679 -496
  465. package/neural-interface/public/shared/ui-sidebar.js +4 -4
  466. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +13 -0
  467. package/neural-interface/public/shared/ui-sidepanel-sessions.js +56 -5
  468. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  469. package/neural-interface/public/shared/ui-sidepanel-tray.js +84 -8
  470. package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
  471. package/neural-interface/public/shared/ui-skills.js +42 -2781
  472. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  473. package/neural-interface/public/shared/ui-sync.js +22 -5
  474. package/neural-interface/public/shared/ui-terminal.js +159 -199
  475. package/neural-interface/public/shared/ui-tool-updates.js +3 -1
  476. package/neural-interface/public/shared/ui-tooltip.js +10 -5
  477. package/neural-interface/public/shared/ui-trash.js +14 -5
  478. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  479. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  480. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -61
  481. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  482. package/neural-interface/public/shared/ui-tutorial.js +285 -499
  483. package/neural-interface/public/shared/ui-update.js +121 -16
  484. package/neural-interface/public/shared/ui-whiteboard.js +313 -59
  485. package/neural-interface/public/shared/ui-worker-end.js +4 -0
  486. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  487. package/neural-interface/public/shared/view-variant.js +66 -0
  488. package/neural-interface/public/shared/whatsapp/wa-view.js +1 -1
  489. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  490. package/neural-interface/public/shared/worker-end.js +10 -3
  491. package/neural-interface/public/shared/worker-restart.js +12 -0
  492. package/neural-interface/public/sidepanel-session.html +1 -1
  493. package/neural-interface/public/variant/2d/background.js +2 -1
  494. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  495. package/neural-interface/public/variant/2d/graph.js +42 -20
  496. package/neural-interface/public/variant/2d/hulls.js +14 -9
  497. package/neural-interface/public/variant/2d/lasso.js +11 -7
  498. package/neural-interface/public/variant/2d/main.js +36 -2
  499. package/neural-interface/public/variant/2d/minimap.js +11 -13
  500. package/neural-interface/public/variant/3d/main.js +72 -6
  501. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  502. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  503. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  504. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  505. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  506. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  507. package/neural-interface/public/vendor/highlight/LICENSE +29 -0
  508. package/neural-interface/public/vendor/highlight/github-dark-dimmed-11.12.0.min.css +9 -0
  509. package/neural-interface/public/vendor/highlight/highlight-11.12.0.min.js +1262 -0
  510. package/neural-interface/public/vendor/highlight/manifest.json +5 -0
  511. package/neural-interface/public/vendor/html2canvas/LICENSE +22 -0
  512. package/neural-interface/public/vendor/html2canvas/html2canvas-1.4.1.min.js +20 -0
  513. package/neural-interface/public/vendor/html2canvas/manifest.json +4 -0
  514. package/neural-interface/public/vendor/marked/LICENSE.md +44 -0
  515. package/neural-interface/public/vendor/marked/manifest.json +4 -0
  516. package/neural-interface/public/vendor/marked/marked-14.1.4.esm.js +2502 -0
  517. package/neural-interface/public/vendor/mermaid/LICENSE +21 -0
  518. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/abnfDiagram-PAR5IXJI.mjs +1 -0
  519. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architecture-7GRP2DOG-M7G3SWCO.mjs +1 -0
  520. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architectureDiagram-2PNWDENW.mjs +36 -0
  521. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/blockDiagram-PUWGUBOA.mjs +129 -0
  522. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/c4Diagram-3NLNHZP5.mjs +38 -0
  523. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-2NMSUPJH.mjs +1 -0
  524. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-32MCUW2P.mjs +206 -0
  525. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3NPNU5GP.mjs +1 -0
  526. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3SMGFRGC.mjs +1 -0
  527. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4CAJECRU.mjs +14 -0
  528. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4OADUZ5Q.mjs +10 -0
  529. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IMINLNL.mjs +1 -0
  530. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IQCK5RY.mjs +3 -0
  531. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5MVFYWFU.mjs +1 -0
  532. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AQ6EADP3.mjs +1 -0
  533. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AZZRMDJM.mjs +15 -0
  534. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-CLS4B6BI.mjs +168 -0
  535. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-DZP67EKU.mjs +70 -0
  536. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-EICP7K5X.mjs +1 -0
  537. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-GDY2UAB4.mjs +1 -0
  538. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-H7VHZCWX.mjs +1 -0
  539. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-IJBDOHL6.mjs +1 -0
  540. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JFFVMJIA.mjs +1 -0
  541. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JQRUD6KW.mjs +1 -0
  542. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JZGDI5JK.mjs +1 -0
  543. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-KD6SPIPN.mjs +2 -0
  544. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NF366YI6.mjs +231 -0
  545. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NUDPKBEF.mjs +32 -0
  546. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-OJINMHTS.mjs +1 -0
  547. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Q6NGPIAH.mjs +2 -0
  548. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-QJSWEUOL.mjs +132 -0
  549. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-R7JDMUKV.mjs +1 -0
  550. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RCXAM2GK.mjs +1 -0
  551. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RT4MAWR3.mjs +1 -0
  552. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SFMINX4W.mjs +1 -0
  553. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SLDQ463B.mjs +88 -0
  554. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-STOV2HOB.mjs +1 -0
  555. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-T5OCTHI4.mjs +1 -0
  556. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-TCEHX7R3.mjs +1 -0
  557. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VQC2EELJ.mjs +1 -0
  558. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VRZKL3EH.mjs +1 -0
  559. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VTHDQ7BV.mjs +1 -0
  560. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VY2OSTJR.mjs +2 -0
  561. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-WUBWJARI.mjs +1 -0
  562. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YBMQ5JGJ.mjs +2 -0
  563. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YDMLL4PJ.mjs +1 -0
  564. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Z6V44ARX.mjs +62 -0
  565. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZJJ7VQJP.mjs +339 -0
  566. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZNLK7HRR.mjs +1 -0
  567. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZQN7UHIL.mjs +1 -0
  568. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZS6VBONO.mjs +174 -0
  569. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZUNWM646.mjs +1 -0
  570. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-FGAMPOII.mjs +1 -0
  571. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-v2-AI5RJEK4.mjs +1 -0
  572. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cose-bilkent-Q72C2OJ3.mjs +1 -0
  573. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefin-OW5HDTMX-6OCTWOGG.mjs +1 -0
  574. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefinDiagram-2OOWUY4M.mjs +62 -0
  575. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/dagre-MPVFI544.mjs +4 -0
  576. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-AE4NWXFW.mjs +24 -0
  577. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-BUJID5UG.mjs +41 -0
  578. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-C44CZ5NI.mjs +24 -0
  579. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-EYOLEXXS.mjs +30 -0
  580. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-P7B6PWOJ.mjs +3 -0
  581. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ebnfDiagram-FTPZ3PV6.mjs +1 -0
  582. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/erDiagram-H3ERR26V.mjs +99 -0
  583. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/eventmodeling-NTZA5JFV-WKSWQHFS.mjs +1 -0
  584. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/flowDiagram-YHGXBVSY.mjs +1 -0
  585. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ganttDiagram-RWFTB7ED.mjs +292 -0
  586. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraph-4MIJSDKK-JH2HKYUO.mjs +1 -0
  587. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraphDiagram-MAR6GKOP.mjs +106 -0
  588. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/info-A6RAGUB7-3TX3OFWW.mjs +1 -0
  589. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/infoDiagram-LV547AFH.mjs +2 -0
  590. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ishikawaDiagram-PUJQGNDS.mjs +70 -0
  591. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/journeyDiagram-EW5QJT4W.mjs +139 -0
  592. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/kanban-definition-JSQERAZB.mjs +89 -0
  593. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/katex-CZ4GXH2S.mjs +257 -0
  594. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/mindmap-definition-VBJCLQLM.mjs +96 -0
  595. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/packet-AYTQ26CC-MKII6P3Y.mjs +1 -0
  596. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pegDiagram-7WILOQTJ.mjs +1 -0
  597. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pie-WAS4IAKB-6B4OPMJ5.mjs +1 -0
  598. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pieDiagram-EFA7CBSB.mjs +39 -0
  599. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/quadrantDiagram-WARVYA7P.mjs +7 -0
  600. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/radar-RG4KPBEZ-UPTR3XUL.mjs +1 -0
  601. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-74A4TZTK-MEFUPFMS.mjs +1 -0
  602. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-abnf-HS5TGJTU-R5YG2S5D.mjs +1 -0
  603. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-ebnf-LZEXJU2U-G5QEX2L6.mjs +1 -0
  604. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-peg-WCYAUIDC-H5I2ZRY2.mjs +1 -0
  605. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroadDiagram-5NIQVNLQ.mjs +1 -0
  606. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/requirementDiagram-SXREGOKZ.mjs +84 -0
  607. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sankeyDiagram-VV74M2VP.mjs +40 -0
  608. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sequenceDiagram-52ZFIFDL.mjs +162 -0
  609. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sizeCapture-FGA5AGYP.mjs +1 -0
  610. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-3QAKPIVI.mjs +1 -0
  611. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-v2-HN2P4RDZ.mjs +1 -0
  612. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanes-QLVP42QD.mjs +1 -0
  613. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanesDiagram-JKPDBFCN.mjs +8 -0
  614. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/timeline-definition-GS45XAXW.mjs +120 -0
  615. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treeView-Q6P3EWNA-ZRJGANNQ.mjs +1 -0
  616. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treemap-WGGIJYW6-K64VN5AS.mjs +1 -0
  617. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/vennDiagram-QIQU2ZRJ.mjs +34 -0
  618. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardley-WFR3VGLG-D67OWCCH.mjs +1 -0
  619. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardleyDiagram-U6YNM66N.mjs +78 -0
  620. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/xychartDiagram-XJAZEDNM.mjs +7 -0
  621. package/neural-interface/public/vendor/mermaid/manifest.json +4 -0
  622. package/neural-interface/public/vendor/mermaid/mermaid-11.17.2.esm.min.mjs +14 -0
  623. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  624. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  625. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  626. package/neural-interface/scripts/build-vendor.mjs +116 -3
  627. package/neural-interface/server.js +4834 -2541
  628. package/neural-interface/templates/rulesets/core.md +1 -1
  629. package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
  630. package/neural-interface/templates/rulesets/manifest.json +8 -8
  631. package/npm-shrinkwrap.json +18 -12
  632. package/package.json +16 -3
  633. package/postinstall.js +9 -4
  634. package/preuninstall.js +1 -1
  635. package/setup.js +97 -322
  636. package/skills/skill-forge/SKILL.md +177 -0
  637. package/skills/skill-forge/evals/evals.json +54 -0
  638. package/skills/skill-forge/references/package.md +105 -0
  639. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  640. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  641. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  642. package/skills/synabun/SKILL.md +10 -7
  643. package/skills/synabun/modules/audit.md +1 -5
  644. package/skills/synabun/modules/changelog.md +1 -5
  645. package/skills/synabun/modules/idea.md +1 -1
  646. package/skills/synabun/modules/memorize.md +6 -9
  647. package/skills/synabun/modules/schedule.md +5 -5
  648. package/mcp-server/dist/services/profiles.d.ts +0 -120
  649. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  650. package/mcp-server/dist/services/profiles.js +0 -387
  651. package/mcp-server/dist/services/profiles.js.map +0 -1
  652. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  653. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  654. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  655. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  656. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  657. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  658. package/mcp-server/dist/tools/leonardo.js +0 -21
  659. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  660. package/mcp-server/dist/tools/profile.d.ts +0 -17
  661. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  662. package/mcp-server/dist/tools/profile.js +0 -114
  663. package/mcp-server/dist/tools/profile.js.map +0 -1
  664. package/mcp-server/src/services/profiles.ts +0 -428
  665. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  666. package/mcp-server/src/tools/leonardo.ts +0 -30
  667. package/mcp-server/src/tools/profile.ts +0 -122
  668. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  669. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  670. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  671. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  672. package/skills/leonardo/SKILL.md +0 -168
  673. package/skills/leonardo/icon.svg +0 -1
  674. package/skills/leonardo/modules/browser-guide.md +0 -378
  675. package/skills/leonardo/modules/image-prompter.md +0 -283
  676. package/skills/leonardo/modules/model-advisor.md +0 -100
  677. package/skills/leonardo/modules/prompt-library.md +0 -110
  678. package/skills/leonardo/modules/style-guide.md +0 -186
  679. package/skills/leonardo/modules/video-prompter.md +0 -317
@@ -4,9 +4,19 @@
4
4
  // tool may run; a refusal becomes permissionDecision "deny" with the reason.
5
5
  // The call's whole tool_input travels (the remote denylist reads paths from
6
6
  // it), marked inputComplete; one too big to send goes as its command/action
7
- // only, marked incomplete. Any failure (no env, server unreachable, bad reply)
8
- // allows the call — except in a WhatsApp session (SYNABUN_ROUTE_GATE_REMOTE=1),
9
- // where a call SynaBun could not check is denied.
7
+ // only, marked incomplete. No env or no answer at all (the server unreachable
8
+ // or slow) allows the call — except in a WhatsApp session
9
+ // (SYNABUN_ROUTE_GATE_REMOTE=1), where a call SynaBun could not check is
10
+ // denied. An answer that is not a decision (the check itself refused, such as
11
+ // 403 PEER_REFUSED, an error status, a body without `allow`) denies the call in
12
+ // every session and says what SynaBun answered: a refusal never passes for an
13
+ // allow.
14
+ //
15
+ // The request carries the session's pin (X-Synabun-Assistant): this hook runs
16
+ // under the brain's Codex app-server, an AI agent's process tree, which
17
+ // SynaBun's owner gate (lib/owner-authority.js) refuses unless the call says
18
+ // it is an agent's own. The per-session token in the body is what the route
19
+ // itself checks.
10
20
 
11
21
  const url = process.env.SYNABUN_ROUTE_GATE_URL;
12
22
  const session = process.env.SYNABUN_ROUTE_GATE_SESSION;
@@ -14,6 +24,7 @@ const token = process.env.SYNABUN_ROUTE_GATE_TOKEN;
14
24
  const remote = process.env.SYNABUN_ROUTE_GATE_REMOTE === '1';
15
25
  const MAX_INPUT_BYTES = 256 * 1024;
16
26
  const UNCHECKED = 'SynaBun could not check this call, so a WhatsApp session does not run it.';
27
+ const PIN_HEADER = 'x-synabun-assistant';
17
28
 
18
29
  let raw = '';
19
30
  try { for await (const chunk of process.stdin) raw += chunk; } catch {}
@@ -37,20 +48,32 @@ function callArguments(toolInput) {
37
48
  function deny(reason) {
38
49
  process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: String(reason).replace(/[.\s]+$/, '') } }));
39
50
  }
51
+ /** The refusal of a call whose check got an answer that is not a decision: what SynaBun answered, in short. */
52
+ function notADecision(status, body) {
53
+ const code = body && typeof body === 'object' && typeof body.code === 'string' ? ` ${body.code.slice(0, 64)}` : '';
54
+ const said = body && typeof body === 'object' && typeof body.error === 'string' ? `: ${body.error.slice(0, 300)}` : '';
55
+ return `SynaBun could not check this call (its route gate answered ${status}${code}${said}), so it did not run.`;
56
+ }
40
57
 
41
58
  if (url && session && token) {
59
+ let response = null;
42
60
  try {
43
- const response = await fetch(url, {
61
+ response = await fetch(url, {
44
62
  method: 'POST',
45
- headers: { 'content-type': 'application/json' },
63
+ // The session id as a header value: printable ASCII only (fetch refuses anything else before sending).
64
+ headers: { 'content-type': 'application/json', [PIN_HEADER]: String(session).replace(/[^\x21-\x7e]/g, '').slice(0, 200) },
46
65
  body: JSON.stringify({ session, token, host: 'codex', tool: String(input.tool_name || input.toolName || input.tool || ''), agent: input.agent_id || null, ...callArguments(input.tool_input) }),
47
66
  signal: AbortSignal.timeout(5000),
48
67
  });
49
- const decision = await response.json();
50
- if (decision && decision.allow === false) deny(decision.reason || 'SynaBun refused this call.');
51
- else if (remote && !(decision && decision.allow === true)) deny(UNCHECKED);
52
- } catch {
68
+ } catch { response = null; }
69
+ if (!response) {
53
70
  if (remote) deny(UNCHECKED);
71
+ } else {
72
+ let decision = null;
73
+ try { decision = await response.json(); } catch { decision = null; }
74
+ if (response.ok && decision && decision.allow === true) { /* allowed: Codex runs the call */ }
75
+ else if (response.ok && decision && decision.allow === false) deny(decision.reason || 'SynaBun refused this call.');
76
+ else deny(notADecision(response.status, decision));
54
77
  }
55
78
  }
56
79
  process.exit(0);
@@ -14,6 +14,8 @@ import { createCodexEnvelopeTranslator, codexControlResponse } from '../assistan
14
14
  import { baseModelId, contextVariantOf } from '../assistant-catalog.js';
15
15
  import { codexPlanPermission, codexReadOnlyPermission, planDenyMessage, readOnlyDenyMessage } from '../assistant-plan-permissions.js';
16
16
  import { planModeInstructions } from '../assistant-persona.js';
17
+ import { shouldAutoAcceptCodexMcpToolApproval } from '../codex-mcp-approvals.js';
18
+ import { codexMcpToolApproval } from '../../public/shared/cdx/cdx-protocol.js';
17
19
 
18
20
  const READY_TIMEOUT_MS = 90_000;
19
21
  // Approvals the Codex sidepanel's Auto-accept answers on its own (cdx-requests.js).
@@ -83,7 +85,7 @@ export function createCodexBrain({ session, sink, deps = {}, persona = '' } = {}
83
85
  }
84
86
  if (planned) {
85
87
  const method = packet.request?.brain_native?.method || packet.request?.method || '';
86
- const tool = packet.request?.brain_native?.params?._meta?.tool_name || packet.request?.tool_name || 'request';
88
+ const tool = codexMcpToolApproval(packet.request?.brain_native?.params)?.fullName || packet.request?.tool_name || 'request';
87
89
  const response = planned === 'allow'
88
90
  ? { behavior: 'allow', ...(!remoteReadOnly && approvalMode === 'auto' ? { always: true } : {}) }
89
91
  : { behavior: 'deny', decline: true, message: remoteReadOnly ? readOnlyDenyMessage(tool) : planDenyMessage(tool, { host: 'codex' }) };
@@ -91,7 +93,9 @@ export function createCodexBrain({ session, sink, deps = {}, persona = '' } = {}
91
93
  sink.send({ type: 'stderr', text: `${planMode ? 'Plan mode' : 'Read-only (WhatsApp)'}: ${planned === 'allow' ? 'allowed' : 'declined'} ${String(method).split('/').slice(1, -1).join('/') || 'request'} ${tool}${planned === 'allow' ? '' : remoteReadOnly ? ' (read-only)' : ' (no code changes)'}` });
92
94
  return;
93
95
  }
94
- if (packet.type === 'control_request' && !planMode && !remoteReadOnly && approvalMode === 'auto' && AUTO_ACCEPT_METHODS.has(packet.request?.brain_native?.method || packet.request?.method)) {
96
+ const method = packet.request?.brain_native?.method || packet.request?.method;
97
+ const autoMcp = method === 'mcpServer/elicitation/request' && shouldAutoAcceptCodexMcpToolApproval(packet.request?.brain_native?.params, { autoAccept: approvalMode === 'auto', role: 'assistant' });
98
+ if (packet.type === 'control_request' && !planMode && !remoteReadOnly && (autoMcp || (approvalMode === 'auto' && AUTO_ACCEPT_METHODS.has(method)))) {
95
99
  // Auto-accept: approve at once (for the session when offered), as the Codex sidepanel does.
96
100
  send({ type: 'server_request_response', ...codexControlResponse(packet, { behavior: 'allow', always: true }) });
97
101
  sink.send({ type: 'stderr', text: `Auto-accepted: ${String(packet.request?.brain_native?.method || packet.request?.method).split('/').slice(1, -1).join('/')}` });
@@ -119,8 +123,8 @@ export function createCodexBrain({ session, sink, deps = {}, persona = '' } = {}
119
123
  });
120
124
  const socket = createVirtualSocket({
121
125
  name: `codex-brain-${session.id}`,
122
- // A WhatsApp conversation's brain credential rides on the socket object, never in a message: the skin
123
- // handler gives it to this app-server's SynaBun MCP child through its environment (whatsapp_send_file).
126
+ // The brain's launch credential rides on the socket object, never in a message: the skin handler gives it to
127
+ // this app-server's SynaBun MCP child through its environment (whatsapp_send_file, the Skills Service).
124
128
  credential: deps.brainCredential || null,
125
129
  onSend: (packet) => {
126
130
  if (disposed || !packet || typeof packet !== 'object') return;
@@ -159,7 +163,7 @@ export function createCodexBrain({ session, sink, deps = {}, persona = '' } = {}
159
163
  readyResolve = () => { clearTimeout(timer); resolve(true); };
160
164
  });
161
165
  send({
162
- type: 'bootstrap', windowId, accountId: brain.accountId || 'default', mcpProfile: brain.mcpProfile || null,
166
+ type: 'bootstrap', windowId, accountId: brain.accountId || 'default',
163
167
  cwd: brain.cwd || deps.PACKAGE_ROOT || undefined, threadId: threadId || null, role: 'assistant',
164
168
  // Unlocks the capability-gated `computer` MCP group for this brain only.
165
169
  desktopGrant: deps.desktopGrant || null,
@@ -1,20 +1,23 @@
1
+ import { OPENCODE_BRAIN_TOOLS } from '../assistant-tools.js';
1
2
  // ═══════════════════════════════════════════
2
3
  // SynaBun — Assistant brain: OpenCode (isolated serve + SDK client)
3
4
  // ═══════════════════════════════════════════
4
5
  //
5
6
  // One isolated `opencode serve` per assistant session (same helpers the
6
7
  // OpenCode sidepanel uses). The persona is installed as a custom primary agent
7
- // (`agent.assistant.prompt`) in the per-serve config so the model sees it as
8
- // its system prompt; SSE events are translated to the unified envelope.
8
+ // (`agents.assistant.system`) in the per-serve opencode.json so the model sees
9
+ // it as its system prompt; SSE events are translated to the unified envelope.
9
10
 
10
- import { chmodSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
11
+ import { chmodSync, writeFileSync } from 'node:fs';
11
12
  import { dirname, resolve } from 'node:path';
12
13
  import { fileURLToPath, pathToFileURL } from 'node:url';
13
14
  import { normalizeOpenCodeModel } from '../native-loop-providers.js';
14
- import { compactOrSummarize } from '../opencode-v2-client.js';
15
+ import { agentOf, mcpServersOf, opencodeConfigFilePath, readOpencodeConfigDocument, setAgent, setMcpServer, withPlugin, withoutPlugin } from '../opencode-config.js';
15
16
  import { createOpenCodeEnvelopeTranslator, opencodeControlResponse } from '../assistant-envelope.js';
16
17
  import { opencodePlanPermission, opencodeReadOnlyPermission, planDenyMessage, readOnlyDenyMessage } from '../assistant-plan-permissions.js';
17
18
  import { planModeInstructions } from '../assistant-persona.js';
19
+ import { waitForSynabunTools, synabunConfigured, synabunToolsTimeoutText, OPENCODE_MCP_READY_TIMEOUT_MS, OPENCODE_MCP_SETTLE_MS, OPENCODE_MCP_LIST_GRACE_MS } from '../opencode-mcp-ready.js';
20
+ export { synabunMcpState } from '../opencode-mcp-ready.js';
18
21
 
19
22
  /** The MCP terminal pin of an assistant session's OpenCode brain. */
20
23
  export function opencodeTermIdFor(sessionId) {
@@ -34,8 +37,8 @@ export function opencodeImageParts(images = []) {
34
37
  return parts;
35
38
  }
36
39
 
37
- /** The route-gate plugin (opencode-route-gate.js) as a file URL the serve can load. */
38
- export const OPENCODE_ROUTE_GATE_PLUGIN = pathToFileURL(resolve(dirname(fileURLToPath(import.meta.url)), 'opencode-route-gate.js')).href;
40
+ /** The route-gate plugin (opencode2-route-gate/, a plugin folder OpenCode loads from `plugins`) as a file URL. */
41
+ export const OPENCODE_ROUTE_GATE_PLUGIN = pathToFileURL(resolve(dirname(fileURLToPath(import.meta.url)), 'opencode2-route-gate')).href;
39
42
 
40
43
  /**
41
44
  * SynaBun's plan agent. OpenCode adds its own read-only reminder ("commands may
@@ -46,65 +49,111 @@ export const OPENCODE_ROUTE_GATE_PLUGIN = pathToFileURL(resolve(dirname(fileURLT
46
49
  */
47
50
  export const OPENCODE_PLAN_AGENT = 'synabun-plan';
48
51
 
52
+ /**
53
+ * Tools this brain's agents must never call. Code Mode's `execute` runs arbitrary code (a `fetch`
54
+ * included) that no argument check can read, so the route gate refuses it before routing - and this
55
+ * brain's SynaBun tools are direct (codemode: false), so the only thing `execute` can do here is earn
56
+ * that refusal. Denied at the agent, the model is not offered it at all.
57
+ */
58
+ export const OPENCODE_BRAIN_DENIED_TOOLS = Object.freeze(['execute']);
59
+
49
60
  /** The brain's SynaBun MCP tool-call timeout (ms): as long as the Codex brain's tool_timeout_sec (server.js). */
50
61
  export const OPENCODE_BRAIN_MCP_TIMEOUT_MS = 180_000;
51
62
 
63
+ // Compatibility exports for the brain's existing consumers and tests.
64
+ export const OPENCODE_BRAIN_MCP_READY_TIMEOUT_MS = OPENCODE_MCP_READY_TIMEOUT_MS;
65
+ export const OPENCODE_BRAIN_MCP_SETTLE_MS = OPENCODE_MCP_SETTLE_MS;
66
+ export const OPENCODE_BRAIN_MCP_LIST_GRACE_MS = OPENCODE_MCP_LIST_GRACE_MS;
67
+ export const assistantSynabunConfigured = synabunConfigured;
68
+ export { OPENCODE_BRAIN_TOOLS } from '../assistant-tools.js';
69
+
70
+ /**
71
+ * Why the brain's serve would start with SynaBun behind Code Mode (`execute` only, which the route gate
72
+ * refuses before routing, so agent_route would be unreachable), read back from the written config; null
73
+ * when it is fine. No config file at all: the serve has no SynaBun server, the gate turns itself off.
74
+ */
75
+ export function assistantConfigProblem(xdgRoot) {
76
+ let doc;
77
+ try { doc = readOpencodeConfigDocument(opencodeConfigFilePath(resolve(xdgRoot, 'opencode'))); } catch (err) { return `its OpenCode configuration could not be read (${err?.message || err})`; }
78
+ if (!doc.exists) return null;
79
+ if (doc.error) return 'its OpenCode configuration could not be read';
80
+ const synabun = mcpServersOf(doc.config).SynaBun;
81
+ if (synabun && synabun.codemode !== false) return 'SynaBun\'s tools could not be set up for direct use (OpenCode Code Mode stayed on)';
82
+ return null;
83
+ }
84
+
52
85
  /**
53
86
  * `routeGate` ({ url, session, token }) installs the route-gate plugin in this
54
- * isolated serve's config only (assistant brains; never the shared sidepanel setup).
87
+ * isolated serve's opencode.json only (assistant brains; never the shared
88
+ * sidepanel setup). Everything is written in OpenCode 2's schema.
55
89
  */
56
90
  export function patchOpenCodeAssistantConfig(xdgRoot, { persona = '', role = 'assistant', model = null, desktopGrant = null, routeGate = null, brainCredential = null } = {}) {
57
- const configPath = resolve(xdgRoot, 'opencode', 'config.json');
58
- if (!existsSync(configPath)) return false;
59
- const config = JSON.parse(readFileSync(configPath, 'utf8'));
60
- if (config.mcp?.SynaBun && typeof config.mcp.SynaBun === 'object') {
61
- const envKey = config.mcp.SynaBun.environment ? 'environment' : (config.mcp.SynaBun.env ? 'env' : 'environment');
62
- const env = { ...(config.mcp.SynaBun[envKey] || {}), SYNABUN_ROLE: role };
91
+ const configPath = opencodeConfigFilePath(resolve(xdgRoot, 'opencode'));
92
+ const doc = readOpencodeConfigDocument(configPath);
93
+ if (!doc.exists || doc.error) return false;
94
+ const config = doc.config;
95
+ const synabun = mcpServersOf(config).SynaBun;
96
+ if (synabun) {
97
+ const env = { ...(synabun.environment || {}), SYNABUN_ROLE: role };
63
98
  // Computer use: an unforgeable per-brain grant unlocks the `computer` group.
64
99
  if (desktopGrant) env.SYNABUN_DESKTOP_GRANT = desktopGrant;
65
100
  else delete env.SYNABUN_DESKTOP_GRANT;
66
- // A WhatsApp conversation's brain credential (whatsapp_send_file), for this serve's SynaBun MCP child only.
101
+ // The brain's launch credential (whatsapp_send_file, the Skills Service), for this serve's SynaBun MCP child only.
67
102
  // This file names the variable; the value is in the serve's own environment (ensureIsolatedServe), so
68
103
  // neither this file (it is in every backup of data/) nor OPENCODE_CONFIG_CONTENT ever holds it.
69
104
  if (brainCredential) env.SYNABUN_BRAIN_TOKEN = '{env:SYNABUN_BRAIN_TOKEN}';
70
105
  else delete env.SYNABUN_BRAIN_TOKEN;
71
- config.mcp.SynaBun[envKey] = env;
72
106
  // OpenCode gives an MCP tool call 60 s unless the server says otherwise; agent_route may wait on the
73
107
  // user's route card and whatsapp_send_file on an upload (130 s): the Codex brain's 180 s here too.
74
- config.mcp.SynaBun.timeout = OPENCODE_BRAIN_MCP_TIMEOUT_MS;
108
+ // OpenCode 2.1's MCP default is Code Mode: only `execute` reaches these tools. The route gate must
109
+ // refuse arbitrary execute code until routed, so wrapping agent_route (and exempt memory tools) deadlocks
110
+ // the brain. Expose this brain's SynaBun tools directly instead. The serve's OPENCODE_CONFIG_CONTENT
111
+ // overlay carries this entry past project config too; other servers, workers and sidepanels keep their mode.
112
+ setMcpServer(config, 'SynaBun', { ...synabun, codemode: false, environment: env, timeout: { ...(synabun.timeout || {}), execution: OPENCODE_BRAIN_MCP_TIMEOUT_MS } });
75
113
  }
76
- config.agent = { ...(config.agent || {}) };
77
- config.agent.assistant = {
78
- ...(config.agent.assistant || {}),
114
+ const rule = (action, effect, resource = '*') => ({ action, resource, effect });
115
+ // An agent's rules with ours last, in place of any it had for the same tools (as OpenCode 1's
116
+ // `permission.<tool>` replaced the user's value): every command asks whatever was allowed before, and the
117
+ // list stays as it is when the config is patched again.
118
+ const withOurRules = (agent, ours) => [...(agent.permissions || []).filter((own) => !ours.some((r) => r.action === own?.action)), ...ours];
119
+ const withoutExecute = OPENCODE_BRAIN_DENIED_TOOLS.map((name) => rule(name, 'deny'));
120
+ const assistant = agentOf(config, 'assistant');
121
+ setAgent(config, 'assistant', {
122
+ ...assistant,
79
123
  mode: 'primary',
80
124
  description: 'SynaBun central assistant',
81
- prompt: persona || undefined,
125
+ ...(persona ? { system: persona } : {}),
82
126
  ...(model ? { model } : {}),
83
- };
127
+ permissions: withOurRules(assistant, withoutExecute),
128
+ });
84
129
  // SynaBun's plan agent (desktop plan turns): no code changes, anything else as the approval mode says.
85
- config.agent[OPENCODE_PLAN_AGENT] = {
86
- ...(config.agent[OPENCODE_PLAN_AGENT] || {}),
130
+ const synabunPlan = agentOf(config, OPENCODE_PLAN_AGENT);
131
+ setAgent(config, OPENCODE_PLAN_AGENT, {
132
+ ...synabunPlan,
87
133
  mode: 'primary',
88
134
  hidden: true,
89
135
  description: 'SynaBun plan mode: explore, run commands and use every tool; no code changes',
90
- prompt: persona || undefined,
136
+ ...(persona ? { system: persona } : {}),
91
137
  ...(model ? { model } : {}),
92
- permission: { ...(config.agent[OPENCODE_PLAN_AGENT]?.permission || {}), edit: 'deny', bash: 'ask', question: 'allow', task: { general: 'deny' } },
93
- };
138
+ permissions: withOurRules(synabunPlan, [...withoutExecute, rule('edit', 'deny'), rule('shell', 'ask'), rule('question', 'allow'), rule('subagent', 'deny', 'general')]),
139
+ });
94
140
  // OpenCode's own plan agent (a WhatsApp session's read-only brain) refuses only
95
141
  // edits and runs any command without asking: here every command asks, so the
96
142
  // read-only classifier decides on the whole line.
97
- config.agent.plan = { ...(config.agent.plan || {}), permission: { ...(config.agent.plan?.permission || {}), bash: 'ask' } };
98
- const plugins = (Array.isArray(config.plugin) ? config.plugin : []).filter((entry) => (Array.isArray(entry) ? entry[0] : entry) !== OPENCODE_ROUTE_GATE_PLUGIN);
143
+ const plan = agentOf(config, 'plan');
144
+ setAgent(config, 'plan', { ...plan, permissions: withOurRules(plan, [rule('shell', 'ask')]) });
145
+ withoutPlugin(config, OPENCODE_ROUTE_GATE_PLUGIN);
99
146
  // `remote`: a WhatsApp session's serve — the plugin refuses a call it could not check (fail closed).
100
- if (routeGate?.url && routeGate?.session && routeGate?.token) plugins.push([OPENCODE_ROUTE_GATE_PLUGIN, { url: routeGate.url, session: routeGate.session, token: routeGate.token, ...(routeGate.remote === true ? { remote: true } : {}) }]);
101
- if (plugins.length) config.plugin = plugins; else delete config.plugin;
102
- writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
147
+ if (routeGate?.url && routeGate?.session && routeGate?.token) {
148
+ withPlugin(config, OPENCODE_ROUTE_GATE_PLUGIN, { url: routeGate.url, session: routeGate.session, token: routeGate.token, ...(routeGate.remote === true ? { remote: true } : {}) });
149
+ }
150
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { encoding: 'utf8', mode: 0o600 });
103
151
  // It carries this brain's grants (the desktop grant): readable by this user only.
104
152
  try { chmodSync(configPath, 0o600); } catch { /* a filesystem without modes */ }
105
153
  return true;
106
154
  }
107
155
 
156
+
108
157
  /** The assistant's OpenCode approval mode: 'auto' (auto-accept) or 'default'. */
109
158
  export function opencodeApprovalMode(mode) {
110
159
  return mode === 'auto' || mode === 'acceptEdits' || mode === 'bypassPermissions' ? 'auto' : 'default';
@@ -157,8 +206,13 @@ export function createOpenCodeBrain({ session, sink, deps = {}, persona = '' } =
157
206
  let keepAliveTimer = null;
158
207
  let costUsd = 0;
159
208
  let startPromise = null;
160
- // The model the last turn ran on: what a compaction summarises with.
161
- let lastTurnModel = null;
209
+ let synabunExpected = false;
210
+ let stops = 0;
211
+ let waitingAbort = null;
212
+ const mcpWait = {
213
+ readyTimeoutMs: deps.mcpReadyTimeoutMs, settleMs: deps.mcpSettleMs,
214
+ listGraceMs: deps.mcpListGraceMs, pollMs: deps.mcpPollMs,
215
+ };
162
216
  // Plan mode runs SynaBun's plan agent (OPENCODE_PLAN_AGENT; OpenCode's own
163
217
  // `plan` agent, the persona riding as `system`, when the config patch failed).
164
218
  let approvalMode = opencodeApprovalMode(brain.permissionMode);
@@ -207,17 +261,29 @@ export function createOpenCodeBrain({ session, sink, deps = {}, persona = '' } =
207
261
  }
208
262
 
209
263
  /** The serve's MCP servers as an `mcp_status` event (the runtime reads whether SynaBun, and so agent_route, is reachable). */
264
+ function sendMcpStatus(servers) { sink.send({ type: 'event', event: { type: 'system', subtype: 'mcp_status', servers } }); }
210
265
  async function reportMcpStatus() {
211
- try { const status = await client?.mcp?.status?.({ directory: cwd }); sink.send({ type: 'event', event: { type: 'system', subtype: 'mcp_status', servers: status?.data || status || [] } }); } catch {}
266
+ try { const status = await client?.mcp?.status?.({ directory: cwd }); sendMcpStatus(status?.data || status || []); } catch {}
212
267
  }
213
268
 
214
269
  async function start() {
215
270
  if (disposed) throw new Error('OpenCode brain disposed');
216
271
  if (startPromise) return startPromise;
217
272
  startPromise = (async () => {
218
- const xdgRoot = deps.setupOpencodeSidepanelConfig(termId, brain.mcpProfile || null);
219
- try { personaInstalled = patchOpenCodeAssistantConfig(xdgRoot, { persona, model: null, desktopGrant: deps.desktopGrant || null, routeGate: deps.routeGate || null, brainCredential: deps.brainCredential || null }); } catch { personaInstalled = false; }
220
- entry = await deps.ensureIsolatedServe(termId, { xdgRoot, keepAlive: true, mcpProfile: brain.mcpProfile || null, brainCredential: deps.brainCredential || null });
273
+ const xdgRoot = deps.setupOpencodeSidepanelConfig(termId, brain.tools ?? OPENCODE_BRAIN_TOOLS, { cwd: brain.cwd, scopeExternal: false });
274
+ // A brain whose config could not be patched would start with Code Mode on: SynaBun's tools only behind
275
+ // `execute`, which the route gate refuses before routing, so agent_route is unreachable. Refuse to start.
276
+ let patchError = null;
277
+ try { personaInstalled = patchOpenCodeAssistantConfig(xdgRoot, { persona, model: null, desktopGrant: deps.desktopGrant || null, routeGate: deps.routeGate || null, brainCredential: deps.brainCredential || null }); } catch (err) { personaInstalled = false; patchError = err; }
278
+ const unready = assistantConfigProblem(xdgRoot);
279
+ if (unready) {
280
+ throw new Error(`OpenCode Assistant could not start: ${unready}${patchError?.message ? ` (${patchError.message})` : ''}. Check Settings → OpenCode, or switch the Assistant to another provider.`);
281
+ }
282
+ // Its turns go out once SynaBun's tools are on the model's list (waitForSynabunTools).
283
+ synabunExpected = assistantSynabunConfigured(xdgRoot);
284
+ // An inherited OPENCODE_CONFIG_DIR would replace this isolated configuration (route-gate plugin,
285
+ // the assistant and plan agents): the brain's serve never reads it.
286
+ entry = await deps.ensureIsolatedServe(termId, { xdgRoot, keepAlive: true, tools: brain.tools ?? OPENCODE_BRAIN_TOOLS, brainCredential: deps.brainCredential || null, extraEnv: { OPENCODE_CONFIG_DIR: null } });
221
287
  if (!entry?.client) throw new Error('OpenCode isolated serve failed to start');
222
288
  client = entry.client;
223
289
  await client.waitUntilConnected?.(20_000);
@@ -241,7 +307,9 @@ export function createOpenCodeBrain({ session, sink, deps = {}, persona = '' } =
241
307
  kind: 'opencode',
242
308
  start,
243
309
  async sendUserTurn({ text, images = [], model = null, effort = null, permissionMode: mode = null, planMode: plan = null } = {}) {
310
+ const stop = stops;
244
311
  await start();
312
+ if (disposed || stops !== stop) return false;
245
313
  applyModes(mode, plan);
246
314
  turnActive = true;
247
315
  // The runtime passes the effective model/effort on every turn (the record
@@ -250,7 +318,6 @@ export function createOpenCodeBrain({ session, sink, deps = {}, persona = '' } =
250
318
  const request = {
251
319
  sessionID: sessionId, parts, model: normalizeOpenCodeModel(model || brain.model), directory: cwd,
252
320
  };
253
- if (request.model) lastTurnModel = request.model;
254
321
  if (effort) request.variant = String(effort);
255
322
  turnPlanned = planMode && !remoteReadOnly;
256
323
  if (turnPlanned && personaInstalled) {
@@ -265,14 +332,25 @@ export function createOpenCodeBrain({ session, sink, deps = {}, persona = '' } =
265
332
  else if (personaInstalled) request.agent = brain.agent || 'assistant';
266
333
  else { request.agent = brain.agent || 'build'; if (persona) request.system = persona; }
267
334
  if (entry) entry.lastUsed = Date.now();
268
- // SynaBun may have connected (or failed) since the last turn: the route gate follows it.
269
- await reportMcpStatus();
335
+ // SynaBun's tools on the model's list first (a fresh serve may still be connecting them); the route gate
336
+ // follows what was seen. Stopped meanwhile (its `aborted` is out) or disposed: the turn never goes out.
337
+ const controller = new AbortController();
338
+ waitingAbort = controller;
339
+ let ready;
340
+ try {
341
+ ready = await waitForSynabunTools(client, { ...mcpWait, directory: cwd, expected: synabunExpected,
342
+ signal: controller.signal, stopped: () => disposed || stops !== stop,
343
+ onStatus: sendMcpStatus,
344
+ onTimeout: (ms) => sink.send({ type: 'event', event: { type: 'system', subtype: 'status', text: synabunToolsTimeoutText(ms, 'brain') } }),
345
+ });
346
+ } finally { if (waitingAbort === controller) waitingAbort = null; }
347
+ if (!ready || disposed || stops !== stop) { turnActive = false; return false; }
270
348
  const response = await client.session.promptAsync(request);
271
349
  const status = Number(response?.status);
272
350
  if (Number.isFinite(status) && status >= 400) { turnActive = false; throw new Error(`OpenCode prompt failed (${status})`); }
273
351
  return true;
274
352
  },
275
- async abort() { if (client && sessionId) await client.session.abort({ sessionID: sessionId, directory: cwd }).catch(() => {}); emit({ type: 'aborted' }); },
353
+ async abort() { stops += 1; waitingAbort?.abort(); if (client && sessionId) await client.session.abort({ sessionID: sessionId, directory: cwd }).catch(() => {}); emit({ type: 'aborted' }); },
276
354
  async setPermissionMode(mode, { planMode: plan = null } = {}) { applyModes(mode, plan); sink.send({ type: 'mode_changed', mode: approvalMode, planMode }); },
277
355
  respondControl(requestId, response) {
278
356
  const pending = pendingControls.get(String(requestId));
@@ -284,12 +362,11 @@ export function createOpenCodeBrain({ session, sink, deps = {}, persona = '' } =
284
362
  : client.permission.reply({ requestID: body.requestID, reply: body.reply, directory: cwd });
285
363
  Promise.resolve(call).catch((error) => sink.send({ type: 'error', message: `OpenCode reply failed: ${error?.message || error}` }));
286
364
  },
287
- // OpenCode 1.18.34 answers v2.session.compact with 503 "not available yet":
288
- // compactOrSummarize then summarises on the model of the last turn.
365
+ // OpenCode compacts the session on the model it runs on.
289
366
  async compact() {
290
367
  await start();
291
368
  turnPlanned = false;
292
- await compactOrSummarize(client, { sessionID: sessionId, directory: cwd, model: lastTurnModel || normalizeOpenCodeModel(brain.model) });
369
+ await client.session.compact({ sessionID: sessionId, directory: cwd });
293
370
  },
294
371
  async mcpStatus() { await reportMcpStatus(); },
295
372
  async reconcileUsage(meter) {
@@ -325,6 +402,7 @@ export function createOpenCodeBrain({ session, sink, deps = {}, persona = '' } =
325
402
  async dispose() {
326
403
  if (disposed) return;
327
404
  disposed = true;
405
+ waitingAbort?.abort();
328
406
  if (keepAliveTimer) clearInterval(keepAliveTimer);
329
407
  if (unsubscribe) { try { unsubscribe(); } catch {} }
330
408
  try { deps.stopIsolatedServe(termId); } catch {}
@@ -0,0 +1,59 @@
1
+ // SynaBun — OpenCode plugin: the browser policy of an Assistant task run.
2
+ // Loaded only by the isolated `opencode serve` of a worker the Assistant
3
+ // dispatched (its opencode.json's `plugins` entry, { package: <this folder as a
4
+ // file URL>, options }, added by withOpenCodeBrowserPolicy from server.js
5
+ // setupOpencodeLoopConfig); loops, schedules and the OpenCode sidepanel never
6
+ // load it. OpenCode 2's plugin API: the default export is `{ id, setup(context) }`,
7
+ // registering `context.tool.hook('execute.before', …)`, which sees `{ tool, sessionID, input }`;
8
+ // a refusal is thrown as a plain Error, which OpenCode records as that tool's
9
+ // error, and the loop continues. Before every tool call it asks
10
+ // lib/browser-tool-policy.js here, with no server round trip. OpenCode calls the
11
+ // shell tool `shell` and the sub-agent tool `subagent`: the policy is asked with
12
+ // the names the rest of SynaBun knows (`bash`, `task`). Script paths resolve
13
+ // against the run's cwd (the plugin options), else the serve's directory; the
14
+ // options' `roots` name the registered code projects its test runners may also
15
+ // run in (the serve is sandboxed and cannot read SynaBun's data home: server.js
16
+ // lists them as the run starts). A
17
+ // policy module that cannot load fails closed: the failure is logged once, and
18
+ // the shell, webfetch, websearch and every tool that is not OpenCode's own or
19
+ // SynaBun's (another MCP server's, another plugin's) are refused with that
20
+ // reason until the run ends.
21
+
22
+ // An absolute file URL: the policy loads from SynaBun's lib/ wherever OpenCode imports this file from.
23
+ const POLICY_URL = new URL('../../browser-tool-policy.js', import.meta.url).href;
24
+ const V1_NAMES = { shell: 'bash', subagent: 'task' };
25
+
26
+ // OpenCode's own tools that run no command, fetch no page and open no browser (by the names above). The shell,
27
+ // webfetch, websearch and OpenCode's browser are not here; any other name belongs to an MCP server or a plugin.
28
+ const OWN_TOOLS = new Set([
29
+ 'read', 'list', 'glob', 'grep', 'edit', 'write', 'patch', 'todo', 'task', 'skill', 'lsp', 'question',
30
+ 'invalid', 'plan_exit', 'plan_enter',
31
+ ]);
32
+
33
+ export default {
34
+ id: 'synabun.browser-policy',
35
+ async setup(context) {
36
+ const options = context?.options || {};
37
+ let policy = null;
38
+ let loadError = null;
39
+ try { policy = await import(POLICY_URL); } catch (error) { loadError = error; }
40
+ const cwd = (typeof options.cwd === 'string' && options.cwd) || context?.location?.directory || process.cwd();
41
+ const roots = Array.isArray(options.roots) ? options.roots.filter((path) => typeof path === 'string') : [];
42
+ if (typeof policy?.browserToolDenial !== 'function') {
43
+ const why = loadError?.message || 'browserToolDenial is missing';
44
+ console.error(`[SynaBun] browser policy could not load from ${POLICY_URL} (${why}); refusing the shell, webfetch, websearch and other servers' tools for this run`);
45
+ await context.tool.hook('execute.before', async (call) => {
46
+ const raw = String(call?.tool || '');
47
+ const tool = V1_NAMES[raw] || raw;
48
+ if (/^synabun_/i.test(tool) || OWN_TOOLS.has(tool.toLowerCase())) return;
49
+ throw new Error(`SynaBun browser policy: ${raw} was refused — SynaBun's browser policy could not load (${why}), so no command, web tool or other server's tool can be checked for a browser launch. SynaBun's own tools (SynaBun_*) and file tools still work. Stop and report this.`);
50
+ });
51
+ return;
52
+ }
53
+ await context.tool.hook('execute.before', async (call) => {
54
+ const raw = String(call?.tool || '');
55
+ const reason = policy.browserToolDenial(V1_NAMES[raw] || raw, call?.input || {}, { host: 'opencode', cwd, roots });
56
+ if (reason) throw new Error(reason);
57
+ });
58
+ },
59
+ };
@@ -0,0 +1,97 @@
1
+ // SynaBun — OpenCode plugin for the Assistant's route gate.
2
+ // Loaded only by the assistant brain's isolated `opencode serve` (its
3
+ // opencode.json's `plugins` entry, { package: <this folder as a file URL>,
4
+ // options }, written by patchOpenCodeAssistantConfig); the OpenCode sidepanel
5
+ // never loads it. OpenCode 2's plugin API: the default export is
6
+ // `{ id, setup(context) }`; the hook it registers with
7
+ // `context.tool.hook('execute.before', …)` sees `{ tool, sessionID, input }`
8
+ // and refuses a call by throwing (OpenCode records
9
+ // the message as that tool's error and the loop continues; only
10
+ // permission/question rejections stop a turn). Before every tool call it asks
11
+ // the Neural Interface whether the call may run (the route gate, and plan
12
+ // mode's read-only policy on every session of this serve). When the gate
13
+ // allows, the user's own OpenCode permission rules apply exactly as before.
14
+ // OpenCode calls two tools by other names than the rest of SynaBun knows
15
+ // (`shell` for bash, `subagent` for task): the gate is asked with those names.
16
+ // The call's whole arguments travel (the remote denylist reads paths from
17
+ // them), marked inputComplete; arguments too big to send go as their
18
+ // command/action only. No answer at all (the server unreachable or slow)
19
+ // allows the call — except with `remote` (a WhatsApp session's serve), where a
20
+ // call SynaBun could not check is refused. An answer that is not a decision
21
+ // (the check itself refused, such as 403 PEER_REFUSED, an error status, a body
22
+ // without `allow`) refuses the call in every session and says what SynaBun
23
+ // answered: a refusal never passes for an allow.
24
+ //
25
+ // Every request carries the session's pin (X-Synabun-Assistant): this plugin
26
+ // runs inside the brain's `opencode serve`, an AI agent's process tree, which
27
+ // SynaBun's owner gate (lib/owner-authority.js) refuses unless the call says
28
+ // it is an agent's own. The per-session `token` in the body is what the route
29
+ // itself checks.
30
+ //
31
+ // On load it says hello: until the Neural Interface hears it, it enforces the
32
+ // gate reactively (interrupting a turn after an unrouted tool started), so a
33
+ // plugin that never loads still leaves the brain gated. A WhatsApp session
34
+ // runs no turn at all until the hello arrives.
35
+
36
+ const MAX_INPUT_BYTES = 256 * 1024;
37
+ const UNCHECKED = 'SynaBun could not check this call, so a WhatsApp session does not run it.';
38
+ const V1_NAMES = { shell: 'bash', subagent: 'task' };
39
+ const PIN_HEADER = 'x-synabun-assistant';
40
+
41
+ /** The session id as a header value (printable ASCII only: fetch refuses anything else before sending). */
42
+ function pinOf(session) {
43
+ return String(session).replace(/[^\x21-\x7e]/g, '').slice(0, 200);
44
+ }
45
+
46
+ /** The refusal of a call whose check got an answer that is not a decision: what SynaBun answered, in short. */
47
+ function notADecision(status, body) {
48
+ const code = body && typeof body === 'object' && typeof body.code === 'string' ? ` ${body.code.slice(0, 64)}` : '';
49
+ const said = body && typeof body === 'object' && typeof body.error === 'string' ? `: ${body.error.slice(0, 300)}` : '';
50
+ return `SynaBun could not check this call (its route gate answered ${status}${code}${said}), so it did not run.`;
51
+ }
52
+
53
+ /** { input, inputComplete }: the whole arguments when small enough to send, else their command/action. */
54
+ function callArguments(args) {
55
+ if (!args || typeof args !== 'object' || Array.isArray(args)) return { input: {}, inputComplete: false };
56
+ let size = Infinity;
57
+ try { size = JSON.stringify(args).length; } catch {}
58
+ if (size <= MAX_INPUT_BYTES) return { input: args, inputComplete: true };
59
+ const subset = {};
60
+ for (const key of ['command', 'action']) {
61
+ if (typeof args[key] === 'string' && args[key].length <= 64 * 1024) subset[key] = args[key];
62
+ }
63
+ return { input: subset, inputComplete: false };
64
+ }
65
+
66
+ export default {
67
+ id: 'synabun.route-gate',
68
+ async setup(context) {
69
+ const { url, session, token, remote = false } = context?.options || {};
70
+ if (!url || !session || !token) return;
71
+ const post = (body) => fetch(url, {
72
+ method: 'POST',
73
+ headers: { 'content-type': 'application/json', [PIN_HEADER]: pinOf(session) },
74
+ body: JSON.stringify({ session, token, host: 'opencode', ...body }),
75
+ signal: AbortSignal.timeout(5000),
76
+ });
77
+ // Never blocks loading; a lost hello only keeps the reactive fallback on (a refused one is said in the serve's log).
78
+ post({ hello: true }).then((response) => {
79
+ if (!response.ok) console.error(`[SynaBun] the route gate refused this serve's hello (${response.status}); every tool call will be refused until it answers`);
80
+ }).catch(() => {});
81
+ await context.tool.hook('execute.before', async (call) => {
82
+ const name = String(call?.tool || '');
83
+ let response;
84
+ try {
85
+ response = await post({ tool: V1_NAMES[name] || name, providerSessionId: call?.sessionID || null, ...callArguments(call?.input) });
86
+ } catch {
87
+ if (remote === true) throw new Error(UNCHECKED);
88
+ return;
89
+ }
90
+ let decision = null;
91
+ try { decision = await response.json(); } catch { decision = null; }
92
+ if (response.ok && decision && decision.allow === true) return;
93
+ if (response.ok && decision && decision.allow === false) throw new Error(String(decision.reason || 'SynaBun route gate: call agent_route first.'));
94
+ throw new Error(notADecision(response.status, decision));
95
+ });
96
+ },
97
+ };