synabun 2.0.10 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +22 -0
  4. package/bin/synabun.js +71 -24
  5. package/docs/whatsapp.md +2 -2
  6. package/hooks/claude-code/pre-websearch.mjs +12 -1
  7. package/hooks/claude-code/shared.mjs +5 -0
  8. package/hooks/claude-code/stop.mjs +1 -1
  9. package/lib/claude-hooks.js +172 -18
  10. package/lib/client-config-repair.js +17 -8
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +1 -1
  13. package/lib/first-launch-protection.js +57 -12
  14. package/lib/mcp-dist.js +176 -0
  15. package/lib/release-npm-ci.mjs +138 -0
  16. package/lib/release-publish.mjs +91 -0
  17. package/lib/release-scan.mjs +50 -0
  18. package/lib/server-crash-record.js +123 -0
  19. package/lib/server-exit.js +318 -0
  20. package/lib/server-supervisor.js +508 -0
  21. package/lib/start-launcher.js +37 -4
  22. package/lib/tools-cli.js +45 -0
  23. package/lib/update-snapshot.js +228 -0
  24. package/lib/virustotal.mjs +192 -0
  25. package/lib/windows-crash-event.js +269 -0
  26. package/mcp-server/dist/http.d.ts +20 -1
  27. package/mcp-server/dist/http.d.ts.map +1 -1
  28. package/mcp-server/dist/http.js +59 -12
  29. package/mcp-server/dist/http.js.map +1 -1
  30. package/mcp-server/dist/index.d.ts +33 -27
  31. package/mcp-server/dist/index.d.ts.map +1 -1
  32. package/mcp-server/dist/index.js +128 -143
  33. package/mcp-server/dist/index.js.map +1 -1
  34. package/mcp-server/dist/preload.js +1 -1
  35. package/mcp-server/dist/preload.js.map +1 -1
  36. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  37. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  38. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  39. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  40. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  41. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  42. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  43. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  44. package/mcp-server/dist/services/neural-interface.d.ts +16 -10
  45. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  46. package/mcp-server/dist/services/neural-interface.js +67 -11
  47. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  48. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  49. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  50. package/mcp-server/dist/services/server-instructions.js +20 -62
  51. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  52. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  53. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  54. package/mcp-server/dist/services/tool-catalog.js +339 -0
  55. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  56. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  57. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  58. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  59. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  60. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  61. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  62. package/mcp-server/dist/services/tool-list.js +334 -0
  63. package/mcp-server/dist/services/tool-list.js.map +1 -0
  64. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  65. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  66. package/mcp-server/dist/services/tool-runtime.js +400 -0
  67. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  68. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  69. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  70. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  71. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  72. package/mcp-server/dist/tools/agents.d.ts +10 -10
  73. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  74. package/mcp-server/dist/tools/agents.js +22 -13
  75. package/mcp-server/dist/tools/agents.js.map +1 -1
  76. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  77. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  78. package/mcp-server/dist/tools/image-tools.js +1 -1
  79. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  80. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  81. package/mcp-server/dist/tools/skill-tools.js +639 -0
  82. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  83. package/mcp-server/dist/tools/skill.d.ts +7 -0
  84. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  85. package/mcp-server/dist/tools/skill.js +11 -0
  86. package/mcp-server/dist/tools/skill.js.map +1 -0
  87. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  88. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  89. package/mcp-server/dist/tools/tool-groups.js +147 -0
  90. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  91. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  92. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  93. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  94. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  95. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  96. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  97. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  98. package/mcp-server/package-lock.json +2 -2
  99. package/mcp-server/package.json +1 -1
  100. package/mcp-server/src/http.ts +75 -12
  101. package/mcp-server/src/index.ts +147 -154
  102. package/mcp-server/src/preload.ts +12 -12
  103. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  104. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  105. package/mcp-server/src/services/neural-interface.ts +79 -20
  106. package/mcp-server/src/services/server-instructions.ts +27 -63
  107. package/mcp-server/src/services/tool-catalog.ts +403 -0
  108. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  109. package/mcp-server/src/services/tool-list.ts +410 -0
  110. package/mcp-server/src/services/tool-runtime.ts +457 -0
  111. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  112. package/mcp-server/src/tools/agents.ts +22 -14
  113. package/mcp-server/src/tools/image-tools.ts +1 -1
  114. package/mcp-server/src/tools/skill-tools.ts +589 -0
  115. package/mcp-server/src/tools/skill.ts +13 -0
  116. package/mcp-server/src/tools/tool-groups.ts +164 -0
  117. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  118. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  119. package/neural-interface/i18n/en.json +3463 -200
  120. package/neural-interface/i18n/pt-BR.json +3411 -151
  121. package/neural-interface/lib/assistant-api.js +127 -28
  122. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  123. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  124. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  125. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  126. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  127. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  128. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  129. package/neural-interface/lib/assistant-catalog.js +6 -7
  130. package/neural-interface/lib/assistant-dispatch.js +871 -156
  131. package/neural-interface/lib/assistant-envelope.js +3 -1
  132. package/neural-interface/lib/assistant-persona.js +80 -11
  133. package/neural-interface/lib/assistant-plan-permissions.js +10 -9
  134. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  135. package/neural-interface/lib/assistant-route-gate.js +6 -4
  136. package/neural-interface/lib/assistant-router.js +13 -8
  137. package/neural-interface/lib/assistant-runtime.js +56 -18
  138. package/neural-interface/lib/assistant-task-prompt.js +78 -14
  139. package/neural-interface/lib/assistant-tools.js +51 -0
  140. package/neural-interface/lib/backup-service.js +620 -3
  141. package/neural-interface/lib/backup-zip-reader.js +10 -5
  142. package/neural-interface/lib/backup-zip-writer.js +257 -0
  143. package/neural-interface/lib/browser-execution.js +10 -2
  144. package/neural-interface/lib/browser-guard-cdp.js +83 -0
  145. package/neural-interface/lib/browser-network-guard.js +284 -0
  146. package/neural-interface/lib/browser-policy-roots.js +64 -0
  147. package/neural-interface/lib/browser-tool-policy.js +186 -31
  148. package/neural-interface/lib/claude-agent-bridge.js +4 -2
  149. package/neural-interface/lib/claude-hooks-status.js +103 -0
  150. package/neural-interface/lib/claude-temporary.js +5 -11
  151. package/neural-interface/lib/cli-install.js +18 -138
  152. package/neural-interface/lib/cli-resolver.js +4 -1
  153. package/neural-interface/lib/cli-update-planner.js +32 -31
  154. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  155. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  156. package/neural-interface/lib/codex-worker-app-server.js +172 -0
  157. package/neural-interface/lib/confined-fs.js +30 -3
  158. package/neural-interface/lib/crash-notice-api.js +98 -0
  159. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  160. package/neural-interface/lib/exec-loop-command.js +4 -8
  161. package/neural-interface/lib/http-guards.js +8 -2
  162. package/neural-interface/lib/install-details.js +4 -1
  163. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  164. package/neural-interface/lib/mcp-client-config.js +0 -29
  165. package/neural-interface/lib/mcp-external-servers.js +323 -0
  166. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  167. package/neural-interface/lib/morelogin.js +30 -0
  168. package/neural-interface/lib/native-loop-providers.js +547 -47
  169. package/neural-interface/lib/native-loop-runtime.js +268 -41
  170. package/neural-interface/lib/opencode-config.js +557 -0
  171. package/neural-interface/lib/opencode-db-schema.js +17 -34
  172. package/neural-interface/lib/opencode-history.js +48 -218
  173. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  174. package/neural-interface/lib/opencode-native-boundary.js +44 -0
  175. package/neural-interface/lib/opencode-protocol.js +249 -112
  176. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  177. package/neural-interface/lib/opencode-serve-records.js +39 -21
  178. package/neural-interface/lib/opencode-v2-client.js +48 -153
  179. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  180. package/neural-interface/lib/opencode-worker-data.js +27 -0
  181. package/neural-interface/lib/opencode2-client.js +73 -37
  182. package/neural-interface/lib/opencode2-proxy.js +23 -63
  183. package/neural-interface/lib/opencode2-translate.js +51 -2
  184. package/neural-interface/lib/owner-authority.js +249 -0
  185. package/neural-interface/lib/page-session.js +275 -0
  186. package/neural-interface/lib/peer-identity.js +763 -0
  187. package/neural-interface/lib/request-gate.js +17 -2
  188. package/neural-interface/lib/rulesets/api.js +1 -1
  189. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  190. package/neural-interface/lib/rulesets/installer.js +92 -27
  191. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  192. package/neural-interface/lib/session-cache-builder.js +17 -30
  193. package/neural-interface/lib/session-title-generator.js +58 -36
  194. package/neural-interface/lib/skills/api-v2.js +495 -0
  195. package/neural-interface/lib/skills/bundle.js +418 -0
  196. package/neural-interface/lib/skills/catalog.js +294 -0
  197. package/neural-interface/lib/skills/creation-api.js +191 -0
  198. package/neural-interface/lib/skills/creation-brief.js +247 -0
  199. package/neural-interface/lib/skills/creation-sources.js +267 -0
  200. package/neural-interface/lib/skills/creation.js +843 -0
  201. package/neural-interface/lib/skills/deploy.js +564 -0
  202. package/neural-interface/lib/skills/digest.js +119 -0
  203. package/neural-interface/lib/skills/discover.js +111 -0
  204. package/neural-interface/lib/skills/draft-confinement.js +214 -0
  205. package/neural-interface/lib/skills/eval-confinement.js +397 -0
  206. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  207. package/neural-interface/lib/skills/eval-trace.js +119 -0
  208. package/neural-interface/lib/skills/evals-api.js +212 -0
  209. package/neural-interface/lib/skills/evals.js +1573 -0
  210. package/neural-interface/lib/skills/export.js +200 -0
  211. package/neural-interface/lib/skills/frontmatter.js +64 -0
  212. package/neural-interface/lib/skills/health.js +75 -0
  213. package/neural-interface/lib/skills/json-edit.js +165 -0
  214. package/neural-interface/lib/skills/known-bridge-digests.json +387 -0
  215. package/neural-interface/lib/skills/known-bridges.js +96 -0
  216. package/neural-interface/lib/skills/library.js +823 -0
  217. package/neural-interface/lib/skills/local-store.js +21 -0
  218. package/neural-interface/lib/skills/migration.js +433 -0
  219. package/neural-interface/lib/skills/operations.js +45 -0
  220. package/neural-interface/lib/skills/ownership.js +427 -0
  221. package/neural-interface/lib/skills/packages.js +88 -0
  222. package/neural-interface/lib/skills/reviews.js +212 -0
  223. package/neural-interface/lib/skills/revision.js +80 -0
  224. package/neural-interface/lib/skills/roots.js +262 -0
  225. package/neural-interface/lib/skills/runtime-checks.js +355 -0
  226. package/neural-interface/lib/skills/scan-assets.js +252 -0
  227. package/neural-interface/lib/skills/scan-context.js +26 -0
  228. package/neural-interface/lib/skills/scan-shell.js +324 -0
  229. package/neural-interface/lib/skills/scan.js +364 -0
  230. package/neural-interface/lib/skills/scanners.js +54 -0
  231. package/neural-interface/lib/skills/service.js +522 -0
  232. package/neural-interface/lib/skills/telemetry.js +113 -0
  233. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  234. package/neural-interface/lib/tool-lists.js +124 -0
  235. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  236. package/neural-interface/lib/worker-confinement.js +1192 -0
  237. package/neural-interface/lib/worker-guard-setting.js +56 -0
  238. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  239. package/neural-interface/lib/worker-relay-ports.js +227 -0
  240. package/neural-interface/lib/worker-resume.js +229 -0
  241. package/neural-interface/lib/worker-sandbox.js +299 -0
  242. package/neural-interface/package-lock.json +18 -12
  243. package/neural-interface/package.json +2 -2
  244. package/neural-interface/public/index.html +3 -1
  245. package/neural-interface/public/index2d.html +19 -11
  246. package/neural-interface/public/onboarding.html +2 -2
  247. package/neural-interface/public/shared/account-menu.js +8 -5
  248. package/neural-interface/public/shared/agent-runtime-options.js +35 -19
  249. package/neural-interface/public/shared/api.js +1527 -1336
  250. package/neural-interface/public/shared/app-frame.js +192 -0
  251. package/neural-interface/public/shared/assistant/asst-agents-dock.js +33 -2
  252. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  253. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  254. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  255. package/neural-interface/public/shared/assistant/asst-brain-picker.js +49 -35
  256. package/neural-interface/public/shared/assistant/asst-control.js +157 -26
  257. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  258. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  259. package/neural-interface/public/shared/assistant/asst-limit-dock.js +40 -0
  260. package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -0
  261. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  262. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  263. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  264. package/neural-interface/public/shared/assistant/asst-panel.js +106 -11
  265. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  266. package/neural-interface/public/shared/assistant/asst-render.js +401 -77
  267. package/neural-interface/public/shared/assistant/asst-route.js +83 -12
  268. package/neural-interface/public/shared/assistant/asst-scenes.js +2 -0
  269. package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
  270. package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
  271. package/neural-interface/public/shared/assistant/asst-state.js +11 -15
  272. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  273. package/neural-interface/public/shared/assistant/asst-styles.js +59 -21
  274. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +156 -16
  275. package/neural-interface/public/shared/automation-context.js +5 -2
  276. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  277. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  278. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  279. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  280. package/neural-interface/public/shared/cdx/cdx-output.js +8 -7
  281. package/neural-interface/public/shared/cdx/cdx-panel.js +45 -149
  282. package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
  283. package/neural-interface/public/shared/cdx/cdx-render.js +47 -29
  284. package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
  285. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  286. package/neural-interface/public/shared/cdx/cdx-styles.js +11 -3
  287. package/neural-interface/public/shared/cdx/cdx-tabs.js +52 -39
  288. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  289. package/neural-interface/public/shared/cli-install-view.js +4 -8
  290. package/neural-interface/public/shared/cli-status.js +2 -2
  291. package/neural-interface/public/shared/constants.js +2 -2
  292. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  293. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  294. package/neural-interface/public/shared/context-menu-model.js +366 -0
  295. package/neural-interface/public/shared/context-menu.js +372 -0
  296. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  297. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  298. package/neural-interface/public/shared/desktop-update-view.js +20 -0
  299. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  300. package/neural-interface/public/shared/html-shell.js +9 -11
  301. package/neural-interface/public/shared/i18n.js +2 -0
  302. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  303. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  304. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  305. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  306. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  307. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  308. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  309. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  310. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  311. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  312. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  313. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +47 -252
  314. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  315. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  316. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +6 -21
  317. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  318. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  319. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  320. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  321. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  322. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  323. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  324. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +0 -21
  325. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  326. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +14 -47
  327. package/neural-interface/public/shared/page-session.js +96 -0
  328. package/neural-interface/public/shared/registry.js +5 -3
  329. package/neural-interface/public/shared/retired-2d.js +3 -0
  330. package/neural-interface/public/shared/schedules-view.js +195 -61
  331. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  332. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  333. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  334. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  335. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  336. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  337. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  338. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  339. package/neural-interface/public/shared/skills/ss-creation.js +219 -0
  340. package/neural-interface/public/shared/skills/ss-dialog.js +130 -0
  341. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  342. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  343. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  344. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  345. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  346. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  347. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  348. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  349. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  350. package/neural-interface/public/shared/skills/ss-lint.js +141 -0
  351. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  352. package/neural-interface/public/shared/skills/ss-profiles.js +475 -0
  353. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  354. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  355. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  356. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  357. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  358. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  359. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  360. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +236 -0
  361. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  362. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  363. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  364. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  365. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  366. package/neural-interface/public/shared/skills/studio/sx-dom.js +229 -0
  367. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  368. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  369. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  370. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  371. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  372. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  373. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +279 -0
  374. package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
  375. package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
  376. package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
  377. package/neural-interface/public/shared/skills/studio/sx-main.js +681 -0
  378. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  379. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  380. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  381. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  382. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  383. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  384. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  385. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  386. package/neural-interface/public/shared/skills/studio/sx-subject.js +248 -0
  387. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  388. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  389. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  390. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +425 -0
  391. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  392. package/neural-interface/public/shared/styles.css +1525 -1779
  393. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  394. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  395. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  396. package/neural-interface/public/shared/tool-list-view.js +112 -0
  397. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  398. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  399. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  400. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  401. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  402. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  403. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  404. package/neural-interface/public/shared/tour/tour.css +144 -0
  405. package/neural-interface/public/shared/ui-automation-studio.js +91 -128
  406. package/neural-interface/public/shared/ui-claude-panel.js +77 -5
  407. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  408. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  409. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  410. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  411. package/neural-interface/public/shared/ui-detail.js +15 -3
  412. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  413. package/neural-interface/public/shared/ui-keybinds.js +26 -1
  414. package/neural-interface/public/shared/ui-menubar.js +8 -18
  415. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  416. package/neural-interface/public/shared/ui-native-loop-router.js +7 -1
  417. package/neural-interface/public/shared/ui-navbar.js +4 -24
  418. package/neural-interface/public/shared/ui-panels.js +96 -65
  419. package/neural-interface/public/shared/ui-schedules-studio.js +507 -423
  420. package/neural-interface/public/shared/ui-sessions.js +5 -3
  421. package/neural-interface/public/shared/ui-settings.js +594 -462
  422. package/neural-interface/public/shared/ui-sidepanel-sessions.js +1 -1
  423. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  424. package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
  425. package/neural-interface/public/shared/ui-skills.js +33 -2830
  426. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  427. package/neural-interface/public/shared/ui-sync.js +15 -5
  428. package/neural-interface/public/shared/ui-terminal.js +124 -180
  429. package/neural-interface/public/shared/ui-tool-updates.js +3 -1
  430. package/neural-interface/public/shared/ui-tooltip.js +10 -5
  431. package/neural-interface/public/shared/ui-trash.js +6 -4
  432. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  433. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  434. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  435. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  436. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  437. package/neural-interface/public/shared/ui-update.js +38 -2
  438. package/neural-interface/public/shared/ui-whiteboard.js +311 -58
  439. package/neural-interface/public/shared/ui-worker-end.js +4 -0
  440. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  441. package/neural-interface/public/shared/view-variant.js +66 -0
  442. package/neural-interface/public/shared/whatsapp/wa-view.js +1 -1
  443. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  444. package/neural-interface/public/shared/worker-end.js +10 -3
  445. package/neural-interface/public/shared/worker-restart.js +12 -0
  446. package/neural-interface/public/sidepanel-session.html +1 -1
  447. package/neural-interface/public/variant/2d/background.js +2 -1
  448. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  449. package/neural-interface/public/variant/2d/graph.js +42 -20
  450. package/neural-interface/public/variant/2d/hulls.js +14 -9
  451. package/neural-interface/public/variant/2d/lasso.js +11 -7
  452. package/neural-interface/public/variant/2d/main.js +32 -1
  453. package/neural-interface/public/variant/2d/minimap.js +11 -13
  454. package/neural-interface/public/variant/3d/main.js +69 -6
  455. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  456. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  457. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  458. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  459. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  460. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  461. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  462. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  463. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  464. package/neural-interface/scripts/build-vendor.mjs +32 -0
  465. package/neural-interface/server.js +3934 -2454
  466. package/neural-interface/templates/rulesets/core.md +1 -1
  467. package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
  468. package/neural-interface/templates/rulesets/manifest.json +8 -8
  469. package/npm-shrinkwrap.json +18 -12
  470. package/package.json +16 -3
  471. package/postinstall.js +9 -4
  472. package/preuninstall.js +1 -1
  473. package/setup.js +97 -322
  474. package/skills/skill-forge/SKILL.md +177 -0
  475. package/skills/skill-forge/evals/evals.json +54 -0
  476. package/skills/skill-forge/references/package.md +105 -0
  477. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  478. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  479. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  480. package/skills/synabun/SKILL.md +10 -7
  481. package/skills/synabun/modules/audit.md +1 -5
  482. package/skills/synabun/modules/changelog.md +1 -5
  483. package/skills/synabun/modules/idea.md +1 -1
  484. package/skills/synabun/modules/memorize.md +6 -9
  485. package/skills/synabun/modules/schedule.md +4 -4
  486. package/mcp-server/dist/services/profiles.d.ts +0 -120
  487. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  488. package/mcp-server/dist/services/profiles.js +0 -387
  489. package/mcp-server/dist/services/profiles.js.map +0 -1
  490. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  491. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  492. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  493. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  494. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  495. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  496. package/mcp-server/dist/tools/leonardo.js +0 -21
  497. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  498. package/mcp-server/dist/tools/profile.d.ts +0 -17
  499. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  500. package/mcp-server/dist/tools/profile.js +0 -114
  501. package/mcp-server/dist/tools/profile.js.map +0 -1
  502. package/mcp-server/src/services/profiles.ts +0 -428
  503. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  504. package/mcp-server/src/tools/leonardo.ts +0 -30
  505. package/mcp-server/src/tools/profile.ts +0 -122
  506. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  507. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  508. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  509. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  510. package/skills/leonardo/SKILL.md +0 -168
  511. package/skills/leonardo/icon.svg +0 -1
  512. package/skills/leonardo/modules/browser-guide.md +0 -378
  513. package/skills/leonardo/modules/image-prompter.md +0 -283
  514. package/skills/leonardo/modules/model-advisor.md +0 -100
  515. package/skills/leonardo/modules/prompt-library.md +0 -110
  516. package/skills/leonardo/modules/style-guide.md +0 -186
  517. package/skills/leonardo/modules/video-prompter.md +0 -317
@@ -0,0 +1,284 @@
1
+ // Playwright context.route(), even with a narrow matcher, enables Fetch("*")
2
+ // AND disables HTTP cache on every target. Keep our safety rules on a separate
3
+ // CDP client with native, selective Fetch patterns. Never change cache, Runtime,
4
+ // identity, emulation, or page scripts here. Unmatched requests stay in Chromium.
5
+ //
6
+ // Auto-attach pauses new pages, OOPIFs and workers so
7
+ // their FIRST request is guarded too. Closing this client releases its sessions;
8
+ // it never closes a user's target or browser.
9
+ import { connectGuardCdp } from './browser-guard-cdp.js';
10
+ const guards = new WeakMap();
11
+ const endpoints = new WeakMap();
12
+ const legacyRules = new WeakMap();
13
+ const FILTER = ['page', 'iframe', 'worker', 'shared_worker', 'service_worker'].map(type => ({ type }));
14
+ const AUTO = { autoAttach: true, waitForDebuggerOnStart: true, flatten: true, filter: FILTER };
15
+ const gone = error => /closed|detached|No session|No target|Target.*not found|Session with given id not found/i.test(error?.message || '');
16
+ const expiredRequest = error => /^Fetch\.(?:continueRequest|failRequest)$/.test(error?.method || '')
17
+ && /Invalid InterceptionId|Invalid interception id/i.test(error.message);
18
+ export const NETWORK_GUARD_FAULT_EVENT = 'synabun-network-guard-fault';
19
+
20
+ /** Register only externally owned Chromium contexts with an existing endpoint. */
21
+ export function registerBrowserNetworkEndpoint(context, endpoint, { connect = connectGuardCdp } = {}) {
22
+ endpoints.set(context, { endpoint, connect });
23
+ }
24
+
25
+ export function usesNativeBrowserNetworkGuard(context) { return endpoints.has(context); }
26
+
27
+ class ContextGuard {
28
+ get fault() { return this._fault; }
29
+ set fault(error) {
30
+ if (this.disposed) return;
31
+ this._fault = error;
32
+ if (error) {
33
+ this.context.__browserNetworkGuardError = error.message;
34
+ this.context.emit?.(NETWORK_GUARD_FAULT_EVENT, error.message);
35
+ }
36
+ }
37
+ constructor(context) {
38
+ this.context = context;
39
+ this.rules = new Map();
40
+ this.children = new Map();
41
+ this.installing = new Set();
42
+ this.fault = null;
43
+ this.queue = Promise.resolve();
44
+ }
45
+ patterns() {
46
+ return [...new Set([...this.rules.values()].flatMap(rule => rule.patterns))].map(urlPattern => ({ urlPattern, requestStage: 'Request' }));
47
+ }
48
+ async configure(child) {
49
+ // Dedicated workers have no Fetch domain in Chromium. Their requests are
50
+ // intercepted by the owning page/frame (also for nested workers), as in
51
+ // Playwright's CRNetworkManager workerFrame path. Never resume a worker
52
+ // until that parent's current selective guard is installed.
53
+ if (child.target?.type === 'worker') {
54
+ if (!child.parent?.guarded || !child.parent.configuration) {
55
+ throw new Error(`Network guard worker ${child.target.targetId} has no protected network parent`);
56
+ }
57
+ await child.parent.configuration;
58
+ return;
59
+ }
60
+ const patterns = this.patterns().map(pattern => child === this.root ? { ...pattern, resourceType: 'Document' } : pattern);
61
+ await child.send(patterns.length ? 'Fetch.enable' : 'Fetch.disable', patterns.length ? { patterns } : {});
62
+ }
63
+ async ownsDocument(frameId) {
64
+ try {
65
+ const { targetInfo } = await this.root.send('Target.getTargetInfo', { targetId: frameId });
66
+ return targetInfo.browserContextId === this.contextId;
67
+ } catch (error) {
68
+ // Same-process subframes have frame IDs, but no separate Target. Find
69
+ // their owning protected page; unrelated incognito frames stay native.
70
+ if (!/No target with given id found/i.test(error.message)) throw error;
71
+ const contains = tree => tree.frame.id === frameId || tree.childFrames?.some(contains);
72
+ for (const child of this.children.values()) {
73
+ if (!child.guarded || !['page', 'iframe'].includes(child.target.type)) continue;
74
+ try {
75
+ if (contains((await child.send('Page.getFrameTree')).frameTree)) return true;
76
+ } catch (error) { if (!gone(error)) throw error; }
77
+ }
78
+ return false;
79
+ }
80
+ }
81
+ async start() {
82
+ this.onContextClose = () => { void this.dispose(); };
83
+ this.onBrowserDisconnect = () => { void this.dispose(); };
84
+ this.context.once('close', this.onContextClose);
85
+ this.context.browser().once('disconnected', this.onBrowserDisconnect);
86
+ const page = this.context.pages().find(page => !page.isClosed());
87
+ if (!page) throw new Error('Network guard requires the attachment tab');
88
+ const probe = await this.context.newCDPSession(page);
89
+ try { this.contextId = (await probe.send('Target.getTargetInfo')).targetInfo.browserContextId; }
90
+ finally { await probe.detach(); }
91
+ if (this.disposed) throw new Error('Network guard disposed during setup');
92
+ const { endpoint, connect } = endpoints.get(this.context);
93
+ this.connecting = connect(endpoint);
94
+ this.root = await this.connecting;
95
+ if (this.disposed) { await this.root.detach(); throw new Error('Network guard disposed during setup'); }
96
+ this.root.on('event', event => this.dispatch(event.sessionId ? this.children.get(event.sessionId) : this.root, event.method, event.params));
97
+ this.root.on('close', () => {
98
+ if (this.disposed) return;
99
+ this.fault = new Error('Network guard CDP disconnected; reconnect the browser session');
100
+ // Cancel pending automation and refuse subsequent actions until a fresh
101
+ // protected attachment exists. Never reinstate context.route on MoreLogin:
102
+ // it would mutate unrelated native traffic and cache even during teardown.
103
+ console.error('[browser-network-guard] CDP disconnected; browser automation disabled until reconnection');
104
+ });
105
+ // A page-target attachment can arrive after a popup's initial navigation
106
+ // has started (another CDP client may resume it). The browser Fetch domain
107
+ // closes that gap for selective Document requests only. Attribute each to
108
+ // this profile before deciding; never apply rules to a foreign context.
109
+ await this.configure(this.root);
110
+ await this.root.send('Target.setAutoAttach', AUTO);
111
+ while (this.installing.size) await Promise.all([...this.installing]);
112
+ if (this.fault) throw this.fault;
113
+ }
114
+ dispatch(parent, method, event) {
115
+ if (this.disposed) return;
116
+ if (method === 'Target.attachedToTarget') {
117
+ const child = {
118
+ id: event.sessionId, parent, target: event.targetInfo,
119
+ send: async (method, params) => {
120
+ try { return await this.root.send(method, params, event.sessionId); }
121
+ catch (error) {
122
+ Object.assign(error, { method, targetType: child.target.type, targetId: child.target.targetId,
123
+ parentTargetType: parent?.target?.type, parentTargetId: parent?.target?.targetId });
124
+ error.message = `${method} [target=${child.target.type}:${child.target.targetId}, session=${child.id}, parent=${parent?.target?.type || 'browser'}:${parent?.target?.targetId || 'root'}]: ${error.protocolMessage || error.message}`;
125
+ throw error;
126
+ }
127
+ },
128
+ close: () => this.root.rejectSession(event.sessionId),
129
+ };
130
+ this.children.set(event.sessionId, child);
131
+ const installing = this.attach(child, event).catch(error => {
132
+ if (!gone(error)) {
133
+ this.fault = error;
134
+ // Do not resume an unguarded new target. Existing user tabs are never
135
+ // closed. Future tool operations fail until a clean reconnect.
136
+ console.error('[browser-network-guard] target protection failed:', error.message);
137
+ }
138
+ }).finally(() => this.installing.delete(installing));
139
+ this.installing.add(installing);
140
+ } else if (method === 'Target.detachedFromTarget') {
141
+ this.children.get(event.sessionId)?.close();
142
+ this.children.delete(event.sessionId);
143
+ } else if (method === 'Fetch.requestPaused') {
144
+ if (!parent) return; // event queued before this target's detach arrived
145
+ void this.request(parent, event).catch(error => {
146
+ if (!gone(error)) { this.fault = error; console.error('[browser-network-guard] request refused after guard failure:', error.message); }
147
+ });
148
+ }
149
+ }
150
+ async attach(child, event) {
151
+ if (this.disposed) return;
152
+ const inherited = !event.targetInfo.browserContextId && child.parent?.guarded;
153
+ if (event.targetInfo.browserContextId !== this.contextId && !inherited) {
154
+ // A browser-level CDP connection also sees other incognito contexts.
155
+ if (event.waitingForDebugger) await child.send('Runtime.runIfWaitingForDebugger');
156
+ await child.parent.send('Target.detachFromTarget', { sessionId: child.id });
157
+ return;
158
+ }
159
+ child.guarded = true;
160
+ await (child.configuration = this.configure(child));
161
+ if (this.disposed) return;
162
+ await child.send('Target.setAutoAttach', AUTO);
163
+ await child.send('Runtime.runIfWaitingForDebugger');
164
+ }
165
+ async request(child, event) {
166
+ const { requestId, request } = event;
167
+ try {
168
+ if (this.fault) throw this.fault;
169
+ if (child === this.root && !await this.ownsDocument(event.frameId)) {
170
+ await child.send('Fetch.continueRequest', { requestId });
171
+ return;
172
+ }
173
+ let headers;
174
+ for (const rule of this.rules.values()) {
175
+ const decision = rule.decide(request);
176
+ if (decision?.abort) {
177
+ await child.send('Fetch.failRequest', { requestId, errorReason: 'BlockedByClient' });
178
+ return;
179
+ }
180
+ if (decision?.headers) headers = { ...headers, ...decision.headers };
181
+ }
182
+ const params = { requestId };
183
+ if (headers) {
184
+ const replacements = new Set(Object.keys(headers).map(name => name.toLowerCase()));
185
+ params.headers = Object.entries(request.headers).filter(([name]) => !replacements.has(name.toLowerCase()))
186
+ .concat(Object.entries(headers)).map(([name, value]) => ({ name, value: String(value) }));
187
+ }
188
+ await child.send('Fetch.continueRequest', params);
189
+ } catch (error) {
190
+ // A navigation/closed tab can retire the request before continue/fail is
191
+ // processed. These protocol replies do not invalidate other targets.
192
+ if (gone(error) || expiredRequest(error)) return;
193
+ // Never continue without a required financial/local marker decision.
194
+ await child.send('Fetch.failRequest', { requestId, errorReason: 'BlockedByClient' }).catch(() => {});
195
+ throw error;
196
+ }
197
+ }
198
+ async update(key, rule) {
199
+ if (this.disposed) throw new Error('Network guard disposed');
200
+ if (this.fault) throw this.fault;
201
+ if (rule) this.rules.set(key, rule); else this.rules.delete(key);
202
+ if (!this.ready) this.ready = this.start().catch(async error => { await this.dispose(); throw error; });
203
+ await this.ready;
204
+ await this.configure(this.root);
205
+ await Promise.all([...this.children.values()].filter(child => child.guarded).map(child =>
206
+ (child.configuration = this.configure(child)).catch(error => { if (!gone(error)) throw error; })));
207
+ }
208
+ dispose() {
209
+ if (this.disposal) return this.disposal;
210
+ this.disposed = true;
211
+ if (this.onContextClose) this.context.removeListener('close', this.onContextClose);
212
+ if (this.onBrowserDisconnect) this.context.browser().removeListener('disconnected', this.onBrowserDisconnect);
213
+ // Detaching our browser CDP session also detaches its child sessions and
214
+ // releases paused targets. No Target.closeTarget or Browser.close.
215
+ this.disposal = (async () => {
216
+ // Disposal may race a handshake. Await and detach that late connection
217
+ // as well; returning early would briefly leave a new client attached.
218
+ if (!this.root && this.connecting) this.root = await this.connecting.catch(() => null);
219
+ await this.root?.detach().catch(() => {});
220
+ for (const child of this.children.values()) child.close();
221
+ this.children.clear();
222
+ if (guards.get(this.context) === this) guards.delete(this.context);
223
+ })();
224
+ return this.disposal;
225
+ }
226
+ }
227
+
228
+ /** Explicitly release only this context's safety transport, including failed setup. */
229
+ export async function disposeBrowserNetworkGuard(context) {
230
+ await guards.get(context)?.dispose();
231
+ }
232
+
233
+ /** Add/remove a named rule. Decisions compose: an abort always wins over headers. */
234
+ export function setBrowserNetworkRule(context, key, rule) {
235
+ if (!context) return Promise.reject(new Error('Network guard needs a browser context'));
236
+ if (rule && (!rule.patterns?.length || rule.patterns.some(pattern => pattern === '*' || pattern === '*://*/*'))) {
237
+ return Promise.reject(new Error('Network guard requires selective URL patterns'));
238
+ }
239
+ // Managed browsers retain their established Playwright guards. MoreLogin is
240
+ // registered at attachment and MUST use the native transport; a failure there
241
+ // rejects setup rather than silently falling back to wildcard interception.
242
+ if (!endpoints.has(context)) return setManagedBrowserRule(context, key, rule);
243
+ let guard = guards.get(context);
244
+ if (!guard) { guard = new ContextGuard(context); guards.set(context, guard); }
245
+ const updated = guard.queue.then(() => guard.update(key, rule));
246
+ guard.queue = updated.catch(error => { guard.fault = error; });
247
+ return updated;
248
+ }
249
+
250
+ async function setManagedBrowserRule(context, key, rule) {
251
+ let entries = legacyRules.get(context);
252
+ if (!entries) { entries = new Map(); legacyRules.set(context, entries); }
253
+ const old = entries.get(key);
254
+ if (old) { await context.unroute(old); entries.delete(key); }
255
+ if (!rule) return;
256
+ const matches = url => !!rule.decide({ url: url.href });
257
+ await context.route(matches, async route => {
258
+ const decision = rule.decide({ url: route.request().url() });
259
+ if (decision?.abort) return route.abort('blockedbyclient');
260
+ if (decision?.headers) return route.fallback({ headers: { ...await route.request().allHeaders(), ...decision.headers } });
261
+ return route.fallback();
262
+ });
263
+ entries.set(key, matches);
264
+ }
265
+
266
+ // A serve may start at any time. Inspect explicit ports only, then decide using
267
+ // the CURRENT live-port set. Default-port public HTTPS never enters Fetch.
268
+ export const SERVE_PORT_PATTERNS = ['*://*:*/*'];
269
+ // Include authority spellings (trailing dot / explicit port) the exact existing
270
+ // regex already matches. The decide predicate still determines every abort.
271
+ export const MONEY_PATTERNS = ['*://*.facebook.com*/*', '*://facebook.com*/*'];
272
+
273
+ /** Native URL patterns covering isLocalMarkerHost, with the exact check in decide. */
274
+ export function localMarkerPatterns(hostNames = []) {
275
+ const hosts = ['localhost*', '*.localhost*', '127.*', '10.*', '0.*', '192.168.*', '169.254.*', '[*]'];
276
+ for (let n = 16; n <= 31; n++) hosts.push(`172.${n}.*`);
277
+ for (let n = 64; n <= 127; n++) hosts.push(`100.${n}.*`);
278
+ for (const raw of hostNames) {
279
+ const name = String(raw).toLowerCase().replace(/\.+$/, '').replace(/\.local$/, '');
280
+ // DNS names only; never turn an untrusted machine name into a wildcard.
281
+ if (/^[a-z0-9_-]+(?:\.[a-z0-9_-]+)*$/.test(name)) hosts.push(`${name}*`, `${name}.local*`);
282
+ }
283
+ return [...new Set(hosts)].flatMap(host => [`*://${host}/*`, `*://${host}:*/*`]);
284
+ }
@@ -0,0 +1,64 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — Browser policy: the projects where automated tests may run
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // The browser policy (lib/browser-tool-policy.js) lets a test runner (npm
6
+ // test, node --test, vitest, jest, npx playwright test) run browser tests from
7
+ // inside the session's own project, and from inside the `roots` its caller
8
+ // passes: the registered SynaBun projects (DATA_HOME/data/claude-code-projects.json,
9
+ // the "Registered projects" of the Assistant's routing sheet) that are code
10
+ // projects. A registered project is a code project when its folder
11
+ // - is an absolute path,
12
+ // - holds `.git` (a git work tree's root; a worktree's or a submodule's `.git`
13
+ // file counts), `package.json`, `deno.json` or `deno.jsonc` at its top,
14
+ // - is not the home folder or a folder above it, and
15
+ // - is not the Downloads folder or anything inside it (downloaded files are
16
+ // untrusted, whatever they hold).
17
+ // Read where a run starts (server.js for workers, assistant-runtime.js for the
18
+ // brain); the policy module itself reads nothing and gets the list.
19
+
20
+ import { statSync } from 'node:fs';
21
+ import { homedir } from 'node:os';
22
+ import { isAbsolute, relative, resolve } from 'node:path';
23
+
24
+ /** What at a folder's top makes it a code project. */
25
+ export const CODE_PROJECT_MARKERS = Object.freeze(['.git', 'package.json', 'deno.json', 'deno.jsonc']);
26
+
27
+ // macOS and Windows name a folder in any letter case: the exclusions compare that way.
28
+ const caseless = (path) => (process.platform === 'darwin' || process.platform === 'win32' ? path.toLowerCase() : path);
29
+ function inside(child, parent) {
30
+ const rel = relative(caseless(resolve(parent)), caseless(resolve(child)));
31
+ return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
32
+ }
33
+
34
+ /** Why `path` is not a code project the browser policy lets tests run in, else null. `stat`: tests. */
35
+ export function codeProjectRefusal(path, { home = homedir(), stat = statSync } = {}) {
36
+ const text = typeof path === 'string' ? path.trim() : '';
37
+ if (!text || !isAbsolute(text)) return 'not an absolute path';
38
+ const root = resolve(text);
39
+ if (inside(home, root)) return 'the home folder or a folder above it';
40
+ if (inside(root, resolve(home, 'Downloads'))) return 'the Downloads folder (downloaded files)';
41
+ const marked = CODE_PROJECT_MARKERS.some((name) => {
42
+ try {
43
+ const entry = stat(resolve(root, name));
44
+ return name === '.git' ? entry.isDirectory() || entry.isFile() : entry.isFile();
45
+ } catch { return false; }
46
+ });
47
+ return marked ? null : 'no .git, package.json, deno.json or deno.jsonc at its top';
48
+ }
49
+
50
+ /**
51
+ * The registered projects (claude-code-projects.json rows `{ path }` or plain
52
+ * paths) that are code projects, resolved, each once: the browser policy's
53
+ * `roots`.
54
+ */
55
+ export function browserPolicyRoots(projects, options = {}) {
56
+ const out = [];
57
+ for (const row of Array.isArray(projects) ? projects : []) {
58
+ const path = typeof row === 'string' ? row : row?.path;
59
+ if (typeof path !== 'string' || codeProjectRefusal(path, options) !== null) continue;
60
+ const root = resolve(path.trim());
61
+ if (!out.includes(root)) out.push(root);
62
+ }
63
+ return out;
64
+ }