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
@@ -1,428 +0,0 @@
1
- /**
2
- * Profile state and logic — shared between index.ts (registration) and tools/profile.ts.
3
- * Extracted to its own module to avoid circular imports.
4
- */
5
- import type { RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
6
- import { config } from '../config.js';
7
- import { sanitizeDesktopGrant, sanitizeRole, type CallerRole } from './identity.js';
8
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
9
- import { dirname, join } from 'path';
10
-
11
- // ── Presets and constants ──
12
-
13
- const ALL_BROWSER_GROUPS = ['browser', 'browser_twitter', 'browser_facebook', 'browser_tiktok', 'browser_whatsapp', 'browser_instagram', 'browser_linkedin', 'browser_bluesky'];
14
-
15
- export const PROFILE_PRESETS: Record<string, string[]> = {
16
- core: ['git', 'image', 'styleguide'],
17
- standard: ['git', 'image', 'whiteboard', 'card', 'tictactoe', 'styleguide'],
18
- 'codex-browser': ['git', 'image', 'browser', 'browser_twitter', 'styleguide'],
19
- twitter: ['git', 'image', 'browser', 'browser_twitter'],
20
- facebook: ['git', 'image', 'browser', 'browser_facebook'],
21
- tiktok: ['git', 'image', 'browser', 'browser_tiktok'],
22
- whatsapp: ['git', 'image', 'browser', 'browser_whatsapp'],
23
- instagram: ['git', 'image', 'browser', 'browser_instagram'],
24
- linkedin: ['git', 'image', 'browser', 'browser_linkedin'],
25
- bluesky: ['git', 'image', 'browser', 'browser_bluesky'],
26
- browser: ['git', 'image', 'whiteboard', 'card', 'tictactoe', ...ALL_BROWSER_GROUPS, 'leonardo', 'gsc', 'youtube', 'styleguide', 'morelogin'],
27
- full: ['git', 'image', 'whiteboard', 'card', 'tictactoe', ...ALL_BROWSER_GROUPS, 'leonardo', 'discord', 'gsc', 'youtube', 'styleguide', 'morelogin'],
28
- leonardoai: ['leonardo'],
29
- gsc: ['git', 'image', 'browser', 'gsc'],
30
- youtube: ['git', 'image', 'browser', 'youtube'],
31
- };
32
-
33
- export const VALID_GROUPS = new Set([
34
- ...ALL_BROWSER_GROUPS,
35
- 'whiteboard', 'card', 'tictactoe', 'discord', 'git', 'leonardo', 'image', 'gsc', 'youtube', 'styleguide', 'morelogin',
36
- 'agents', 'computer',
37
- ]);
38
-
39
- /**
40
- * Groups that only a caller with the matching role may see. They are never
41
- * part of a preset: the role — not the profile — decides, so `profile set`
42
- * can neither reveal `agents` to a plain runtime nor hide it from the
43
- * assistant, and a deferred Codex catalog does not leak it either.
44
- */
45
- export const ROLE_GATED_GROUPS: Readonly<Record<string, CallerRole>> = Object.freeze({ agents: 'assistant' as const });
46
-
47
- export function isRoleGatedGroup(group: string): boolean {
48
- return Object.prototype.hasOwnProperty.call(ROLE_GATED_GROUPS, group);
49
- }
50
-
51
- /**
52
- * Groups unlocked by a capability the caller proves, not by a role or a
53
- * profile: `computer` needs a desktop grant the Neural Interface minted for
54
- * this brain or worker run (and macOS). Like role-gated groups they are never
55
- * part of a preset and a deferred catalog never leaks them.
56
- */
57
- export type CallerCapability = 'computer';
58
- export const CAPABILITY_GATED_GROUPS: Readonly<Record<string, CallerCapability>> = Object.freeze({ computer: 'computer' as const });
59
-
60
- export function isCapabilityGatedGroup(group: string): boolean {
61
- return Object.prototype.hasOwnProperty.call(CAPABILITY_GATED_GROUPS, group);
62
- }
63
-
64
- export function isGatedGroup(group: string): boolean {
65
- return isRoleGatedGroup(group) || isCapabilityGatedGroup(group);
66
- }
67
-
68
- export const PROFILE_PATH = join(config.dataDir, 'active-profile.json');
69
- const PROFILE_REGISTRY_PATH = join(config.dataHome, 'data', 'mcp-registry.json');
70
- const RUNTIME_PROFILE_PATH_ENV = 'SYNABUN_RUNTIME_PROFILE_PATH';
71
- export const TOOL_CATALOG_MODE_ENV = 'SYNABUN_TOOL_CATALOG_MODE';
72
-
73
- export type ToolCatalogMode = 'profiled' | 'deferred';
74
-
75
- /**
76
- * Codex snapshots its deferred MCP catalog at the start of each model turn.
77
- * A tools/list_changed notification updates Codex's MCP inventory, but tools
78
- * added after the turn starts cannot enter that turn's deferred catalog. For
79
- * Codex runtimes we therefore advertise every SynaBun tool up front and use
80
- * profiles as a focus selection instead of an availability boundary.
81
- */
82
- export function readToolCatalogMode(): ToolCatalogMode {
83
- const configured = String(process.env[TOOL_CATALOG_MODE_ENV] || '').trim().toLowerCase();
84
- if (configured === 'deferred') return 'deferred';
85
- if (configured === 'profiled') return 'profiled';
86
- // Managed Codex sidepanels have always used this stable runtime prefix. The
87
- // fallback makes upgraded sidepanels reliable even before their next spawn
88
- // picks up the explicit catalog-mode environment override.
89
- if (/^codex-sp-/.test(String(process.env.SYNABUN_TERMINAL_SESSION || ''))) return 'deferred';
90
- return 'profiled';
91
- }
92
-
93
- /**
94
- * Return the profile definitions visible to the current runtime.
95
- *
96
- * Neural Interface lets users add or edit profile presets in
97
- * data/mcp-registry.json. Reading that registry here keeps the always-on
98
- * `profile` tool and startup profile resolution aligned with the sidepanel
99
- * selector instead of silently treating a custom preset name as an empty
100
- * profile. Built-ins remain the fallback for headless/standalone MCP use.
101
- */
102
- export function getProfilePresets(): Record<string, string[]> {
103
- const presets: Record<string, string[]> = Object.fromEntries(
104
- Object.entries(PROFILE_PRESETS).map(([name, groups]) => [name, [...groups]])
105
- );
106
- try {
107
- if (!existsSync(PROFILE_REGISTRY_PATH)) return presets;
108
- const registry = JSON.parse(readFileSync(PROFILE_REGISTRY_PATH, 'utf-8'));
109
- for (const [name, profile] of Object.entries(registry?.profiles || {})) {
110
- const registryGroups = Array.isArray((profile as { groups?: unknown[] })?.groups)
111
- ? (profile as { groups: unknown[] }).groups
112
- .filter((group): group is string => typeof group === 'string' && VALID_GROUPS.has(group))
113
- : [];
114
- const normalizedName = String(name).toLowerCase().trim();
115
- // Built-ins are forward-migrated additively. Older persisted registries
116
- // predate groups such as styleguide/morelogin; letting them replace the
117
- // current defaults would silently remove tools from new MCP processes.
118
- presets[normalizedName] = PROFILE_PRESETS[normalizedName]
119
- ? [...new Set([...PROFILE_PRESETS[normalizedName], ...registryGroups])]
120
- : registryGroups;
121
- }
122
- } catch (err) {
123
- console.error('[SynaBun] Failed to read MCP profile registry:', err);
124
- }
125
- return presets;
126
- }
127
-
128
- // ── Claude Code detection ──
129
- // Claude Code sets CLAUDECODE=1 in the environment. It has ToolSearch for
130
- // deferred tool loading, so it never needs profile restrictions — always full.
131
- export function isClaudeCode(): boolean {
132
- return process.env.CLAUDECODE === '1';
133
- }
134
-
135
- // ── Helpers ──
136
-
137
- export function resolveProfileGroups(profileName: string): Set<string> {
138
- const raw = profileName.toLowerCase().trim();
139
- const presets = getProfilePresets();
140
- if (Object.prototype.hasOwnProperty.call(presets, raw)) return new Set(presets[raw]);
141
- const groups = new Set<string>();
142
- for (const g of raw.split(',')) {
143
- const name = g.trim();
144
- if (VALID_GROUPS.has(name)) groups.add(name);
145
- }
146
- return groups;
147
- }
148
-
149
- export function isValidProfileSelection(profileName: string): boolean {
150
- const raw = String(profileName || '').toLowerCase().trim();
151
- if (!raw) return false;
152
- if (Object.prototype.hasOwnProperty.call(getProfilePresets(), raw)) return true;
153
- const groups = raw.split(',').map((group) => group.trim()).filter(Boolean);
154
- return groups.length > 0 && groups.every((group) => VALID_GROUPS.has(group));
155
- }
156
-
157
- let _loggedCodexConfigNotice = false;
158
-
159
- export function readInitialProfile(): string {
160
- // 1. SYNABUN_RUNTIME_PROFILE_PATH — an isolated, runtime-owned selection.
161
- // OpenCode gives every sidepanel/loop/schedule a unique path so an MCP
162
- // child restart keeps that runtime's latest agent-selected profile even
163
- // though the process-wide/default profile is never changed.
164
- // 2. SYNABUN_PROFILE env var (set by Codex/OpenCode MCP env block, or by
165
- // .env via preload.ts) — the runtime's launch-time profile.
166
- // 3. active-profile.json — persisted future-runtime default, owned by SynaBun.
167
- // 4. default 'full'.
168
- const runtimeProfile = readProfileFile(process.env[RUNTIME_PROFILE_PATH_ENV]);
169
- if (runtimeProfile) return runtimeProfile;
170
- // Claude Code has ToolSearch and normally runs full. Check this only after
171
- // an explicit runtime-owned file so an inherited CLAUDECODE=1 from the
172
- // parent shell cannot erase a managed OpenCode runtime pin.
173
- if (isClaudeCode()) return 'full';
174
- if (process.env.SYNABUN_PROFILE) {
175
- if (isValidProfileSelection(process.env.SYNABUN_PROFILE)) {
176
- return process.env.SYNABUN_PROFILE.toLowerCase().trim();
177
- }
178
- // An explicit but invalid runtime pin must fail closed locally. Falling
179
- // through to the shared future-runtime default would make a typo in one
180
- // isolated window silently depend on another window's selection.
181
- console.error(`[SynaBun] Ignoring invalid SYNABUN_PROFILE=${JSON.stringify(process.env.SYNABUN_PROFILE)}; using full.`);
182
- return 'full';
183
- }
184
- const defaultProfile = readProfileFile(PROFILE_PATH);
185
- if (defaultProfile) return defaultProfile;
186
- return 'full';
187
- }
188
-
189
- function readProfileFile(profilePath: string | undefined): string | null {
190
- if (!profilePath) return null;
191
- try {
192
- if (!existsSync(profilePath)) return null;
193
- const data = JSON.parse(readFileSync(profilePath, 'utf-8'));
194
- if (typeof data?.profile === 'string' && isValidProfileSelection(data.profile)) {
195
- return data.profile.toLowerCase().trim();
196
- }
197
- } catch {}
198
- return null;
199
- }
200
-
201
- export function logCodexConfigNoticeOnce(): void {
202
- if (_loggedCodexConfigNotice) return;
203
- _loggedCodexConfigNotice = true;
204
- console.error(
205
- '[SynaBun] Runtime profile switches never rewrite ~/.codex/config.toml. ' +
206
- 'The canonical Codex registration uses the complete deferred SynaBun catalog; managed profile choices ' +
207
- 'are runtime-local focus selections. Other hosts use active-profile.json as their future-runtime default.'
208
- );
209
- }
210
-
211
- // ── Per-server runtime state ──
212
-
213
- export interface ProfileApplyResult {
214
- profile: string;
215
- enabled: string[];
216
- disabled: string[];
217
- totalTools: number;
218
- changed: boolean;
219
- catalogMode: ToolCatalogMode;
220
- }
221
-
222
- /**
223
- * Profile state belongs to one MCP server/transport, never to this module.
224
- *
225
- * The HTTP transport keeps several stateful McpServer instances in one Node
226
- * process. Module-global active groups/tool refs made one client's profile.set
227
- * mutate whichever server happened to register last. Stdio still gets one
228
- * ProfileRuntime per process, while HTTP gets one per client session.
229
- */
230
- export class ProfileRuntime {
231
- private activeGroups: Set<string>;
232
- private activeProfileName: string;
233
- private readonly catalogMode: ToolCatalogMode;
234
- private role: CallerRole | null;
235
- private capabilities: Set<CallerCapability>;
236
- private readonly platform: string;
237
- private readonly toolGroups = new Map<string, RegisteredTool[]>();
238
- private onProfileChanged: (() => void | Promise<void>) | null = null;
239
- private notificationTimer: ReturnType<typeof setTimeout> | null = null;
240
-
241
- constructor(initialProfile: string, options: { catalogMode?: ToolCatalogMode; role?: CallerRole | null; capabilities?: CallerCapability[] | null; platform?: string } = {}) {
242
- const normalized = String(initialProfile || 'full').toLowerCase().trim() || 'full';
243
- if (!isValidProfileSelection(normalized)) {
244
- throw new Error(`Unknown MCP profile or tool group selection: ${initialProfile}`);
245
- }
246
- // stdio children of the Codex/OpenCode assistant brains receive the role
247
- // through their launch env; HTTP sessions bind it later via setRole().
248
- this.role = options.role !== undefined ? options.role : sanitizeRole(process.env.SYNABUN_ROLE);
249
- // Same for the desktop grant: env for stdio, setCapabilities() for HTTP.
250
- this.capabilities = new Set(options.capabilities ?? (sanitizeDesktopGrant(process.env.SYNABUN_DESKTOP_GRANT) ? ['computer'] : []));
251
- this.platform = options.platform || process.platform;
252
- this.activeProfileName = normalized;
253
- this.activeGroups = this.resolveGroupsForRole(normalized);
254
- this.catalogMode = options.catalogMode || readToolCatalogMode();
255
- }
256
-
257
- getCapabilities(): CallerCapability[] {
258
- return [...this.capabilities];
259
- }
260
-
261
- /** Plain setter — callers re-apply the current profile afterwards. */
262
- setCapabilities(capabilities: CallerCapability[]): void {
263
- this.capabilities = new Set(capabilities);
264
- }
265
-
266
- getActiveProfile(): { profile: string; activeGroups: string[] } {
267
- return { profile: this.activeProfileName, activeGroups: Array.from(this.activeGroups) };
268
- }
269
-
270
- getActiveProfileName(): string {
271
- return this.activeProfileName;
272
- }
273
-
274
- getActiveGroups(): Set<string> {
275
- return this.activeGroups;
276
- }
277
-
278
- getCatalogMode(): ToolCatalogMode {
279
- return this.catalogMode;
280
- }
281
-
282
- getRole(): CallerRole | null {
283
- return this.role;
284
- }
285
-
286
- /** Plain setter — callers re-apply the current profile afterwards so
287
- * role-gated groups flip (index.ts setServerRole does both). */
288
- setRole(role: CallerRole | null): void {
289
- this.role = role;
290
- }
291
-
292
- /** Profile groups with the role gate applied: a gated group is active iff
293
- * this runtime's role matches, whatever the profile or registry says. */
294
- private resolveGroupsForRole(profileName: string): Set<string> {
295
- const groups = resolveProfileGroups(profileName);
296
- for (const [group, gate] of Object.entries(ROLE_GATED_GROUPS)) {
297
- if (this.role === gate) groups.add(group);
298
- else groups.delete(group);
299
- }
300
- // Capability gates: computer use exists only on macOS, for grant holders.
301
- for (const [group, capability] of Object.entries(CAPABILITY_GATED_GROUPS)) {
302
- const available = this.capabilities.has(capability) && (capability !== 'computer' || this.platform === 'darwin');
303
- if (available) groups.add(group);
304
- else groups.delete(group);
305
- }
306
- return groups;
307
- }
308
-
309
- setToolGroup(name: string, tools: RegisteredTool[]): void {
310
- this.toolGroups.set(name, tools);
311
- }
312
-
313
- setOnProfileChanged(fn: (() => void | Promise<void>) | null): void {
314
- this.onProfileChanged = fn;
315
- }
316
-
317
- dispose(): void {
318
- if (this.notificationTimer) clearTimeout(this.notificationTimer);
319
- this.notificationTimer = null;
320
- this.onProfileChanged = null;
321
- }
322
-
323
- /**
324
- * Coalesce one delayed list-changed notification. Delaying is essential:
325
- * OpenCode used to receive the notification while profile.set itself was
326
- * still in flight and could abort/cache the old tool roundtrip.
327
- */
328
- scheduleProfileChangedNotification(delayMs = 10): boolean {
329
- if (!this.onProfileChanged) return false;
330
- if (this.notificationTimer) clearTimeout(this.notificationTimer);
331
- this.notificationTimer = setTimeout(() => {
332
- this.notificationTimer = null;
333
- try {
334
- void Promise.resolve(this.onProfileChanged?.()).catch((err) => {
335
- console.error('[SynaBun] profile-change notifier failed:', err);
336
- });
337
- } catch (err) {
338
- console.error('[SynaBun] profile-change notifier failed:', err);
339
- }
340
- }, Math.max(0, delayMs));
341
- this.notificationTimer.unref?.();
342
- return true;
343
- }
344
-
345
- applyProfile(profileName: string): ProfileApplyResult {
346
- if (!isValidProfileSelection(profileName)) {
347
- throw new Error(`Unknown MCP profile or tool group selection: ${profileName}`);
348
- }
349
- const normalized = profileName.toLowerCase().trim();
350
- const newGroups = this.resolveGroupsForRole(normalized);
351
- const enabled: string[] = [];
352
- const disabled: string[] = [];
353
-
354
- for (const [group, tools] of this.toolGroups) {
355
- const profileEnablesGroup = newGroups.has(group);
356
- // Gated groups (role or capability) ignore the catalog mode: the deferred
357
- // Codex catalog advertises everything else up front, but never a group
358
- // the caller's role or grant does not unlock.
359
- const shouldAdvertise = isGatedGroup(group)
360
- ? profileEnablesGroup
361
- : this.catalogMode === 'deferred' || profileEnablesGroup;
362
- for (const tool of tools) {
363
- // Direct mutation bypasses RegisteredTool.enable()/disable(), each of
364
- // which emits its own notification. The caller schedules one refresh
365
- // only after the profile tool result is ready to return.
366
- if (shouldAdvertise && !tool.enabled) tool.enabled = true;
367
- if (!shouldAdvertise && tool.enabled) tool.enabled = false;
368
- }
369
- if (profileEnablesGroup && !this.activeGroups.has(group)) enabled.push(group);
370
- if (!profileEnablesGroup && this.activeGroups.has(group)) disabled.push(group);
371
- }
372
-
373
- const previousProfile = this.activeProfileName;
374
- this.activeGroups = newGroups;
375
- this.activeProfileName = normalized;
376
-
377
- let totalTools = 11;
378
- for (const [group, tools] of this.toolGroups) {
379
- const advertised = isGatedGroup(group)
380
- ? this.activeGroups.has(group)
381
- : this.catalogMode === 'deferred' || this.activeGroups.has(group);
382
- if (advertised) totalTools += tools.length;
383
- }
384
-
385
- const changed = previousProfile !== normalized || enabled.length > 0 || disabled.length > 0;
386
- if (changed) {
387
- console.error(`[SynaBun] Profile switched to "${normalized}" (${this.activeGroups.size} groups, ${totalTools} tools, +${enabled.join(',') || 'none'}, -${disabled.join(',') || 'none'})`);
388
- }
389
- return { profile: normalized, enabled, disabled, totalTools, changed, catalogMode: this.catalogMode };
390
- }
391
- }
392
-
393
- export function persistProfile(profileName: string) {
394
- const payload = JSON.stringify({ profile: profileName }, null, 2) + '\n';
395
- const paths = new Set<string>([PROFILE_PATH]);
396
-
397
- if (process.env.SYNABUN_DATA_HOME) {
398
- paths.add(join(process.env.SYNABUN_DATA_HOME, 'mcp-data', 'active-profile.json'));
399
- paths.add(join(process.env.SYNABUN_DATA_HOME, 'data', 'active-profile.json'));
400
- }
401
-
402
- for (const profilePath of paths) {
403
- writeProfileFile(profilePath, payload);
404
- }
405
- }
406
-
407
- /**
408
- * Persist only the current host-created runtime selection, when one exists.
409
- * This path is unique to an OpenCode sidepanel/loop/schedule and is removed
410
- * with that runtime. It must never fall back to PROFILE_PATH.
411
- */
412
- export function persistRuntimeProfile(profileName: string): boolean {
413
- const profilePath = process.env[RUNTIME_PROFILE_PATH_ENV];
414
- if (!profilePath || !isValidProfileSelection(profileName)) return false;
415
- return writeProfileFile(profilePath, JSON.stringify({ profile: profileName.toLowerCase().trim() }, null, 2) + '\n');
416
- }
417
-
418
- function writeProfileFile(profilePath: string, payload: string): boolean {
419
- try {
420
- const dir = dirname(profilePath);
421
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
422
- writeFileSync(profilePath, payload, 'utf-8');
423
- return true;
424
- } catch (err) {
425
- console.error(`[SynaBun] Failed to persist profile at ${profilePath}:`, err);
426
- return false;
427
- }
428
- }