synabun 2.0.10 → 2.2.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 (656) hide show
  1. package/CHANGELOG.md +207 -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 +13 -13
  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 +30 -17
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +7 -6
  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 +302 -0
  24. package/lib/virustotal.mjs +203 -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/budget-judgments.d.ts +1 -1
  37. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
  38. package/mcp-server/dist/services/budget-judgments.js +5 -3
  39. package/mcp-server/dist/services/budget-judgments.js.map +1 -1
  40. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  41. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  42. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  43. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  44. package/mcp-server/dist/services/identity.d.ts +2 -2
  45. package/mcp-server/dist/services/identity.js +2 -2
  46. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  47. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  48. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  49. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  50. package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
  51. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
  52. package/mcp-server/dist/services/memory-sessions.js +28 -2
  53. package/mcp-server/dist/services/memory-sessions.js.map +1 -1
  54. package/mcp-server/dist/services/neural-interface.d.ts +18 -11
  55. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  56. package/mcp-server/dist/services/neural-interface.js +67 -11
  57. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  58. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  59. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  60. package/mcp-server/dist/services/server-instructions.js +22 -63
  61. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  62. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  63. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  64. package/mcp-server/dist/services/tool-catalog.js +339 -0
  65. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  66. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  67. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  68. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  69. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  70. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  71. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  72. package/mcp-server/dist/services/tool-list.js +334 -0
  73. package/mcp-server/dist/services/tool-list.js.map +1 -0
  74. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  75. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  76. package/mcp-server/dist/services/tool-runtime.js +400 -0
  77. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  78. package/mcp-server/dist/services/typesafe-config.js +1 -1
  79. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  80. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  81. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  82. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  83. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  84. package/mcp-server/dist/tools/agents.d.ts +14 -14
  85. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  86. package/mcp-server/dist/tools/agents.js +29 -19
  87. package/mcp-server/dist/tools/agents.js.map +1 -1
  88. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  89. package/mcp-server/dist/tools/choice.d.ts +6 -0
  90. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  91. package/mcp-server/dist/tools/choice.js +18 -13
  92. package/mcp-server/dist/tools/choice.js.map +1 -1
  93. package/mcp-server/dist/tools/git-tools.js +2 -2
  94. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  95. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  96. package/mcp-server/dist/tools/image-tools.js +1 -1
  97. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  98. package/mcp-server/dist/tools/morelogin.js +9 -6
  99. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  100. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  101. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  102. package/mcp-server/dist/tools/skill-tools.js +642 -0
  103. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  104. package/mcp-server/dist/tools/skill.d.ts +7 -0
  105. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  106. package/mcp-server/dist/tools/skill.js +11 -0
  107. package/mcp-server/dist/tools/skill.js.map +1 -0
  108. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  109. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  110. package/mcp-server/dist/tools/tool-groups.js +147 -0
  111. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  112. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  113. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  114. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  115. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  116. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  117. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  118. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  119. package/mcp-server/package-lock.json +2 -2
  120. package/mcp-server/package.json +1 -1
  121. package/mcp-server/src/http.ts +75 -12
  122. package/mcp-server/src/index.ts +147 -154
  123. package/mcp-server/src/preload.ts +12 -12
  124. package/mcp-server/src/services/budget-judgments.ts +5 -3
  125. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  126. package/mcp-server/src/services/identity.ts +2 -2
  127. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  128. package/mcp-server/src/services/memory-sessions.ts +24 -3
  129. package/mcp-server/src/services/neural-interface.ts +81 -21
  130. package/mcp-server/src/services/server-instructions.ts +29 -64
  131. package/mcp-server/src/services/tool-catalog.ts +403 -0
  132. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  133. package/mcp-server/src/services/tool-list.ts +410 -0
  134. package/mcp-server/src/services/tool-runtime.ts +457 -0
  135. package/mcp-server/src/services/typesafe-config.ts +1 -1
  136. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  137. package/mcp-server/src/tools/agents.ts +29 -20
  138. package/mcp-server/src/tools/choice.ts +17 -12
  139. package/mcp-server/src/tools/git-tools.ts +2 -2
  140. package/mcp-server/src/tools/image-tools.ts +1 -1
  141. package/mcp-server/src/tools/morelogin.ts +6 -4
  142. package/mcp-server/src/tools/skill-tools.ts +592 -0
  143. package/mcp-server/src/tools/skill.ts +13 -0
  144. package/mcp-server/src/tools/tool-groups.ts +164 -0
  145. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  146. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  147. package/neural-interface/i18n/en.json +3953 -228
  148. package/neural-interface/i18n/pt-BR.json +3901 -179
  149. package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
  150. package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
  151. package/neural-interface/lib/antigravity/acp-connection.js +299 -0
  152. package/neural-interface/lib/antigravity/bypass.js +100 -0
  153. package/neural-interface/lib/antigravity/catalog.js +273 -0
  154. package/neural-interface/lib/antigravity/home.js +260 -0
  155. package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
  156. package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
  157. package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
  158. package/neural-interface/lib/antigravity/policy.js +74 -0
  159. package/neural-interface/lib/antigravity/tool-call.js +178 -0
  160. package/neural-interface/lib/antigravity/transcripts.js +252 -0
  161. package/neural-interface/lib/antigravity/usage.js +43 -0
  162. package/neural-interface/lib/assistant-api.js +128 -28
  163. package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
  164. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  165. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  166. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  167. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  168. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  169. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  170. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  171. package/neural-interface/lib/assistant-budget-planner.js +7 -3
  172. package/neural-interface/lib/assistant-budget-split.js +42 -15
  173. package/neural-interface/lib/assistant-catalog.js +81 -15
  174. package/neural-interface/lib/assistant-config.js +6 -3
  175. package/neural-interface/lib/assistant-dispatch.js +1073 -200
  176. package/neural-interface/lib/assistant-envelope.js +156 -2
  177. package/neural-interface/lib/assistant-evidence.js +80 -0
  178. package/neural-interface/lib/assistant-hidden-models.js +7 -5
  179. package/neural-interface/lib/assistant-persona.js +93 -19
  180. package/neural-interface/lib/assistant-plan-permissions.js +25 -9
  181. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  182. package/neural-interface/lib/assistant-route-gate.js +6 -4
  183. package/neural-interface/lib/assistant-router.js +245 -38
  184. package/neural-interface/lib/assistant-runtime.js +214 -30
  185. package/neural-interface/lib/assistant-task-prompt.js +87 -21
  186. package/neural-interface/lib/assistant-tools.js +51 -0
  187. package/neural-interface/lib/assistant-usage.js +29 -0
  188. package/neural-interface/lib/backup-service.js +626 -4
  189. package/neural-interface/lib/backup-zip-reader.js +10 -5
  190. package/neural-interface/lib/backup-zip-writer.js +257 -0
  191. package/neural-interface/lib/browser-execution.js +10 -2
  192. package/neural-interface/lib/browser-guard-cdp.js +84 -0
  193. package/neural-interface/lib/browser-network-guard.js +476 -0
  194. package/neural-interface/lib/browser-policy-roots.js +64 -0
  195. package/neural-interface/lib/browser-tool-policy.js +198 -38
  196. package/neural-interface/lib/claude-agent-bridge.js +11 -2
  197. package/neural-interface/lib/claude-history-cache.js +210 -0
  198. package/neural-interface/lib/claude-hooks-status.js +103 -0
  199. package/neural-interface/lib/claude-model-catalog.js +5 -1
  200. package/neural-interface/lib/claude-temporary.js +5 -11
  201. package/neural-interface/lib/cli-install-api.js +1 -1
  202. package/neural-interface/lib/cli-install.js +163 -154
  203. package/neural-interface/lib/cli-resolver.js +13 -3
  204. package/neural-interface/lib/cli-update-planner.js +52 -41
  205. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  206. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  207. package/neural-interface/lib/codex-rollout-reader.js +52 -0
  208. package/neural-interface/lib/codex-worker-app-server.js +191 -0
  209. package/neural-interface/lib/confined-fs.js +30 -3
  210. package/neural-interface/lib/crash-notice-api.js +98 -0
  211. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  212. package/neural-interface/lib/editor-git-api.js +3 -20
  213. package/neural-interface/lib/exec-loop-command.js +13 -10
  214. package/neural-interface/lib/file-explorer-api.js +74 -40
  215. package/neural-interface/lib/file-explorer-watch.js +9 -3
  216. package/neural-interface/lib/git-bash/install.js +52 -6
  217. package/neural-interface/lib/git-bash/manager.js +59 -17
  218. package/neural-interface/lib/git-bash/pins.js +12 -0
  219. package/neural-interface/lib/git-read.js +2 -2
  220. package/neural-interface/lib/git-status-runner.js +390 -0
  221. package/neural-interface/lib/git-status-watchdog.js +40 -0
  222. package/neural-interface/lib/greeting/budgets.js +1 -0
  223. package/neural-interface/lib/greeting/engine.js +2 -2
  224. package/neural-interface/lib/greeting/sources.js +10 -12
  225. package/neural-interface/lib/greeting/writer.js +1 -1
  226. package/neural-interface/lib/http-guards.js +8 -2
  227. package/neural-interface/lib/install-details.js +4 -1
  228. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  229. package/neural-interface/lib/mcp-client-config.js +35 -33
  230. package/neural-interface/lib/mcp-external-servers.js +332 -0
  231. package/neural-interface/lib/mcp-installer.js +2 -1
  232. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  233. package/neural-interface/lib/memory-session-capture.js +17 -3
  234. package/neural-interface/lib/morelogin.js +177 -25
  235. package/neural-interface/lib/native-loop-providers.js +965 -66
  236. package/neural-interface/lib/native-loop-runtime.js +290 -42
  237. package/neural-interface/lib/opencode-config.js +557 -0
  238. package/neural-interface/lib/opencode-db-schema.js +17 -34
  239. package/neural-interface/lib/opencode-history.js +48 -218
  240. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  241. package/neural-interface/lib/opencode-native-boundary.js +53 -0
  242. package/neural-interface/lib/opencode-protocol.js +249 -112
  243. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  244. package/neural-interface/lib/opencode-serve-records.js +39 -21
  245. package/neural-interface/lib/opencode-v2-client.js +48 -153
  246. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  247. package/neural-interface/lib/opencode-worker-data.js +27 -0
  248. package/neural-interface/lib/opencode2-client.js +73 -37
  249. package/neural-interface/lib/opencode2-proxy.js +23 -63
  250. package/neural-interface/lib/opencode2-translate.js +51 -2
  251. package/neural-interface/lib/owner-authority.js +249 -0
  252. package/neural-interface/lib/page-session.js +275 -0
  253. package/neural-interface/lib/path-confine.js +12 -9
  254. package/neural-interface/lib/peer-identity.js +793 -0
  255. package/neural-interface/lib/pty-host/core.js +28 -1
  256. package/neural-interface/lib/pty-host/lifetime.js +12 -0
  257. package/neural-interface/lib/pty-host/manager.js +12 -1
  258. package/neural-interface/lib/remote-policy.js +1 -1
  259. package/neural-interface/lib/request-gate.js +20 -2
  260. package/neural-interface/lib/rulesets/api.js +7 -6
  261. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  262. package/neural-interface/lib/rulesets/installer.js +180 -36
  263. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  264. package/neural-interface/lib/rulesets/render.js +1 -1
  265. package/neural-interface/lib/session-cache-builder.js +81 -31
  266. package/neural-interface/lib/session-title-generator.js +58 -36
  267. package/neural-interface/lib/skills/api-v2.js +495 -0
  268. package/neural-interface/lib/skills/bundle.js +418 -0
  269. package/neural-interface/lib/skills/catalog.js +298 -0
  270. package/neural-interface/lib/skills/creation-api.js +191 -0
  271. package/neural-interface/lib/skills/creation-brief.js +247 -0
  272. package/neural-interface/lib/skills/creation-sources.js +285 -0
  273. package/neural-interface/lib/skills/creation.js +843 -0
  274. package/neural-interface/lib/skills/deploy.js +569 -0
  275. package/neural-interface/lib/skills/digest.js +119 -0
  276. package/neural-interface/lib/skills/discover.js +111 -0
  277. package/neural-interface/lib/skills/draft-confinement.js +216 -0
  278. package/neural-interface/lib/skills/eval-confinement.js +399 -0
  279. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  280. package/neural-interface/lib/skills/eval-trace.js +135 -0
  281. package/neural-interface/lib/skills/evals-api.js +212 -0
  282. package/neural-interface/lib/skills/evals.js +1573 -0
  283. package/neural-interface/lib/skills/export.js +203 -0
  284. package/neural-interface/lib/skills/frontmatter.js +64 -0
  285. package/neural-interface/lib/skills/health.js +75 -0
  286. package/neural-interface/lib/skills/json-edit.js +165 -0
  287. package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
  288. package/neural-interface/lib/skills/known-bridges.js +96 -0
  289. package/neural-interface/lib/skills/library.js +823 -0
  290. package/neural-interface/lib/skills/local-store.js +21 -0
  291. package/neural-interface/lib/skills/migration.js +433 -0
  292. package/neural-interface/lib/skills/operations.js +45 -0
  293. package/neural-interface/lib/skills/ownership.js +427 -0
  294. package/neural-interface/lib/skills/packages.js +88 -0
  295. package/neural-interface/lib/skills/reviews.js +212 -0
  296. package/neural-interface/lib/skills/revision.js +80 -0
  297. package/neural-interface/lib/skills/roots.js +269 -0
  298. package/neural-interface/lib/skills/runtime-checks.js +358 -0
  299. package/neural-interface/lib/skills/scan-assets.js +252 -0
  300. package/neural-interface/lib/skills/scan-context.js +26 -0
  301. package/neural-interface/lib/skills/scan-shell.js +324 -0
  302. package/neural-interface/lib/skills/scan.js +364 -0
  303. package/neural-interface/lib/skills/scanners.js +54 -0
  304. package/neural-interface/lib/skills/service.js +530 -0
  305. package/neural-interface/lib/skills/telemetry.js +119 -0
  306. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  307. package/neural-interface/lib/synabun-version.js +1 -1
  308. package/neural-interface/lib/system-activity.js +1 -1
  309. package/neural-interface/lib/tool-lists.js +124 -0
  310. package/neural-interface/lib/whatsapp/brain.js +7 -3
  311. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  312. package/neural-interface/lib/whatsapp/cards.js +22 -9
  313. package/neural-interface/lib/whatsapp/config.js +1 -1
  314. package/neural-interface/lib/worker-confinement.js +1268 -0
  315. package/neural-interface/lib/worker-guard-setting.js +56 -0
  316. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  317. package/neural-interface/lib/worker-question.js +74 -0
  318. package/neural-interface/lib/worker-relay-ports.js +227 -0
  319. package/neural-interface/lib/worker-resume.js +238 -0
  320. package/neural-interface/lib/worker-sandbox.js +329 -0
  321. package/neural-interface/package-lock.json +34 -12
  322. package/neural-interface/package.json +3 -2
  323. package/neural-interface/public/index.html +3 -1
  324. package/neural-interface/public/index2d.html +19 -11
  325. package/neural-interface/public/onboarding.html +3 -3
  326. package/neural-interface/public/shared/account-menu.js +8 -5
  327. package/neural-interface/public/shared/agent-runtime-options.js +125 -31
  328. package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
  329. package/neural-interface/public/shared/agy/agy-client.js +266 -0
  330. package/neural-interface/public/shared/agy/agy-commands.js +120 -0
  331. package/neural-interface/public/shared/agy/agy-copy.js +326 -0
  332. package/neural-interface/public/shared/agy/agy-diff.js +161 -0
  333. package/neural-interface/public/shared/agy/agy-events.js +469 -0
  334. package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
  335. package/neural-interface/public/shared/agy/agy-options.js +232 -0
  336. package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
  337. package/neural-interface/public/shared/agy/agy-render.js +392 -0
  338. package/neural-interface/public/shared/agy/agy-setup.js +149 -0
  339. package/neural-interface/public/shared/agy/agy-styles.js +604 -0
  340. package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
  341. package/neural-interface/public/shared/api.js +1527 -1336
  342. package/neural-interface/public/shared/app-frame.js +192 -0
  343. package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
  344. package/neural-interface/public/shared/assistant/asst-api.js +1 -1
  345. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  346. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  347. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  348. package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
  349. package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
  350. package/neural-interface/public/shared/assistant/asst-control.js +205 -26
  351. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  352. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  353. package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
  354. package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
  355. package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
  356. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  357. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  358. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  359. package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
  360. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  361. package/neural-interface/public/shared/assistant/asst-render.js +445 -82
  362. package/neural-interface/public/shared/assistant/asst-route.js +304 -53
  363. package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
  364. package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
  365. package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
  366. package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
  367. package/neural-interface/public/shared/assistant/asst-state.js +87 -24
  368. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  369. package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
  370. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
  371. package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
  372. package/neural-interface/public/shared/automation-context.js +5 -2
  373. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  374. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  375. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  376. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  377. package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
  378. package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
  379. package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
  380. package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
  381. package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
  382. package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
  383. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  384. package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
  385. package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
  386. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  387. package/neural-interface/public/shared/cli-install-controller.js +218 -0
  388. package/neural-interface/public/shared/cli-install-view.js +11 -12
  389. package/neural-interface/public/shared/cli-status.js +11 -10
  390. package/neural-interface/public/shared/constants.js +5 -4
  391. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  392. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  393. package/neural-interface/public/shared/context-menu-model.js +367 -0
  394. package/neural-interface/public/shared/context-menu.js +372 -0
  395. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  396. package/neural-interface/public/shared/cp/cp-restore.js +162 -0
  397. package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
  398. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  399. package/neural-interface/public/shared/desktop-bridge.js +17 -0
  400. package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
  401. package/neural-interface/public/shared/desktop-titlebar.js +13 -4
  402. package/neural-interface/public/shared/desktop-update-view.js +21 -0
  403. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  404. package/neural-interface/public/shared/explorer/fx-api.js +4 -4
  405. package/neural-interface/public/shared/explorer/fx-links.js +3 -3
  406. package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
  407. package/neural-interface/public/shared/explorer/fx-main.js +48 -16
  408. package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
  409. package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
  410. package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
  411. package/neural-interface/public/shared/html-shell.js +30 -15
  412. package/neural-interface/public/shared/i18n.js +2 -0
  413. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  414. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  415. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  416. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  417. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  418. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  419. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  420. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  421. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  422. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  423. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  424. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
  425. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  426. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  427. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
  428. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
  429. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  430. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  431. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  432. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  433. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  434. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  435. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  436. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
  437. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  438. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
  439. package/neural-interface/public/shared/page-session.js +96 -0
  440. package/neural-interface/public/shared/provider-icons.js +4 -2
  441. package/neural-interface/public/shared/registry.js +5 -3
  442. package/neural-interface/public/shared/retired-2d.js +3 -0
  443. package/neural-interface/public/shared/schedules-view.js +195 -61
  444. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  445. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  446. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  447. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  448. package/neural-interface/public/shared/settings/settings-rules.js +2 -2
  449. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  450. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  451. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  452. package/neural-interface/public/shared/showcase-privacy.js +6 -1
  453. package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
  454. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  455. package/neural-interface/public/shared/skills/ss-creation.js +222 -0
  456. package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
  457. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  458. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  459. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  460. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  461. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  462. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  463. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  464. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  465. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  466. package/neural-interface/public/shared/skills/ss-lint.js +149 -0
  467. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  468. package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
  469. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  470. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  471. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  472. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  473. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  474. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  475. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  476. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
  477. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  478. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  479. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  480. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  481. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  482. package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
  483. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  484. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  485. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  486. package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
  487. package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
  488. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  489. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  490. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  491. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
  492. package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
  493. package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
  494. package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
  495. package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
  496. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  497. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  498. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  499. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  500. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  501. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  502. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  503. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  504. package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
  505. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  506. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  507. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  508. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
  509. package/neural-interface/public/shared/state.js +1 -1
  510. package/neural-interface/public/shared/streaming-markdown.js +58 -0
  511. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  512. package/neural-interface/public/shared/styles.css +1822 -1756
  513. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  514. package/neural-interface/public/shared/text-cache.js +29 -0
  515. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  516. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  517. package/neural-interface/public/shared/tool-list-view.js +112 -0
  518. package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
  519. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  520. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  521. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  522. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  523. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  524. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  525. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  526. package/neural-interface/public/shared/tour/tour.css +144 -0
  527. package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
  528. package/neural-interface/public/shared/ui-assistant.js +2 -0
  529. package/neural-interface/public/shared/ui-automation-studio.js +111 -140
  530. package/neural-interface/public/shared/ui-claude-panel.js +376 -82
  531. package/neural-interface/public/shared/ui-cli-banner.js +23 -167
  532. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  533. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  534. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  535. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  536. package/neural-interface/public/shared/ui-detail.js +15 -3
  537. package/neural-interface/public/shared/ui-file-explorer.js +48 -6
  538. package/neural-interface/public/shared/ui-file-links.js +2 -2
  539. package/neural-interface/public/shared/ui-games.js +2 -2
  540. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  541. package/neural-interface/public/shared/ui-judgments.js +1 -1
  542. package/neural-interface/public/shared/ui-keybinds.js +33 -2
  543. package/neural-interface/public/shared/ui-link.js +3 -3
  544. package/neural-interface/public/shared/ui-menubar.js +10 -20
  545. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  546. package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
  547. package/neural-interface/public/shared/ui-navbar.js +49 -24
  548. package/neural-interface/public/shared/ui-notifications.js +1 -0
  549. package/neural-interface/public/shared/ui-panels.js +96 -65
  550. package/neural-interface/public/shared/ui-resume.js +9 -7
  551. package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
  552. package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
  553. package/neural-interface/public/shared/ui-sessions.js +27 -15
  554. package/neural-interface/public/shared/ui-settings.js +683 -526
  555. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
  556. package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
  557. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  558. package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
  559. package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
  560. package/neural-interface/public/shared/ui-skills.js +33 -2830
  561. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  562. package/neural-interface/public/shared/ui-sync.js +15 -5
  563. package/neural-interface/public/shared/ui-terminal.js +270 -190
  564. package/neural-interface/public/shared/ui-tool-updates.js +6 -4
  565. package/neural-interface/public/shared/ui-tooltip.js +81 -51
  566. package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
  567. package/neural-interface/public/shared/ui-trash.js +6 -4
  568. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  569. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  570. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  571. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  572. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  573. package/neural-interface/public/shared/ui-update.js +38 -2
  574. package/neural-interface/public/shared/ui-whiteboard.js +312 -59
  575. package/neural-interface/public/shared/ui-worker-end.js +5 -1
  576. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  577. package/neural-interface/public/shared/view-variant.js +66 -0
  578. package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
  579. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  580. package/neural-interface/public/shared/worker-end.js +10 -3
  581. package/neural-interface/public/shared/worker-questions.js +34 -0
  582. package/neural-interface/public/shared/worker-restart.js +12 -0
  583. package/neural-interface/public/sidepanel-session.html +2 -2
  584. package/neural-interface/public/variant/2d/background.js +2 -1
  585. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  586. package/neural-interface/public/variant/2d/graph.js +42 -20
  587. package/neural-interface/public/variant/2d/hulls.js +14 -9
  588. package/neural-interface/public/variant/2d/lasso.js +11 -7
  589. package/neural-interface/public/variant/2d/main.js +32 -1
  590. package/neural-interface/public/variant/2d/minimap.js +11 -13
  591. package/neural-interface/public/variant/3d/main.js +69 -6
  592. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  593. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  594. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  595. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  596. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  597. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  598. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  599. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  600. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  601. package/neural-interface/scripts/build-vendor.mjs +32 -0
  602. package/neural-interface/server.js +4553 -2855
  603. package/neural-interface/templates/rulesets/README.md +1 -1
  604. package/neural-interface/templates/rulesets/core.md +1 -1
  605. package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
  606. package/neural-interface/templates/rulesets/manifest.json +8 -8
  607. package/npm-shrinkwrap.json +34 -12
  608. package/package.json +17 -3
  609. package/postinstall.js +9 -4
  610. package/preuninstall.js +1 -1
  611. package/setup.js +97 -322
  612. package/skills/skill-forge/SKILL.md +177 -0
  613. package/skills/skill-forge/evals/evals.json +54 -0
  614. package/skills/skill-forge/references/package.md +105 -0
  615. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  616. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  617. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  618. package/skills/synabun/SKILL.md +10 -7
  619. package/skills/synabun/modules/audit.md +1 -5
  620. package/skills/synabun/modules/changelog.md +1 -5
  621. package/skills/synabun/modules/idea.md +1 -1
  622. package/skills/synabun/modules/memorize.md +6 -9
  623. package/skills/synabun/modules/schedule.md +6 -6
  624. package/mcp-server/dist/services/profiles.d.ts +0 -120
  625. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  626. package/mcp-server/dist/services/profiles.js +0 -387
  627. package/mcp-server/dist/services/profiles.js.map +0 -1
  628. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  629. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  630. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  631. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  632. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  633. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  634. package/mcp-server/dist/tools/leonardo.js +0 -21
  635. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  636. package/mcp-server/dist/tools/profile.d.ts +0 -17
  637. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  638. package/mcp-server/dist/tools/profile.js +0 -114
  639. package/mcp-server/dist/tools/profile.js.map +0 -1
  640. package/mcp-server/src/services/profiles.ts +0 -428
  641. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  642. package/mcp-server/src/tools/leonardo.ts +0 -30
  643. package/mcp-server/src/tools/profile.ts +0 -122
  644. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  645. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  646. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  647. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  648. package/skills/leonardo/SKILL.md +0 -168
  649. package/skills/leonardo/icon.svg +0 -1
  650. package/skills/leonardo/modules/browser-guide.md +0 -378
  651. package/skills/leonardo/modules/image-prompter.md +0 -283
  652. package/skills/leonardo/modules/model-advisor.md +0 -100
  653. package/skills/leonardo/modules/prompt-library.md +0 -110
  654. package/skills/leonardo/modules/style-guide.md +0 -186
  655. package/skills/leonardo/modules/video-prompter.md +0 -317
  656. /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
@@ -1,37 +1,34 @@
1
1
  // ─────────────────────────────────────────────────────────────────────────────
2
- // OpenCode 2 — the raw OpenCode 1 requests SynaBun makes, answered on OpenCode 2.
2
+ // The raw requests SynaBun makes to a serve, answered through OpenCode 2's API.
3
3
  //
4
- // Besides the SDK, server.js and the panel's request module call a serve over
5
- // plain HTTP (`ocpProxy(method, path, body)`): /provider, /agent, /question,
6
- // /config, /mcp, DELETE /session/:id, … Those are OpenCode 1 paths. On an
7
- // OpenCode 2 serve every one of them would land on the web app (an HTML page,
8
- // status 200), so ocpProxy hands them here instead: each known path is
9
- // answered through the OpenCode 2 client (lib/opencode2-client.js), in the
10
- // shape OpenCode 1 gave, as `{ status, data }`. A path under /api/ is the same
11
- // family of routes on both majors (OpenCode 1.18's own /api/* surface became
12
- // OpenCode 2's API) and goes through with the serve's password. Anything else
13
- // gets a clear 501 instead of a web page.
4
+ // Besides the client's methods, server.js and the panel's request module call
5
+ // a serve by path (`ocpProxy(method, path, body)`): the provider and agent
6
+ // lists, a session's deletion, the pending questions and a question's answer,
7
+ // the MCP resources, and OpenCode 2's own /api/* routes. Those paths are the
8
+ // ones SynaBun has always named (OpenCode 1's); every one of them would land
9
+ // on OpenCode 2's web app (an HTML page, status 200), so each is answered here
10
+ // through the OpenCode 2 client (lib/opencode2-client.js), in the shapes
11
+ // SynaBun reads, as `{ status, data }`. A path under /api/ goes through with
12
+ // the serve's password. Anything else gets a clear 501 instead of a web page.
14
13
  // ─────────────────────────────────────────────────────────────────────────────
15
14
 
16
15
  const json = (status, data) => ({ status, data });
17
16
 
18
17
  function asProxyResult(result, okStatus = 200) {
19
- if (!result) return json(500, { error: 'OpenCode 2 gave no answer' });
18
+ if (!result) return json(500, { error: 'OpenCode gave no answer' });
20
19
  if (result.error) {
21
20
  const status = Number(result.response?.status) || 500;
22
21
  const error = result.error;
23
- const message = typeof error === 'string' ? error : (error?.message || error?.data?.message || 'OpenCode 2 request failed');
22
+ const message = typeof error === 'string' ? error : (error?.message || error?.data?.message || 'OpenCode request failed');
24
23
  return json(status >= 400 ? status : 500, { error: message, ...(error && typeof error === 'object' ? { name: error._tag || error.name || undefined } : {}) });
25
24
  }
26
25
  return json(okStatus, result.data === undefined ? true : result.data);
27
26
  }
28
27
 
29
- const notOnV2 = (what) => json(501, { error: `${what} is not available on OpenCode 2 from SynaBun yet. Use the OpenCode 2 app or CLI for it.` });
30
-
31
28
  /**
32
- * Answer one raw OpenCode 1 request on an OpenCode 2 serve. `client` is an
33
- * OpenCode 2 client (createOpencode2Client), `rawFetch(path, init)` sends a
34
- * request under /api/ with the serve's password (the pass-through).
29
+ * Answer one raw request on a serve. `client` is an OpenCode 2 client
30
+ * (createOpencode2Client), `rawFetch(path, init)` sends a request under /api/
31
+ * with the serve's password (the pass-through).
35
32
  */
36
33
  export async function opencode2Proxy(client, method, path, body = null, { rawFetch = null } = {}) {
37
34
  const url = new URL(path, 'http://opencode.invalid');
@@ -45,37 +42,17 @@ export async function opencode2Proxy(client, method, path, body = null, { rawFet
45
42
  return rawFetch(`${route}${url.search}`, { method: verb, body });
46
43
  }
47
44
 
48
- // ── The serve itself ──
49
- if (route === '/global/health' && verb === 'GET') return asProxyResult(await client.global.health());
50
- // OpenCode 2 has no "dispose": its instances end with the process, which
51
- // SynaBun stops right after asking.
52
- if (route === '/global/dispose' && verb === 'POST') return json(200, true);
53
-
54
- // ── Providers, agents, config ──
45
+ // ── Providers, agents ──
55
46
  if (route === '/provider' && verb === 'GET') return asProxyResult(await client.provider.list({ directory }));
56
- if (route === '/provider/auth' && verb === 'GET') return json(200, {});
57
- if (segments[0] === 'provider' && segments[2] === 'oauth') return notOnV2('Signing in to a provider');
58
- if (segments[0] === 'auth' && segments.length === 2) return notOnV2('Saving provider credentials');
59
47
  if (route === '/config/providers' && verb === 'GET') return asProxyResult(await client.config.providers({ directory }));
60
- if (route === '/config' && verb === 'GET') return asProxyResult(await client.config.get({ directory }));
61
- if (route === '/config' && verb === 'PATCH') return notOnV2('Changing the running OpenCode config');
62
48
  if (route === '/agent' && verb === 'GET') return asProxyResult(await client.app.agents({ directory }));
63
- if (route === '/command' && verb === 'GET') return asProxyResult(await client.command.list({ directory }));
64
- if (route === '/experimental/tool/ids' && verb === 'GET') return json(200, []);
65
49
 
66
- // ── MCP ──
67
- if (route === '/mcp' && verb === 'GET') return asProxyResult(await client.mcp.status({ directory }));
68
- if (route === '/mcp' && verb === 'POST') return asProxyResult(await client.mcp.add({ name: body?.name, config: body?.config, directory }));
69
- if (segments[0] === 'mcp' && segments.length === 3 && verb === 'POST') {
70
- if (segments[2] === 'connect') return asProxyResult(await client.mcp.connect({ name: segments[1], directory }));
71
- if (segments[2] === 'disconnect') return asProxyResult(await client.mcp.disconnect({ name: segments[1], directory }));
72
- }
73
- if (segments[0] === 'mcp' && segments[2] === 'auth') return notOnV2('Signing in to an MCP server');
50
+ // ── MCP resources ──
74
51
  if (route === '/experimental/resource' && verb === 'GET' && typeof rawFetch === 'function') {
75
52
  const located = directory ? `?location%5Bdirectory%5D=${encodeURIComponent(directory)}` : '';
76
53
  const listed = await rawFetch(`/api/mcp/resource${located}`, { method: 'GET' });
77
54
  if (listed.status !== 200) return listed;
78
- // OpenCode 1: { "<server>:<uri>": { name, uri, client, … } }
55
+ // { "<server>:<uri>": { name, uri, client, … } }
79
56
  const out = {};
80
57
  for (const resource of Array.isArray(listed.data?.data?.resources) ? listed.data.data.resources : []) {
81
58
  if (!resource?.uri) continue;
@@ -86,31 +63,14 @@ export async function opencode2Proxy(client, method, path, body = null, { rawFet
86
63
 
87
64
  // ── Questions ──
88
65
  if (route === '/question' && verb === 'GET') return asProxyResult(await client.question.list({ directory }));
89
- if (segments[0] === 'question' && segments.length === 3 && verb === 'POST') {
90
- if (segments[2] === 'reply') return asProxyResult(await client.question.reply({ requestID: segments[1], answers: body?.answers, directory }));
91
- if (segments[2] === 'reject') return asProxyResult(await client.question.reject({ requestID: segments[1], directory }));
92
- }
93
-
94
- // ── Permissions ──
95
- if (route === '/permission' && verb === 'GET') return asProxyResult(await client.permission.list({ directory }));
96
- if (segments[0] === 'permission' && segments.length === 3 && segments[2] === 'reply' && verb === 'POST') {
97
- return asProxyResult(await client.permission.reply({ requestID: segments[1], reply: body?.reply, message: body?.message, directory }));
66
+ if (segments[0] === 'question' && segments.length === 3 && segments[2] === 'reply' && verb === 'POST') {
67
+ return asProxyResult(await client.question.reply({ requestID: segments[1], answers: body?.answers, directory }));
98
68
  }
99
69
 
100
70
  // ── Sessions ──
101
- if (route === '/session' && verb === 'GET') return asProxyResult(await client.session.list({ directory }));
102
- if (segments[0] === 'session' && segments.length === 2) {
103
- const sessionID = segments[1];
104
- if (verb === 'GET') return asProxyResult(await client.session.get({ sessionID }));
105
- if (verb === 'DELETE') return asProxyResult(await client.session.delete({ sessionID }));
106
- if (verb === 'PATCH') return asProxyResult(await client.session.update({ sessionID, ...(body || {}) }));
107
- }
108
- if (segments[0] === 'session' && segments.length === 3 && verb === 'POST' && segments[2] === 'abort') {
109
- return asProxyResult(await client.session.abort({ sessionID: segments[1] }));
110
- }
111
- if (segments[0] === 'session' && segments.length === 3 && verb === 'GET' && segments[2] === 'message') {
112
- return asProxyResult(await client.session.messages({ sessionID: segments[1], directory }));
71
+ if (segments[0] === 'session' && segments.length === 2 && verb === 'DELETE') {
72
+ return asProxyResult(await client.session.delete({ sessionID: segments[1] }));
113
73
  }
114
74
 
115
- return json(501, { error: `SynaBun does not translate ${verb} ${route} for OpenCode 2.` });
75
+ return json(501, { error: `SynaBun does not translate ${verb} ${route} for OpenCode.` });
116
76
  }
@@ -84,9 +84,58 @@ export function rulesToV1(rules) {
84
84
  .map((rule) => ({ permission: v1ToolName(rule.action), pattern: str(rule.resource || '*'), action: str(rule.effect) }));
85
85
  }
86
86
 
87
+ /** The variables an OpenCode 2 integration reads a provider's key from (its `env` methods). */
88
+ export function integrationEnvNames(integration) {
89
+ const names = [];
90
+ for (const method of Array.isArray(integration?.methods) ? integration.methods : []) {
91
+ if (method?.type !== 'env' || !Array.isArray(method.names)) continue;
92
+ for (const name of method.names) if (typeof name === 'string' && name && !names.includes(name)) names.push(name);
93
+ }
94
+ return names;
95
+ }
96
+
97
+ /**
98
+ * How each provider is connected, from OpenCode 2's integrations, in OpenCode 1's shape:
99
+ * `{ [id]: [{ type: 'api', label? } | { type: 'oauth', label, id }] }` — a key method is `api`, a sign-in method
100
+ * `oauth` (its `id` is the method SynaBun starts). Methods that take a form of their own (an AWS profile, a
101
+ * Google Cloud project) or run a command are left out; so is an integration with no method left.
102
+ */
103
+ export function integrationsToAuthMethods(integrations) {
104
+ const out = {};
105
+ for (const integration of Array.isArray(integrations) ? integrations : []) {
106
+ const id = str(integration?.id);
107
+ if (!id) continue;
108
+ const methods = [];
109
+ for (const method of Array.isArray(integration.methods) ? integration.methods : []) {
110
+ if (method?.type === 'key' && !(Array.isArray(method.form) && method.form.length)) methods.push({ type: 'api', ...(method.label ? { label: str(method.label) } : {}) });
111
+ else if (method?.type === 'oauth' && method.id && !(Array.isArray(method.form) && method.form.some((field) => field?.required && !field.hidden && field.default === undefined))) {
112
+ methods.push({ type: 'oauth', label: str(method.label || 'Sign in'), id: str(method.id) });
113
+ }
114
+ }
115
+ if (methods.length) out[id] = methods;
116
+ }
117
+ return out;
118
+ }
119
+
120
+ /** The integrations with a credential of their own stored (an `env` connection is the user's environment, not one). */
121
+ export function integrationsWithCredentials(integrations) {
122
+ return (Array.isArray(integrations) ? integrations : [])
123
+ .filter((integration) => integration?.id && (Array.isArray(integration.connections) ? integration.connections : []).some((connection) => connection?.type === 'credential' && connection.id))
124
+ .map((integration) => str(integration.id));
125
+ }
126
+
127
+ /** The credential ids an integration stored. */
128
+ export function integrationCredentialIds(integration) {
129
+ return (Array.isArray(integration?.connections) ? integration.connections : [])
130
+ .filter((connection) => connection?.type === 'credential' && connection.id)
131
+ .map((connection) => str(connection.id));
132
+ }
133
+
87
134
  /**
88
- * OpenCode 1 rules (`[{ permission, pattern, action }]`, or the config's
89
- * `{ bash: 'ask', edit: { '*.md': 'allow' } }` map) → OpenCode 2 rules.
135
+ * Permission rules as OpenCode 2 takes them: its own `{ action, resource,
136
+ * effect }` as they are, the OpenCode 1 shapes a caller or a user's file may
137
+ * still hold (`[{ permission, pattern, action }]`, or the
138
+ * `{ bash: 'ask', edit: { '*.md': 'allow' } }` map) converted.
90
139
  */
91
140
  export function rulesToV2(rules) {
92
141
  if (rules == null) return undefined;
@@ -0,0 +1,249 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — the one decision for the owner's routes: who may act with the owner's powers
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Many of SynaBun's routes act with the owner's own powers without asking for the page secret: they were guarded
6
+ // by the Host, the Origin and the guest rules only (lib/http-guards.js ownerRouteGuard, lib/request-gate.js). A
7
+ // page of the app passes those by being a page of the app — and so did SynaBun's automation browser, which a
8
+ // sandboxed worker drives with its sanctioned browser tools: it could open the File Explorer and write anywhere,
9
+ // save in the code editor, run git, start the tunnel, make an invite, change Settings, open a terminal tab or an
10
+ // agent panel and type into it — each a way out of the worker's sandbox. A local relay (a proxy, ssh -L, any program
11
+ // that listens and calls SynaBun) was the same way out for a worker that cannot reach SynaBun's port itself.
12
+ //
13
+ // This module is the one decision for all of them, made on what the request cannot choose: the automation
14
+ // browser's marker (lib/page-session.js) and the process at the other end of the connection (lib/peer-identity.js,
15
+ // whose verdict the peer middleware keeps on the request). It covers:
16
+ // • every request to /api that is not a GET / HEAD / OPTIONS (default-deny: a route added later is covered), but
17
+ // for FEATURE_OPEN_PREFIXES — the hooks' own routes and the feature data the agents' MCP tools write too
18
+ // (memories, cards, the whiteboard…), where a refusal would stop the owner's integrations and buy nothing;
19
+ // • the two reads that hand out a secret: GET /api/mcp-key (the whole MCP key) and GET /api/mcp/env/<name>?reveal=1;
20
+ // • the owner's own reads (OWNER_READ_PREFIXES: what a guest is refused, and git), for the peers that are never the
21
+ // owner — the code editor's and File Explorer's roots include SynaBun's data home, whose secrets the worker
22
+ // sandbox keeps from a worker; an agent's tree reads them as before;
23
+ // • the owner's sockets: a terminal, the Claude / Codex / OpenCode panels, the Assistant, the browser panel —
24
+ // and /ws/sync, which stays open (the app's pages need it to draw) but read-only.
25
+ //
26
+ // Refused, whatever the request says (headers, pins, cookies, Origin): a request with the automation browser's
27
+ // marker; a peer that is SynaBun's automation browser or any browser started for automation, a relay (named, or a
28
+ // program that listens), another SynaBun server, a remote login (sshd), or a client that left before it was
29
+ // identified. Refused too, unless it is an agent's own call: an AI agent's process tree, and SynaBun's own MCP server
30
+ // over HTTP (mcp-server/dist/http.js: it listens, so it would read as a relay; lib/peer-identity.js knows it by its
31
+ // main script inside this install, and its tools call with the stdio MCP server's pin). An agent's own call is
32
+ // one that says who it is — an agent pin (X-Synabun-Terminal / -Role / -Assistant / -Desktop-Grant) or a brain
33
+ // credential that survived the peer check — and stays on its route's rules (the MCP git tool, desktop, loop and
34
+ // browser tools; the brain; the Assistant's route gate, asked with the session's pin by the OpenCode plugin and the
35
+ // Codex hook, which checks the session's own token), as do the few routes agents call without a pin
36
+ // (AGENT_OPEN_PREFIXES: the server's stop and restart the CLI asks, the MCP server's tab release, and the loops and
37
+ // schedules the /synabun skill creates with curl).
38
+ //
39
+ // Never refused by this module: the owner's own browser and the SynaBun app (the peer lookup allows them), this
40
+ // server itself, a request from outside (the tunnel, the invite proxy: the guest rules decide those, and the
41
+ // tunnel's own process would otherwise read as a relay), and any request whose peer could not be looked up (the
42
+ // rules from before apply: a failed lookup never locks the owner out).
43
+
44
+ import { readFileSync } from 'node:fs';
45
+ import { AGENT_HEADERS, sendGuardError } from './http-guards.js';
46
+ import { BRAIN_HEADER, PEER_VERDICT } from './peer-identity.js';
47
+ import { ADMIN_ONLY_PREFIXES, routedForms } from './request-gate.js';
48
+
49
+ const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
50
+
51
+ /** Writes left open to every caller the rules before allowed: the hooks' own routes, and the feature data the
52
+ * agents' MCP tools write too. A path counts as open only when every reading of it is open. */
53
+ export const FEATURE_OPEN_PREFIXES = Object.freeze([
54
+ '/api/hook-', '/api/greeting', '/api/sessions',
55
+ '/api/memory', '/api/memories', '/api/memory-maintenance', '/api/categories', '/api/trash', '/api/search',
56
+ '/api/cards', '/api/whiteboard', '/api/images', '/api/games',
57
+ '/api/cache', '/api/fetch-markdown', '/api/last-session', '/api/health',
58
+ '/api/ui-blobs',
59
+ ]);
60
+ /** Paths under an open prefix that are not open: the code editor's copies of unsaved buffers (file content). */
61
+ export const NEVER_OPEN_PREFIXES = Object.freeze(['/api/ui-blobs/editor-backups']);
62
+ /** Routes agents call without a pin: an agent's tree may call them as it did (the other peers are still refused). */
63
+ export const AGENT_OPEN_PREFIXES = Object.freeze(['/api/server/', '/api/browser/release', '/api/loop', '/api/schedules', '/api/schedule-groups']);
64
+ /** The peers whose own calls (pinned, or on an agent-open route) keep their route's rules: an AI agent's process tree,
65
+ * and SynaBun's own MCP server over HTTP (lib/peer-identity.js isSynabunMcpServer), as the stdio one in an agent's tree. */
66
+ export const AGENT_CALL_KINDS = Object.freeze(['agent', 'synabun-mcp']);
67
+ /**
68
+ * The owner's own reads: what a guest is refused (lib/request-gate.js ADMIN_ONLY_PREFIXES — the owner's settings,
69
+ * the code editor's and the File Explorer's file contents, whose roots include SynaBun's data home with its secrets,
70
+ * the runs' transcripts, MCP and plugin configuration…) and git. Refused to the automation browser, relays, other
71
+ * SynaBun servers, remote logins and closed clients (the sandbox keeps a worker out of the data home; these reads
72
+ * would hand it over through a browser or a relay). An agent's tree reads them as before (it is not sandboxed when
73
+ * it can reach SynaBun at all, and the CLI and the MCP tools read some of them). The hooks' own routes are not here.
74
+ */
75
+ export const OWNER_READ_PREFIXES = Object.freeze([...ADMIN_ONLY_PREFIXES.filter((prefix) => prefix !== '/api/hook-'), '/api/git']);
76
+ /** The owner's sockets: a terminal, the agent panels, the Assistant, the browser panel. */
77
+ export const OWNER_SOCKET_PREFIXES = Object.freeze(['/ws/terminal/', '/ws/claude-skin', '/ws/codex-skin', '/ws/opencode-v2', '/ws/antigravity', '/ws/assistant/', '/ws/browser/']);
78
+ /** Sockets that stay open for the app's pages to draw, read-only for a peer the owner's powers are refused to. */
79
+ export const READ_ONLY_SOCKET_PATHS = Object.freeze(['/ws/sync']);
80
+
81
+ /** A path form under a prefix: a prefix ending in "/" or "-" is a plain prefix, any other is a whole segment. */
82
+ function under(form, prefix) {
83
+ if (prefix.endsWith('/') || prefix.endsWith('-')) return form.startsWith(prefix);
84
+ return form === prefix || form.startsWith(`${prefix}/`);
85
+ }
86
+
87
+ // ── A proxy between the owner's browser and SynaBun ──────────────────────────
88
+ // A relay is refused because it hides who asked: through a system proxy, ssh -D or a proxy extension, the owner's own
89
+ // browser reads as the relay. Browsers normally send localhost and 127.0.0.1 straight past a system proxy, so this
90
+ // takes a browser told to proxy them (an extension, a PAC file, Firefox's localhost setting) or SynaBun opened by a
91
+ // name or address the bypass list lacks. The refusal then says what to do, in the request's language (Accept-Language:
92
+ // the i18n files' `ownerAuthority` strings). A relay is never trusted instead, not even one whose parents lead back to
93
+ // the owner's browser: who its client is cannot be seen from SynaBun, and a guarded worker's sandbox keeps the system
94
+ // proxy reachable for the worker's internet, so its requests would arrive from that same relay.
95
+
96
+ /** The refusal kinds that mean "something carries this request for someone else". */
97
+ export const PROXY_REFUSAL_KINDS = Object.freeze(['relay', 'listener']);
98
+ const COPY_LOCALES = Object.freeze(['en', 'pt-BR']);
99
+ let ownerCopies = null;
100
+ /** The `ownerAuthority` strings of every locale (read once, when a refusal first needs them). */
101
+ function ownerCopy(locale) {
102
+ if (!ownerCopies) {
103
+ ownerCopies = {};
104
+ for (const code of COPY_LOCALES) {
105
+ try { ownerCopies[code] = JSON.parse(readFileSync(new URL(`../i18n/${code}.json`, import.meta.url), 'utf8'))?.ownerAuthority || {}; } catch { ownerCopies[code] = {}; }
106
+ }
107
+ }
108
+ return { ...(ownerCopies.en || {}), ...(ownerCopies[locale] || {}) };
109
+ }
110
+ /** The request's language among the i18n files' (pt-* → pt-BR), by the Accept-Language preference order; else en. */
111
+ export function requestLocale(req) {
112
+ const header = String(req?.headers?.['accept-language'] || '');
113
+ const ranked = header.split(',').map((part, index) => {
114
+ const [tag, ...params] = part.trim().split(';');
115
+ const q = Number(params.map((p) => /^\s*q=([\d.]+)\s*$/.exec(p)?.[1]).find(Boolean) ?? 1);
116
+ return { tag: tag.trim().toLowerCase(), q: Number.isFinite(q) ? q : 0, index };
117
+ }).filter((x) => x.tag && x.q > 0).sort((a, b) => b.q - a.q || a.index - b.index);
118
+ for (const { tag } of ranked) {
119
+ if (tag === 'pt' || tag.startsWith('pt-')) return 'pt-BR';
120
+ if (tag === 'en' || tag.startsWith('en-')) return 'en';
121
+ }
122
+ return 'en';
123
+ }
124
+ /** What to do when the owner's browser reaches SynaBun through a proxy (`ownerAuthority.proxyRefused`), filled in. */
125
+ export function proxyRefusalText(req, refuse) {
126
+ const template = ownerCopy(requestLocale(req)).proxyRefused;
127
+ const params = { name: String(refuse?.name || 'a proxy').slice(0, 64), pid: String(refuse?.pid ?? '?') };
128
+ if (typeof template !== 'string' || !template) return `Your browser reaches SynaBun through ${params.name} (pid ${params.pid}), a proxy or relay, so SynaBun refused this: add localhost and 127.0.0.1 to the proxy's bypass list, or turn the proxy off for SynaBun, then reload.`;
129
+ return template.replace(/\{(\w+)\}/g, (whole, key) => (params[key] != null ? params[key] : whole));
130
+ }
131
+
132
+ /** Does a request say it is an agent's own call (a pin, or a brain credential that survived the peer check)? */
133
+ export function isAgentCall(req) {
134
+ const h = req?.headers || {};
135
+ return AGENT_HEADERS.some((name) => h[name] !== undefined) || typeof h[BRAIN_HEADER] === 'string';
136
+ }
137
+
138
+ /**
139
+ * Where an HTTP request stands: `gated` (one of the owner's writes, one of the owner's reads, or a secret read), and
140
+ * `agentOpen` (an agent's tree may call it without a pin: every owner's read but the secret ones, and the
141
+ * AGENT_OPEN_PREFIXES writes). A path with no safe reading is gated.
142
+ */
143
+ export function restScope(req) {
144
+ const method = String(req?.method || 'GET').toUpperCase();
145
+ const forms = routedForms(String(req?.path ?? req?.url ?? ''));
146
+ if (!forms) return { gated: !SAFE_METHODS.has(method), agentOpen: false, reason: 'no safe reading of the path' };
147
+ if (SAFE_METHODS.has(method)) {
148
+ if (method === 'OPTIONS') return { gated: false, agentOpen: false };
149
+ const reveal = String(req?.query?.reveal || '') === '1';
150
+ if (forms.some((form) => form === '/api/mcp-key' || (reveal && form.startsWith('/api/mcp/env/')))) {
151
+ return { gated: true, agentOpen: false, reason: 'a read that hands out a secret' };
152
+ }
153
+ // (ADMIN_ONLY_PREFIXES are plain prefixes, as lib/request-gate.js reads them)
154
+ const ownerRead = forms.some((form) => OWNER_READ_PREFIXES.some((prefix) => form.startsWith(prefix)));
155
+ return { gated: ownerRead, agentOpen: true, reason: ownerRead ? 'one of the owner\'s reads' : null };
156
+ }
157
+ if (!forms.some((form) => under(form, '/api'))) return { gated: false, agentOpen: false };
158
+ const open = (form) => FEATURE_OPEN_PREFIXES.some((prefix) => under(form, prefix)) && !NEVER_OPEN_PREFIXES.some((prefix) => under(form, prefix));
159
+ if (forms.every(open)) return { gated: false, agentOpen: false };
160
+ return { gated: true, agentOpen: forms.every((form) => AGENT_OPEN_PREFIXES.some((prefix) => under(form, prefix))), reason: 'one of the owner\'s writes' };
161
+ }
162
+
163
+ /** Where a socket stands: `owner` (refused to the peers below) or `readOnly` (open, read-only for them). */
164
+ export function socketScope(pathname) {
165
+ const p = String(pathname || '');
166
+ if (OWNER_SOCKET_PREFIXES.some((prefix) => (prefix.endsWith('/') ? p.startsWith(prefix) : p === prefix))) return { owner: true, readOnly: false };
167
+ if (READ_ONLY_SOCKET_PATHS.includes(p)) return { owner: false, readOnly: true };
168
+ return { owner: false, readOnly: false };
169
+ }
170
+
171
+ /**
172
+ * The decision for one request whose peer verdict is on it (or not: then only the marker counts).
173
+ * @param {object} req
174
+ * @param {{ agentOpen?: boolean, fromWorkerBrowser?: (req) => boolean }} o
175
+ * @returns {{ code: string, error: string, hint?: string, peer?: object } | null} `hint: 'proxy'` (with the relay's
176
+ * kind, pid and name) when the peer carries requests for others: `error` then says what to do, in the request's language
177
+ */
178
+ export function ownerRefusal(req, { agentOpen = false, fromWorkerBrowser = () => false } = {}) {
179
+ let marked = false;
180
+ try { marked = !!fromWorkerBrowser(req); } catch { marked = false; }
181
+ if (marked) return { code: 'WORKER_BROWSER', error: 'SynaBun\'s automation browser cannot act as the owner: it reads SynaBun\'s pages, clicks and screenshots; the owner\'s own settings, files and actions are the owner\'s, from the owner\'s browser or the app.' };
182
+ const peer = req?.[PEER_VERDICT];
183
+ if (!peer) return null;
184
+ if (peer.status === 'gone') return { code: 'PEER_REFUSED', error: `This is the owner's, and ${peer.reason || 'the connection closed before its request was identified'}.` };
185
+ if (peer.status !== 'ok' || peer.self || !peer.refuse) return null;
186
+ if (AGENT_CALL_KINDS.includes(peer.refuse.kind) && (agentOpen || isAgentCall(req))) return null; // an agent's own call: its route's rules
187
+ if (PROXY_REFUSAL_KINDS.includes(peer.refuse.kind)) {
188
+ return { code: 'PEER_REFUSED', error: proxyRefusalText(req, peer.refuse), hint: 'proxy', peer: { kind: peer.refuse.kind, pid: peer.refuse.pid, name: peer.refuse.name } };
189
+ }
190
+ return { code: 'PEER_REFUSED', error: `This is the owner's, from the owner's own browser or the app; this request comes from ${peer.refuse.why}: pid ${peer.refuse.pid} (${peer.refuse.name}).` };
191
+ }
192
+
193
+ /**
194
+ * @param {object} o
195
+ * @param {() => ({ fromWorkerBrowser(req): boolean } | null)} [o.pageSession] the page session (read at request time)
196
+ * @param {(req) => boolean} [o.isRemote] a request from outside (the tunnel, the invite proxy): the guest rules decide
197
+ * @param {{ lookup(req): Promise<object> }} [o.peer] lib/peer-identity.js (for sockets: no middleware runs for them)
198
+ * @param {(line: string) => void} [o.log]
199
+ */
200
+ export function createOwnerAuthority({ pageSession = () => null, isRemote = () => false, peer = null, log = () => {} } = {}) {
201
+ const fromWorkerBrowser = (req) => { const s = pageSession(); return typeof s?.fromWorkerBrowser === 'function' ? s.fromWorkerBrowser(req) : false; };
202
+ const remote = (req) => { try { return isRemote(req) === true; } catch { return false; } };
203
+ const logged = new Map();
204
+ const note = (key, line) => {
205
+ const now = Date.now();
206
+ if (now - (logged.get(key) || 0) < 60_000) return;
207
+ logged.set(key, now);
208
+ if (logged.size > 500) logged.delete(logged.keys().next().value);
209
+ try { log(line); } catch { /* a logger's own failure */ }
210
+ };
211
+
212
+ /** Whether the peer middleware should look this request up (it is one of the owner's, and not from outside). */
213
+ function needsLookup(req) {
214
+ if (remote(req)) return false;
215
+ try { return restScope(req).gated; } catch { return true; }
216
+ }
217
+
218
+ /** Express middleware, mounted after the peer middleware: 403 for a refused request to one of the owner's routes
219
+ * (its writes, its reads, a secret read). */
220
+ function restGate(req, res, next) {
221
+ let scope;
222
+ try { scope = restScope(req); } catch { scope = { gated: true, agentOpen: false }; }
223
+ if (!scope.gated || remote(req)) return next();
224
+ const refused = ownerRefusal(req, { agentOpen: scope.agentOpen, fromWorkerBrowser });
225
+ if (!refused) return next();
226
+ note(`${refused.code}:${req[PEER_VERDICT]?.pid || 'marker'}:${String(req.path).slice(0, 80)}`, `[owner-authority] refused ${req.method} ${String(req.path).slice(0, 120)}: ${refused.hint === 'proxy' ? `${req[PEER_VERDICT]?.refuse?.why}: pid ${refused.peer?.pid} (${refused.peer?.name})` : refused.error}`);
227
+ if (refused.hint) return res.status(403).json({ ok: false, code: refused.code, error: refused.error, hint: refused.hint, peer: refused.peer });
228
+ return sendGuardError(res, 403, refused.code, refused.error);
229
+ }
230
+
231
+ /**
232
+ * The decision for a WebSocket upgrade (no middleware runs for one): looks the peer up for an owner socket and for
233
+ * /ws/sync. → { refuse: boolean, readOnly: boolean, code?, error? }. Never rejects; a lookup that cannot run
234
+ * refuses nothing.
235
+ */
236
+ async function checkUpgrade(req, pathname) {
237
+ const scope = socketScope(pathname);
238
+ if ((!scope.owner && !scope.readOnly) || remote(req)) return { refuse: false, readOnly: false };
239
+ if (peer && typeof peer.lookup === 'function' && !req[PEER_VERDICT]) {
240
+ try { req[PEER_VERDICT] = await peer.lookup(req); } catch { /* unknown: the rules from before */ }
241
+ }
242
+ const refused = ownerRefusal(req, { agentOpen: false, fromWorkerBrowser });
243
+ if (!refused) return { refuse: false, readOnly: false };
244
+ note(`ws:${refused.code}:${req[PEER_VERDICT]?.pid || 'marker'}:${pathname}`, `[owner-authority] ${scope.owner ? 'refused' : 'read-only'} socket ${pathname}: ${refused.error}`);
245
+ return scope.owner ? { refuse: true, readOnly: false, ...refused } : { refuse: false, readOnly: true, ...refused };
246
+ }
247
+
248
+ return { needsLookup, restGate, checkUpgrade, restScope, socketScope };
249
+ }