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
@@ -200,10 +200,15 @@ export async function openZipArchive(path) {
200
200
  }
201
201
  }
202
202
 
203
- export async function hashZipEntry(zip, entry) {
203
+ /** SHA-256 of one entry's bytes; `onBytes(n)` hears how many went by (a progress bar). */
204
+ export async function hashZipEntry(zip, entry, { onBytes = null } = {}) {
204
205
  const digest = createHash('sha256');
205
206
  await zip.pipeEntry(entry, new Writable({
206
- write(chunk, _encoding, callback) { digest.update(chunk); callback(); },
207
+ write(chunk, _encoding, callback) {
208
+ digest.update(chunk);
209
+ if (onBytes) { try { onBytes(chunk.length); } catch { /* reporting never stops a check */ } }
210
+ callback();
211
+ },
207
212
  }));
208
213
  return digest.digest('hex');
209
214
  }
@@ -249,13 +254,13 @@ export function backupEntryName(prefix, archivePath) {
249
254
  return prefix ? `${prefix}/${archivePath}` : archivePath;
250
255
  }
251
256
 
252
- /** Stream every manifest-listed entry through sha256 and compare. */
253
- export async function verifyBackupChecksums(zip, { prefix, manifest, label = 'Backup verification failed' }) {
257
+ /** Stream every manifest-listed entry through sha256 and compare. `onBytes`: as for hashZipEntry. */
258
+ export async function verifyBackupChecksums(zip, { prefix, manifest, label = 'Backup verification failed', onBytes = null }) {
254
259
  for (const [archivePath, expected] of Object.entries(manifest.checksums || {})) {
255
260
  const entry = zip.getEntry(backupEntryName(prefix, archivePath));
256
261
  if (!entry) throw new Error(`${label}: ${archivePath} is missing`);
257
262
  let actual;
258
- try { actual = `sha256:${await hashZipEntry(zip, entry)}`; }
263
+ try { actual = `sha256:${await hashZipEntry(zip, entry, { onBytes })}`; }
259
264
  catch (error) { throw new Error(`${label}: ${archivePath} is unreadable (${error.message})`); }
260
265
  if (actual !== expected) throw new Error(`${label}: checksum mismatch for ${archivePath}`);
261
266
  }
@@ -0,0 +1,257 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { open, readFile, stat } from 'node:fs/promises';
3
+ import { crc32, deflateRawSync } from 'node:zlib';
4
+
5
+ /**
6
+ * A ZIP writer for snapshots that have to be quick at any size: the pre-update
7
+ * snapshot is written while SynaBun restarts into a new version, and its
8
+ * database can be several gigabytes.
9
+ *
10
+ * Every entry is written in one pass. Its CRC-32 (zlib's native crc32) and its
11
+ * SHA-256 come from the same bytes as they go to disk, so nothing is read again
12
+ * to checksum it. An entry marked `store` (a SQLite database, a file that is
13
+ * already compressed) goes in as it is; anything else is deflated in memory,
14
+ * which is only ever asked of small files. ZIP64 records are written whenever
15
+ * a size, an offset or the entry count needs them, in exactly the shape
16
+ * backup-zip-reader.js reads (and Info-ZIP's unzip -t accepts).
17
+ *
18
+ * The CRC of a streamed entry is unknown until its last byte, so its local
19
+ * header is written with a zero CRC and patched in place afterwards: no data
20
+ * descriptors, and the sizes in every header are the real ones.
21
+ */
22
+
23
+ const SIG_LOCAL = 0x04034b50;
24
+ const SIG_CENTRAL = 0x02014b50;
25
+ const SIG_EOCD = 0x06054b50;
26
+ const SIG_ZIP64_EOCD = 0x06064b50;
27
+ const SIG_ZIP64_LOCATOR = 0x07064b50;
28
+ const UTF8_NAMES = 0x0800;
29
+ const MAX32 = 0xffffffff;
30
+ const MAX16 = 0xffff;
31
+ const CHUNK = 4 * 1024 * 1024;
32
+ // Files above this are never deflated in memory (the writer is for snapshots, where those are databases).
33
+ export const MAX_DEFLATE_BYTES = 64 * 1024 * 1024;
34
+
35
+ /** MS-DOS date and time (local time, two-second steps), as ZIP headers carry them. */
36
+ function dosDateTime(date) {
37
+ const year = Math.min(2107, Math.max(1980, date.getFullYear()));
38
+ return {
39
+ time: (date.getHours() << 11) | (date.getMinutes() << 5) | Math.floor(date.getSeconds() / 2),
40
+ date: ((year - 1980) << 9) | ((date.getMonth() + 1) << 5) | date.getDate(),
41
+ };
42
+ }
43
+
44
+ function zip64Extra(fields) {
45
+ if (!fields.length) return Buffer.alloc(0);
46
+ const extra = Buffer.alloc(4 + fields.length * 8);
47
+ extra.writeUInt16LE(0x0001, 0);
48
+ extra.writeUInt16LE(fields.length * 8, 2);
49
+ fields.forEach((value, index) => extra.writeBigUInt64LE(BigInt(value), 4 + index * 8));
50
+ return extra;
51
+ }
52
+
53
+ /**
54
+ * Write `entries` into a new file at `path` (it must not exist).
55
+ * entries [{ name, diskPath, store }] or [{ name, data: Buffer|string, store }]; `data` may be a
56
+ * function, called when its turn comes with what was written so far ([{ name, size, crc32,
57
+ * sha256 }]): a manifest that lists the checksums of the entries before it
58
+ * onProgress({ bytes, totalBytes }) as data goes in, at most every 64 MB and at the end
59
+ * forceZip64 write ZIP64 records even when nothing needs them (tests)
60
+ * Resolves { bytes, entries: [{ name, size, crc32, sha256 }] } (sha256 in hex).
61
+ */
62
+ export async function writeZipArchive(path, entries, { onProgress = null, now = () => new Date(), forceZip64 = false } = {}) {
63
+ const report = typeof onProgress === 'function' ? onProgress : () => {};
64
+ const stamp = dosDateTime(now());
65
+ // Sizes first, so the progress has a total and a stored entry's headers carry its real size.
66
+ const planned = [];
67
+ for (const entry of entries) {
68
+ const name = String(entry?.name || '');
69
+ if (!name || name.startsWith('/') || name.includes('\\') || name.split('/').includes('..')) throw new Error(`Invalid archive entry name: ${name}`);
70
+ if (typeof entry.data === 'function') {
71
+ planned.push({ name, make: entry.data, size: 0, store: entry.store === true });
72
+ } else if (entry.data !== undefined) {
73
+ const data = Buffer.isBuffer(entry.data) ? entry.data : Buffer.from(String(entry.data), 'utf8');
74
+ planned.push({ name, data, size: data.length, store: entry.store === true });
75
+ } else {
76
+ const size = (await stat(entry.diskPath)).size;
77
+ const store = entry.store === true || size > MAX_DEFLATE_BYTES;
78
+ planned.push({ name, diskPath: entry.diskPath, size, store });
79
+ }
80
+ }
81
+ let totalBytes = planned.reduce((sum, item) => sum + item.size, 0);
82
+ let doneBytes = 0;
83
+ let reportedAt = 0;
84
+ const progress = (force = false) => {
85
+ if (force || doneBytes - reportedAt >= 64 * 1024 * 1024) {
86
+ reportedAt = doneBytes;
87
+ try { report({ bytes: doneBytes, totalBytes }); } catch { /* reporting never stops a snapshot */ }
88
+ }
89
+ };
90
+
91
+ const handle = await open(path, 'wx');
92
+ const written = [];
93
+ let offset = 0;
94
+ try {
95
+ const write = async (buffer) => {
96
+ let at = 0;
97
+ while (at < buffer.length) {
98
+ const { bytesWritten } = await handle.write(buffer, at, buffer.length - at, offset + at);
99
+ at += bytesWritten;
100
+ }
101
+ offset += buffer.length;
102
+ };
103
+
104
+ for (const item of planned) {
105
+ if (item.make) {
106
+ const made = item.make(written.map(entry => ({ name: entry.name, size: entry.size, crc32: entry.crc, sha256: entry.sha256 })));
107
+ item.data = Buffer.isBuffer(made) ? made : Buffer.from(String(made), 'utf8');
108
+ item.size = item.data.length;
109
+ totalBytes += item.size;
110
+ }
111
+ const nameBytes = Buffer.from(item.name, 'utf8');
112
+ const localOffset = offset;
113
+ let crc = 0;
114
+ const digest = createHash('sha256');
115
+ let payload = null;
116
+ if (item.data !== undefined) {
117
+ crc = crc32(item.data, 0);
118
+ digest.update(item.data);
119
+ payload = item.store ? item.data : deflateRawSync(item.data, { level: 6 });
120
+ } else if (!item.store) {
121
+ const data = await readFile(item.diskPath);
122
+ if (data.length !== item.size) throw new Error(`${item.name} changed while it was archived`);
123
+ crc = crc32(data, 0);
124
+ digest.update(data);
125
+ payload = deflateRawSync(data, { level: 6 });
126
+ }
127
+ const method = item.store ? 0 : 8;
128
+ const compressedSize = payload ? payload.length : item.size;
129
+ const zip64 = forceZip64 || item.size >= MAX32 || compressedSize >= MAX32 || localOffset >= MAX32;
130
+ const localExtra = zip64 ? zip64Extra([item.size, compressedSize]) : Buffer.alloc(0);
131
+ const header = Buffer.alloc(30);
132
+ header.writeUInt32LE(SIG_LOCAL, 0);
133
+ header.writeUInt16LE(zip64 ? 45 : method === 8 ? 20 : 10, 4);
134
+ header.writeUInt16LE(UTF8_NAMES, 6);
135
+ header.writeUInt16LE(method, 8);
136
+ header.writeUInt16LE(stamp.time, 10);
137
+ header.writeUInt16LE(stamp.date, 12);
138
+ header.writeUInt32LE(crc >>> 0, 14);
139
+ header.writeUInt32LE(zip64 ? MAX32 : compressedSize, 18);
140
+ header.writeUInt32LE(zip64 ? MAX32 : item.size, 22);
141
+ header.writeUInt16LE(nameBytes.length, 26);
142
+ header.writeUInt16LE(localExtra.length, 28);
143
+ await write(Buffer.concat([header, nameBytes, localExtra]));
144
+
145
+ if (payload) {
146
+ await write(payload);
147
+ doneBytes += item.size;
148
+ progress();
149
+ } else {
150
+ // Streamed: CRC and SHA-256 of the very bytes that go to disk, exactly `size` of them.
151
+ // Two buffers: the next chunk is being read while this one is hashed and written.
152
+ const source = await open(item.diskPath, 'r');
153
+ try {
154
+ const size = Math.min(CHUNK, Math.max(1, item.size));
155
+ const buffers = [Buffer.allocUnsafe(size), Buffer.allocUnsafe(size)];
156
+ let left = item.size;
157
+ let position = 0;
158
+ let turn = 0;
159
+ let reading = left > 0 ? source.read(buffers[0], 0, Math.min(size, left), 0) : null;
160
+ while (left > 0) {
161
+ const { bytesRead } = await reading;
162
+ if (bytesRead === 0) throw new Error(`${item.name} ended before its ${item.size} bytes (it changed while it was archived)`);
163
+ const chunk = buffers[turn].subarray(0, bytesRead);
164
+ left -= bytesRead;
165
+ position += bytesRead;
166
+ reading = left > 0 ? source.read(buffers[1 - turn], 0, Math.min(size, left), position) : null;
167
+ crc = crc32(chunk, crc);
168
+ digest.update(chunk);
169
+ await write(chunk);
170
+ turn = 1 - turn;
171
+ doneBytes += bytesRead;
172
+ progress();
173
+ }
174
+ } finally {
175
+ await source.close();
176
+ }
177
+ const crcBuffer = Buffer.alloc(4);
178
+ crcBuffer.writeUInt32LE(crc >>> 0, 0);
179
+ await handle.write(crcBuffer, 0, 4, localOffset + 14);
180
+ }
181
+ written.push({ name: item.name, nameBytes, method, crc: crc >>> 0, size: item.size, compressedSize, localOffset, zip64, sha256: digest.digest('hex') });
182
+ }
183
+
184
+ // The central directory: one record per entry, then the end records.
185
+ const directoryOffset = offset;
186
+ const records = [];
187
+ for (const entry of written) {
188
+ const overflow = [];
189
+ if (forceZip64 || entry.size >= MAX32) overflow.push(entry.size);
190
+ if (forceZip64 || entry.compressedSize >= MAX32) overflow.push(entry.compressedSize);
191
+ if (forceZip64 || entry.localOffset >= MAX32) overflow.push(entry.localOffset);
192
+ const extra = zip64Extra(overflow);
193
+ const record = Buffer.alloc(46);
194
+ record.writeUInt32LE(SIG_CENTRAL, 0);
195
+ record.writeUInt16LE((3 << 8) | 45, 4);
196
+ record.writeUInt16LE(entry.zip64 ? 45 : entry.method === 8 ? 20 : 10, 6);
197
+ record.writeUInt16LE(UTF8_NAMES, 8);
198
+ record.writeUInt16LE(entry.method, 10);
199
+ record.writeUInt16LE(stamp.time, 12);
200
+ record.writeUInt16LE(stamp.date, 14);
201
+ record.writeUInt32LE(entry.crc, 16);
202
+ record.writeUInt32LE(forceZip64 || entry.compressedSize >= MAX32 ? MAX32 : entry.compressedSize, 20);
203
+ record.writeUInt32LE(forceZip64 || entry.size >= MAX32 ? MAX32 : entry.size, 24);
204
+ record.writeUInt16LE(entry.nameBytes.length, 28);
205
+ record.writeUInt16LE(extra.length, 30);
206
+ record.writeUInt16LE(0, 32);
207
+ record.writeUInt16LE(0, 34);
208
+ record.writeUInt16LE(0, 36);
209
+ // A regular file, rw-r--r-- (unzip and ditto give it these permissions).
210
+ record.writeUInt32LE((0o100644 << 16) >>> 0, 38);
211
+ record.writeUInt32LE(forceZip64 || entry.localOffset >= MAX32 ? MAX32 : entry.localOffset, 42);
212
+ records.push(record, entry.nameBytes, extra);
213
+ }
214
+ const directory = Buffer.concat(records);
215
+ await write(directory);
216
+ const directorySize = directory.length;
217
+ const needs64 = forceZip64 || written.length >= MAX16 || directorySize >= MAX32 || directoryOffset >= MAX32;
218
+ if (needs64) {
219
+ const zip64At = offset;
220
+ const record = Buffer.alloc(56);
221
+ record.writeUInt32LE(SIG_ZIP64_EOCD, 0);
222
+ record.writeBigUInt64LE(44n, 4);
223
+ record.writeUInt16LE((3 << 8) | 45, 12);
224
+ record.writeUInt16LE(45, 14);
225
+ record.writeUInt32LE(0, 16);
226
+ record.writeUInt32LE(0, 20);
227
+ record.writeBigUInt64LE(BigInt(written.length), 24);
228
+ record.writeBigUInt64LE(BigInt(written.length), 32);
229
+ record.writeBigUInt64LE(BigInt(directorySize), 40);
230
+ record.writeBigUInt64LE(BigInt(directoryOffset), 48);
231
+ const locator = Buffer.alloc(20);
232
+ locator.writeUInt32LE(SIG_ZIP64_LOCATOR, 0);
233
+ locator.writeUInt32LE(0, 4);
234
+ locator.writeBigUInt64LE(BigInt(zip64At), 8);
235
+ locator.writeUInt32LE(1, 16);
236
+ await write(Buffer.concat([record, locator]));
237
+ }
238
+ const end = Buffer.alloc(22);
239
+ end.writeUInt32LE(SIG_EOCD, 0);
240
+ end.writeUInt16LE(0, 4);
241
+ end.writeUInt16LE(0, 6);
242
+ end.writeUInt16LE(needs64 ? MAX16 : written.length, 8);
243
+ end.writeUInt16LE(needs64 ? MAX16 : written.length, 10);
244
+ end.writeUInt32LE(needs64 ? MAX32 : directorySize, 12);
245
+ end.writeUInt32LE(needs64 ? MAX32 : directoryOffset, 16);
246
+ end.writeUInt16LE(0, 20);
247
+ await write(end);
248
+ await handle.sync();
249
+ progress(true);
250
+ } finally {
251
+ await handle.close();
252
+ }
253
+ return {
254
+ bytes: offset,
255
+ entries: written.map(entry => ({ name: entry.name, size: entry.size, crc32: entry.crc, sha256: entry.sha256 })),
256
+ };
257
+ }
@@ -19,6 +19,9 @@ export async function measureBrowserPhase(name, work) {
19
19
 
20
20
  export function assertBrowserRequestActive(req) {
21
21
  const state = req?.browserRequest || requests.getStore();
22
+ if (state?.protectionError) {
23
+ throw Object.assign(new Error(`Browser network protection unavailable: ${state.protectionError}`), { code: 'BROWSER_NETWORK_GUARD_UNAVAILABLE' });
24
+ }
22
25
  if (state && (state.signal.aborted || Date.now() >= state.deadline)) {
23
26
  const error = new Error(state.actionStarted
24
27
  ? 'Browser request expired after execution began; outcome is uncertain. Inspect the page before retrying.'
@@ -48,9 +51,13 @@ export async function runBrowserRequest(req, work, fallback = 10000) {
48
51
  let timer, abort;
49
52
  try {
50
53
  return await Promise.race([
51
- Promise.resolve().then(work),
54
+ Promise.resolve().then(() => { assertBrowserRequestActive(req); return work(); }),
52
55
  new Promise((_, reject) => {
53
- const fail = () => reject(Object.assign(new Error('Browser operation deadline exceeded; inspect state before retrying.'), { code: 'BROWSER_OPERATION_TIMEOUT' }));
56
+ const fail = () => {
57
+ if (state?.protectionError) {
58
+ try { assertBrowserRequestActive(req); } catch (error) { reject(error); }
59
+ } else reject(Object.assign(new Error('Browser operation deadline exceeded; inspect state before retrying.'), { code: 'BROWSER_OPERATION_TIMEOUT' }));
60
+ };
54
61
  timer = setTimeout(fail, Math.max(1, Math.min(fallback, state ? state.deadline - Date.now() : fallback)));
55
62
  abort = fail;
56
63
  state?.signal.addEventListener('abort', abort, { once: true });
@@ -89,6 +96,7 @@ export function browserRequestMiddleware(req, res, next) {
89
96
  const deadline = Number.isFinite(requestedDeadline) && requestedDeadline > 0
90
97
  ? Math.min(requestedDeadline, Date.now() + 120_000) : Date.now() + 120_000;
91
98
  const state = { requestId, deadline, signal: controller.signal, actionStarted: false, phases: {}, counts: {} };
99
+ state.cancelForProtection = reason => { state.protectionError = String(reason); controller.abort(); };
92
100
  req.browserRequest = state;
93
101
  res.setHeader('X-Synabun-Request-Id', requestId);
94
102
  let responseBytes = 0;
@@ -0,0 +1,83 @@
1
+ // A separate, flattened CDP transport. Browser-level Target.setAutoAttach
2
+ // requires flat sessions; Playwright's public CDPSession cannot address those
3
+ // child session IDs. Do not reach into its private connection or patch Runtime.
4
+ import { EventEmitter } from 'node:events';
5
+ import WebSocket from 'ws';
6
+
7
+ export class GuardCdpConnection extends EventEmitter {
8
+ constructor(socket) {
9
+ super();
10
+ this.socket = socket;
11
+ this.pending = new Map();
12
+ this.sequence = 0;
13
+ this.closed = false;
14
+ socket.on('message', data => {
15
+ let message;
16
+ try { message = JSON.parse(String(data)); } catch { return; }
17
+ if (message.id) {
18
+ const pending = this.pending.get(message.id);
19
+ if (!pending) return;
20
+ clearTimeout(pending.timer);
21
+ this.pending.delete(message.id);
22
+ if (message.error) pending.reject(Object.assign(new Error(`${pending.method} [session=${pending.sessionId || 'browser'}]: ${message.error.message}`), {
23
+ code: message.error.code, method: pending.method, sessionId: pending.sessionId,
24
+ protocolMessage: message.error.message,
25
+ ...(!pending.sessionId ? { targetType: 'browser', targetId: 'root' } : {}),
26
+ })); else pending.resolve(message.result);
27
+ } else this.emit('event', message);
28
+ });
29
+ socket.on('close', () => { this.closed = true; this.rejectSession(); this.emit('close'); });
30
+ socket.on('error', error => { this.rejectSession(undefined, error); });
31
+ }
32
+ send(method, params = {}, sessionId) {
33
+ if (this.closed || this.closing) return Promise.reject(new Error('Network guard CDP transport closed'));
34
+ const id = ++this.sequence;
35
+ return new Promise((resolve, reject) => {
36
+ const timer = setTimeout(() => { this.pending.delete(id); reject(new Error(`Network guard: ${method} timed out`)); }, 5000);
37
+ this.pending.set(id, { resolve, reject, timer, sessionId, method });
38
+ const failed = error => {
39
+ if (!error) return;
40
+ const pending = this.pending.get(id);
41
+ if (pending) { clearTimeout(timer); this.pending.delete(id); reject(error); }
42
+ };
43
+ try { this.socket.send(JSON.stringify({ id, method, params, ...(sessionId ? { sessionId } : {}) }), failed); }
44
+ catch (error) { failed(error); }
45
+ });
46
+ }
47
+ rejectSession(sessionId, error = new Error('Network guard target detached')) {
48
+ for (const [id, pending] of this.pending) {
49
+ if (sessionId && pending.sessionId !== sessionId) continue;
50
+ clearTimeout(pending.timer); this.pending.delete(id); pending.reject(error);
51
+ }
52
+ }
53
+ detach() {
54
+ if (this.detaching) return this.detaching;
55
+ this.closing = true;
56
+ this.rejectSession();
57
+ this.detaching = new Promise(resolve => {
58
+ if (this.closed) return resolve();
59
+ const finish = () => { clearTimeout(timer); this.socket.removeListener('close', finish); resolve(); };
60
+ // Closing our transport never closes browser targets. Await the actual
61
+ // disconnect; terminate only this socket if the peer misses its close ACK.
62
+ const timer = setTimeout(() => { this.socket.terminate?.(); finish(); }, 1000);
63
+ this.socket.once('close', finish);
64
+ try { this.socket.close(); } catch { this.socket.terminate?.(); finish(); }
65
+ });
66
+ return this.detaching;
67
+ }
68
+ }
69
+
70
+ export async function connectGuardCdp(endpoint) {
71
+ let address = endpoint;
72
+ if (!/^wss?:\/\//.test(address)) {
73
+ // The owned DevTools JSON API, not page retrieval. No cookies or profile
74
+ // configuration are read or written; use the same endpoint as Playwright.
75
+ const response = await fetch(new URL('/json/version', endpoint), { signal: AbortSignal.timeout(5000) });
76
+ if (!response.ok) throw new Error(`Network guard: DevTools endpoint answered ${response.status}`);
77
+ address = (await response.json()).webSocketDebuggerUrl;
78
+ }
79
+ if (typeof address !== 'string' || !/^wss?:\/\//.test(address)) throw new Error('Network guard: no DevTools WebSocket endpoint');
80
+ const socket = new WebSocket(address, { handshakeTimeout: 5000, maxPayload: 16 * 1024 * 1024 });
81
+ await new Promise((resolve, reject) => { socket.once('open', resolve); socket.once('error', reject); });
82
+ return new GuardCdpConnection(socket);
83
+ }