synabun 2.0.9 → 2.0.10
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.
- package/CHANGELOG.md +29 -0
- package/README.md +1 -1
- package/THIRD-PARTY-LICENSES.md +46 -4
- package/launcher.mjs +9 -3
- package/lib/start-launcher.js +6 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/neural-interface/i18n/en.json +218 -7
- package/neural-interface/i18n/pt-BR.json +220 -9
- package/neural-interface/lib/account-usage.js +5 -3
- package/neural-interface/lib/app-controls-api.js +161 -0
- package/neural-interface/lib/assistant-api.js +21 -7
- package/neural-interface/lib/assistant-brains/opencode.js +13 -1
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +44 -0
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +57 -0
- package/neural-interface/lib/assistant-catalog.js +17 -2
- package/neural-interface/lib/assistant-dispatch.js +3 -0
- package/neural-interface/lib/assistant-envelope.js +19 -1
- package/neural-interface/lib/assistant-runtime.js +127 -8
- package/neural-interface/lib/claude-model-catalog.js +64 -14
- package/neural-interface/lib/codex-settings-schema.js +109 -47
- package/neural-interface/lib/editor-completion-opencode.js +132 -35
- package/neural-interface/lib/exec-loop-command.js +8 -1
- package/neural-interface/lib/launch-cache.js +293 -0
- package/neural-interface/lib/login-start.js +524 -0
- package/neural-interface/lib/native-loop-providers.js +18 -3
- package/neural-interface/lib/native-loop-runtime.js +19 -0
- package/neural-interface/lib/opencode-db-schema.js +75 -0
- package/neural-interface/lib/opencode-history.js +16 -1
- package/neural-interface/lib/opencode-protocol.js +173 -0
- package/neural-interface/lib/opencode-provider-view.js +81 -0
- package/neural-interface/lib/opencode-runtime-config.js +10 -3
- package/neural-interface/lib/opencode-serve-records.js +606 -0
- package/neural-interface/lib/opencode-v2-client.js +33 -6
- package/neural-interface/lib/opencode-v2-ws-requests.js +19 -5
- package/neural-interface/lib/opencode-worker-activity.js +229 -0
- package/neural-interface/lib/opencode2-client.js +760 -0
- package/neural-interface/lib/opencode2-proxy.js +116 -0
- package/neural-interface/lib/opencode2-translate.js +1008 -0
- package/neural-interface/lib/process-identity.js +361 -0
- package/neural-interface/lib/session-cache-builder.js +26 -5
- package/neural-interface/lib/session-title-generator.js +18 -0
- package/neural-interface/lib/style-guide/api.js +4 -3
- package/neural-interface/lib/untrusted-file-headers.js +27 -0
- package/neural-interface/package-lock.json +1343 -45
- package/neural-interface/package.json +5 -1
- package/neural-interface/public/index.html +2 -2
- package/neural-interface/public/shared/agent-runtime-options.js +55 -11
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +172 -17
- package/neural-interface/public/shared/assistant/asst-api.js +11 -3
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +195 -80
- package/neural-interface/public/shared/assistant/asst-composer.js +1 -1
- package/neural-interface/public/shared/assistant/asst-hosts.js +49 -2
- package/neural-interface/public/shared/assistant/asst-menu.js +77 -6
- package/neural-interface/public/shared/assistant/asst-panel.js +197 -33
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +28 -10
- package/neural-interface/public/shared/assistant/asst-redact.js +186 -0
- package/neural-interface/public/shared/assistant/asst-render.js +382 -36
- package/neural-interface/public/shared/assistant/asst-run-stage.js +231 -0
- package/neural-interface/public/shared/assistant/asst-sanitize.js +193 -3
- package/neural-interface/public/shared/assistant/asst-scene-styles.js +273 -0
- package/neural-interface/public/shared/assistant/asst-scenes.js +528 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +3 -15
- package/neural-interface/public/shared/assistant/asst-state.js +14 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +43 -0
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +13 -1
- package/neural-interface/public/shared/cc-dropdown.js +480 -0
- package/neural-interface/public/shared/cdx/cdx-panel.js +13 -1
- package/neural-interface/public/shared/cdx/cdx-render.js +15 -3
- package/neural-interface/public/shared/cdx/cdx-styles.js +4 -0
- package/neural-interface/public/shared/cdx/cdx-tabs.js +149 -35
- package/neural-interface/public/shared/cp/cp-markdown.js +4 -57
- package/neural-interface/public/shared/data-cache.js +223 -0
- package/neural-interface/public/shared/desktop-bridge.js +11 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +78 -1
- package/neural-interface/public/shared/desktop-titlebar.js +214 -28
- package/neural-interface/public/shared/desktop-update-view.js +15 -5
- package/neural-interface/public/shared/file-links.js +73 -8
- package/neural-interface/public/shared/html-shell.js +74 -80
- package/neural-interface/public/shared/launch-prefetch.js +59 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +3 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +7 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +54 -17
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +93 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +3 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +11 -9
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +15 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +401 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +16 -9
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +60 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +48 -19
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +195 -19
- package/neural-interface/public/shared/opencode-providers.js +39 -0
- package/neural-interface/public/shared/schedules-view.js +318 -0
- package/neural-interface/public/shared/settings/settings-app-pane.js +335 -0
- package/neural-interface/public/shared/settings/settings-app.js +243 -0
- package/neural-interface/public/shared/settings/settings-data.js +88 -0
- package/neural-interface/public/shared/settings/settings-ia.js +17 -0
- package/neural-interface/public/shared/sidepanel-session-status.js +49 -0
- package/neural-interface/public/shared/styles.css +540 -371
- package/neural-interface/public/shared/ui-assistant.js +27 -5
- package/neural-interface/public/shared/ui-automation-studio.js +67 -27
- package/neural-interface/public/shared/ui-bookmarks.js +2 -1
- package/neural-interface/public/shared/ui-claude-panel.js +76 -8
- package/neural-interface/public/shared/ui-codex-panel.js +1 -0
- package/neural-interface/public/shared/ui-detail.js +6 -6
- package/neural-interface/public/shared/ui-file-links.js +1 -0
- package/neural-interface/public/shared/ui-image-gallery.js +6 -5
- package/neural-interface/public/shared/ui-invite.js +18 -2
- package/neural-interface/public/shared/ui-link.js +9 -9
- package/neural-interface/public/shared/ui-menubar.js +232 -33
- package/neural-interface/public/shared/ui-native-loop-router.js +2 -0
- package/neural-interface/public/shared/ui-opencode-panel-v2.js +1 -0
- package/neural-interface/public/shared/ui-schedules-studio.js +2099 -869
- package/neural-interface/public/shared/ui-sessions.js +15 -4
- package/neural-interface/public/shared/ui-settings.js +87 -36
- package/neural-interface/public/shared/ui-sidebar.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +13 -0
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +55 -4
- package/neural-interface/public/shared/ui-sidepanel-tray.js +84 -8
- package/neural-interface/public/shared/ui-skills.js +70 -12
- package/neural-interface/public/shared/ui-sync.js +7 -0
- package/neural-interface/public/shared/ui-terminal.js +36 -20
- package/neural-interface/public/shared/ui-trash.js +8 -1
- package/neural-interface/public/shared/ui-tutorial-steps.js +7 -3
- package/neural-interface/public/shared/ui-tutorial.js +15 -5
- package/neural-interface/public/shared/ui-update.js +83 -14
- package/neural-interface/public/shared/ui-whiteboard.js +2 -1
- package/neural-interface/public/variant/2d/main.js +4 -1
- package/neural-interface/public/variant/3d/main.js +3 -0
- package/neural-interface/public/vendor/highlight/LICENSE +29 -0
- package/neural-interface/public/vendor/highlight/github-dark-dimmed-11.12.0.min.css +9 -0
- package/neural-interface/public/vendor/highlight/highlight-11.12.0.min.js +1262 -0
- package/neural-interface/public/vendor/highlight/manifest.json +5 -0
- package/neural-interface/public/vendor/html2canvas/LICENSE +22 -0
- package/neural-interface/public/vendor/html2canvas/html2canvas-1.4.1.min.js +20 -0
- package/neural-interface/public/vendor/html2canvas/manifest.json +4 -0
- package/neural-interface/public/vendor/marked/LICENSE.md +44 -0
- package/neural-interface/public/vendor/marked/manifest.json +4 -0
- package/neural-interface/public/vendor/marked/marked-14.1.4.esm.js +2502 -0
- package/neural-interface/public/vendor/mermaid/LICENSE +21 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/abnfDiagram-PAR5IXJI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architecture-7GRP2DOG-M7G3SWCO.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architectureDiagram-2PNWDENW.mjs +36 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/blockDiagram-PUWGUBOA.mjs +129 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/c4Diagram-3NLNHZP5.mjs +38 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-2NMSUPJH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-32MCUW2P.mjs +206 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3NPNU5GP.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3SMGFRGC.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4CAJECRU.mjs +14 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4OADUZ5Q.mjs +10 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IMINLNL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IQCK5RY.mjs +3 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5MVFYWFU.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AQ6EADP3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AZZRMDJM.mjs +15 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-CLS4B6BI.mjs +168 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-DZP67EKU.mjs +70 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-EICP7K5X.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-GDY2UAB4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-H7VHZCWX.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-IJBDOHL6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JFFVMJIA.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JQRUD6KW.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JZGDI5JK.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-KD6SPIPN.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NF366YI6.mjs +231 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NUDPKBEF.mjs +32 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-OJINMHTS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Q6NGPIAH.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-QJSWEUOL.mjs +132 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-R7JDMUKV.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RCXAM2GK.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RT4MAWR3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SFMINX4W.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SLDQ463B.mjs +88 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-STOV2HOB.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-T5OCTHI4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-TCEHX7R3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VQC2EELJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VRZKL3EH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VTHDQ7BV.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VY2OSTJR.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-WUBWJARI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YBMQ5JGJ.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YDMLL4PJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Z6V44ARX.mjs +62 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZJJ7VQJP.mjs +339 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZNLK7HRR.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZQN7UHIL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZS6VBONO.mjs +174 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZUNWM646.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-FGAMPOII.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-v2-AI5RJEK4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cose-bilkent-Q72C2OJ3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefin-OW5HDTMX-6OCTWOGG.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefinDiagram-2OOWUY4M.mjs +62 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/dagre-MPVFI544.mjs +4 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-AE4NWXFW.mjs +24 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-BUJID5UG.mjs +41 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-C44CZ5NI.mjs +24 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-EYOLEXXS.mjs +30 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-P7B6PWOJ.mjs +3 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ebnfDiagram-FTPZ3PV6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/erDiagram-H3ERR26V.mjs +99 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/eventmodeling-NTZA5JFV-WKSWQHFS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/flowDiagram-YHGXBVSY.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ganttDiagram-RWFTB7ED.mjs +292 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraph-4MIJSDKK-JH2HKYUO.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraphDiagram-MAR6GKOP.mjs +106 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/info-A6RAGUB7-3TX3OFWW.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/infoDiagram-LV547AFH.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ishikawaDiagram-PUJQGNDS.mjs +70 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/journeyDiagram-EW5QJT4W.mjs +139 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/kanban-definition-JSQERAZB.mjs +89 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/katex-CZ4GXH2S.mjs +257 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/mindmap-definition-VBJCLQLM.mjs +96 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/packet-AYTQ26CC-MKII6P3Y.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pegDiagram-7WILOQTJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pie-WAS4IAKB-6B4OPMJ5.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pieDiagram-EFA7CBSB.mjs +39 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/quadrantDiagram-WARVYA7P.mjs +7 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/radar-RG4KPBEZ-UPTR3XUL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-74A4TZTK-MEFUPFMS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-abnf-HS5TGJTU-R5YG2S5D.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-ebnf-LZEXJU2U-G5QEX2L6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-peg-WCYAUIDC-H5I2ZRY2.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroadDiagram-5NIQVNLQ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/requirementDiagram-SXREGOKZ.mjs +84 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sankeyDiagram-VV74M2VP.mjs +40 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sequenceDiagram-52ZFIFDL.mjs +162 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sizeCapture-FGA5AGYP.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-3QAKPIVI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-v2-HN2P4RDZ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanes-QLVP42QD.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanesDiagram-JKPDBFCN.mjs +8 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/timeline-definition-GS45XAXW.mjs +120 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treeView-Q6P3EWNA-ZRJGANNQ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treemap-WGGIJYW6-K64VN5AS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/vennDiagram-QIQU2ZRJ.mjs +34 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardley-WFR3VGLG-D67OWCCH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardleyDiagram-U6YNM66N.mjs +78 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/xychartDiagram-XJAZEDNM.mjs +7 -0
- package/neural-interface/public/vendor/mermaid/manifest.json +4 -0
- package/neural-interface/public/vendor/mermaid/mermaid-11.17.2.esm.min.mjs +14 -0
- package/neural-interface/scripts/build-vendor.mjs +84 -3
- package/neural-interface/server.js +1099 -286
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/skills/synabun/modules/schedule.md +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// Which OpenCode database SynaBun is reading.
|
|
3
|
+
//
|
|
4
|
+
// SynaBun reads OpenCode's own SQLite database ($XDG_DATA_HOME/opencode/
|
|
5
|
+
// opencode.db) for the session lists of every registered project and for the
|
|
6
|
+
// Resume cache. OpenCode 1 keeps sessions in `session` / `message` / `part`;
|
|
7
|
+
// OpenCode 2 keeps them in `session_v2` / `session_message`, in the same file.
|
|
8
|
+
// An OpenCode 2 that opened an OpenCode 1 database copies its sessions into
|
|
9
|
+
// `session_v2` and leaves the old tables behind, frozen: read by OpenCode 1's
|
|
10
|
+
// queries they would show yesterday's sessions and none of today's. So the
|
|
11
|
+
// tables are picked by the OpenCode SynaBun talks to, and by what the file has.
|
|
12
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
/** The table names of an open node:sqlite database, or an empty set. */
|
|
15
|
+
export function tableNamesOf(db) {
|
|
16
|
+
try {
|
|
17
|
+
return new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => String(row?.name || '')));
|
|
18
|
+
} catch {
|
|
19
|
+
return new Set();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 'v2' (OpenCode 2's tables), 'v1' (OpenCode 1's) or null (neither). `protocol`
|
|
25
|
+
* is the major SynaBun talks to (1, 2, or null when it is not known): with 2,
|
|
26
|
+
* OpenCode 2's tables are read when the file has them; with 1, OpenCode 1's;
|
|
27
|
+
* not known, OpenCode 2's when there are any.
|
|
28
|
+
*/
|
|
29
|
+
export function opencodeDbFlavor(db, protocol = null) {
|
|
30
|
+
if (!db) return null;
|
|
31
|
+
const tables = tableNamesOf(db);
|
|
32
|
+
const v2 = tables.has('session_v2') && tables.has('session_message');
|
|
33
|
+
const v1 = tables.has('session') && tables.has('message');
|
|
34
|
+
if (protocol === 1) return v1 ? 'v1' : null;
|
|
35
|
+
if (protocol === 2) return v2 ? 'v2' : null;
|
|
36
|
+
if (v2) return 'v2';
|
|
37
|
+
return v1 ? 'v1' : null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The session table and the message-count expression (`s` is the session row) of a flavor. */
|
|
41
|
+
export function sessionTablesFor(flavor) {
|
|
42
|
+
if (flavor === 'v2') {
|
|
43
|
+
return {
|
|
44
|
+
session: 'session_v2',
|
|
45
|
+
messageCount: "(SELECT COUNT(*) FROM session_message m WHERE m.session_id = s.id AND m.type IN ('user', 'assistant'))",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return { session: 'session', messageCount: '(SELECT COUNT(*) FROM message m WHERE m.session_id = s.id)' };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The visible text of one OpenCode 2 `session_message` row (its `type` and
|
|
53
|
+
* JSON `data`) as `{ role, text }`, or null for a row without any (a switch, an
|
|
54
|
+
* idle marker, a tool-only step).
|
|
55
|
+
*/
|
|
56
|
+
export function v2MessageText(type, data) {
|
|
57
|
+
let body = data;
|
|
58
|
+
if (typeof data === 'string') {
|
|
59
|
+
try { body = JSON.parse(data); } catch { return null; }
|
|
60
|
+
}
|
|
61
|
+
if (!body || typeof body !== 'object') return null;
|
|
62
|
+
if (type === 'user') {
|
|
63
|
+
const text = typeof body.text === 'string' ? body.text : '';
|
|
64
|
+
return text ? { role: 'user', text } : null;
|
|
65
|
+
}
|
|
66
|
+
if (type === 'assistant') {
|
|
67
|
+
const text = (Array.isArray(body.content) ? body.content : [])
|
|
68
|
+
.filter((item) => item?.type === 'text' && typeof item.text === 'string')
|
|
69
|
+
.map((item) => item.text)
|
|
70
|
+
.join('\n')
|
|
71
|
+
.trim();
|
|
72
|
+
return text ? { role: 'assistant', text } : null;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
@@ -15,6 +15,13 @@ import { isMainThread, parentPort, Worker, workerData } from 'node:worker_thread
|
|
|
15
15
|
|
|
16
16
|
export const OPENCODE_HISTORY_CONFIRMATION = 'DELETE OPENCODE HISTORY';
|
|
17
17
|
|
|
18
|
+
// OpenCode 2 keeps its sessions in other tables of the same file (session_v2,
|
|
19
|
+
// session_message, its event log): the OpenCode 1 list below would delete its
|
|
20
|
+
// messages and events and leave its sessions, which breaks that database. So an
|
|
21
|
+
// OpenCode 2 database is never cleared here.
|
|
22
|
+
export const OPENCODE2_HISTORY_REFUSAL = 'This OpenCode data belongs to OpenCode 2, whose history SynaBun does not clear. Delete OpenCode 2 sessions from OpenCode itself.';
|
|
23
|
+
const isOpencode2Database = (tables) => tables.has('session_v2');
|
|
24
|
+
|
|
18
25
|
const HISTORY_TABLES_CHILD_FIRST = [
|
|
19
26
|
'part',
|
|
20
27
|
'message',
|
|
@@ -111,7 +118,14 @@ export function getOpenCodeHistoryStats({ dbPath, dataRoot = dirname(dbPath) })
|
|
|
111
118
|
db = new DatabaseSync(database, { readOnly: true });
|
|
112
119
|
db.exec('PRAGMA busy_timeout = 2000');
|
|
113
120
|
const tables = tableNames(db);
|
|
114
|
-
|
|
121
|
+
if (isOpencode2Database(tables)) {
|
|
122
|
+
stats.sessions = countRows(db, 'session_v2', tables);
|
|
123
|
+
stats.opencode2 = true;
|
|
124
|
+
stats.clearable = false;
|
|
125
|
+
stats.reason = OPENCODE2_HISTORY_REFUSAL;
|
|
126
|
+
} else {
|
|
127
|
+
stats.sessions = countRows(db, 'session', tables);
|
|
128
|
+
}
|
|
115
129
|
} finally {
|
|
116
130
|
try { db?.close(); } catch {}
|
|
117
131
|
}
|
|
@@ -174,6 +188,7 @@ export function clearOpenCodeHistory({ dbPath, dataRoot = dirname(dbPath), vacuu
|
|
|
174
188
|
db.exec('PRAGMA foreign_keys = ON');
|
|
175
189
|
db.exec('PRAGMA busy_timeout = 10000');
|
|
176
190
|
const tables = tableNames(db);
|
|
191
|
+
if (isOpencode2Database(tables)) throw new Error(OPENCODE2_HISTORY_REFUSAL);
|
|
177
192
|
result.sessionsDeleted = countRows(db, 'session', tables);
|
|
178
193
|
result.messagesDeleted = countRows(db, 'message', tables);
|
|
179
194
|
result.partsDeleted = countRows(db, 'part', tables);
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// Which OpenCode SynaBun talks to, and how to know it is really there.
|
|
3
|
+
//
|
|
4
|
+
// OpenCode 1 and OpenCode 2 are different servers behind the same
|
|
5
|
+
// `opencode serve`:
|
|
6
|
+
// • OpenCode 1 (`opencode --version` → "1.18.34"): its API at the root
|
|
7
|
+
// (/global/health, /session, /global/event, …), no password.
|
|
8
|
+
// • OpenCode 2 (→ "opencode v2.0.32"): its API under /api/*, HTTP Basic auth
|
|
9
|
+
// (user `opencode`) with a password set per launch (OPENCODE_PASSWORD,
|
|
10
|
+
// which OpenCode keeps out of its children's environment); every other
|
|
11
|
+
// path is its web app, an HTML page with status 200.
|
|
12
|
+
// SynaBun reads the major version of the binary it is about to start (the CLI
|
|
13
|
+
// resolver's cached `--version`, keyed by the file, so an upgrade in place is
|
|
14
|
+
// read again), starts it the way that version wants, and calls a serve healthy
|
|
15
|
+
// only when the right API answers JSON: an HTML page never passes.
|
|
16
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
import { randomBytes } from 'node:crypto';
|
|
19
|
+
|
|
20
|
+
/** Protocols SynaBun speaks, by the OpenCode major version that serves them. */
|
|
21
|
+
export const OPENCODE_PROTOCOLS = Object.freeze({ 1: 'opencode1', 2: 'opencode2' });
|
|
22
|
+
export const OPENCODE2_USERNAME = 'opencode';
|
|
23
|
+
|
|
24
|
+
/** "1.18.34", "opencode v2.0.32", "v1.19.3" → 1 / 2; null when no version can be read. */
|
|
25
|
+
export function opencodeMajorOf(version) {
|
|
26
|
+
const match = String(version ?? '').match(/(\d+)\.(\d+)\.(\d+)/);
|
|
27
|
+
if (!match) return null;
|
|
28
|
+
const major = Number(match[1]);
|
|
29
|
+
return Number.isFinite(major) ? major : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The protocol for a version string: `{ protocol: 1 | 2 | null, major,
|
|
34
|
+
* version, supported, reason }`. OpenCode 0.x is the 1.x API's predecessor and
|
|
35
|
+
* speaks it; a major SynaBun does not know is refused with a sentence, never
|
|
36
|
+
* guessed at.
|
|
37
|
+
*/
|
|
38
|
+
export function protocolForVersion(version) {
|
|
39
|
+
const major = opencodeMajorOf(version);
|
|
40
|
+
const text = version ? String(version).trim() : '';
|
|
41
|
+
if (major == null) {
|
|
42
|
+
return { protocol: null, major: null, version: text || null, supported: false, reason: text ? `SynaBun cannot read the OpenCode version "${text}".` : 'SynaBun could not read the OpenCode version.' };
|
|
43
|
+
}
|
|
44
|
+
if (major <= 1) return { protocol: 1, major, version: text, supported: true, reason: null };
|
|
45
|
+
if (major === 2) return { protocol: 2, major, version: text, supported: true, reason: null };
|
|
46
|
+
return { protocol: null, major, version: text, supported: false, reason: `OpenCode ${major} (${text}) is newer than SynaBun supports: SynaBun works with OpenCode 1 and OpenCode 2.` };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** A fresh password for one OpenCode 2 launch. */
|
|
50
|
+
export function newServePassword() {
|
|
51
|
+
return randomBytes(24).toString('base64url');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The Authorization header for an OpenCode 2 serve. */
|
|
55
|
+
export function basicAuthHeader(password, username = OPENCODE2_USERNAME) {
|
|
56
|
+
return `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The arguments and environment of `opencode serve` on `port` for a protocol.
|
|
61
|
+
* OpenCode 1 keeps exactly what SynaBun always ran (`serve --port N`); OpenCode
|
|
62
|
+
* 2 also gets its loopback host name and the launch's password (OPENCODE_PASSWORD;
|
|
63
|
+
* any OPENCODE_SERVER_PASSWORD the environment carries is dropped, so the
|
|
64
|
+
* password SynaBun holds is the one the serve checks). A version SynaBun could
|
|
65
|
+
* not read (`protocol` null: a command line in Settings) starts like OpenCode
|
|
66
|
+
* 2: OpenCode 1 ignores OPENCODE_PASSWORD and takes --hostname too, and the
|
|
67
|
+
* health check then says which one answered.
|
|
68
|
+
*/
|
|
69
|
+
export function serveSpecFor(protocol, port, { env = process.env, password = null } = {}) {
|
|
70
|
+
const args = ['serve', '--port', String(port)];
|
|
71
|
+
if (protocol === 1) return { args, env, password: null };
|
|
72
|
+
const pass = password || newServePassword();
|
|
73
|
+
const next = { ...env, OPENCODE_PASSWORD: pass };
|
|
74
|
+
delete next.OPENCODE_SERVER_PASSWORD;
|
|
75
|
+
return { args: [...args, '--hostname', '127.0.0.1'], env: next, password: pass };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isJsonResponse(res) {
|
|
79
|
+
return /\bapplication\/json\b/i.test(String(res?.headers?.get?.('content-type') || ''));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function readJson(res) {
|
|
83
|
+
if (!isJsonResponse(res)) return { json: null, html: /text\/html/i.test(String(res?.headers?.get?.('content-type') || '')) };
|
|
84
|
+
try { return { json: await res.json(), html: false }; } catch { return { json: null, html: false }; }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Is a real OpenCode API answering on `port`? `protocol` 1 asks
|
|
89
|
+
* /global/health, 2 asks /api/info with `password`; `protocol` null asks both
|
|
90
|
+
* (an unknown serve: which one is it?). Resolves
|
|
91
|
+
* `{ ok, protocol, version, state, error }`, where `state` is
|
|
92
|
+
* 'healthy' the protocol's API answered JSON
|
|
93
|
+
* 'locked' an OpenCode 2 serve whose password SynaBun does not hold
|
|
94
|
+
* 'mismatch' an OpenCode of the other major answered
|
|
95
|
+
* 'html' a web page (OpenCode 2's app, or anything else) — never healthy
|
|
96
|
+
* 'down' nothing answered
|
|
97
|
+
* 'error' something answered, but not an OpenCode API
|
|
98
|
+
* Never throws.
|
|
99
|
+
*/
|
|
100
|
+
export async function checkOpencodeServer({ port, protocol = null, password = null, fetchImpl = globalThis.fetch, timeoutMs = 2000, host = '127.0.0.1' } = {}) {
|
|
101
|
+
const base = `http://${host}:${port}`;
|
|
102
|
+
const get = async (path, headers = {}) => {
|
|
103
|
+
try {
|
|
104
|
+
return await fetchImpl(`${base}${path}`, { headers: { accept: 'application/json', ...headers }, signal: AbortSignal.timeout(timeoutMs) });
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return { failed: true, error };
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const asV1 = async () => {
|
|
110
|
+
const res = await get('/global/health');
|
|
111
|
+
if (res.failed) return { ok: false, protocol: 1, version: null, state: 'down', error: String(res.error?.message || res.error) };
|
|
112
|
+
const { json, html } = await readJson(res);
|
|
113
|
+
if (res.ok && json && (json.healthy === true || typeof json.version === 'string')) {
|
|
114
|
+
return { ok: true, protocol: 1, version: typeof json.version === 'string' ? json.version : null, state: 'healthy', error: null };
|
|
115
|
+
}
|
|
116
|
+
return { ok: false, protocol: 1, version: null, state: html ? 'html' : 'error', error: html ? 'answered with a web page, not the OpenCode 1 API' : `GET /global/health answered ${res.status}` };
|
|
117
|
+
};
|
|
118
|
+
const asV2 = async () => {
|
|
119
|
+
const res = await get('/api/info', password ? { authorization: basicAuthHeader(password) } : {});
|
|
120
|
+
if (res.failed) return { ok: false, protocol: 2, version: null, state: 'down', error: String(res.error?.message || res.error) };
|
|
121
|
+
const { json, html } = await readJson(res);
|
|
122
|
+
if (res.ok && json && typeof json.version === 'string' && Array.isArray(json.urls)) {
|
|
123
|
+
return { ok: true, protocol: 2, version: json.version, state: 'healthy', error: null };
|
|
124
|
+
}
|
|
125
|
+
if (res.status === 401 && json && /unauthori[sz]ed/i.test(String(json._tag || json.name || ''))) {
|
|
126
|
+
return { ok: false, protocol: 2, version: null, state: 'locked', error: password ? 'the OpenCode 2 serve refused SynaBun\'s password' : 'an OpenCode 2 serve SynaBun did not start (it needs that serve\'s password)' };
|
|
127
|
+
}
|
|
128
|
+
return { ok: false, protocol: 2, version: null, state: html ? 'html' : 'error', error: html ? 'answered with a web page, not the OpenCode 2 API' : `GET /api/info answered ${res.status}` };
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
if (protocol === 1) {
|
|
132
|
+
const v1 = await asV1();
|
|
133
|
+
if (v1.ok || v1.state === 'down') return v1;
|
|
134
|
+
// A web page where OpenCode 1 was expected: is it an OpenCode 2?
|
|
135
|
+
const v2 = await asV2();
|
|
136
|
+
if (v2.ok || v2.state === 'locked') return { ...v2, ok: false, state: 'mismatch', error: 'an OpenCode 2 serve answered where SynaBun expected OpenCode 1' };
|
|
137
|
+
return v1;
|
|
138
|
+
}
|
|
139
|
+
if (protocol === 2) {
|
|
140
|
+
const v2 = await asV2();
|
|
141
|
+
if (v2.ok || v2.state === 'down' || v2.state === 'locked') return v2;
|
|
142
|
+
const v1 = await asV1();
|
|
143
|
+
if (v1.ok) return { ...v1, ok: false, state: 'mismatch', error: 'an OpenCode 1 serve answered where SynaBun expected OpenCode 2' };
|
|
144
|
+
return v2;
|
|
145
|
+
}
|
|
146
|
+
const v1 = await asV1();
|
|
147
|
+
if (v1.ok || v1.state === 'down') return v1;
|
|
148
|
+
const v2 = await asV2();
|
|
149
|
+
return v2.ok || v2.state === 'locked' ? v2 : v1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The sentence a person reads when OpenCode cannot be used: what was found and
|
|
154
|
+
* what to do. `check` is a checkOpencodeServer answer, `detected` a
|
|
155
|
+
* protocolForVersion answer.
|
|
156
|
+
*/
|
|
157
|
+
export function opencodeProblemText({ check = null, detected = null, port = null } = {}) {
|
|
158
|
+
if (detected && !detected.supported) return detected.reason;
|
|
159
|
+
if (!check || check.ok) return '';
|
|
160
|
+
const where = port ? ` on port ${port}` : '';
|
|
161
|
+
switch (check.state) {
|
|
162
|
+
case 'locked':
|
|
163
|
+
return `An OpenCode 2 server SynaBun did not start is already running${where}, and SynaBun does not have its password. Stop that server (or free the port) and start OpenCode again from SynaBun.`;
|
|
164
|
+
case 'mismatch':
|
|
165
|
+
return `The OpenCode server${where} is not the version SynaBun found on this computer (${check.error}). Stop it and start OpenCode again from SynaBun.`;
|
|
166
|
+
case 'html':
|
|
167
|
+
return `Something${where} answers with a web page instead of the OpenCode API (${check.error}).`;
|
|
168
|
+
case 'down':
|
|
169
|
+
return `OpenCode is not answering${where}.`;
|
|
170
|
+
default:
|
|
171
|
+
return `OpenCode${where} did not answer as expected: ${check.error || 'unknown error'}.`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Neural Interface — OpenCode provider views
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
// GET /api/opencode/providers/full answers with OpenCode's provider list,
|
|
5
|
+
// `{ all, default, connected }`. `all` is the whole models.dev catalog (on a
|
|
6
|
+
// typical install 231 providers and 9,069 models, about 7 MB of JSON) while a
|
|
7
|
+
// model picker only ever lists the providers that are connected (two or three).
|
|
8
|
+
// The compact view keeps those, with every field of their models a picker,
|
|
9
|
+
// the context gauge, the composer or the Assistant's catalog reads, and leaves
|
|
10
|
+
// out what none of them reads (credentials and request options included).
|
|
11
|
+
// Pure: no I/O, so the route, the catalog's in-process read and the tests share it.
|
|
12
|
+
|
|
13
|
+
const PROVIDER_FIELDS_LEFT_OUT = new Set(['env', 'options', 'key', 'npm', 'api']);
|
|
14
|
+
const MODEL_FIELDS_LEFT_OUT = new Set(['options', 'headers', 'provider']);
|
|
15
|
+
|
|
16
|
+
/** An answer of OpenCode's /provider: `{ all: [...] }` (an object; a web page or an error body is not one). */
|
|
17
|
+
export function isProviderCatalog(data) {
|
|
18
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) return false;
|
|
19
|
+
return Array.isArray(data.all) || (!!data.all && typeof data.all === 'object');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function providersOf(data) {
|
|
23
|
+
if (Array.isArray(data?.all)) return data.all;
|
|
24
|
+
return data?.all && typeof data.all === 'object' ? Object.values(data.all) : [];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function slimModel(model) {
|
|
28
|
+
if (!model || typeof model !== 'object') return model;
|
|
29
|
+
const out = {};
|
|
30
|
+
for (const [key, value] of Object.entries(model)) if (!MODEL_FIELDS_LEFT_OUT.has(key)) out[key] = value;
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function slimProvider(provider) {
|
|
35
|
+
const out = {};
|
|
36
|
+
for (const [key, value] of Object.entries(provider || {})) {
|
|
37
|
+
if (PROVIDER_FIELDS_LEFT_OUT.has(key)) continue;
|
|
38
|
+
if (key === 'models') {
|
|
39
|
+
if (Array.isArray(value)) out.models = value.map(slimModel);
|
|
40
|
+
else if (value && typeof value === 'object') out.models = Object.fromEntries(Object.entries(value).map(([id, model]) => [id, slimModel(model)]));
|
|
41
|
+
else out.models = value;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
out[key] = value;
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The providers a picker lists: the connected ones (every provider when the
|
|
51
|
+
* answer names none), in OpenCode's order, `default` and `connected` as given.
|
|
52
|
+
*/
|
|
53
|
+
export function compactProviderCatalog(data) {
|
|
54
|
+
if (!isProviderCatalog(data)) return null;
|
|
55
|
+
const connected = Array.isArray(data.connected) ? data.connected.map((entry) => String(entry && typeof entry === 'object' ? (entry.id || entry.name || '') : entry || '')).filter(Boolean) : null;
|
|
56
|
+
const wanted = connected ? new Set(connected) : null;
|
|
57
|
+
const all = providersOf(data).filter((provider) => provider?.id && (!wanted || wanted.has(String(provider.id)))).map(slimProvider);
|
|
58
|
+
return {
|
|
59
|
+
all,
|
|
60
|
+
default: data.default && typeof data.default === 'object' ? { ...data.default } : {},
|
|
61
|
+
...(Array.isArray(data.connected) ? { connected: [...data.connected] } : {}),
|
|
62
|
+
// How many providers the whole catalog has (Settings → OpenCode says how many it hides).
|
|
63
|
+
total: providersOf(data).length,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** What makes two answers the same list for a picker: connected providers, their model ids, the defaults, the catalog's size. */
|
|
68
|
+
export function providerCatalogSignature(data) {
|
|
69
|
+
if (!isProviderCatalog(data)) return '';
|
|
70
|
+
const providers = providersOf(data);
|
|
71
|
+
const connected = Array.isArray(data.connected) ? data.connected.map(String) : null;
|
|
72
|
+
const listed = providers
|
|
73
|
+
.filter((provider) => provider?.id && (!connected || connected.includes(String(provider.id))))
|
|
74
|
+
.map((provider) => {
|
|
75
|
+
const models = Array.isArray(provider.models) ? provider.models.map((m) => m?.id || '') : Object.keys(provider.models || {});
|
|
76
|
+
return `${provider.id}:${models.join(',')}`;
|
|
77
|
+
});
|
|
78
|
+
let modelCount = 0;
|
|
79
|
+
for (const provider of providers) modelCount += Array.isArray(provider?.models) ? provider.models.length : Object.keys(provider?.models || {}).length;
|
|
80
|
+
return JSON.stringify([connected, listed, data.default || {}, providers.length, modelCount]);
|
|
81
|
+
}
|
|
@@ -3,16 +3,23 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
3
3
|
|
|
4
4
|
/** The browser-policy plugin (assistant-brains/opencode-browser-policy.js) as a file URL a serve can load. */
|
|
5
5
|
export const OPENCODE_BROWSER_POLICY_PLUGIN = pathToFileURL(resolve(dirname(fileURLToPath(import.meta.url)), 'assistant-brains', 'opencode-browser-policy.js')).href;
|
|
6
|
+
/** Its OpenCode 2 form: a plugin folder, listed under `plugins` (OpenCode 1 ignores that key). */
|
|
7
|
+
export const OPENCODE2_BROWSER_POLICY_PLUGIN = pathToFileURL(resolve(dirname(fileURLToPath(import.meta.url)), 'assistant-brains', 'opencode2-browser-policy')).href;
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* An Assistant task run's serve config gets SynaBun's browser policy as a
|
|
9
|
-
* plugin (`cwd`: the run's project, for the scripts it reads)
|
|
10
|
-
*
|
|
11
|
+
* plugin (`cwd`: the run's project, for the scripts it reads), for OpenCode 1
|
|
12
|
+
* (`plugin`) and OpenCode 2 (`plugins`). The user's own plugins stay; an
|
|
13
|
+
* earlier entry of ours is replaced. Returns `config`.
|
|
11
14
|
*/
|
|
12
15
|
export function withOpenCodeBrowserPolicy(config, { cwd = null } = {}) {
|
|
16
|
+
const options = cwd ? { cwd: String(cwd) } : {};
|
|
13
17
|
const plugins = (Array.isArray(config.plugin) ? config.plugin : []).filter((entry) => (Array.isArray(entry) ? entry[0] : entry) !== OPENCODE_BROWSER_POLICY_PLUGIN);
|
|
14
|
-
plugins.push([OPENCODE_BROWSER_POLICY_PLUGIN,
|
|
18
|
+
plugins.push([OPENCODE_BROWSER_POLICY_PLUGIN, options]);
|
|
15
19
|
config.plugin = plugins;
|
|
20
|
+
const plugins2 = (Array.isArray(config.plugins) ? config.plugins : []).filter((entry) => (entry && typeof entry === 'object' ? entry.package : entry) !== OPENCODE2_BROWSER_POLICY_PLUGIN);
|
|
21
|
+
plugins2.push({ package: OPENCODE2_BROWSER_POLICY_PLUGIN, options });
|
|
22
|
+
config.plugins = plugins2;
|
|
16
23
|
return config;
|
|
17
24
|
}
|
|
18
25
|
|