synabun 2.0.9 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (679) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +68 -4
  4. package/bin/synabun.js +71 -24
  5. package/docs/whatsapp.md +2 -2
  6. package/hooks/claude-code/pre-websearch.mjs +12 -1
  7. package/hooks/claude-code/shared.mjs +5 -0
  8. package/hooks/claude-code/stop.mjs +1 -1
  9. package/launcher.mjs +9 -3
  10. package/lib/claude-hooks.js +172 -18
  11. package/lib/client-config-repair.js +17 -8
  12. package/lib/desktop-app.js +7 -1
  13. package/lib/external-tools.js +1 -1
  14. package/lib/first-launch-protection.js +57 -12
  15. package/lib/mcp-dist.js +176 -0
  16. package/lib/release-npm-ci.mjs +138 -0
  17. package/lib/release-publish.mjs +91 -0
  18. package/lib/release-scan.mjs +50 -0
  19. package/lib/server-crash-record.js +123 -0
  20. package/lib/server-exit.js +318 -0
  21. package/lib/server-supervisor.js +508 -0
  22. package/lib/start-launcher.js +43 -5
  23. package/lib/tools-cli.js +45 -0
  24. package/lib/update-snapshot.js +228 -0
  25. package/lib/virustotal.mjs +192 -0
  26. package/lib/windows-crash-event.js +269 -0
  27. package/mcp-server/dist/http.d.ts +20 -1
  28. package/mcp-server/dist/http.d.ts.map +1 -1
  29. package/mcp-server/dist/http.js +59 -12
  30. package/mcp-server/dist/http.js.map +1 -1
  31. package/mcp-server/dist/index.d.ts +33 -27
  32. package/mcp-server/dist/index.d.ts.map +1 -1
  33. package/mcp-server/dist/index.js +128 -143
  34. package/mcp-server/dist/index.js.map +1 -1
  35. package/mcp-server/dist/preload.js +1 -1
  36. package/mcp-server/dist/preload.js.map +1 -1
  37. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  38. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  39. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  40. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  41. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  42. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  43. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  44. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  45. package/mcp-server/dist/services/neural-interface.d.ts +16 -10
  46. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  47. package/mcp-server/dist/services/neural-interface.js +67 -11
  48. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  49. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  50. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  51. package/mcp-server/dist/services/server-instructions.js +20 -62
  52. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  53. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  54. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  55. package/mcp-server/dist/services/tool-catalog.js +339 -0
  56. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  57. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  58. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  59. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  60. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  61. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  62. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  63. package/mcp-server/dist/services/tool-list.js +334 -0
  64. package/mcp-server/dist/services/tool-list.js.map +1 -0
  65. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  66. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  67. package/mcp-server/dist/services/tool-runtime.js +400 -0
  68. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  69. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  70. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  71. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  72. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  73. package/mcp-server/dist/tools/agents.d.ts +10 -10
  74. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  75. package/mcp-server/dist/tools/agents.js +22 -13
  76. package/mcp-server/dist/tools/agents.js.map +1 -1
  77. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  78. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  79. package/mcp-server/dist/tools/image-tools.js +1 -1
  80. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  81. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  82. package/mcp-server/dist/tools/skill-tools.js +639 -0
  83. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  84. package/mcp-server/dist/tools/skill.d.ts +7 -0
  85. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  86. package/mcp-server/dist/tools/skill.js +11 -0
  87. package/mcp-server/dist/tools/skill.js.map +1 -0
  88. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  89. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  90. package/mcp-server/dist/tools/tool-groups.js +147 -0
  91. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  92. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  93. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  94. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  95. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  96. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  97. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  98. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  99. package/mcp-server/package-lock.json +2 -2
  100. package/mcp-server/package.json +1 -1
  101. package/mcp-server/src/http.ts +75 -12
  102. package/mcp-server/src/index.ts +147 -154
  103. package/mcp-server/src/preload.ts +12 -12
  104. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  105. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  106. package/mcp-server/src/services/neural-interface.ts +79 -20
  107. package/mcp-server/src/services/server-instructions.ts +27 -63
  108. package/mcp-server/src/services/tool-catalog.ts +403 -0
  109. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  110. package/mcp-server/src/services/tool-list.ts +410 -0
  111. package/mcp-server/src/services/tool-runtime.ts +457 -0
  112. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  113. package/mcp-server/src/tools/agents.ts +22 -14
  114. package/mcp-server/src/tools/image-tools.ts +1 -1
  115. package/mcp-server/src/tools/skill-tools.ts +589 -0
  116. package/mcp-server/src/tools/skill.ts +13 -0
  117. package/mcp-server/src/tools/tool-groups.ts +164 -0
  118. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  119. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  120. package/neural-interface/i18n/en.json +3680 -206
  121. package/neural-interface/i18n/pt-BR.json +3628 -157
  122. package/neural-interface/lib/account-usage.js +5 -3
  123. package/neural-interface/lib/app-controls-api.js +161 -0
  124. package/neural-interface/lib/assistant-api.js +148 -35
  125. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  126. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  127. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  128. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  129. package/neural-interface/lib/assistant-brains/opencode.js +122 -44
  130. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +59 -0
  131. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +97 -0
  132. package/neural-interface/lib/assistant-catalog.js +23 -9
  133. package/neural-interface/lib/assistant-dispatch.js +874 -156
  134. package/neural-interface/lib/assistant-envelope.js +22 -2
  135. package/neural-interface/lib/assistant-persona.js +80 -11
  136. package/neural-interface/lib/assistant-plan-permissions.js +10 -9
  137. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  138. package/neural-interface/lib/assistant-route-gate.js +6 -4
  139. package/neural-interface/lib/assistant-router.js +13 -8
  140. package/neural-interface/lib/assistant-runtime.js +183 -26
  141. package/neural-interface/lib/assistant-task-prompt.js +78 -14
  142. package/neural-interface/lib/assistant-tools.js +51 -0
  143. package/neural-interface/lib/backup-service.js +620 -3
  144. package/neural-interface/lib/backup-zip-reader.js +10 -5
  145. package/neural-interface/lib/backup-zip-writer.js +257 -0
  146. package/neural-interface/lib/browser-execution.js +10 -2
  147. package/neural-interface/lib/browser-guard-cdp.js +83 -0
  148. package/neural-interface/lib/browser-network-guard.js +284 -0
  149. package/neural-interface/lib/browser-policy-roots.js +64 -0
  150. package/neural-interface/lib/browser-tool-policy.js +186 -31
  151. package/neural-interface/lib/claude-agent-bridge.js +4 -2
  152. package/neural-interface/lib/claude-hooks-status.js +103 -0
  153. package/neural-interface/lib/claude-model-catalog.js +64 -14
  154. package/neural-interface/lib/claude-temporary.js +5 -11
  155. package/neural-interface/lib/cli-install.js +18 -138
  156. package/neural-interface/lib/cli-resolver.js +4 -1
  157. package/neural-interface/lib/cli-update-planner.js +32 -31
  158. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  159. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  160. package/neural-interface/lib/codex-settings-schema.js +109 -47
  161. package/neural-interface/lib/codex-worker-app-server.js +172 -0
  162. package/neural-interface/lib/confined-fs.js +30 -3
  163. package/neural-interface/lib/crash-notice-api.js +98 -0
  164. package/neural-interface/lib/editor-completion-opencode.js +164 -67
  165. package/neural-interface/lib/exec-loop-command.js +4 -1
  166. package/neural-interface/lib/http-guards.js +8 -2
  167. package/neural-interface/lib/install-details.js +4 -1
  168. package/neural-interface/lib/launch-cache.js +293 -0
  169. package/neural-interface/lib/login-start.js +524 -0
  170. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  171. package/neural-interface/lib/mcp-client-config.js +0 -29
  172. package/neural-interface/lib/mcp-external-servers.js +323 -0
  173. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  174. package/neural-interface/lib/morelogin.js +30 -0
  175. package/neural-interface/lib/native-loop-providers.js +565 -50
  176. package/neural-interface/lib/native-loop-runtime.js +287 -41
  177. package/neural-interface/lib/opencode-config.js +557 -0
  178. package/neural-interface/lib/opencode-db-schema.js +58 -0
  179. package/neural-interface/lib/opencode-history.js +49 -204
  180. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  181. package/neural-interface/lib/opencode-native-boundary.js +44 -0
  182. package/neural-interface/lib/opencode-protocol.js +310 -0
  183. package/neural-interface/lib/opencode-provider-view.js +81 -0
  184. package/neural-interface/lib/opencode-runtime-config.js +32 -15
  185. package/neural-interface/lib/opencode-serve-records.js +624 -0
  186. package/neural-interface/lib/opencode-v2-client.js +53 -131
  187. package/neural-interface/lib/opencode-v2-ws-requests.js +35 -195
  188. package/neural-interface/lib/opencode-worker-activity.js +229 -0
  189. package/neural-interface/lib/opencode-worker-data.js +27 -0
  190. package/neural-interface/lib/opencode2-client.js +796 -0
  191. package/neural-interface/lib/opencode2-proxy.js +76 -0
  192. package/neural-interface/lib/opencode2-translate.js +1057 -0
  193. package/neural-interface/lib/owner-authority.js +249 -0
  194. package/neural-interface/lib/page-session.js +275 -0
  195. package/neural-interface/lib/peer-identity.js +763 -0
  196. package/neural-interface/lib/process-identity.js +361 -0
  197. package/neural-interface/lib/request-gate.js +17 -2
  198. package/neural-interface/lib/rulesets/api.js +1 -1
  199. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  200. package/neural-interface/lib/rulesets/installer.js +92 -27
  201. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  202. package/neural-interface/lib/session-cache-builder.js +18 -10
  203. package/neural-interface/lib/session-title-generator.js +58 -18
  204. package/neural-interface/lib/skills/api-v2.js +495 -0
  205. package/neural-interface/lib/skills/bundle.js +418 -0
  206. package/neural-interface/lib/skills/catalog.js +294 -0
  207. package/neural-interface/lib/skills/creation-api.js +191 -0
  208. package/neural-interface/lib/skills/creation-brief.js +247 -0
  209. package/neural-interface/lib/skills/creation-sources.js +267 -0
  210. package/neural-interface/lib/skills/creation.js +843 -0
  211. package/neural-interface/lib/skills/deploy.js +564 -0
  212. package/neural-interface/lib/skills/digest.js +119 -0
  213. package/neural-interface/lib/skills/discover.js +111 -0
  214. package/neural-interface/lib/skills/draft-confinement.js +214 -0
  215. package/neural-interface/lib/skills/eval-confinement.js +397 -0
  216. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  217. package/neural-interface/lib/skills/eval-trace.js +119 -0
  218. package/neural-interface/lib/skills/evals-api.js +212 -0
  219. package/neural-interface/lib/skills/evals.js +1573 -0
  220. package/neural-interface/lib/skills/export.js +200 -0
  221. package/neural-interface/lib/skills/frontmatter.js +64 -0
  222. package/neural-interface/lib/skills/health.js +75 -0
  223. package/neural-interface/lib/skills/json-edit.js +165 -0
  224. package/neural-interface/lib/skills/known-bridge-digests.json +387 -0
  225. package/neural-interface/lib/skills/known-bridges.js +96 -0
  226. package/neural-interface/lib/skills/library.js +823 -0
  227. package/neural-interface/lib/skills/local-store.js +21 -0
  228. package/neural-interface/lib/skills/migration.js +433 -0
  229. package/neural-interface/lib/skills/operations.js +45 -0
  230. package/neural-interface/lib/skills/ownership.js +427 -0
  231. package/neural-interface/lib/skills/packages.js +88 -0
  232. package/neural-interface/lib/skills/reviews.js +212 -0
  233. package/neural-interface/lib/skills/revision.js +80 -0
  234. package/neural-interface/lib/skills/roots.js +262 -0
  235. package/neural-interface/lib/skills/runtime-checks.js +355 -0
  236. package/neural-interface/lib/skills/scan-assets.js +252 -0
  237. package/neural-interface/lib/skills/scan-context.js +26 -0
  238. package/neural-interface/lib/skills/scan-shell.js +324 -0
  239. package/neural-interface/lib/skills/scan.js +364 -0
  240. package/neural-interface/lib/skills/scanners.js +54 -0
  241. package/neural-interface/lib/skills/service.js +522 -0
  242. package/neural-interface/lib/skills/telemetry.js +113 -0
  243. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  244. package/neural-interface/lib/style-guide/api.js +4 -3
  245. package/neural-interface/lib/tool-lists.js +124 -0
  246. package/neural-interface/lib/untrusted-file-headers.js +27 -0
  247. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  248. package/neural-interface/lib/worker-confinement.js +1192 -0
  249. package/neural-interface/lib/worker-guard-setting.js +56 -0
  250. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  251. package/neural-interface/lib/worker-relay-ports.js +227 -0
  252. package/neural-interface/lib/worker-resume.js +229 -0
  253. package/neural-interface/lib/worker-sandbox.js +299 -0
  254. package/neural-interface/package-lock.json +1354 -50
  255. package/neural-interface/package.json +6 -2
  256. package/neural-interface/public/index.html +5 -3
  257. package/neural-interface/public/index2d.html +19 -11
  258. package/neural-interface/public/onboarding.html +2 -2
  259. package/neural-interface/public/shared/account-menu.js +8 -5
  260. package/neural-interface/public/shared/agent-runtime-options.js +76 -16
  261. package/neural-interface/public/shared/api.js +1527 -1336
  262. package/neural-interface/public/shared/app-frame.js +192 -0
  263. package/neural-interface/public/shared/assistant/asst-agents-dock.js +205 -19
  264. package/neural-interface/public/shared/assistant/asst-api.js +11 -3
  265. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  266. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  267. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  268. package/neural-interface/public/shared/assistant/asst-brain-picker.js +241 -112
  269. package/neural-interface/public/shared/assistant/asst-composer.js +1 -1
  270. package/neural-interface/public/shared/assistant/asst-control.js +157 -26
  271. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  272. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  273. package/neural-interface/public/shared/assistant/asst-hosts.js +49 -2
  274. package/neural-interface/public/shared/assistant/asst-limit-dock.js +40 -0
  275. package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -0
  276. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  277. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  278. package/neural-interface/public/shared/assistant/asst-menu.js +84 -12
  279. package/neural-interface/public/shared/assistant/asst-panel.js +303 -44
  280. package/neural-interface/public/shared/assistant/asst-rack-styles.js +93 -58
  281. package/neural-interface/public/shared/assistant/asst-redact.js +186 -0
  282. package/neural-interface/public/shared/assistant/asst-render.js +770 -100
  283. package/neural-interface/public/shared/assistant/asst-route.js +83 -12
  284. package/neural-interface/public/shared/assistant/asst-run-stage.js +231 -0
  285. package/neural-interface/public/shared/assistant/asst-sanitize.js +193 -3
  286. package/neural-interface/public/shared/assistant/asst-scene-styles.js +273 -0
  287. package/neural-interface/public/shared/assistant/asst-scenes.js +530 -0
  288. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +3 -15
  289. package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
  290. package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
  291. package/neural-interface/public/shared/assistant/asst-state.js +25 -15
  292. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  293. package/neural-interface/public/shared/assistant/asst-styles.js +102 -21
  294. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +165 -13
  295. package/neural-interface/public/shared/automation-context.js +5 -2
  296. package/neural-interface/public/shared/cc-dropdown.js +550 -0
  297. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  298. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  299. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  300. package/neural-interface/public/shared/cdx/cdx-output.js +8 -7
  301. package/neural-interface/public/shared/cdx/cdx-panel.js +58 -150
  302. package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
  303. package/neural-interface/public/shared/cdx/cdx-render.js +62 -32
  304. package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
  305. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  306. package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
  307. package/neural-interface/public/shared/cdx/cdx-tabs.js +201 -74
  308. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  309. package/neural-interface/public/shared/cli-install-view.js +4 -8
  310. package/neural-interface/public/shared/cli-status.js +2 -2
  311. package/neural-interface/public/shared/constants.js +2 -2
  312. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  313. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  314. package/neural-interface/public/shared/context-menu-model.js +366 -0
  315. package/neural-interface/public/shared/context-menu.js +372 -0
  316. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  317. package/neural-interface/public/shared/cp/cp-markdown.js +4 -57
  318. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  319. package/neural-interface/public/shared/data-cache.js +223 -0
  320. package/neural-interface/public/shared/desktop-bridge.js +11 -0
  321. package/neural-interface/public/shared/desktop-titlebar-view.js +78 -1
  322. package/neural-interface/public/shared/desktop-titlebar.js +214 -28
  323. package/neural-interface/public/shared/desktop-update-view.js +35 -5
  324. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  325. package/neural-interface/public/shared/file-links.js +73 -8
  326. package/neural-interface/public/shared/html-shell.js +78 -86
  327. package/neural-interface/public/shared/i18n.js +2 -0
  328. package/neural-interface/public/shared/launch-prefetch.js +59 -0
  329. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  330. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  331. package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +3 -2
  332. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  333. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +9 -2
  334. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  335. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  336. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  337. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  338. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  339. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  340. package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +54 -17
  341. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  342. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +140 -254
  343. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  344. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +97 -203
  345. package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +11 -9
  346. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +15 -4
  347. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -22
  348. package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +401 -0
  349. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +20 -13
  350. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  351. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +53 -82
  352. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  353. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  354. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  355. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  356. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +48 -40
  357. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  358. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +205 -62
  359. package/neural-interface/public/shared/opencode-providers.js +39 -0
  360. package/neural-interface/public/shared/page-session.js +96 -0
  361. package/neural-interface/public/shared/registry.js +5 -3
  362. package/neural-interface/public/shared/retired-2d.js +3 -0
  363. package/neural-interface/public/shared/schedules-view.js +452 -0
  364. package/neural-interface/public/shared/settings/settings-app-pane.js +335 -0
  365. package/neural-interface/public/shared/settings/settings-app.js +243 -0
  366. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  367. package/neural-interface/public/shared/settings/settings-data.js +90 -0
  368. package/neural-interface/public/shared/settings/settings-ia.js +23 -6
  369. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  370. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  371. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  372. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  373. package/neural-interface/public/shared/sidepanel-session-status.js +49 -0
  374. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  375. package/neural-interface/public/shared/skills/ss-creation.js +219 -0
  376. package/neural-interface/public/shared/skills/ss-dialog.js +130 -0
  377. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  378. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  379. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  380. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  381. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  382. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  383. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  384. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  385. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  386. package/neural-interface/public/shared/skills/ss-lint.js +141 -0
  387. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  388. package/neural-interface/public/shared/skills/ss-profiles.js +475 -0
  389. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  390. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  391. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  392. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  393. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  394. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  395. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  396. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +236 -0
  397. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  398. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  399. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  400. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  401. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  402. package/neural-interface/public/shared/skills/studio/sx-dom.js +229 -0
  403. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  404. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  405. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  406. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  407. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  408. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  409. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +279 -0
  410. package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
  411. package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
  412. package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
  413. package/neural-interface/public/shared/skills/studio/sx-main.js +681 -0
  414. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  415. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  416. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  417. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  418. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  419. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  420. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  421. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  422. package/neural-interface/public/shared/skills/studio/sx-subject.js +248 -0
  423. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  424. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  425. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  426. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +425 -0
  427. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  428. package/neural-interface/public/shared/styles.css +2065 -2150
  429. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  430. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  431. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  432. package/neural-interface/public/shared/tool-list-view.js +112 -0
  433. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  434. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  435. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  436. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  437. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  438. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  439. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  440. package/neural-interface/public/shared/tour/tour.css +144 -0
  441. package/neural-interface/public/shared/ui-assistant.js +27 -5
  442. package/neural-interface/public/shared/ui-automation-studio.js +155 -152
  443. package/neural-interface/public/shared/ui-bookmarks.js +2 -1
  444. package/neural-interface/public/shared/ui-claude-panel.js +153 -13
  445. package/neural-interface/public/shared/ui-codex-panel.js +1 -0
  446. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  447. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  448. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  449. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  450. package/neural-interface/public/shared/ui-detail.js +21 -9
  451. package/neural-interface/public/shared/ui-file-links.js +1 -0
  452. package/neural-interface/public/shared/ui-image-gallery.js +56 -52
  453. package/neural-interface/public/shared/ui-invite.js +18 -2
  454. package/neural-interface/public/shared/ui-keybinds.js +26 -1
  455. package/neural-interface/public/shared/ui-link.js +9 -9
  456. package/neural-interface/public/shared/ui-menubar.js +229 -40
  457. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  458. package/neural-interface/public/shared/ui-native-loop-router.js +9 -1
  459. package/neural-interface/public/shared/ui-navbar.js +4 -24
  460. package/neural-interface/public/shared/ui-opencode-panel-v2.js +1 -0
  461. package/neural-interface/public/shared/ui-panels.js +96 -65
  462. package/neural-interface/public/shared/ui-schedules-studio.js +2267 -953
  463. package/neural-interface/public/shared/ui-sessions.js +20 -7
  464. package/neural-interface/public/shared/ui-settings.js +679 -496
  465. package/neural-interface/public/shared/ui-sidebar.js +4 -4
  466. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +13 -0
  467. package/neural-interface/public/shared/ui-sidepanel-sessions.js +56 -5
  468. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  469. package/neural-interface/public/shared/ui-sidepanel-tray.js +84 -8
  470. package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
  471. package/neural-interface/public/shared/ui-skills.js +42 -2781
  472. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  473. package/neural-interface/public/shared/ui-sync.js +22 -5
  474. package/neural-interface/public/shared/ui-terminal.js +159 -199
  475. package/neural-interface/public/shared/ui-tool-updates.js +3 -1
  476. package/neural-interface/public/shared/ui-tooltip.js +10 -5
  477. package/neural-interface/public/shared/ui-trash.js +14 -5
  478. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  479. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  480. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -61
  481. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  482. package/neural-interface/public/shared/ui-tutorial.js +285 -499
  483. package/neural-interface/public/shared/ui-update.js +121 -16
  484. package/neural-interface/public/shared/ui-whiteboard.js +313 -59
  485. package/neural-interface/public/shared/ui-worker-end.js +4 -0
  486. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  487. package/neural-interface/public/shared/view-variant.js +66 -0
  488. package/neural-interface/public/shared/whatsapp/wa-view.js +1 -1
  489. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  490. package/neural-interface/public/shared/worker-end.js +10 -3
  491. package/neural-interface/public/shared/worker-restart.js +12 -0
  492. package/neural-interface/public/sidepanel-session.html +1 -1
  493. package/neural-interface/public/variant/2d/background.js +2 -1
  494. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  495. package/neural-interface/public/variant/2d/graph.js +42 -20
  496. package/neural-interface/public/variant/2d/hulls.js +14 -9
  497. package/neural-interface/public/variant/2d/lasso.js +11 -7
  498. package/neural-interface/public/variant/2d/main.js +36 -2
  499. package/neural-interface/public/variant/2d/minimap.js +11 -13
  500. package/neural-interface/public/variant/3d/main.js +72 -6
  501. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  502. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  503. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  504. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  505. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  506. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  507. package/neural-interface/public/vendor/highlight/LICENSE +29 -0
  508. package/neural-interface/public/vendor/highlight/github-dark-dimmed-11.12.0.min.css +9 -0
  509. package/neural-interface/public/vendor/highlight/highlight-11.12.0.min.js +1262 -0
  510. package/neural-interface/public/vendor/highlight/manifest.json +5 -0
  511. package/neural-interface/public/vendor/html2canvas/LICENSE +22 -0
  512. package/neural-interface/public/vendor/html2canvas/html2canvas-1.4.1.min.js +20 -0
  513. package/neural-interface/public/vendor/html2canvas/manifest.json +4 -0
  514. package/neural-interface/public/vendor/marked/LICENSE.md +44 -0
  515. package/neural-interface/public/vendor/marked/manifest.json +4 -0
  516. package/neural-interface/public/vendor/marked/marked-14.1.4.esm.js +2502 -0
  517. package/neural-interface/public/vendor/mermaid/LICENSE +21 -0
  518. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/abnfDiagram-PAR5IXJI.mjs +1 -0
  519. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architecture-7GRP2DOG-M7G3SWCO.mjs +1 -0
  520. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architectureDiagram-2PNWDENW.mjs +36 -0
  521. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/blockDiagram-PUWGUBOA.mjs +129 -0
  522. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/c4Diagram-3NLNHZP5.mjs +38 -0
  523. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-2NMSUPJH.mjs +1 -0
  524. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-32MCUW2P.mjs +206 -0
  525. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3NPNU5GP.mjs +1 -0
  526. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3SMGFRGC.mjs +1 -0
  527. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4CAJECRU.mjs +14 -0
  528. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4OADUZ5Q.mjs +10 -0
  529. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IMINLNL.mjs +1 -0
  530. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IQCK5RY.mjs +3 -0
  531. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5MVFYWFU.mjs +1 -0
  532. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AQ6EADP3.mjs +1 -0
  533. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AZZRMDJM.mjs +15 -0
  534. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-CLS4B6BI.mjs +168 -0
  535. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-DZP67EKU.mjs +70 -0
  536. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-EICP7K5X.mjs +1 -0
  537. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-GDY2UAB4.mjs +1 -0
  538. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-H7VHZCWX.mjs +1 -0
  539. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-IJBDOHL6.mjs +1 -0
  540. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JFFVMJIA.mjs +1 -0
  541. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JQRUD6KW.mjs +1 -0
  542. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JZGDI5JK.mjs +1 -0
  543. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-KD6SPIPN.mjs +2 -0
  544. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NF366YI6.mjs +231 -0
  545. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NUDPKBEF.mjs +32 -0
  546. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-OJINMHTS.mjs +1 -0
  547. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Q6NGPIAH.mjs +2 -0
  548. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-QJSWEUOL.mjs +132 -0
  549. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-R7JDMUKV.mjs +1 -0
  550. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RCXAM2GK.mjs +1 -0
  551. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RT4MAWR3.mjs +1 -0
  552. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SFMINX4W.mjs +1 -0
  553. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SLDQ463B.mjs +88 -0
  554. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-STOV2HOB.mjs +1 -0
  555. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-T5OCTHI4.mjs +1 -0
  556. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-TCEHX7R3.mjs +1 -0
  557. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VQC2EELJ.mjs +1 -0
  558. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VRZKL3EH.mjs +1 -0
  559. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VTHDQ7BV.mjs +1 -0
  560. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VY2OSTJR.mjs +2 -0
  561. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-WUBWJARI.mjs +1 -0
  562. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YBMQ5JGJ.mjs +2 -0
  563. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YDMLL4PJ.mjs +1 -0
  564. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Z6V44ARX.mjs +62 -0
  565. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZJJ7VQJP.mjs +339 -0
  566. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZNLK7HRR.mjs +1 -0
  567. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZQN7UHIL.mjs +1 -0
  568. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZS6VBONO.mjs +174 -0
  569. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZUNWM646.mjs +1 -0
  570. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-FGAMPOII.mjs +1 -0
  571. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-v2-AI5RJEK4.mjs +1 -0
  572. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cose-bilkent-Q72C2OJ3.mjs +1 -0
  573. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefin-OW5HDTMX-6OCTWOGG.mjs +1 -0
  574. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefinDiagram-2OOWUY4M.mjs +62 -0
  575. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/dagre-MPVFI544.mjs +4 -0
  576. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-AE4NWXFW.mjs +24 -0
  577. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-BUJID5UG.mjs +41 -0
  578. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-C44CZ5NI.mjs +24 -0
  579. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-EYOLEXXS.mjs +30 -0
  580. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-P7B6PWOJ.mjs +3 -0
  581. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ebnfDiagram-FTPZ3PV6.mjs +1 -0
  582. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/erDiagram-H3ERR26V.mjs +99 -0
  583. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/eventmodeling-NTZA5JFV-WKSWQHFS.mjs +1 -0
  584. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/flowDiagram-YHGXBVSY.mjs +1 -0
  585. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ganttDiagram-RWFTB7ED.mjs +292 -0
  586. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraph-4MIJSDKK-JH2HKYUO.mjs +1 -0
  587. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraphDiagram-MAR6GKOP.mjs +106 -0
  588. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/info-A6RAGUB7-3TX3OFWW.mjs +1 -0
  589. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/infoDiagram-LV547AFH.mjs +2 -0
  590. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ishikawaDiagram-PUJQGNDS.mjs +70 -0
  591. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/journeyDiagram-EW5QJT4W.mjs +139 -0
  592. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/kanban-definition-JSQERAZB.mjs +89 -0
  593. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/katex-CZ4GXH2S.mjs +257 -0
  594. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/mindmap-definition-VBJCLQLM.mjs +96 -0
  595. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/packet-AYTQ26CC-MKII6P3Y.mjs +1 -0
  596. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pegDiagram-7WILOQTJ.mjs +1 -0
  597. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pie-WAS4IAKB-6B4OPMJ5.mjs +1 -0
  598. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pieDiagram-EFA7CBSB.mjs +39 -0
  599. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/quadrantDiagram-WARVYA7P.mjs +7 -0
  600. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/radar-RG4KPBEZ-UPTR3XUL.mjs +1 -0
  601. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-74A4TZTK-MEFUPFMS.mjs +1 -0
  602. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-abnf-HS5TGJTU-R5YG2S5D.mjs +1 -0
  603. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-ebnf-LZEXJU2U-G5QEX2L6.mjs +1 -0
  604. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-peg-WCYAUIDC-H5I2ZRY2.mjs +1 -0
  605. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroadDiagram-5NIQVNLQ.mjs +1 -0
  606. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/requirementDiagram-SXREGOKZ.mjs +84 -0
  607. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sankeyDiagram-VV74M2VP.mjs +40 -0
  608. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sequenceDiagram-52ZFIFDL.mjs +162 -0
  609. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sizeCapture-FGA5AGYP.mjs +1 -0
  610. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-3QAKPIVI.mjs +1 -0
  611. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-v2-HN2P4RDZ.mjs +1 -0
  612. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanes-QLVP42QD.mjs +1 -0
  613. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanesDiagram-JKPDBFCN.mjs +8 -0
  614. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/timeline-definition-GS45XAXW.mjs +120 -0
  615. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treeView-Q6P3EWNA-ZRJGANNQ.mjs +1 -0
  616. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treemap-WGGIJYW6-K64VN5AS.mjs +1 -0
  617. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/vennDiagram-QIQU2ZRJ.mjs +34 -0
  618. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardley-WFR3VGLG-D67OWCCH.mjs +1 -0
  619. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardleyDiagram-U6YNM66N.mjs +78 -0
  620. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/xychartDiagram-XJAZEDNM.mjs +7 -0
  621. package/neural-interface/public/vendor/mermaid/manifest.json +4 -0
  622. package/neural-interface/public/vendor/mermaid/mermaid-11.17.2.esm.min.mjs +14 -0
  623. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  624. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  625. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  626. package/neural-interface/scripts/build-vendor.mjs +116 -3
  627. package/neural-interface/server.js +4834 -2541
  628. package/neural-interface/templates/rulesets/core.md +1 -1
  629. package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
  630. package/neural-interface/templates/rulesets/manifest.json +8 -8
  631. package/npm-shrinkwrap.json +18 -12
  632. package/package.json +16 -3
  633. package/postinstall.js +9 -4
  634. package/preuninstall.js +1 -1
  635. package/setup.js +97 -322
  636. package/skills/skill-forge/SKILL.md +177 -0
  637. package/skills/skill-forge/evals/evals.json +54 -0
  638. package/skills/skill-forge/references/package.md +105 -0
  639. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  640. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  641. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  642. package/skills/synabun/SKILL.md +10 -7
  643. package/skills/synabun/modules/audit.md +1 -5
  644. package/skills/synabun/modules/changelog.md +1 -5
  645. package/skills/synabun/modules/idea.md +1 -1
  646. package/skills/synabun/modules/memorize.md +6 -9
  647. package/skills/synabun/modules/schedule.md +5 -5
  648. package/mcp-server/dist/services/profiles.d.ts +0 -120
  649. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  650. package/mcp-server/dist/services/profiles.js +0 -387
  651. package/mcp-server/dist/services/profiles.js.map +0 -1
  652. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  653. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  654. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  655. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  656. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  657. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  658. package/mcp-server/dist/tools/leonardo.js +0 -21
  659. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  660. package/mcp-server/dist/tools/profile.d.ts +0 -17
  661. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  662. package/mcp-server/dist/tools/profile.js +0 -114
  663. package/mcp-server/dist/tools/profile.js.map +0 -1
  664. package/mcp-server/src/services/profiles.ts +0 -428
  665. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  666. package/mcp-server/src/tools/leonardo.ts +0 -30
  667. package/mcp-server/src/tools/profile.ts +0 -122
  668. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  669. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  670. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  671. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  672. package/skills/leonardo/SKILL.md +0 -168
  673. package/skills/leonardo/icon.svg +0 -1
  674. package/skills/leonardo/modules/browser-guide.md +0 -378
  675. package/skills/leonardo/modules/image-prompter.md +0 -283
  676. package/skills/leonardo/modules/model-advisor.md +0 -100
  677. package/skills/leonardo/modules/prompt-library.md +0 -110
  678. package/skills/leonardo/modules/style-guide.md +0 -186
  679. package/skills/leonardo/modules/video-prompter.md +0 -317
@@ -0,0 +1,796 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // OpenCode 2 client — the one client SynaBun speaks to `opencode serve` with.
3
+ //
4
+ // lib/opencode-v2-client.js (`connect`, `createClientInstance`) builds it for
5
+ // every serve. It has the groups and methods SynaBun calls (`session.prompt`,
6
+ // `global.event`, `permission.reply`, …) with the `{ data, error, response }`
7
+ // results SynaBun's consumers read, in the shapes they were written for
8
+ // (OpenCode 1's: lib/opencode2-translate.js). So the wrapper, and everything
9
+ // above it (the OpenCode panel, the Assistant's OpenCode brain, workers, loops,
10
+ // the usage meter), reads one set of shapes.
11
+ //
12
+ // What OpenCode 2's API needs:
13
+ // • HTTP Basic auth (user `opencode`, the launch's password) on every call;
14
+ // • the project folder as `location[directory]`;
15
+ // • a prompt carries no model, agent or system prompt: the session is switched
16
+ // to the model and agent first (only when they change), and a system prompt
17
+ // is the session's instruction entry `synabun-system`;
18
+ // • a prompt returns at once: the synchronous `session.prompt` waits on
19
+ // /api/experimental/session/:id/wait and then reads the reply, and so does
20
+ // `session.command` (a slash command only queues its prompt);
21
+ // • a permission or a question is answered under its session, which the
22
+ // event translator remembers (or the pending lists say).
23
+ // Things OpenCode 2 does not have answer with an empty list (todos, LSP,
24
+ // formatters, symbols) or an error that says so (share).
25
+ // ─────────────────────────────────────────────────────────────────────────────
26
+
27
+ import { basicAuthHeader } from './opencode-protocol.js';
28
+ import { opencodeMcpServerEntry } from './opencode-config.js';
29
+ import {
30
+ answersToForm,
31
+ createEventTranslator,
32
+ formToQuestionV1,
33
+ integrationEnvNames,
34
+ integrationsToAuthMethods,
35
+ messagesToV1,
36
+ modelRefToV2,
37
+ permissionToV1,
38
+ rulesToV1,
39
+ rulesToV2,
40
+ sessionToV1,
41
+ v2ToolName,
42
+ } from './opencode2-translate.js';
43
+
44
+ const SYSTEM_ENTRY = 'synabun-system';
45
+ const PAGE_LIMIT = 200;
46
+ const MAX_PAGES = 50;
47
+ const WAIT_TIMEOUT_MS = 30 * 60 * 1000;
48
+
49
+ const str = (v) => (typeof v === 'string' ? v : v == null ? '' : String(v));
50
+ const obj = (v) => (v && typeof v === 'object' && !Array.isArray(v) ? v : {});
51
+
52
+ function notSupported(what) {
53
+ const error = { _tag: 'NotSupportedError', message: `${what} is not available on OpenCode 2.` };
54
+ return { data: undefined, error, response: { status: 501, ok: false } };
55
+ }
56
+
57
+ /** A diff mode as OpenCode 1 names it ('git', 'branch') → OpenCode 2's (`working`, `branch`, `committed`). */
58
+ export function vcsModeToV2(mode) {
59
+ if (mode === 'branch' || mode === 'committed' || mode === 'working') return mode;
60
+ return 'working';
61
+ }
62
+
63
+ /**
64
+ * `baseUrl` of the serve and the launch's `password`. `version` is the serve's
65
+ * (sessions carry it), `fetchImpl` a fetch (tests pass a fixture's).
66
+ */
67
+ export function createOpencode2Client({ baseUrl, password, fetchImpl = globalThis.fetch, version = '' } = {}) {
68
+ if (!baseUrl) throw new Error('createOpencode2Client: baseUrl required');
69
+ const root = String(baseUrl).replace(/\/+$/, '');
70
+ const auth = password ? basicAuthHeader(password) : null;
71
+ const translator = createEventTranslator({ version });
72
+ // What each session was last switched to (model, agent, system prompt), so a
73
+ // prompt switches only what changed. `system` is undefined until this client
74
+ // has set or removed the session's entry: a session made by another client (a
75
+ // resumed one) may still hold the instructions of an earlier turn, so the
76
+ // first prompt here always says what it wants, an empty one included.
77
+ const sessionState = new Map();
78
+ const stateOf = (sessionID) => {
79
+ let state = sessionState.get(sessionID);
80
+ if (!state) { state = { model: null, agent: null, system: undefined }; sessionState.set(sessionID, state); }
81
+ return state;
82
+ };
83
+
84
+ function url(path, query) {
85
+ const search = new URLSearchParams();
86
+ for (const [key, value] of Object.entries(query || {})) {
87
+ if (value === undefined || value === null || value === '') continue;
88
+ search.append(key, String(value));
89
+ }
90
+ const qs = search.toString();
91
+ return `${root}${path}${qs ? `?${qs}` : ''}`;
92
+ }
93
+ const located = (directory, query = {}) => (directory ? { 'location[directory]': directory, ...query } : query);
94
+
95
+ /** One request → `{ data, error, response }`, like the SDK's (a network failure rejects). */
96
+ async function call(method, path, { query, body, signal, raw = false } = {}) {
97
+ const headers = { accept: raw ? '*/*' : 'application/json' };
98
+ if (auth) headers.authorization = auth;
99
+ if (body !== undefined) headers['content-type'] = 'application/json';
100
+ const res = await fetchImpl(url(path, query), {
101
+ method,
102
+ headers,
103
+ ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
104
+ ...(signal ? { signal } : {}),
105
+ });
106
+ const type = String(res.headers?.get?.('content-type') || '');
107
+ const response = { status: res.status, ok: res.ok, headers: res.headers };
108
+ if (res.status === 204) return { data: undefined, error: undefined, response };
109
+ if (raw && res.ok) return { data: await res.text(), error: undefined, response };
110
+ if (/text\/html/i.test(type)) {
111
+ // OpenCode 2 answers every path outside its API with its web app.
112
+ return { data: undefined, error: { _tag: 'NotOpencodeApiError', message: `OpenCode answered ${method} ${path} with a web page, not its API.` }, response: { ...response, ok: false, status: res.ok ? 502 : res.status } };
113
+ }
114
+ let parsed;
115
+ const text = await res.text();
116
+ try { parsed = text ? JSON.parse(text) : undefined; } catch { parsed = text; }
117
+ if (!res.ok) return { data: undefined, error: parsed ?? { message: `HTTP ${res.status}` }, response };
118
+ return { data: parsed, error: undefined, response };
119
+ }
120
+
121
+ /** `{ data }` with `data` mapped, errors passed through. */
122
+ const map = (result, fn) => (result.error ? result : { ...result, data: fn(result.data) });
123
+ /** The rows of an /api/integration answer (none when it failed: a provider list does not wait on it). */
124
+ const integrationRows = (result) => (result && !result.error && Array.isArray(result.data?.data) ? result.data.data : []);
125
+ const ok = (result, data) => (result.error ? result : { ...result, data });
126
+
127
+ // ── Sessions ──
128
+
129
+ const noteAll = (rows) => rows.map((info) => translator.noteSession(info));
130
+
131
+ async function listSessions({ directory, roots, search, limit, parentID, archived } = {}) {
132
+ const max = Number(limit) > 0 ? Number(limit) : Infinity;
133
+ const out = [];
134
+ let cursor = null;
135
+ let last = null;
136
+ for (let page = 0; page < MAX_PAGES && out.length < max; page++) {
137
+ // A cursor carries its own order and filters: OpenCode 2 refuses either next to one.
138
+ const query = cursor
139
+ ? { cursor, limit: String(Math.min(PAGE_LIMIT, Number.isFinite(max) ? max - out.length : PAGE_LIMIT)) }
140
+ : {
141
+ directory,
142
+ search,
143
+ limit: String(Math.min(PAGE_LIMIT, Number.isFinite(max) ? max - out.length : PAGE_LIMIT)),
144
+ order: 'desc',
145
+ ...(parentID ? { parentID } : (roots === true || roots === 'true' ? { parentID: 'null' } : {})),
146
+ // Archived sessions only (OpenCode lists live ones by default).
147
+ ...(archived === true ? { archived: 'true' } : {}),
148
+ };
149
+ last = await call('GET', '/api/session', { query });
150
+ if (last.error) return last;
151
+ const rows = Array.isArray(last.data?.data) ? last.data.data : [];
152
+ out.push(...rows);
153
+ cursor = last.data?.cursor?.next || null;
154
+ // OpenCode 2 hands out a next cursor even on the last page: a short page is the end.
155
+ if (!cursor || rows.length < Number(query.limit)) break;
156
+ }
157
+ const sessions = noteAll(out);
158
+ sessions.sort((a, b) => (b.time?.updated || 0) - (a.time?.updated || 0));
159
+ return { data: sessions, error: undefined, response: last?.response || { status: 200, ok: true } };
160
+ }
161
+
162
+ async function getSession(sessionID) {
163
+ return map(await call('GET', `/api/session/${encodeURIComponent(sessionID)}`), (body) => translator.noteSession(body?.data));
164
+ }
165
+
166
+ async function readMessages(sessionID, { limit } = {}) {
167
+ const items = [];
168
+ let cursor = null;
169
+ let last = null;
170
+ const max = Number(limit) > 0 ? Number(limit) : Infinity;
171
+ for (let page = 0; page < MAX_PAGES; page++) {
172
+ last = await call('GET', `/api/session/${encodeURIComponent(sessionID)}/message`, { query: cursor ? { cursor, limit: String(PAGE_LIMIT) } : { order: 'desc', limit: String(PAGE_LIMIT) } });
173
+ if (last.error) return last;
174
+ const rows = Array.isArray(last.data?.data) ? last.data.data : [];
175
+ items.push(...rows);
176
+ // A page is newest first; `next` walks back in time (and is there even on the last page).
177
+ cursor = last.data?.cursor?.next || null;
178
+ if (!cursor || rows.length < PAGE_LIMIT || items.length >= max * 4) break;
179
+ }
180
+ return { data: items, error: undefined, response: last?.response || { status: 200, ok: true } };
181
+ }
182
+
183
+ async function messagesV1(sessionID, { directory, limit } = {}) {
184
+ const read = await readMessages(sessionID, { limit });
185
+ if (read.error) return read;
186
+ const dir = directory || translator.sessionDirectory(sessionID);
187
+ let rows = messagesToV1(read.data, { sessionID, directory: dir });
188
+ if (Number(limit) > 0 && rows.length > Number(limit)) rows = rows.slice(-Number(limit));
189
+ return { ...read, data: rows };
190
+ }
191
+
192
+ /** Switch a session to the model / agent / system prompt a request names, when they differ from the last ones. */
193
+ async function prepare(sessionID, { model, variant, agent, system } = {}) {
194
+ const state = stateOf(sessionID);
195
+ const ref = modelRefToV2(model, variant);
196
+ if (ref) {
197
+ const key = `${ref.providerID}/${ref.id}#${ref.variant || ''}`;
198
+ if (state.model !== key) {
199
+ const switched = await call('POST', `/api/session/${encodeURIComponent(sessionID)}/model`, { body: { model: ref } });
200
+ if (switched.error) return switched;
201
+ state.model = key;
202
+ }
203
+ }
204
+ if (agent && state.agent !== agent) {
205
+ const switched = await call('POST', `/api/session/${encodeURIComponent(sessionID)}/agent`, { body: { agent: String(agent) } });
206
+ if (switched.error) return switched;
207
+ state.agent = String(agent);
208
+ }
209
+ const nextSystem = typeof system === 'string' ? system : '';
210
+ if (state.system !== nextSystem) {
211
+ const path = `/api/experimental/session/${encodeURIComponent(sessionID)}/instructions/entries/${SYSTEM_ENTRY}`;
212
+ const written = nextSystem
213
+ ? await call('PUT', path, { body: { value: nextSystem } })
214
+ : await call('DELETE', path);
215
+ // Only an entry that is not there may fail to go: any other failure would
216
+ // run the turn under instructions it did not ask for.
217
+ if (written.error && (nextSystem || written.response?.status !== 404)) return written;
218
+ state.system = nextSystem;
219
+ }
220
+ return null;
221
+ }
222
+
223
+ /**
224
+ * OpenCode 1 prompt parts → OpenCode 2's prompt body, and the synthetic text
225
+ * parts (context for the model the transcript never draws, like the
226
+ * greeting's note), which OpenCode 2 takes as synthetic messages.
227
+ */
228
+ function promptBody({ parts, messageID, format } = {}) {
229
+ const texts = [];
230
+ const files = [];
231
+ const agents = [];
232
+ const synthetic = [];
233
+ for (const part of Array.isArray(parts) ? parts : []) {
234
+ if (!part || typeof part !== 'object') continue;
235
+ if (part.type === 'text' && typeof part.text === 'string' && part.synthetic === true) synthetic.push(part.text);
236
+ else if (part.type === 'text' && typeof part.text === 'string') texts.push(part.text);
237
+ else if (part.type === 'file' && part.url) files.push({ uri: str(part.url), ...(part.filename ? { name: str(part.filename) } : {}) });
238
+ else if (part.type === 'agent' && part.name) agents.push({ name: str(part.name) });
239
+ else if (part.type === 'subtask' && part.prompt) texts.push(str(part.prompt));
240
+ }
241
+ // OpenCode 2 has no structured-output mode: the schema becomes an instruction.
242
+ if (format?.type === 'json_schema' && format.schema) {
243
+ texts.push(`Reply with only a JSON value that matches this JSON schema, and nothing else:\n${JSON.stringify(format.schema)}`);
244
+ }
245
+ const body = { text: texts.join('\n\n') };
246
+ if (files.length) body.files = files;
247
+ if (agents.length) body.agents = agents;
248
+ if (messageID && /^msg_/.test(String(messageID))) body.id = String(messageID);
249
+ return { body, synthetic };
250
+ }
251
+
252
+ /** Send a prompt; resolves the SDK-shaped result and, when one was queued, the time OpenCode queued it. */
253
+ async function sendPrompt(params = {}, options = {}) {
254
+ const { sessionID, model, variant, agent, system, noReply } = params;
255
+ if (!sessionID) return { result: { data: undefined, error: { message: 'sessionID required' }, response: { status: 400, ok: false } } };
256
+ const failed = await prepare(sessionID, { model, variant, agent, system });
257
+ if (failed) return { result: failed };
258
+ const { body, synthetic } = promptBody(params);
259
+ const base = `/api/session/${encodeURIComponent(sessionID)}`;
260
+ // Context first (it must not start a turn of its own), then the prompt.
261
+ for (const text of noReply === true ? [...synthetic, body.text] : synthetic) {
262
+ if (!text) continue;
263
+ const added = await call('POST', `${base}/synthetic`, { body: { text, resume: false }, signal: options?.signal });
264
+ if (added.error) return { result: added };
265
+ }
266
+ if (noReply === true) return { result: { data: undefined, error: undefined, response: { status: 204, ok: true } } };
267
+ const sent = await call('POST', `${base}/prompt`, { body, signal: options?.signal });
268
+ if (sent.error) return { result: sent };
269
+ return {
270
+ result: { data: undefined, error: undefined, response: { ...sent.response, status: 204 } },
271
+ queuedAt: Number(sent.data?.data?.time?.created) || null,
272
+ };
273
+ }
274
+
275
+ async function promptAsync(params = {}, options = {}) {
276
+ return (await sendPrompt(params, options)).result;
277
+ }
278
+
279
+ /**
280
+ * Wait until the turn of something queued at `since` (or later) is over: an
281
+ * error result, or null. /wait answers once the session is idle, which may be
282
+ * before a prompt queued a moment ago has started, so the session must have
283
+ * gone idle since then. `quietEnds`: nothing queued and nothing running after
284
+ * `since` is the end too (a slash command that queued no prompt).
285
+ */
286
+ async function waitForTurn(sessionID, { since, signal, directory, quietEnds = false } = {}) {
287
+ const base = `/api/session/${encodeURIComponent(sessionID)}`;
288
+ for (let round = 0; round < 1000; round++) {
289
+ const waited = await call('POST', `/api/experimental/session/${encodeURIComponent(sessionID)}/wait`, { signal });
290
+ if (waited.error) return waited;
291
+ if (!since) return null;
292
+ const info = await call('GET', base, { signal });
293
+ if (info.error) return info;
294
+ if (Number(info.data?.data?.time?.idle) >= since) return null;
295
+ if (quietEnds) {
296
+ const [queued, active] = await Promise.all([
297
+ call('GET', `${base}/inbox`, { signal }),
298
+ call('GET', '/api/session/active', { query: located(directory || translator.sessionDirectory(sessionID)), signal }),
299
+ ]);
300
+ const pending = Array.isArray(queued.data?.data) && queued.data.data.length > 0;
301
+ if (!queued.error && !active.error && !pending && !obj(active.data?.data)[sessionID]) return null;
302
+ }
303
+ await new Promise((resolveWait) => setTimeout(resolveWait, 200));
304
+ }
305
+ return null;
306
+ }
307
+
308
+ /**
309
+ * The assistant message a turn begun at `before` ended with, as `{ data: { info, parts } }`. `latest`: when
310
+ * the turn left none, the session's last assistant message (a command that queued nothing answers with none).
311
+ */
312
+ async function replyOf(sessionID, { directory, before, latest = true }) {
313
+ const transcript = await messagesV1(sessionID, { directory, limit: 50 });
314
+ if (transcript.error) return transcript;
315
+ const rows = transcript.data;
316
+ let reply = null;
317
+ for (let i = rows.length - 1; i >= 0; i--) {
318
+ if (rows[i].info.role === 'assistant' && (rows[i].info.time?.created || 0) >= before - 1000) { reply = rows[i]; break; }
319
+ if (rows[i].info.role === 'user') break;
320
+ }
321
+ if (!reply && latest) reply = rows.filter((row) => row.info.role === 'assistant').pop() || null;
322
+ // A turn of several steps answers with its last step, which holds the final text.
323
+ return { data: reply || { info: null, parts: [] }, error: undefined, response: { status: 200, ok: true } };
324
+ }
325
+
326
+ async function prompt(params = {}, options = {}) {
327
+ const { sessionID } = params;
328
+ const before = Date.now();
329
+ const { result: sent, queuedAt } = await sendPrompt(params, options);
330
+ if (sent.error) return sent;
331
+ if (params.noReply === true) return { data: { info: null, parts: [] }, error: undefined, response: { status: 200, ok: true } };
332
+ const signal = options?.signal || AbortSignal.timeout(WAIT_TIMEOUT_MS);
333
+ const failed = await waitForTurn(sessionID, { since: queuedAt, signal });
334
+ if (failed) return failed;
335
+ return replyOf(sessionID, { directory: params.directory, before });
336
+ }
337
+
338
+ /**
339
+ * A slash command (/review, /init, a skill, an MCP prompt). OpenCode 1
340
+ * answered when the command's turn was over; OpenCode 2 answers as soon as
341
+ * the command has queued its prompt, so the turn is waited for here (a stop
342
+ * ends it; `options.signal` gives up waiting). The command's attachments
343
+ * (screenshots, files, @ mentions) go as OpenCode 2's prompt fields, which
344
+ * the command's prompt carries.
345
+ */
346
+ async function runCommand({ sessionID, command, arguments: args, agent, model, variant, parts, directory } = {}, options = {}) {
347
+ const failed = await prepare(sessionID, { model, variant, agent });
348
+ if (failed) return failed;
349
+ const { body: attached } = promptBody({ parts });
350
+ const body = { name: String(command || ''), text: String(args || '') };
351
+ if (attached.files) body.files = attached.files;
352
+ if (attached.agents) body.agents = attached.agents;
353
+ const signal = options?.signal || AbortSignal.timeout(WAIT_TIMEOUT_MS);
354
+ const before = Date.now();
355
+ const sent = await call('POST', `/api/session/${encodeURIComponent(sessionID)}/command`, { body, signal });
356
+ if (sent.error) return sent;
357
+ const waited = await waitForTurn(sessionID, { since: before, signal, directory, quietEnds: true });
358
+ if (waited) return waited;
359
+ return replyOf(sessionID, { directory, before, latest: false });
360
+ }
361
+
362
+ // ── Events ──
363
+
364
+ /** `global.event()`: OpenCode 2's /api/event, translated, as `{ stream }` of `{ directory, payload }`. */
365
+ async function globalEvent(options = {}) {
366
+ const headers = { accept: 'text/event-stream' };
367
+ if (auth) headers.authorization = auth;
368
+ const res = await fetchImpl(url('/api/event'), { headers, ...(options?.signal ? { signal: options.signal } : {}) });
369
+ const type = String(res.headers?.get?.('content-type') || '');
370
+ if (!res.ok || !/text\/event-stream/i.test(type)) {
371
+ try { await res.body?.cancel?.(); } catch { /* nothing to release */ }
372
+ const why = res.status === 401 ? 'OpenCode 2 refused the password' : (/text\/html/i.test(type) ? 'OpenCode answered with a web page' : `HTTP ${res.status}`);
373
+ throw new Error(`OpenCode 2 event stream did not open: ${why}`);
374
+ }
375
+ const reader = res.body.getReader();
376
+ const decoder = new TextDecoder();
377
+ async function* stream() {
378
+ let buffer = '';
379
+ try {
380
+ while (true) {
381
+ const { value, done } = await reader.read();
382
+ if (done) break;
383
+ buffer += decoder.decode(value, { stream: true });
384
+ let cut;
385
+ while ((cut = buffer.search(/\r?\n\r?\n/)) >= 0) {
386
+ const frame = buffer.slice(0, cut);
387
+ buffer = buffer.slice(cut).replace(/^\r?\n\r?\n/, '');
388
+ const data = frame.split(/\r?\n/).filter((line) => line.startsWith('data:')).map((line) => line.slice(5).replace(/^ /, '')).join('\n');
389
+ if (!data) continue;
390
+ let event;
391
+ try { event = JSON.parse(data); } catch { continue; }
392
+ for (const translated of translator.translate(event)) yield translated;
393
+ }
394
+ }
395
+ } finally {
396
+ try { reader.releaseLock(); } catch { /* already released */ }
397
+ }
398
+ }
399
+ return { stream: stream() };
400
+ }
401
+
402
+ // ── Asks ──
403
+
404
+ async function permissionSessionOf(requestID, directory) {
405
+ const known = translator.permissionSession(requestID);
406
+ if (known) return known;
407
+ const listed = await call('GET', '/api/permission/request', { query: located(directory) });
408
+ const found = (Array.isArray(listed.data?.data) ? listed.data.data : []).find((row) => row?.id === requestID);
409
+ if (found?.sessionID) translator.notePermission(requestID, found.sessionID);
410
+ return found?.sessionID || null;
411
+ }
412
+
413
+ async function formOf(requestID, directory) {
414
+ const known = translator.form(requestID);
415
+ if (known) return known;
416
+ const listed = await call('GET', '/api/form', { query: located(directory) });
417
+ const found = (Array.isArray(listed.data?.data) ? listed.data.data : []).find((row) => row?.id === requestID);
418
+ if (found) translator.noteForm(found);
419
+ return found || null;
420
+ }
421
+
422
+ // ── Providers and models ──
423
+
424
+ function modelToV1(model) {
425
+ const caps = obj(model.capabilities);
426
+ const input = Array.isArray(caps.input) ? caps.input : ['text'];
427
+ const output = Array.isArray(caps.output) ? caps.output : ['text'];
428
+ const cost = (Array.isArray(model.cost) ? model.cost : []).find((c) => !c?.tier) || (Array.isArray(model.cost) ? model.cost[0] : null) || {};
429
+ const variants = {};
430
+ for (const variant of Array.isArray(model.variants) ? model.variants : []) {
431
+ if (variant?.id) variants[variant.id] = { ...obj(variant.settings) };
432
+ }
433
+ const flags = (list) => ({ text: list.includes('text'), audio: list.includes('audio'), image: list.includes('image'), video: list.includes('video'), pdf: list.includes('pdf') });
434
+ const out = {
435
+ id: str(model.id),
436
+ providerID: str(model.providerID),
437
+ api: { id: str(model.modelID || model.id), url: str(model.settings?.baseURL), npm: str(model.package) },
438
+ name: str(model.name || model.id),
439
+ ...(model.family ? { family: str(model.family) } : {}),
440
+ capabilities: {
441
+ temperature: caps.temperature !== false,
442
+ reasoning: !!(model.compatibility?.reasoningField || (Array.isArray(model.variants) && model.variants.length)),
443
+ attachment: input.some((kind) => kind !== 'text'),
444
+ toolcall: caps.tools !== false,
445
+ input: flags(input),
446
+ output: flags(output),
447
+ interleaved: false,
448
+ },
449
+ cost: { input: Number(cost.input) || 0, output: Number(cost.output) || 0, cache: { read: Number(cost.cache?.read) || 0, write: Number(cost.cache?.write) || 0 } },
450
+ limit: { context: Number(model.limit?.context) || 0, ...(model.limit?.input ? { input: Number(model.limit.input) } : {}), output: Number(model.limit?.output) || 0 },
451
+ status: str(model.status) || 'active',
452
+ options: {},
453
+ headers: obj(model.headers),
454
+ release_date: model.time?.released ? new Date(Number(model.time.released)).toISOString().slice(0, 10) : '',
455
+ };
456
+ if (Object.keys(variants).length) out.variants = variants;
457
+ return out;
458
+ }
459
+
460
+ /**
461
+ * The provider list SynaBun reads (`{ all, connected, defaults }`) from OpenCode 2's providers, enabled models,
462
+ * default model and integrations: every integration a provider can be connected through is in `all` (with the
463
+ * variables it reads its key from), the ones with models are `connected`.
464
+ */
465
+ async function providerCatalog(directory) {
466
+ const [providers, models, fallback, integrations] = await Promise.all([
467
+ call('GET', '/api/provider', { query: located(directory) }),
468
+ call('GET', '/api/model', { query: located(directory) }),
469
+ call('GET', '/api/model/default', { query: located(directory) }),
470
+ call('GET', '/api/integration', { query: located(directory) }),
471
+ ]);
472
+ if (providers.error) return { error: providers.error, response: providers.response };
473
+ if (models.error) return { error: models.error, response: models.response };
474
+ const envOf = new Map();
475
+ for (const integration of integrationRows(integrations)) {
476
+ envOf.set(str(integration.id), integrationEnvNames(integration));
477
+ }
478
+ const byProvider = new Map();
479
+ for (const provider of Array.isArray(providers.data?.data) ? providers.data.data : []) {
480
+ byProvider.set(provider.id, {
481
+ id: str(provider.id),
482
+ name: str(provider.name || provider.id),
483
+ source: provider.activation === 'enabled' ? 'config' : 'api',
484
+ env: envOf.get(str(provider.integrationID || provider.id)) || [],
485
+ options: {},
486
+ models: {},
487
+ });
488
+ }
489
+ for (const integration of integrationRows(integrations)) {
490
+ const id = str(integration.id);
491
+ if (!id || byProvider.has(id)) continue;
492
+ byProvider.set(id, { id, name: str(integration.name || id), source: 'api', env: envOf.get(id) || [], options: {}, models: {} });
493
+ }
494
+ for (const model of Array.isArray(models.data?.data) ? models.data.data : []) {
495
+ if (!model?.id || !model.providerID || model.enabled === false) continue;
496
+ let provider = byProvider.get(model.providerID);
497
+ if (!provider) {
498
+ provider = { id: str(model.providerID), name: str(model.providerID), source: 'api', env: [], options: {}, models: {} };
499
+ byProvider.set(model.providerID, provider);
500
+ }
501
+ provider.models[model.id] = modelToV1(model);
502
+ }
503
+ const all = [...byProvider.values()];
504
+ const connected = all.filter((provider) => Object.keys(provider.models).length).map((provider) => provider.id);
505
+ const defaults = {};
506
+ const fallbackModel = fallback.data?.data;
507
+ if (fallbackModel?.providerID && fallbackModel?.id) defaults[fallbackModel.providerID] = fallbackModel.id;
508
+ for (const provider of all) {
509
+ if (!defaults[provider.id]) {
510
+ const first = Object.keys(provider.models)[0];
511
+ if (first) defaults[provider.id] = first;
512
+ }
513
+ }
514
+ return { all, connected, defaults, response: providers.response };
515
+ }
516
+
517
+ // ── The SDK-shaped client ──
518
+
519
+ const session = {
520
+ list: (p = {}) => listSessions(p),
521
+ create: async (p = {}) => {
522
+ const body = {
523
+ ...(p.directory ? { location: { directory: String(p.directory) } } : {}),
524
+ ...(p.parentID ? { parentID: String(p.parentID) } : {}),
525
+ ...(p.title ? { title: String(p.title) } : {}),
526
+ ...(p.agent ? { agent: String(p.agent) } : {}),
527
+ ...(p.model ? { model: modelRefToV2(p.model.id ? { providerID: p.model.providerID, modelID: p.model.id, variant: p.model.variant } : p.model) } : {}),
528
+ ...(p.metadata ? { metadata: p.metadata } : {}),
529
+ };
530
+ const rules = rulesToV2(p.permission);
531
+ if (rules && rules.length) body.permissions = rules;
532
+ if (body.model === null) delete body.model;
533
+ const created = await call('POST', '/api/session', { body });
534
+ return map(created, (res) => {
535
+ const info = translator.noteSession(res?.data);
536
+ if (info?.id) {
537
+ // A new session holds no instruction entry of SynaBun's.
538
+ stateOf(info.id).system = '';
539
+ if (body.agent) stateOf(info.id).agent = body.agent;
540
+ }
541
+ return info;
542
+ });
543
+ },
544
+ get: ({ sessionID } = {}) => getSession(sessionID),
545
+ update: async ({ sessionID, title, permission, metadata, time } = {}) => {
546
+ const body = {};
547
+ if (typeof title === 'string') body.title = title;
548
+ if (metadata && typeof metadata === 'object') body.metadata = metadata;
549
+ const rules = rulesToV2(permission);
550
+ if (rules) body.permissions = rules;
551
+ // Archiving: `archived: true | false` (OpenCode 1's `time.archived`, a time or 0 to bring a session back).
552
+ // 2.1.4 does it; 2.0.32 answers the same request 204 and keeps the session as it was, so the session is read
553
+ // back and an archive that did not happen is refused with a sentence, never a silent success.
554
+ const archive = time && typeof time === 'object' && 'archived' in time ? Boolean(Number(time.archived)) : null;
555
+ if (archive !== null) body.archived = archive;
556
+ const patched = await call('PATCH', `/api/session/${encodeURIComponent(sessionID)}`, { body });
557
+ if (patched.error) return patched;
558
+ const read = await getSession(sessionID);
559
+ if (archive !== null && !read.error && Boolean(read.data?.time?.archived) !== archive) {
560
+ const error = { _tag: 'NotSupportedError', message: `This OpenCode answered without ${archive ? 'archiving' : 'unarchiving'} the session: it needs a newer OpenCode 2 (run: opencode upgrade).` };
561
+ return { data: undefined, error, response: { status: 501, ok: false } };
562
+ }
563
+ return read;
564
+ },
565
+ delete: async ({ sessionID } = {}) => {
566
+ const removed = await call('DELETE', `/api/session/${encodeURIComponent(sessionID)}`);
567
+ if (!removed.error) sessionState.delete(sessionID);
568
+ return ok(removed, true);
569
+ },
570
+ abort: async ({ sessionID } = {}) => map(await call('POST', `/api/session/${encodeURIComponent(sessionID)}/interrupt`), (body) => body?.interrupted !== false),
571
+ messages: ({ sessionID, directory, limit } = {}) => messagesV1(sessionID, { directory, limit }),
572
+ message: async ({ sessionID, messageID, directory } = {}) => {
573
+ const read = await call('GET', `/api/session/${encodeURIComponent(sessionID)}/message/${encodeURIComponent(messageID)}`);
574
+ return map(read, (body) => messagesToV1([body?.data].filter(Boolean), { sessionID, directory: directory || translator.sessionDirectory(sessionID) })[0] || null);
575
+ },
576
+ prompt: (p, o) => prompt(p, o),
577
+ promptAsync: (p, o) => promptAsync(p, o),
578
+ status: async ({ directory } = {}) => {
579
+ const active = await call('GET', '/api/session/active', { query: located(directory) });
580
+ return map(active, (body) => {
581
+ const out = {};
582
+ for (const [id, status] of Object.entries(obj(body?.data))) out[id] = status?.type === 'running' ? { type: 'busy' } : { type: 'idle' };
583
+ return out;
584
+ });
585
+ },
586
+ children: ({ sessionID, directory } = {}) => listSessions({ parentID: sessionID, directory }),
587
+ todo: async () => ({ data: [], error: undefined, response: { status: 200, ok: true } }),
588
+ diff: async ({ sessionID, messageID } = {}) => {
589
+ const diff = await call('GET', `/api/session/${encodeURIComponent(sessionID)}/diff`, { query: messageID ? { from: messageID } : {} });
590
+ return map(diff, (body) => (Array.isArray(body?.data) ? body.data : []).map((row) => ({ file: str(row.file), patch: str(row.patch), additions: Number(row.additions) || 0, deletions: Number(row.deletions) || 0, status: row.status })));
591
+ },
592
+ fork: async ({ sessionID, messageID } = {}) => map(await call('POST', `/api/session/${encodeURIComponent(sessionID)}/fork`, { body: messageID ? { before: messageID } : {} }), (body) => translator.noteSession(body?.data)),
593
+ revert: async ({ sessionID, messageID } = {}) => {
594
+ const staged = await call('POST', `/api/session/${encodeURIComponent(sessionID)}/revert/stage`, { body: { messageID, files: true } });
595
+ if (staged.error) return staged;
596
+ return getSession(sessionID);
597
+ },
598
+ unrevert: async ({ sessionID } = {}) => {
599
+ const cleared = await call('DELETE', `/api/session/${encodeURIComponent(sessionID)}/revert`);
600
+ if (cleared.error) return cleared;
601
+ return getSession(sessionID);
602
+ },
603
+ summarize: async ({ sessionID } = {}) => ok(await call('POST', `/api/session/${encodeURIComponent(sessionID)}/compact`, { body: {} }), true),
604
+ init: async ({ sessionID } = {}) => ok(await call('POST', `/api/session/${encodeURIComponent(sessionID)}/command`, { body: { name: 'init', text: '' } }), true),
605
+ command: (p, o) => runCommand(p, o),
606
+ shell: async ({ sessionID, command, agent, model } = {}) => {
607
+ const failed = await prepare(sessionID, { model, agent });
608
+ if (failed) return failed;
609
+ return ok(await call('POST', `/api/session/${encodeURIComponent(sessionID)}/shell`, { body: { command: String(command || '') } }), { info: null, parts: [] });
610
+ },
611
+ };
612
+
613
+ const client = {
614
+ global: {
615
+ event: globalEvent,
616
+ health: async () => map(await call('GET', '/api/info'), (body) => ({ healthy: true, version: str(body?.version) })),
617
+ },
618
+ event: { subscribe: globalEvent },
619
+ session,
620
+ v2: {
621
+ session: {
622
+ compact: async ({ sessionID } = {}) => ok(await call('POST', `/api/session/${encodeURIComponent(sessionID)}/compact`, { body: {} }), true),
623
+ context: async ({ sessionID, directory } = {}) => {
624
+ const read = await call('GET', `/api/session/${encodeURIComponent(sessionID)}/context`);
625
+ return map(read, (body) => messagesToV1(Array.isArray(body?.data) ? body.data : [], { sessionID, directory: directory || translator.sessionDirectory(sessionID) }));
626
+ },
627
+ },
628
+ },
629
+ permission: {
630
+ list: async ({ directory } = {}) => map(await call('GET', '/api/permission/request', { query: located(directory) }), (body) => (Array.isArray(body?.data) ? body.data : []).filter((row) => row?.id).map((row) => {
631
+ translator.notePermission(row.id, row.sessionID);
632
+ return permissionToV1(row);
633
+ })),
634
+ reply: async ({ requestID, reply, message, directory } = {}) => {
635
+ const sessionID = await permissionSessionOf(requestID, directory);
636
+ if (!sessionID) return { data: undefined, error: { _tag: 'PermissionNotFoundError', message: `No pending OpenCode permission ${requestID}.` }, response: { status: 404, ok: false } };
637
+ const decision = ['once', 'always', 'reject'].includes(reply) ? reply : 'reject';
638
+ return ok(await call('POST', `/api/session/${encodeURIComponent(sessionID)}/permission/${encodeURIComponent(requestID)}/reply`, { body: { decision, ...(message ? { message: String(message) } : {}) } }), true);
639
+ },
640
+ },
641
+ question: {
642
+ list: async ({ directory } = {}) => map(await call('GET', '/api/form', { query: located(directory) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((form) => {
643
+ const question = formToQuestionV1(form);
644
+ if (question) translator.noteForm(form);
645
+ return question;
646
+ }).filter(Boolean)),
647
+ reply: async ({ requestID, answers, directory } = {}) => {
648
+ const form = await formOf(requestID, directory);
649
+ if (!form) return { data: undefined, error: { _tag: 'QuestionNotFoundError', message: `No pending OpenCode question ${requestID}.` }, response: { status: 404, ok: false } };
650
+ return ok(await call('POST', `/api/session/${encodeURIComponent(form.sessionID)}/form/${encodeURIComponent(requestID)}/reply`, { body: { answer: answersToForm(form, answers) } }), true);
651
+ },
652
+ reject: async ({ requestID, directory } = {}) => {
653
+ const form = await formOf(requestID, directory);
654
+ if (!form) return { data: undefined, error: { _tag: 'QuestionNotFoundError', message: `No pending OpenCode question ${requestID}.` }, response: { status: 404, ok: false } };
655
+ return ok(await call('DELETE', `/api/session/${encodeURIComponent(form.sessionID)}/form/${encodeURIComponent(requestID)}`), true);
656
+ },
657
+ },
658
+ mcp: {
659
+ status: async ({ directory } = {}) => map(await call('GET', '/api/mcp', { query: located(directory) }), (body) => {
660
+ const out = {};
661
+ for (const server of Array.isArray(body?.data) ? body.data : []) {
662
+ if (!server?.name) continue;
663
+ const status = obj(server.status);
664
+ out[server.name] = { status: str(status.status) || 'failed', ...(status.error ? { error: str(status.error) } : {}) };
665
+ }
666
+ return out;
667
+ }),
668
+ connect: async ({ name, directory } = {}) => ok(await call('POST', `/api/experimental/mcp/${encodeURIComponent(name)}/connect`, { query: located(directory) }), true),
669
+ disconnect: async ({ name, directory } = {}) => ok(await call('POST', `/api/experimental/mcp/${encodeURIComponent(name)}/disconnect`, { query: located(directory) }), true),
670
+ add: async ({ name, config, directory } = {}) => {
671
+ // OpenCode 2's MCP server entry, whatever SynaBun described (lib/opencode-config.js).
672
+ const server = opencodeMcpServerEntry(obj(config));
673
+ const added = await call('PUT', `/api/experimental/mcp/${encodeURIComponent(name)}`, { query: located(directory), body: { config: server } });
674
+ if (added.error) return added;
675
+ return client.mcp.status({ directory });
676
+ },
677
+ },
678
+ command: {
679
+ list: async ({ directory } = {}) => map(await call('GET', '/api/command', { query: located(directory) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((command) => ({ name: str(command.name), ...(command.description ? { description: str(command.description) } : {}), source: 'command', template: '', hints: [] }))),
680
+ },
681
+ app: {
682
+ agents: async ({ directory } = {}) => map(await call('GET', '/api/agent', { query: located(directory) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((agent) => ({
683
+ name: str(agent.id || agent.name),
684
+ ...(agent.description ? { description: str(agent.description) } : {}),
685
+ mode: str(agent.mode) || 'all',
686
+ hidden: agent.hidden === true,
687
+ ...(agent.color ? { color: str(agent.color) } : {}),
688
+ permission: rulesToV1(agent.permissions) || [],
689
+ ...(agent.model?.id ? { model: { providerID: str(agent.model.providerID), modelID: str(agent.model.id) } } : {}),
690
+ ...(agent.model?.variant ? { variant: str(agent.model.variant) } : {}),
691
+ ...(agent.system ? { prompt: str(agent.system) } : {}),
692
+ ...(agent.steps ? { steps: Number(agent.steps) } : {}),
693
+ options: {},
694
+ }))),
695
+ skills: async ({ directory } = {}) => map(await call('GET', '/api/skill', { query: located(directory) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((skill) => ({ name: str(skill.name), description: str(skill.description), location: str(skill.path), content: str(skill.content) }))),
696
+ },
697
+ config: {
698
+ get: async ({ directory } = {}) => map(await call('GET', '/api/config', { query: located(directory) }), (body) => {
699
+ // OpenCode 2 lists the config documents it read; their merge is the config.
700
+ const merged = {};
701
+ for (const entry of Array.isArray(body) ? body : (Array.isArray(body?.data) ? body.data : [])) {
702
+ if (entry?.type !== 'document' || !entry.info) continue;
703
+ const info = entry.info;
704
+ if (info.model) merged.model = typeof info.model === 'string' ? info.model : `${info.model.providerID}/${info.model.model}`;
705
+ if (info.default_agent) merged.default_agent = info.default_agent;
706
+ if (info.agents) merged.agent = { ...(merged.agent || {}), ...Object.fromEntries(Object.entries(info.agents).map(([name, agent]) => [name, { ...agent, ...(agent.system ? { prompt: agent.system } : {}) }])) };
707
+ if (info.mcp?.servers) merged.mcp = { ...(merged.mcp || {}), ...info.mcp.servers };
708
+ if (info.permissions) merged.permission = rulesToV1(info.permissions);
709
+ if (Array.isArray(info.plugins)) merged.plugin = info.plugins.map((p) => (typeof p === 'string' ? p : p.package));
710
+ if (info.providers) merged.provider = { ...(merged.provider || {}), ...info.providers };
711
+ }
712
+ return merged;
713
+ }),
714
+ providers: async ({ directory } = {}) => {
715
+ const catalog = await providerCatalog(directory);
716
+ if (catalog.error) return { data: undefined, error: catalog.error, response: catalog.response };
717
+ return { data: { providers: catalog.all.filter((p) => Object.keys(p.models).length), default: catalog.defaults }, error: undefined, response: catalog.response };
718
+ },
719
+ },
720
+ provider: {
721
+ list: async ({ directory } = {}) => {
722
+ const catalog = await providerCatalog(directory);
723
+ if (catalog.error) return { data: undefined, error: catalog.error, response: catalog.response };
724
+ return { data: { all: catalog.all, default: catalog.defaults, connected: catalog.connected }, error: undefined, response: catalog.response };
725
+ },
726
+ // How each provider is connected (OpenCode 1's shape: { [id]: [{ type: 'api' | 'oauth', label, id }] }).
727
+ auth: async ({ directory } = {}) => map(await call('GET', '/api/integration', { query: located(directory) }), (body) => integrationsToAuthMethods(Array.isArray(body?.data) ? body.data : [])),
728
+ },
729
+ // OpenCode 2's integrations (how a provider is connected) and the credentials they stored. Secrets never come
730
+ // back from here: an integration's `connections` name a credential, never its value.
731
+ integration: {
732
+ list: async ({ directory } = {}) => map(await call('GET', '/api/integration', { query: located(directory) }), (body) => (Array.isArray(body?.data) ? body.data : [])),
733
+ connectKey: async ({ integrationID, key, label, answer, directory } = {}) => ok(await call('POST', `/api/integration/${encodeURIComponent(integrationID)}/connect/key`, {
734
+ query: located(directory),
735
+ body: { key: str(key), ...(label ? { label: str(label) } : {}), ...(answer && typeof answer === 'object' ? { answer } : {}) },
736
+ }), true),
737
+ connectOAuth: async ({ integrationID, methodID, answer, directory } = {}) => map(await call('POST', `/api/integration/${encodeURIComponent(integrationID)}/connect/oauth`, {
738
+ query: located(directory),
739
+ body: { methodID: str(methodID), ...(answer && typeof answer === 'object' ? { answer } : {}) },
740
+ }), (body) => obj(body?.data)),
741
+ oauthStatus: async ({ integrationID, attemptID, directory } = {}) => map(await call('GET', `/api/integration/${encodeURIComponent(integrationID)}/connect/oauth/${encodeURIComponent(attemptID)}`, { query: located(directory) }), (body) => obj(body?.data)),
742
+ oauthComplete: async ({ integrationID, attemptID, code, directory } = {}) => ok(await call('POST', `/api/integration/${encodeURIComponent(integrationID)}/connect/oauth/${encodeURIComponent(attemptID)}/complete`, {
743
+ query: located(directory),
744
+ body: { code: code == null ? null : str(code) },
745
+ }), true),
746
+ },
747
+ credential: {
748
+ remove: async ({ credentialID } = {}) => ok(await call('DELETE', `/api/credential/${encodeURIComponent(credentialID)}`), true),
749
+ },
750
+ find: {
751
+ files: async ({ query, directory, limit, type } = {}) => map(await call('GET', '/api/fs/find', { query: located(directory, { query: str(query), ...(type ? { type } : { type: 'file' }), ...(limit ? { limit: String(limit) } : {}) }) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((entry) => str(entry?.path || entry?.name || entry))),
752
+ text: async () => ({ data: [], error: undefined, response: { status: 200, ok: true } }),
753
+ symbols: async () => ({ data: [], error: undefined, response: { status: 200, ok: true } }),
754
+ },
755
+ file: {
756
+ list: async ({ path, directory } = {}) => map(await call('GET', '/api/fs/list', { query: located(directory, { path }) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((entry) => ({
757
+ name: str(entry.name),
758
+ path: str(entry.path || entry.name),
759
+ absolute: str(entry.absolute || entry.path),
760
+ type: entry.type === 'directory' ? 'directory' : 'file',
761
+ ignored: entry.ignored === true,
762
+ }))),
763
+ read: async ({ path, directory } = {}) => {
764
+ const safe = String(path || '').split('/').map(encodeURIComponent).join('/');
765
+ return map(await call('GET', `/api/fs/read/${safe}`, { query: located(directory), raw: true }), (content) => ({ type: 'text', content: str(content) }));
766
+ },
767
+ status: async ({ directory } = {}) => map(await call('GET', '/api/vcs/status', { query: located(directory) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((row) => ({ path: str(row.file || row.path), added: Number(row.additions) || 0, removed: Number(row.deletions) || 0, status: row.status || 'modified' }))),
768
+ },
769
+ vcs: {
770
+ get: async ({ directory } = {}) => map(await call('GET', '/api/vcs', { query: located(directory) }), (body) => {
771
+ const branch = body?.data?.branch;
772
+ return { branch: typeof branch === 'string' ? branch : str(branch?.name) };
773
+ }),
774
+ status: async ({ directory } = {}) => map(await call('GET', '/api/vcs/status', { query: located(directory) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((row) => ({ file: str(row.file || row.path), additions: Number(row.additions) || 0, deletions: Number(row.deletions) || 0, status: row.status || 'modified' }))),
775
+ // OpenCode 1's 'git' (the working tree against HEAD) is OpenCode 2's 'working', 'branch' (against the
776
+ // default branch) its 'branch'. OpenCode 2 refuses a diff that names no mode.
777
+ diff: async ({ directory, mode } = {}) => map(await call('GET', '/api/vcs/diff', { query: located(directory, { mode: vcsModeToV2(mode) }) }), (body) => (Array.isArray(body?.data) ? body.data : []).map((row) => ({ file: str(row.file), patch: str(row.patch), additions: Number(row.additions) || 0, deletions: Number(row.deletions) || 0, status: row.status }))),
778
+ },
779
+ lsp: { status: async () => ({ data: [], error: undefined, response: { status: 200, ok: true } }) },
780
+ formatter: { status: async () => ({ data: [], error: undefined, response: { status: 200, ok: true } }) },
781
+ path: {
782
+ get: async ({ directory } = {}) => {
783
+ const info = await call('GET', '/api/info');
784
+ return map(info, () => ({ home: '', state: '', config: '', worktree: str(directory), directory: str(directory) }));
785
+ },
786
+ },
787
+ // A stateless one-shot (editor autocomplete, titles): OpenCode 2's generator.
788
+ generate: async ({ prompt: text, model, directory, signal } = {}) => {
789
+ const ref = modelRefToV2(model);
790
+ return map(await call('POST', '/api/experimental/generate', { query: located(directory), body: { prompt: String(text || ''), ...(ref ? { model: ref } : {}) }, signal }), (body) => ({ text: str(body?.data?.text) }));
791
+ },
792
+ };
793
+ return client;
794
+ }
795
+
796
+ export const OPENCODE2_CLIENT_INTERNALS = Object.freeze({ SYSTEM_ENTRY, v2ToolName });