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
@@ -0,0 +1,249 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — the one decision for the owner's routes: who may act with the owner's powers
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Many of SynaBun's routes act with the owner's own powers without asking for the page secret: they were guarded
6
+ // by the Host, the Origin and the guest rules only (lib/http-guards.js ownerRouteGuard, lib/request-gate.js). A
7
+ // page of the app passes those by being a page of the app — and so did SynaBun's automation browser, which a
8
+ // sandboxed worker drives with its sanctioned browser tools: it could open the File Explorer and write anywhere,
9
+ // save in the code editor, run git, start the tunnel, make an invite, change Settings, open a terminal tab or an
10
+ // agent panel and type into it — each a way out of the worker's sandbox. A local relay (a proxy, ssh -L, any program
11
+ // that listens and calls SynaBun) was the same way out for a worker that cannot reach SynaBun's port itself.
12
+ //
13
+ // This module is the one decision for all of them, made on what the request cannot choose: the automation
14
+ // browser's marker (lib/page-session.js) and the process at the other end of the connection (lib/peer-identity.js,
15
+ // whose verdict the peer middleware keeps on the request). It covers:
16
+ // • every request to /api that is not a GET / HEAD / OPTIONS (default-deny: a route added later is covered), but
17
+ // for FEATURE_OPEN_PREFIXES — the hooks' own routes and the feature data the agents' MCP tools write too
18
+ // (memories, cards, the whiteboard…), where a refusal would stop the owner's integrations and buy nothing;
19
+ // • the two reads that hand out a secret: GET /api/mcp-key (the whole MCP key) and GET /api/mcp/env/<name>?reveal=1;
20
+ // • the owner's own reads (OWNER_READ_PREFIXES: what a guest is refused, and git), for the peers that are never the
21
+ // owner — the code editor's and File Explorer's roots include SynaBun's data home, whose secrets the worker
22
+ // sandbox keeps from a worker; an agent's tree reads them as before;
23
+ // • the owner's sockets: a terminal, the Claude / Codex / OpenCode panels, the Assistant, the browser panel —
24
+ // and /ws/sync, which stays open (the app's pages need it to draw) but read-only.
25
+ //
26
+ // Refused, whatever the request says (headers, pins, cookies, Origin): a request with the automation browser's
27
+ // marker; a peer that is SynaBun's automation browser or any browser started for automation, a relay (named, or a
28
+ // program that listens), another SynaBun server, a remote login (sshd), or a client that left before it was
29
+ // identified. Refused too, unless it is an agent's own call: an AI agent's process tree, and SynaBun's own MCP server
30
+ // over HTTP (mcp-server/dist/http.js: it listens, so it would read as a relay; lib/peer-identity.js knows it by its
31
+ // main script inside this install, and its tools call with the stdio MCP server's pin). An agent's own call is
32
+ // one that says who it is — an agent pin (X-Synabun-Terminal / -Role / -Assistant / -Desktop-Grant) or a brain
33
+ // credential that survived the peer check — and stays on its route's rules (the MCP git tool, desktop, loop and
34
+ // browser tools; the brain; the Assistant's route gate, asked with the session's pin by the OpenCode plugin and the
35
+ // Codex hook, which checks the session's own token), as do the few routes agents call without a pin
36
+ // (AGENT_OPEN_PREFIXES: the server's stop and restart the CLI asks, the MCP server's tab release, and the loops and
37
+ // schedules the /synabun skill creates with curl).
38
+ //
39
+ // Never refused by this module: the owner's own browser and the SynaBun app (the peer lookup allows them), this
40
+ // server itself, a request from outside (the tunnel, the invite proxy: the guest rules decide those, and the
41
+ // tunnel's own process would otherwise read as a relay), and any request whose peer could not be looked up (the
42
+ // rules from before apply: a failed lookup never locks the owner out).
43
+
44
+ import { readFileSync } from 'node:fs';
45
+ import { AGENT_HEADERS, sendGuardError } from './http-guards.js';
46
+ import { BRAIN_HEADER, PEER_VERDICT } from './peer-identity.js';
47
+ import { ADMIN_ONLY_PREFIXES, routedForms } from './request-gate.js';
48
+
49
+ const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
50
+
51
+ /** Writes left open to every caller the rules before allowed: the hooks' own routes, and the feature data the
52
+ * agents' MCP tools write too. A path counts as open only when every reading of it is open. */
53
+ export const FEATURE_OPEN_PREFIXES = Object.freeze([
54
+ '/api/hook-', '/api/greeting', '/api/sessions',
55
+ '/api/memory', '/api/memories', '/api/memory-maintenance', '/api/categories', '/api/trash', '/api/search',
56
+ '/api/cards', '/api/whiteboard', '/api/images', '/api/games',
57
+ '/api/cache', '/api/fetch-markdown', '/api/last-session', '/api/health',
58
+ '/api/ui-blobs',
59
+ ]);
60
+ /** Paths under an open prefix that are not open: the code editor's copies of unsaved buffers (file content). */
61
+ export const NEVER_OPEN_PREFIXES = Object.freeze(['/api/ui-blobs/editor-backups']);
62
+ /** Routes agents call without a pin: an agent's tree may call them as it did (the other peers are still refused). */
63
+ export const AGENT_OPEN_PREFIXES = Object.freeze(['/api/server/', '/api/browser/release', '/api/loop', '/api/schedules', '/api/schedule-groups']);
64
+ /** The peers whose own calls (pinned, or on an agent-open route) keep their route's rules: an AI agent's process tree,
65
+ * and SynaBun's own MCP server over HTTP (lib/peer-identity.js isSynabunMcpServer), as the stdio one in an agent's tree. */
66
+ export const AGENT_CALL_KINDS = Object.freeze(['agent', 'synabun-mcp']);
67
+ /**
68
+ * The owner's own reads: what a guest is refused (lib/request-gate.js ADMIN_ONLY_PREFIXES — the owner's settings,
69
+ * the code editor's and the File Explorer's file contents, whose roots include SynaBun's data home with its secrets,
70
+ * the runs' transcripts, MCP and plugin configuration…) and git. Refused to the automation browser, relays, other
71
+ * SynaBun servers, remote logins and closed clients (the sandbox keeps a worker out of the data home; these reads
72
+ * would hand it over through a browser or a relay). An agent's tree reads them as before (it is not sandboxed when
73
+ * it can reach SynaBun at all, and the CLI and the MCP tools read some of them). The hooks' own routes are not here.
74
+ */
75
+ export const OWNER_READ_PREFIXES = Object.freeze([...ADMIN_ONLY_PREFIXES.filter((prefix) => prefix !== '/api/hook-'), '/api/git']);
76
+ /** The owner's sockets: a terminal, the agent panels, the Assistant, the browser panel. */
77
+ export const OWNER_SOCKET_PREFIXES = Object.freeze(['/ws/terminal/', '/ws/claude-skin', '/ws/codex-skin', '/ws/opencode-v2', '/ws/assistant/', '/ws/browser/']);
78
+ /** Sockets that stay open for the app's pages to draw, read-only for a peer the owner's powers are refused to. */
79
+ export const READ_ONLY_SOCKET_PATHS = Object.freeze(['/ws/sync']);
80
+
81
+ /** A path form under a prefix: a prefix ending in "/" or "-" is a plain prefix, any other is a whole segment. */
82
+ function under(form, prefix) {
83
+ if (prefix.endsWith('/') || prefix.endsWith('-')) return form.startsWith(prefix);
84
+ return form === prefix || form.startsWith(`${prefix}/`);
85
+ }
86
+
87
+ // ── A proxy between the owner's browser and SynaBun ──────────────────────────
88
+ // A relay is refused because it hides who asked: through a system proxy, ssh -D or a proxy extension, the owner's own
89
+ // browser reads as the relay. Browsers normally send localhost and 127.0.0.1 straight past a system proxy, so this
90
+ // takes a browser told to proxy them (an extension, a PAC file, Firefox's localhost setting) or SynaBun opened by a
91
+ // name or address the bypass list lacks. The refusal then says what to do, in the request's language (Accept-Language:
92
+ // the i18n files' `ownerAuthority` strings). A relay is never trusted instead, not even one whose parents lead back to
93
+ // the owner's browser: who its client is cannot be seen from SynaBun, and a guarded worker's sandbox keeps the system
94
+ // proxy reachable for the worker's internet, so its requests would arrive from that same relay.
95
+
96
+ /** The refusal kinds that mean "something carries this request for someone else". */
97
+ export const PROXY_REFUSAL_KINDS = Object.freeze(['relay', 'listener']);
98
+ const COPY_LOCALES = Object.freeze(['en', 'pt-BR']);
99
+ let ownerCopies = null;
100
+ /** The `ownerAuthority` strings of every locale (read once, when a refusal first needs them). */
101
+ function ownerCopy(locale) {
102
+ if (!ownerCopies) {
103
+ ownerCopies = {};
104
+ for (const code of COPY_LOCALES) {
105
+ try { ownerCopies[code] = JSON.parse(readFileSync(new URL(`../i18n/${code}.json`, import.meta.url), 'utf8'))?.ownerAuthority || {}; } catch { ownerCopies[code] = {}; }
106
+ }
107
+ }
108
+ return { ...(ownerCopies.en || {}), ...(ownerCopies[locale] || {}) };
109
+ }
110
+ /** The request's language among the i18n files' (pt-* → pt-BR), by the Accept-Language preference order; else en. */
111
+ export function requestLocale(req) {
112
+ const header = String(req?.headers?.['accept-language'] || '');
113
+ const ranked = header.split(',').map((part, index) => {
114
+ const [tag, ...params] = part.trim().split(';');
115
+ const q = Number(params.map((p) => /^\s*q=([\d.]+)\s*$/.exec(p)?.[1]).find(Boolean) ?? 1);
116
+ return { tag: tag.trim().toLowerCase(), q: Number.isFinite(q) ? q : 0, index };
117
+ }).filter((x) => x.tag && x.q > 0).sort((a, b) => b.q - a.q || a.index - b.index);
118
+ for (const { tag } of ranked) {
119
+ if (tag === 'pt' || tag.startsWith('pt-')) return 'pt-BR';
120
+ if (tag === 'en' || tag.startsWith('en-')) return 'en';
121
+ }
122
+ return 'en';
123
+ }
124
+ /** What to do when the owner's browser reaches SynaBun through a proxy (`ownerAuthority.proxyRefused`), filled in. */
125
+ export function proxyRefusalText(req, refuse) {
126
+ const template = ownerCopy(requestLocale(req)).proxyRefused;
127
+ const params = { name: String(refuse?.name || 'a proxy').slice(0, 64), pid: String(refuse?.pid ?? '?') };
128
+ if (typeof template !== 'string' || !template) return `Your browser reaches SynaBun through ${params.name} (pid ${params.pid}), a proxy or relay, so SynaBun refused this: add localhost and 127.0.0.1 to the proxy's bypass list, or turn the proxy off for SynaBun, then reload.`;
129
+ return template.replace(/\{(\w+)\}/g, (whole, key) => (params[key] != null ? params[key] : whole));
130
+ }
131
+
132
+ /** Does a request say it is an agent's own call (a pin, or a brain credential that survived the peer check)? */
133
+ export function isAgentCall(req) {
134
+ const h = req?.headers || {};
135
+ return AGENT_HEADERS.some((name) => h[name] !== undefined) || typeof h[BRAIN_HEADER] === 'string';
136
+ }
137
+
138
+ /**
139
+ * Where an HTTP request stands: `gated` (one of the owner's writes, one of the owner's reads, or a secret read), and
140
+ * `agentOpen` (an agent's tree may call it without a pin: every owner's read but the secret ones, and the
141
+ * AGENT_OPEN_PREFIXES writes). A path with no safe reading is gated.
142
+ */
143
+ export function restScope(req) {
144
+ const method = String(req?.method || 'GET').toUpperCase();
145
+ const forms = routedForms(String(req?.path ?? req?.url ?? ''));
146
+ if (!forms) return { gated: !SAFE_METHODS.has(method), agentOpen: false, reason: 'no safe reading of the path' };
147
+ if (SAFE_METHODS.has(method)) {
148
+ if (method === 'OPTIONS') return { gated: false, agentOpen: false };
149
+ const reveal = String(req?.query?.reveal || '') === '1';
150
+ if (forms.some((form) => form === '/api/mcp-key' || (reveal && form.startsWith('/api/mcp/env/')))) {
151
+ return { gated: true, agentOpen: false, reason: 'a read that hands out a secret' };
152
+ }
153
+ // (ADMIN_ONLY_PREFIXES are plain prefixes, as lib/request-gate.js reads them)
154
+ const ownerRead = forms.some((form) => OWNER_READ_PREFIXES.some((prefix) => form.startsWith(prefix)));
155
+ return { gated: ownerRead, agentOpen: true, reason: ownerRead ? 'one of the owner\'s reads' : null };
156
+ }
157
+ if (!forms.some((form) => under(form, '/api'))) return { gated: false, agentOpen: false };
158
+ const open = (form) => FEATURE_OPEN_PREFIXES.some((prefix) => under(form, prefix)) && !NEVER_OPEN_PREFIXES.some((prefix) => under(form, prefix));
159
+ if (forms.every(open)) return { gated: false, agentOpen: false };
160
+ return { gated: true, agentOpen: forms.every((form) => AGENT_OPEN_PREFIXES.some((prefix) => under(form, prefix))), reason: 'one of the owner\'s writes' };
161
+ }
162
+
163
+ /** Where a socket stands: `owner` (refused to the peers below) or `readOnly` (open, read-only for them). */
164
+ export function socketScope(pathname) {
165
+ const p = String(pathname || '');
166
+ if (OWNER_SOCKET_PREFIXES.some((prefix) => (prefix.endsWith('/') ? p.startsWith(prefix) : p === prefix))) return { owner: true, readOnly: false };
167
+ if (READ_ONLY_SOCKET_PATHS.includes(p)) return { owner: false, readOnly: true };
168
+ return { owner: false, readOnly: false };
169
+ }
170
+
171
+ /**
172
+ * The decision for one request whose peer verdict is on it (or not: then only the marker counts).
173
+ * @param {object} req
174
+ * @param {{ agentOpen?: boolean, fromWorkerBrowser?: (req) => boolean }} o
175
+ * @returns {{ code: string, error: string, hint?: string, peer?: object } | null} `hint: 'proxy'` (with the relay's
176
+ * kind, pid and name) when the peer carries requests for others: `error` then says what to do, in the request's language
177
+ */
178
+ export function ownerRefusal(req, { agentOpen = false, fromWorkerBrowser = () => false } = {}) {
179
+ let marked = false;
180
+ try { marked = !!fromWorkerBrowser(req); } catch { marked = false; }
181
+ if (marked) return { code: 'WORKER_BROWSER', error: 'SynaBun\'s automation browser cannot act as the owner: it reads SynaBun\'s pages, clicks and screenshots; the owner\'s own settings, files and actions are the owner\'s, from the owner\'s browser or the app.' };
182
+ const peer = req?.[PEER_VERDICT];
183
+ if (!peer) return null;
184
+ if (peer.status === 'gone') return { code: 'PEER_REFUSED', error: `This is the owner's, and ${peer.reason || 'the connection closed before its request was identified'}.` };
185
+ if (peer.status !== 'ok' || peer.self || !peer.refuse) return null;
186
+ if (AGENT_CALL_KINDS.includes(peer.refuse.kind) && (agentOpen || isAgentCall(req))) return null; // an agent's own call: its route's rules
187
+ if (PROXY_REFUSAL_KINDS.includes(peer.refuse.kind)) {
188
+ return { code: 'PEER_REFUSED', error: proxyRefusalText(req, peer.refuse), hint: 'proxy', peer: { kind: peer.refuse.kind, pid: peer.refuse.pid, name: peer.refuse.name } };
189
+ }
190
+ return { code: 'PEER_REFUSED', error: `This is the owner's, from the owner's own browser or the app; this request comes from ${peer.refuse.why}: pid ${peer.refuse.pid} (${peer.refuse.name}).` };
191
+ }
192
+
193
+ /**
194
+ * @param {object} o
195
+ * @param {() => ({ fromWorkerBrowser(req): boolean } | null)} [o.pageSession] the page session (read at request time)
196
+ * @param {(req) => boolean} [o.isRemote] a request from outside (the tunnel, the invite proxy): the guest rules decide
197
+ * @param {{ lookup(req): Promise<object> }} [o.peer] lib/peer-identity.js (for sockets: no middleware runs for them)
198
+ * @param {(line: string) => void} [o.log]
199
+ */
200
+ export function createOwnerAuthority({ pageSession = () => null, isRemote = () => false, peer = null, log = () => {} } = {}) {
201
+ const fromWorkerBrowser = (req) => { const s = pageSession(); return typeof s?.fromWorkerBrowser === 'function' ? s.fromWorkerBrowser(req) : false; };
202
+ const remote = (req) => { try { return isRemote(req) === true; } catch { return false; } };
203
+ const logged = new Map();
204
+ const note = (key, line) => {
205
+ const now = Date.now();
206
+ if (now - (logged.get(key) || 0) < 60_000) return;
207
+ logged.set(key, now);
208
+ if (logged.size > 500) logged.delete(logged.keys().next().value);
209
+ try { log(line); } catch { /* a logger's own failure */ }
210
+ };
211
+
212
+ /** Whether the peer middleware should look this request up (it is one of the owner's, and not from outside). */
213
+ function needsLookup(req) {
214
+ if (remote(req)) return false;
215
+ try { return restScope(req).gated; } catch { return true; }
216
+ }
217
+
218
+ /** Express middleware, mounted after the peer middleware: 403 for a refused request to one of the owner's routes
219
+ * (its writes, its reads, a secret read). */
220
+ function restGate(req, res, next) {
221
+ let scope;
222
+ try { scope = restScope(req); } catch { scope = { gated: true, agentOpen: false }; }
223
+ if (!scope.gated || remote(req)) return next();
224
+ const refused = ownerRefusal(req, { agentOpen: scope.agentOpen, fromWorkerBrowser });
225
+ if (!refused) return next();
226
+ note(`${refused.code}:${req[PEER_VERDICT]?.pid || 'marker'}:${String(req.path).slice(0, 80)}`, `[owner-authority] refused ${req.method} ${String(req.path).slice(0, 120)}: ${refused.hint === 'proxy' ? `${req[PEER_VERDICT]?.refuse?.why}: pid ${refused.peer?.pid} (${refused.peer?.name})` : refused.error}`);
227
+ if (refused.hint) return res.status(403).json({ ok: false, code: refused.code, error: refused.error, hint: refused.hint, peer: refused.peer });
228
+ return sendGuardError(res, 403, refused.code, refused.error);
229
+ }
230
+
231
+ /**
232
+ * The decision for a WebSocket upgrade (no middleware runs for one): looks the peer up for an owner socket and for
233
+ * /ws/sync. → { refuse: boolean, readOnly: boolean, code?, error? }. Never rejects; a lookup that cannot run
234
+ * refuses nothing.
235
+ */
236
+ async function checkUpgrade(req, pathname) {
237
+ const scope = socketScope(pathname);
238
+ if ((!scope.owner && !scope.readOnly) || remote(req)) return { refuse: false, readOnly: false };
239
+ if (peer && typeof peer.lookup === 'function' && !req[PEER_VERDICT]) {
240
+ try { req[PEER_VERDICT] = await peer.lookup(req); } catch { /* unknown: the rules from before */ }
241
+ }
242
+ const refused = ownerRefusal(req, { agentOpen: false, fromWorkerBrowser });
243
+ if (!refused) return { refuse: false, readOnly: false };
244
+ note(`ws:${refused.code}:${req[PEER_VERDICT]?.pid || 'marker'}:${pathname}`, `[owner-authority] ${scope.owner ? 'refused' : 'read-only'} socket ${pathname}: ${refused.error}`);
245
+ return scope.owner ? { refuse: true, readOnly: false, ...refused } : { refuse: false, readOnly: true, ...refused };
246
+ }
247
+
248
+ return { needsLookup, restGate, checkUpgrade, restScope, socketScope };
249
+ }
@@ -0,0 +1,275 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — The page secret: what tells the owner's own page from a local process
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // The owner's writes to Skills Studio (a skill creation, an install, a review decision) used to be told apart from
6
+ // an agent's by headers alone: an agent sends X-Synabun-Terminal / -Role, the page sends X-SynaBun-UI. Both are
7
+ // plain headers any local process can send or leave out, so a shell-capable worker could omit the agent headers
8
+ // and start a creation "as the owner" (the P3 review, ea44bd5f).
9
+ //
10
+ // Now the server mints one random secret per boot and hands it to the page as an HttpOnly, SameSite=Strict cookie
11
+ // on the app's own pages (and on the Studio's first read, so a page the service worker served still gets it). The
12
+ // browser sends it back by itself with every same-origin request; the page's code never sees it (HttpOnly) and
13
+ // never has to send it. An owner write without it is refused (403 PAGE_SECRET_REQUIRED / UI_ONLY). A worker never
14
+ // gets it: nothing SynaBun starts is given the cookie, it is in no environment, no file and no API answer a worker
15
+ // reads.
16
+ //
17
+ // Per boot, not per install: the secret lives in this process only (no file in the data home, so nothing a worker
18
+ // can read outside the server hands it out), and a restart makes a new one. The owner's open tab keeps the old
19
+ // cookie, so its first write after a restart is refused; the page recovers by itself (public/shared/page-session.js
20
+ // wraps the page's fetch: a 403 UI_ONLY / PAGE_SECRET_REQUIRED on a same-origin write asks GET /api/page-session,
21
+ // which sets this boot's cookie, and sends the write once more; no reload, no toast, nothing lost).
22
+ //
23
+ // Per port: the browser's cookie jar ignores ports, so every server on localhost sees every localhost cookie. The
24
+ // cookie's name carries the port (synabun_page_<port>): two SynaBun servers side by side (the app and a test
25
+ // instance, or a second checkout) each read their own and neither overwrites the other's. Other servers on
26
+ // localhost still receive it with every request a page of theirs makes, as they receive any localhost cookie: a
27
+ // local process that fetches one of the pages itself reads the Set-Cookie header the same way the browser does.
28
+ // Both are the same class of limit, stated plainly: the secret raises the bar from "leave the headers out" to
29
+ // "know this and fetch a page first"; the worker confinement (lib/worker-confinement.js) is what keeps a
30
+ // prompt-injected worker from doing that with its shell (a guarded run's shell may not call SynaBun's own port),
31
+ // and the two are meant to be used together. A browser worker that opens SynaBun's pages in the automation browser
32
+ // is told apart by the marker cookie (WORKER_BROWSER_COOKIE, set on that browser's context by server.js): its
33
+ // owner writes are refused. The marker's name carries no port on purpose: it only ever refuses, so a marker from
34
+ // one SynaBun instance refusing an owner write at another is the safe direction, and each automation browser is a
35
+ // Playwright context of its own, so no instance's marker is overwritten by another's.
36
+
37
+ //
38
+ // Owner authority by peer identity (lib/peer-identity.js): markers are told by the browser, the TCP table cannot be
39
+ // talked into anything. When the server wires a peer lookup in (`peer`), every way the secret is handed out or
40
+ // used asks it too: a request from SynaBun's automation browser, a browser started for automation, an agent's
41
+ // process tree or a relay is never handed the secret (the pages, GET /api/page-session, a Studio read's attach) and
42
+ // never counts as the owner (verify), whatever host, port, cookie or marker it carries, and a service worker there
43
+ // gets a worker that takes itself away (serviceWorker). A lookup that could not run leaves the rules above.
44
+
45
+ import { randomBytes, timingSafeEqual } from 'node:crypto';
46
+ import { isIP } from 'node:net';
47
+ import { parseCookies } from './http-guards.js';
48
+ import { ipv6Groups, mappedIPv4 } from './peer-identity.js';
49
+ import { setBrowserNetworkRule, localMarkerPatterns } from './browser-network-guard.js';
50
+
51
+ /** The cookie's name without a port (tests, hosts that pass none); with one it is pageSecretCookieName(port). */
52
+ export const PAGE_SECRET_COOKIE = 'synabun_page';
53
+ /** The page secret cookie's name for a server at `port`: synabun_page_<port>, or synabun_page without a port. */
54
+ export function pageSecretCookieName(port) {
55
+ const n = Number(port);
56
+ return Number.isInteger(n) && n > 0 ? `${PAGE_SECRET_COOKIE}_${n}` : PAGE_SECRET_COOKIE;
57
+ }
58
+ /**
59
+ * The marker SynaBun's automation browser carries for SynaBun's own origin: a worker that opens SynaBun's pages in
60
+ * that browser (visual QA of the Studio) gets the page secret cookie like any page, so its writes would pass; this
61
+ * cookie, set on the browser context itself (HttpOnly, by SynaBun, never by a page), tells those tabs apart and an
62
+ * owner write that carries it is refused. Reads, screenshots and clicks still work there.
63
+ */
64
+ export const WORKER_BROWSER_COOKIE = 'synabun_worker';
65
+ /**
66
+ * The host-proof twin of the marker cookie: a request HEADER SynaBun's browser layer adds to every request its
67
+ * automation browser makes to any local destination (markWorkerBrowserContext, via CDP request interception). The
68
+ * cookie jar is per host, so a worker that drives the automation browser to the LAN IP, the hostname or [::1]
69
+ * instead of localhost gets a fresh page-secret cookie for that host and no marker cookie — it would pass as the
70
+ * owner. The header travels with EVERY request whatever the host or port, and page JS cannot see or remove a
71
+ * header the browser adds at the network layer (and item 1 keeps raw CDP away from a guarded worker, so it cannot
72
+ * strip it there either). The server refuses the page secret and owner authority to any request carrying it.
73
+ */
74
+ export const WORKER_BROWSER_HEADER = 'x-synabun-worker';
75
+ /** Does a request carry the automation-browser marker (cookie or the host-proof header)? */
76
+ function hasWorkerMarker(req) {
77
+ if (req?.headers?.[WORKER_BROWSER_HEADER] !== undefined) return true;
78
+ const jar = parseCookies(req?.headers?.cookie);
79
+ return !!jar && jar[WORKER_BROWSER_COOKIE] !== undefined;
80
+ }
81
+ /**
82
+ * A host as one spelling: lowercase, no brackets, no trailing dot ("localhost.", "Mac."), an IPv4 address in any of
83
+ * the forms the URL parser takes (127.1, 2130706433, 0x7f.1) as its dotted quad, an IPv4-mapped IPv6 literal
84
+ * ([::ffff:127.0.0.1], [::ffff:7f00:1]) as the IPv4 address it stands for, any other IPv6 literal as its eight groups.
85
+ */
86
+ export function canonicalMarkerHost(hostname) {
87
+ let h = String(hostname ?? '').trim().toLowerCase().replace(/^\[|\]$/g, '');
88
+ while (h.endsWith('.')) h = h.slice(0, -1);
89
+ if (!h) return '';
90
+ if (h.includes(':')) {
91
+ const v4 = mappedIPv4(h);
92
+ if (v4) return v4;
93
+ const groups = ipv6Groups(h);
94
+ return groups ? groups.map((g) => g.toString(16)).join(':') : h;
95
+ }
96
+ if (/^[0-9a-fx.]+$/.test(h)) {
97
+ // A name made of digits, dots and hex: what the browser would connect to (WHATWG IPv4 parsing), if it is an address.
98
+ try { const parsed = new URL(`http://${h}/`).hostname; if (isIP(parsed) === 4) return parsed; } catch { /* not an address */ }
99
+ }
100
+ return h;
101
+ }
102
+
103
+ function isLocalIPv4(dotted) {
104
+ const [a, b] = dotted.split('.').map(Number);
105
+ return a === 127 || a === 10 || a === 0 // loopback, private, "this network"
106
+ || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168) // private
107
+ || (a === 169 && b === 254) // link-local
108
+ || (a === 100 && b >= 64 && b <= 127); // shared address space (CGNAT, a tailnet's addresses)
109
+ }
110
+
111
+ /** Loopback / private-network / link-local host — a local destination the marker header is safe to add to (never a
112
+ * public site, so the automation browser's fingerprint on real sites is unchanged). Address ranges are matched on
113
+ * address literals only (127.example.com is a name, and a public one); names match "localhost", *.localhost and this
114
+ * computer's own names (also as <name>.local), whatever their spelling. */
115
+ export function isLocalMarkerHost(hostname, extraNames = []) {
116
+ const h = canonicalMarkerHost(hostname);
117
+ if (!h) return false;
118
+ if (h === 'localhost' || h.endsWith('.localhost')) return true;
119
+ if (isIP(h) === 4) return isLocalIPv4(h);
120
+ const groups = h.includes(':') ? ipv6Groups(h) : null;
121
+ if (groups) {
122
+ if (groups.slice(0, 7).every((g) => g === 0) && groups[7] <= 1) return true; // :: and ::1
123
+ if ((groups[0] & 0xffc0) === 0xfe80 || (groups[0] & 0xfe00) === 0xfc00) return true; // link-local, unique-local
124
+ if (groups.slice(0, 6).every((g) => g === 0)) return isLocalIPv4(`${groups[6] >> 8}.${groups[6] & 255}.${groups[7] >> 8}.${groups[7] & 255}`); // ::a.b.c.d
125
+ return false;
126
+ }
127
+ return (Array.isArray(extraNames) ? extraNames : []).some((name) => {
128
+ const n = canonicalMarkerHost(name);
129
+ if (!n) return false;
130
+ const bare = n.endsWith('.local') ? n.slice(0, -'.local'.length) : n;
131
+ return h === n || h === bare || h === `${bare}.local`;
132
+ });
133
+ }
134
+ /**
135
+ * The pages the cookie is set on: the app's shells and the detached side panel's window, each the first page a
136
+ * browser window loads. The Studio's library read sets it too (server.js), as does GET /api/page-session.
137
+ */
138
+ export const PAGE_SECRET_PATHS = Object.freeze(['/', '/index.html', '/index2d.html', '/onboarding.html', '/sidepanel-session.html']);
139
+ /** The route an open tab asks for this boot's cookie after a restart (public/shared/page-session.js). */
140
+ export const PAGE_SECRET_REFRESH_PATH = '/api/page-session';
141
+ /** The app's service worker (public/sw.js): a browser that may not hold the secret gets SERVICE_WORKER_NOOP instead. */
142
+ export const SERVICE_WORKER_PATH = '/sw.js';
143
+ /**
144
+ * The service worker SynaBun's automation browser (and anything else refused the page secret) is given in place of
145
+ * public/sw.js: no fetch handler, so none of that browser's requests is answered by a worker, and it unregisters
146
+ * itself once active (an older worker it replaces goes with it).
147
+ */
148
+ export const SERVICE_WORKER_NOOP = `// SynaBun: this browser gets no service worker (it is not the owner's own browser), so every request it makes
149
+ // reaches the server as itself. This worker takes itself away.
150
+ self.addEventListener('install', () => self.skipWaiting());
151
+ self.addEventListener('activate', (event) => { event.waitUntil(self.registration.unregister().catch(() => {})); });
152
+ `;
153
+
154
+ /**
155
+ * @param {object} [o]
156
+ * @param {{ refusal(req): string|null }} [o.peer] lib/peer-identity.js: why a request's peer process may not hold or
157
+ * use the secret (null when it may, or when it could not be told)
158
+ */
159
+ export function createPageSession({ secret = null, cookieName = null, port = null, secure = false, isGuest = null, peer = null, networkRule = setBrowserNetworkRule } = {}) {
160
+ const value = typeof secret === 'string' && secret.length >= 32 ? secret : randomBytes(32).toString('hex');
161
+ const expected = Buffer.from(value);
162
+ const name = typeof cookieName === 'string' && cookieName ? cookieName : pageSecretCookieName(port);
163
+ const guest = (req) => { try { return typeof isGuest === 'function' && isGuest(req) === true; } catch { return true; } };
164
+ /** Why the peer lookup refuses this request the secret, or null (never asked, could not tell, or allowed). */
165
+ const peerRefusal = (req) => { try { return typeof peer?.refusal === 'function' ? (peer.refusal(req) || null) : null; } catch { return null; } };
166
+ /** A request that may neither be handed the secret nor use it: a marker of the automation browser, or its peer. */
167
+ const heldBack = (req) => hasWorkerMarker(req) || !!peerRefusal(req);
168
+
169
+ /** The Set-Cookie header value (HttpOnly, SameSite=Strict, the whole site). */
170
+ function cookie() {
171
+ return `${name}=${value}; Path=/; HttpOnly; SameSite=Strict${secure ? '; Secure' : ''}`;
172
+ }
173
+ /**
174
+ * Add the cookie to a response (once; a header already there is kept and this one appended). Never to a guest, a
175
+ * request with the automation browser's marker or one whose peer is refused: `req` is the response's own request
176
+ * (Express's res.req) unless given, so every caller that hands the page the secret asks the same questions.
177
+ */
178
+ function attach(res, req = res?.req) {
179
+ if (!res || typeof res.getHeader !== 'function' || typeof res.setHeader !== 'function') return;
180
+ if (req && (heldBack(req) || guest(req))) return;
181
+ const current = res.getHeader('Set-Cookie');
182
+ const list = current === undefined ? [] : Array.isArray(current) ? [...current] : [String(current)];
183
+ if (list.some((line) => String(line).startsWith(`${name}=`))) return;
184
+ list.push(cookie());
185
+ res.setHeader('Set-Cookie', list);
186
+ }
187
+ /** Whether a request carries this boot's secret cookie (nothing else asked: the cheap test for "look the peer up"). */
188
+ function carriesSecret(req) {
189
+ const jar = parseCookies(req?.headers?.cookie);
190
+ const got = jar && typeof jar[name] === 'string' ? Buffer.from(jar[name]) : null;
191
+ return !!got && got.length === expected.length && timingSafeEqual(got, expected);
192
+ }
193
+ /** Whether a request carries this boot's secret, and neither the automation browser's marker (cookie or header)
194
+ * nor a peer the lookup refuses. */
195
+ function verify(req) {
196
+ if (heldBack(req)) return false;
197
+ return carriesSecret(req);
198
+ }
199
+ /** Whether a request comes from a tab of SynaBun's automation browser (the marker cookie or the host-proof header). */
200
+ function fromWorkerBrowser(req) {
201
+ return hasWorkerMarker(req);
202
+ }
203
+ /**
204
+ * Mark a Playwright browser context as SynaBun's automation browser. Two markers, both HttpOnly / network-level so
205
+ * no page script reads or drops them, and never throws:
206
+ * • a cookie for localhost and 127.0.0.1 at the server's port (kept for compatibility and defence in depth);
207
+ * • a host-proof request header (WORKER_BROWSER_HEADER) added to every request the context makes to a LOCAL
208
+ * destination, whatever the host or port (so the LAN IP / hostname / [::1] forms are covered, which the
209
+ * per-host cookie is not). Public sites are left untouched, so the browser's fingerprint there is unchanged.
210
+ * @param {string[]} [hostNames] this machine's own names (os.hostname / scutil), for the header's local-host test.
211
+ */
212
+ async function markWorkerBrowserContext(context, { port: atPort, hostNames = [] } = {}) {
213
+ if (!context || !(Number(atPort) > 0)) return false;
214
+ if (typeof context.addCookies === 'function') {
215
+ const cookies = ['localhost', '127.0.0.1'].map((host) => ({ name: WORKER_BROWSER_COOKIE, value: '1', url: `http://${host}:${Number(atPort)}/`, httpOnly: true, sameSite: 'Lax' }));
216
+ try { await context.addCookies(cookies); } catch { /* a CDP-attached context may refuse; the header still marks it */ }
217
+ }
218
+ try {
219
+ await networkRule(context, 'worker-marker', {
220
+ patterns: localMarkerPatterns(hostNames),
221
+ decide(request) {
222
+ return isLocalMarkerHost(new URL(request.url).hostname, hostNames) ? { headers: { [WORKER_BROWSER_HEADER]: '1' } } : null;
223
+ },
224
+ });
225
+ return true;
226
+ } catch (error) {
227
+ // Cookies alone miss LAN IPs/hostnames. The caller must not silently
228
+ // navigate an unmarked browser when the host-proof header failed.
229
+ console.warn('[worker-browser] network marker unavailable:', error.message);
230
+ return false;
231
+ }
232
+ }
233
+ /** Express middleware for an owner write: 403 PAGE_SECRET_REQUIRED without the secret. */
234
+ function require(req, res, next) {
235
+ if (verify(req)) return next();
236
+ res.status(403).json({ ok: false, code: 'PAGE_SECRET_REQUIRED', error: 'This change is made from SynaBun\'s own page. Reload the page and try again.' });
237
+ }
238
+ /** Express middleware that sets the cookie on the pages it belongs to (GET only, the app's shells; never a guest's
239
+ * and never a request that carries the automation-browser marker or whose peer is refused — a marked tab, an
240
+ * automation browser, an agent or a relay must never be handed the secret). */
241
+ function pages(req, res, next) {
242
+ if ((req.method === 'GET' || req.method === 'HEAD') && PAGE_SECRET_PATHS.includes(req.path) && !guest(req) && !heldBack(req)) attach(res, req);
243
+ next();
244
+ }
245
+ /**
246
+ * GET /api/page-session: this boot's cookie for a page that is already open (its cookie is an earlier boot's
247
+ * after a restart). Answers { ok: true } with the cookie; a guest gets 403 and no cookie. A tab of SynaBun's
248
+ * automation browser (the marker cookie or the host-proof header) is refused the secret too (403 WORKER_BROWSER),
249
+ * as is a request whose peer process the lookup refuses (403 PEER_REFUSED: an automation browser, an agent's
250
+ * process tree, a relay). Never cached.
251
+ */
252
+ function refresh(req, res) {
253
+ res.setHeader('Cache-Control', 'no-store');
254
+ if (guest(req)) return res.status(403).json({ ok: false, code: 'GUEST_FORBIDDEN', error: 'Available to the owner only.' });
255
+ if (hasWorkerMarker(req)) return res.status(403).json({ ok: false, code: 'WORKER_BROWSER', error: 'SynaBun\'s automation browser does not hold the owner\'s page secret.' });
256
+ const why = peerRefusal(req);
257
+ if (why) return res.status(403).json({ ok: false, code: 'PEER_REFUSED', error: `SynaBun hands its page secret to the owner's own browser only; this request comes from ${why}.` });
258
+ attach(res, req);
259
+ res.json({ ok: true });
260
+ }
261
+ /**
262
+ * Express middleware for GET /sw.js: a browser that may not hold the secret (the automation browser's marker, or a
263
+ * refused peer) gets SERVICE_WORKER_NOOP, so no service worker answers its requests out of the server's sight;
264
+ * everyone else falls through to the real public/sw.js.
265
+ */
266
+ function serviceWorker(req, res, next) {
267
+ if ((req.method === 'GET' || req.method === 'HEAD') && req.path === SERVICE_WORKER_PATH && heldBack(req)) {
268
+ res.setHeader('Cache-Control', 'no-store');
269
+ res.setHeader('Content-Type', 'text/javascript; charset=utf-8');
270
+ return res.end(req.method === 'HEAD' ? undefined : SERVICE_WORKER_NOOP);
271
+ }
272
+ next();
273
+ }
274
+ return { cookieName: name, cookie, attach, carriesSecret, verify, require, pages, refresh, serviceWorker, fromWorkerBrowser, peerRefusal, markWorkerBrowserContext };
275
+ }