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,528 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Assistant — worker scenes
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
// What a dispatched worker is doing, as a small scene: one per task class
|
|
5
|
+
// (the route's class, else the run's own), plus a generic one. A run card's
|
|
6
|
+
// stage (asst-run-stage.js) shows the full scene beside the mascot; the
|
|
7
|
+
// agents tray shows the mini one; the Assistant's own activity rack shows it
|
|
8
|
+
// too while it works on a direct route (asst-render.js). The scene follows
|
|
9
|
+
// the worker's live tool activity (sync:sidepanel:provider-event: Claude and
|
|
10
|
+
// Codex workers, and a compact copy of an OpenCode worker's tool calls) and
|
|
11
|
+
// the rack's current call: a coding run that drives the browser shows the
|
|
12
|
+
// browser scene for as long as that is what it does, the class is the fallback.
|
|
13
|
+
//
|
|
14
|
+
// DOM-free on purpose (node:test, tests/assistant-worker-stage.test.mjs):
|
|
15
|
+
// the phases, the scene a run shows, its step line and its accessible name,
|
|
16
|
+
// and the scenes' SVG markup as strings. The motion is CSS
|
|
17
|
+
// (asst-scene-styles.js): transform and opacity only, run while the scene
|
|
18
|
+
// carries data-live. Decorative SVG only: the stage is named by stageLabel().
|
|
19
|
+
|
|
20
|
+
import { isRunIdle, isTerminalRunStatus, runNeedsAttention, runStatusFromState, runTone } from './asst-state.js';
|
|
21
|
+
import { kindOf, parseToolName, sayCall, tFallback, verbText } from './asst-tool-kinds.js';
|
|
22
|
+
import { redactSecrets, safeStepInput } from './asst-redact.js';
|
|
23
|
+
|
|
24
|
+
/** The scenes: one per task class SynaBun dispatches, and the generic one. */
|
|
25
|
+
export const SCENES = Object.freeze(['quick', 'code', 'complex', 'review', 'research', 'browser', 'computer', 'automation', 'design', 'image_gen', 'video_gen', 'generic']);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Per scene: its words (an i18n key and the English), the mascot's pose
|
|
29
|
+
* (synabun-mascot.js MASCOT_POSES; the stage drives `gaze` and `pop` on the
|
|
30
|
+
* ticker's 1 Hz beat, see asst-run-stage.js).
|
|
31
|
+
*/
|
|
32
|
+
export const SCENE_SPECS = Object.freeze({
|
|
33
|
+
quick: { label: ['assistant.stage.scene.quick', 'Quick fix'], pose: 'mcp' },
|
|
34
|
+
code: { label: ['assistant.stage.scene.code', 'Coding'], pose: 'shell' },
|
|
35
|
+
complex: { label: ['assistant.stage.scene.complex', 'Complex task'], pose: 'think' },
|
|
36
|
+
review: { label: ['assistant.stage.scene.review', 'Reviewing'], pose: 'read' },
|
|
37
|
+
research: { label: ['assistant.stage.scene.research', 'Researching'], pose: 'search' },
|
|
38
|
+
browser: { label: ['assistant.stage.scene.browser', 'Browsing'], pose: 'web' },
|
|
39
|
+
computer: { label: ['assistant.stage.scene.computer', 'Using the computer'], pose: 'computer', gaze: 'pointer' },
|
|
40
|
+
automation: { label: ['assistant.stage.scene.automation', 'Automating'], pose: 'plan', pop: true },
|
|
41
|
+
design: { label: ['assistant.stage.scene.design', 'Designing'], pose: 'edit' },
|
|
42
|
+
image_gen: { label: ['assistant.stage.scene.image_gen', 'Making an image'], pose: 'watch', gaze: 'canvas' },
|
|
43
|
+
video_gen: { label: ['assistant.stage.scene.video_gen', 'Making a video'], pose: 'watch', gaze: 'strip' },
|
|
44
|
+
generic: { label: ['assistant.stage.scene.generic', 'Working'], pose: 'think' },
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/** Phases a stage is open and moving (or waiting on you) in; the rest settle it. */
|
|
48
|
+
export const LIVE_PHASES = Object.freeze(['queued', 'starting', 'working', 'waiting']);
|
|
49
|
+
const LIVE = new Set(LIVE_PHASES);
|
|
50
|
+
|
|
51
|
+
/** How long the worker's last tool call speaks for it: the step line, and the scene it implies. */
|
|
52
|
+
export const ACTIVITY_FRESH_MS = 90_000;
|
|
53
|
+
|
|
54
|
+
const str = (v) => (v == null ? '' : String(v));
|
|
55
|
+
|
|
56
|
+
/** The run's task class: its own, else its route's ('' when neither says). */
|
|
57
|
+
export function runTaskClass(run) {
|
|
58
|
+
return str(run?.taskClass || run?.route?.taskClass || '').trim();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** The scene of a task class (chat, unknown or none → generic). */
|
|
62
|
+
export function sceneOfClass(taskClass) {
|
|
63
|
+
const id = str(taskClass).trim();
|
|
64
|
+
return id && id !== 'generic' && Object.hasOwn(SCENE_SPECS, id) ? id : 'generic';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Where a run stands for its stage: queued | starting | working | waiting
|
|
69
|
+
* (on you: a permission, a question, a route card, or a turn that ended
|
|
70
|
+
* asking you) (live), idle (a warm worker between turns) | done | failed |
|
|
71
|
+
* stopped (settled), or null for no run.
|
|
72
|
+
*/
|
|
73
|
+
export function stagePhase(run) {
|
|
74
|
+
if (!run || typeof run !== 'object') return null;
|
|
75
|
+
const status = str(run.status || runStatusFromState(run.state));
|
|
76
|
+
if (status === 'completed') return 'done';
|
|
77
|
+
if (status === 'failed' || status === 'interrupted') return 'failed';
|
|
78
|
+
if (status === 'stopped') return 'stopped';
|
|
79
|
+
if (isTerminalRunStatus(status)) return 'done';
|
|
80
|
+
if (runNeedsAttention(run) || awaitsAnswer({ ...run, status })) return 'waiting';
|
|
81
|
+
if (isRunIdle({ ...run, status })) return 'idle';
|
|
82
|
+
if (status === 'queued' || run.queued === true || run.state === 'queued') return 'queued';
|
|
83
|
+
if (status === 'starting' || run.state === 'starting') return 'starting';
|
|
84
|
+
if (status === 'running') return 'working';
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const isLivePhase = (phase) => LIVE.has(phase);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The worker waits on your answer. Either its turn ended asking you something:
|
|
92
|
+
* the dispatcher reports that as a warm run (state and turnState idle) whose
|
|
93
|
+
* outcome (lastResult.status) is needs_input, until a follow-up starts the next
|
|
94
|
+
* turn (state running). Or it asked mid-turn: awaiting_permission with a
|
|
95
|
+
* pending question (Claude's AskUserQuestion, OpenCode's question tool).
|
|
96
|
+
*/
|
|
97
|
+
export function awaitsAnswer(run) {
|
|
98
|
+
if (!run || typeof run !== 'object') return false;
|
|
99
|
+
if (run.turnState === 'needs_input') return true;
|
|
100
|
+
if (run.state === 'awaiting_permission' || run.turnState === 'awaiting_permission') {
|
|
101
|
+
return (Array.isArray(run.pending) ? run.pending : []).some((request) => request?.kind === 'question');
|
|
102
|
+
}
|
|
103
|
+
return isRunIdle(run) && str(run.outcome || run.lastResult?.status) === 'needs_input';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The run card's status chip, `{ tone, label }` (asst-render.js updateRunCard).
|
|
108
|
+
* A run that waits on your answer says so as its stage does (awaitsAnswer:
|
|
109
|
+
* "Waiting for your answer"), in the waiting tone, a warm worker whose turn
|
|
110
|
+
* ended asking you included; a warm worker between turns otherwise says what
|
|
111
|
+
* its last turn ended with.
|
|
112
|
+
*/
|
|
113
|
+
export function runChip(run, t = tFallback) {
|
|
114
|
+
if (run?.state === 'awaiting_route' || run?.turnState === 'awaiting_route' || run?.route?.status === 'pending') {
|
|
115
|
+
return { tone: 'action', label: t('assistant.run.awaitingRoute', 'waiting for your model choice') };
|
|
116
|
+
}
|
|
117
|
+
if (awaitsAnswer(run)) return { tone: 'action', label: t('assistant.run.waitingInput', 'waiting for your answer') };
|
|
118
|
+
const tone = runTone(run);
|
|
119
|
+
if (run?.turnState === 'awaiting_permission') return { tone, label: t('assistant.run.needsApproval', 'needs approval') };
|
|
120
|
+
if (run?.turnState === 'needs_input') return { tone, label: t('assistant.run.needsInput', 'needs input') };
|
|
121
|
+
if (run?.queued && run.status !== 'running') return { tone, label: t('assistant.run.queued', 'queued') };
|
|
122
|
+
if (isRunIdle(run)) {
|
|
123
|
+
const outcome = run.outcome || run.lastResult?.status;
|
|
124
|
+
return { tone, label: outcome ? t('assistant.run.idleWith', '{outcome} · idle', { outcome }) : t('assistant.run.idle', 'idle') };
|
|
125
|
+
}
|
|
126
|
+
return { tone, label: run?.status || tone };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** The final frame a settled phase draws: done, failed or stopped. */
|
|
130
|
+
export function finalFrame(phase, run = null) {
|
|
131
|
+
if (phase === 'failed') return 'failed';
|
|
132
|
+
if (phase === 'stopped') return 'stopped';
|
|
133
|
+
if (phase === 'idle') {
|
|
134
|
+
const outcome = str(run?.outcome || run?.lastResult?.status);
|
|
135
|
+
return outcome === 'failed' ? 'failed' : outcome === 'blocked' ? 'stopped' : 'done';
|
|
136
|
+
}
|
|
137
|
+
return 'done';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── The worker's live activity (provider events) ─────────────────────────────
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Which of Codex's item events (codex exec --json, @openai/codex-sdk
|
|
144
|
+
* ThreadEvent) say what the worker does now, per item type. A command, an MCP
|
|
145
|
+
* call and the plan begin with item.started (their item.completed reports a
|
|
146
|
+
* call that is over; the plan's comes at the turn's end), the plan changes
|
|
147
|
+
* with item.updated. A patch and a reasoning summary arrive only as
|
|
148
|
+
* item.completed (the SDK's FileChangeItem is "emitted once the patch succeeds
|
|
149
|
+
* or fails"); a web search has come either way.
|
|
150
|
+
*/
|
|
151
|
+
export const CODEX_ITEM_EVENTS = Object.freeze({
|
|
152
|
+
command_execution: Object.freeze(['item.started']),
|
|
153
|
+
mcp_tool_call: Object.freeze(['item.started']),
|
|
154
|
+
todo_list: Object.freeze(['item.started', 'item.updated']),
|
|
155
|
+
file_change: Object.freeze(['item.started', 'item.completed']),
|
|
156
|
+
reasoning: Object.freeze(['item.started', 'item.completed']),
|
|
157
|
+
web_search: Object.freeze(['item.started', 'item.completed']),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Which of an OpenCode tool part's states (message.part.updated, the SDK's
|
|
162
|
+
* ToolPart) say what the worker does: `running` is a call that started (a
|
|
163
|
+
* `pending` part's input is still streaming), `completed` or `error` one that
|
|
164
|
+
* ended. The server forwards one start and one finish per call
|
|
165
|
+
* (lib/opencode-worker-activity.js); a finish counts, like Codex's
|
|
166
|
+
* completion-only items, for a call whose start the bounded relay folded into it.
|
|
167
|
+
*/
|
|
168
|
+
export const OPENCODE_TOOL_STATES = Object.freeze(['running', 'completed', 'error']);
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* A worker's provider event ({ provider, eventType?, event }, the payload of
|
|
172
|
+
* sync:sidepanel:provider-event) as what it is doing: { kind, name, input }
|
|
173
|
+
* for a tool call (the asst-tool-kinds.js kind), { kind: 'think' } for a
|
|
174
|
+
* thinking block, or null (text, results, stream deltas: nothing new). The
|
|
175
|
+
* stage and the tray keep only compactActivity() of it. OpenCode names its
|
|
176
|
+
* tools bash, read, edit, write, patch, glob, grep, list, webfetch,
|
|
177
|
+
* websearch, codesearch, task, todowrite, and MCP tools `<server>_<tool>`
|
|
178
|
+
* (SynaBun_browser_navigate): kindOf() reads all of them.
|
|
179
|
+
*/
|
|
180
|
+
export function activityOf(payload) {
|
|
181
|
+
const provider = str(payload?.provider);
|
|
182
|
+
const event = payload?.event && typeof payload.event === 'object' ? payload.event : null;
|
|
183
|
+
if (!event) return null;
|
|
184
|
+
if (provider === 'claude-code' || provider === 'claude') {
|
|
185
|
+
if (event.type !== 'assistant') return null;
|
|
186
|
+
const blocks = Array.isArray(event.message?.content) ? event.message.content : [];
|
|
187
|
+
let found = null;
|
|
188
|
+
for (const block of blocks) {
|
|
189
|
+
if (block?.type === 'tool_use' && block.name) found = { kind: kindOf(block.name, block.input), name: String(block.name), input: obj(block.input) };
|
|
190
|
+
else if (!found && (block?.type === 'thinking' || block?.type === 'redacted_thinking')) found = { kind: 'think', name: 'thinking', input: {} };
|
|
191
|
+
}
|
|
192
|
+
return found;
|
|
193
|
+
}
|
|
194
|
+
if (provider === 'codex') {
|
|
195
|
+
const item = event.item && typeof event.item === 'object' ? event.item : {};
|
|
196
|
+
if (!Object.hasOwn(CODEX_ITEM_EVENTS, str(item.type)) || !CODEX_ITEM_EVENTS[item.type].includes(event.type)) return null;
|
|
197
|
+
switch (item.type) {
|
|
198
|
+
case 'command_execution': return { kind: 'shell', name: 'exec_command', input: { command: str(item.command) } };
|
|
199
|
+
case 'file_change': {
|
|
200
|
+
const paths = (Array.isArray(item.changes) ? item.changes : []).map((c) => str(c?.path)).filter(Boolean);
|
|
201
|
+
return { kind: 'edit', name: 'apply_patch', input: paths.length > 1 ? { files: paths.map((path) => ({ path })) } : { file_path: paths[0] || '' } };
|
|
202
|
+
}
|
|
203
|
+
case 'mcp_tool_call': {
|
|
204
|
+
const name = `mcp__${str(item.server) || 'tool'}__${str(item.tool) || 'call'}`;
|
|
205
|
+
const input = obj(item.arguments);
|
|
206
|
+
return { kind: kindOf(name, input), name, input };
|
|
207
|
+
}
|
|
208
|
+
case 'web_search': return { kind: 'web', name: 'WebSearch', input: { query: str(item.query) } };
|
|
209
|
+
case 'todo_list': return { kind: 'plan', name: 'update_plan', input: { items: Array.isArray(item.items) ? item.items : [] } };
|
|
210
|
+
case 'reasoning': return { kind: 'think', name: 'thinking', input: {} };
|
|
211
|
+
default: return null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (provider === 'opencode') {
|
|
215
|
+
// { eventType: 'message.part.updated', event: { sessionID, part: ToolPart } }; a sub-agent's session is not the worker's call.
|
|
216
|
+
if (payload.childSession || !/^message[.:]part[.:]updated$/i.test(str(payload.eventType))) return null;
|
|
217
|
+
const part = event.part && typeof event.part === 'object' ? event.part : null;
|
|
218
|
+
if (part?.type !== 'tool' || !str(part.tool).trim() || !OPENCODE_TOOL_STATES.includes(str(part.state?.status))) return null;
|
|
219
|
+
const name = str(part.tool).trim();
|
|
220
|
+
const input = obj(part.state?.input);
|
|
221
|
+
return { kind: kindOf(name, input), name, input };
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function obj(v) {
|
|
227
|
+
if (v && typeof v === 'object' && !Array.isArray(v)) return v;
|
|
228
|
+
if (typeof v === 'string' && v.trim().startsWith('{')) { try { const parsed = JSON.parse(v); return parsed && typeof parsed === 'object' ? parsed : {}; } catch { return {}; } }
|
|
229
|
+
return {};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** The scene a tool call implies on its own, or null (the class decides). */
|
|
233
|
+
export function activityScene(activity, taskClass = '') {
|
|
234
|
+
if (!activity?.kind) return null;
|
|
235
|
+
if (activity.kind === 'computer') return 'computer';
|
|
236
|
+
if (activity.kind !== 'web') return null;
|
|
237
|
+
const tool = parseToolName(activity.name).tool;
|
|
238
|
+
if (tool.startsWith('browser_')) return 'browser';
|
|
239
|
+
// A page read or a web search reads as research, unless the run already browses or researches.
|
|
240
|
+
const cls = sceneOfClass(taskClass);
|
|
241
|
+
return cls === 'browser' || cls === 'research' ? null : 'research';
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** The activity while it still speaks for the worker (at most ACTIVITY_FRESH_MS old), else null. */
|
|
245
|
+
export function freshActivity(activity, now = Date.now()) {
|
|
246
|
+
if (!activity?.kind) return null;
|
|
247
|
+
const at = Number(activity.at);
|
|
248
|
+
return Number.isFinite(at) && now - at > ACTIVITY_FRESH_MS ? null : activity;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** The scene a run's stage shows now: what its current call implies, else its class's. */
|
|
252
|
+
export function sceneFor(run, activity = null, now = Date.now()) {
|
|
253
|
+
const cls = runTaskClass(run);
|
|
254
|
+
return activityScene(freshActivity(activity, now), cls) || sceneOfClass(cls);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** The longest step line a stage or the tray keeps. */
|
|
258
|
+
export const STEP_MAX_CHARS = 120;
|
|
259
|
+
|
|
260
|
+
const clip = (v, max) => {
|
|
261
|
+
const s = str(v).replace(/\s+/g, ' ').trim();
|
|
262
|
+
return s.length > max ? `${s.slice(0, max - 1).trimEnd()}…` : s;
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* A call in words: its verb and subject, clipped. Worded from the input as a step line may read it
|
|
267
|
+
* (asst-redact.js: credentials masked, a command's heredoc and inline file bodies omitted, an address without its
|
|
268
|
+
* query), so no step line ever shows a credential, whichever worker's call it is.
|
|
269
|
+
*/
|
|
270
|
+
function wordStep(a, t) {
|
|
271
|
+
if (a.kind === 'think') return verbText('think', true, t);
|
|
272
|
+
const say = sayCall({ name: a.name, kind: a.kind, input: safeStepInput(a.input || {}), state: 'running' }, { t });
|
|
273
|
+
const subject = redactSecrets(str(say.text)).replace(/^\$ /, '').replace(/\s+/g, ' ').trim();
|
|
274
|
+
return clip(`${verbText(say.verb, true, t)}${subject ? ` ${subject}` : ''}`, STEP_MAX_CHARS);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* What a stage and the tray keep of a worker's call: { kind, name, step, at },
|
|
279
|
+
* the kind and tool name its scene reads, its step line worded once and
|
|
280
|
+
* clipped, and when it was seen. Never the call's arguments: an edit's can
|
|
281
|
+
* hold a whole file; and never a credential the call carries. null for no call.
|
|
282
|
+
*/
|
|
283
|
+
export function compactActivity(activity, t = tFallback, now = Date.now()) {
|
|
284
|
+
if (!activity?.kind) return null;
|
|
285
|
+
const at = Number(activity.at);
|
|
286
|
+
return {
|
|
287
|
+
kind: str(activity.kind),
|
|
288
|
+
name: clip(activity.name, 160),
|
|
289
|
+
step: typeof activity.step === 'string' ? clip(redactSecrets(activity.step), STEP_MAX_CHARS) : wordStep(activity, t),
|
|
290
|
+
at: Number.isFinite(at) && at > 0 ? at : now,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** "Editing asst-render.js", "Running npm test", "Thinking"; '' when nothing current is known. */
|
|
295
|
+
export function stepLine(activity, t = tFallback, now = Date.now()) {
|
|
296
|
+
const a = freshActivity(activity, now);
|
|
297
|
+
if (!a) return '';
|
|
298
|
+
return typeof a.step === 'string' ? redactSecrets(a.step) : wordStep(a, t);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** A scene's words ("Coding"), localized. */
|
|
302
|
+
export function sceneLabel(scene, t = tFallback) {
|
|
303
|
+
const [key, fallback] = (SCENE_SPECS[scene] || SCENE_SPECS.generic).label;
|
|
304
|
+
return t(key, fallback);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** The stage's line when no step is known: the phase's words, or "Coding…" while it works. */
|
|
308
|
+
export function phaseLine(phase, run, scene, t = tFallback) {
|
|
309
|
+
switch (phase) {
|
|
310
|
+
case 'queued': return Number(run?.position) > 0 ? t('assistant.stage.queuedAt', 'Queued · position {n}', { n: run.position }) : t('assistant.stage.queued', 'Queued');
|
|
311
|
+
case 'starting': return t('assistant.stage.starting', 'Starting…');
|
|
312
|
+
case 'waiting':
|
|
313
|
+
if (run?.state === 'awaiting_route' || run?.route?.status === 'pending' || run?.awaitingRoute) return t('assistant.stage.waitingRoute', 'Waiting for your model choice');
|
|
314
|
+
if (awaitsAnswer(run)) return t('assistant.stage.waitingInput', 'Waiting for your answer');
|
|
315
|
+
return t('assistant.stage.waitingApproval', 'Waiting for your approval');
|
|
316
|
+
case 'idle': case 'done': return finalFrame(phase, run) === 'failed' ? t('assistant.stage.failed', 'Failed')
|
|
317
|
+
: finalFrame(phase, run) === 'stopped' ? t('assistant.stage.stopped', 'Stopped') : t('assistant.stage.done', 'Done');
|
|
318
|
+
case 'failed': return t('assistant.stage.failed', 'Failed');
|
|
319
|
+
case 'stopped': return t('assistant.stage.stopped', 'Stopped');
|
|
320
|
+
default: return t('assistant.stage.doing', '{scene}…', { scene: sceneLabel(scene, t) });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** Whole minutes of `ms`, as the stage's name says them: "under a minute", "1 min", "12 min". */
|
|
325
|
+
export function minutesText(ms, t = tFallback) {
|
|
326
|
+
const m = Math.floor(Math.max(0, Number(ms) || 0) / 60000);
|
|
327
|
+
if (m < 1) return t('assistant.stage.underMinute', 'under a minute');
|
|
328
|
+
return m === 1 ? t('assistant.stage.minutes.one', '{count} min', { count: m }) : t('assistant.stage.minutes.other', '{count} min', { count: m });
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* The stage's accessible name, one line that changes at most once a minute
|
|
333
|
+
* (the step is visible text only, so nothing chatters):
|
|
334
|
+
* "Coding · Settings: App controls section · 3 min"; waiting says why first.
|
|
335
|
+
*/
|
|
336
|
+
export function stageLabel({ scene = 'generic', phase = 'working', title = '', ms = 0, run = null } = {}, t = tFallback) {
|
|
337
|
+
const what = phase === 'waiting' ? phaseLine('waiting', run, scene, t)
|
|
338
|
+
: isLivePhase(phase) ? sceneLabel(scene, t) : phaseLine(phase, run, scene, t);
|
|
339
|
+
return [what, str(title).replace(/\s+/g, ' ').trim(), minutesText(ms, t)].filter(Boolean).join(' · ');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── Scene markup ─────────────────────────────────────────────────────────────
|
|
343
|
+
// Full scenes are drawn in a 120×40 box (the stage shows them at 1:1 beside
|
|
344
|
+
// the mascot); minis in 40×20 (the tray, at 32×16). Strokes are 1.5 units in
|
|
345
|
+
// currentColor (the container's muted text); `sc-gold` is the one live part
|
|
346
|
+
// (gold only means live). Every part sits where its still frame wants it:
|
|
347
|
+
// with no animation (reduced motion, waiting, settled) the scene still reads.
|
|
348
|
+
|
|
349
|
+
/** The code scene's six lines, repeated twice so its stepped scroll loops seamlessly: [indent, keyword, rest]. */
|
|
350
|
+
export const CODE_LINES = Object.freeze([[6, 8, 26], [12, 10, 42], [12, 6, 22], [18, 9, 35], [12, 12, 48], [6, 7, 14]]);
|
|
351
|
+
export const CODE_STEP = 6; // one line, in viewBox units
|
|
352
|
+
|
|
353
|
+
const r1 = (v) => Math.round(v * 100) / 100;
|
|
354
|
+
|
|
355
|
+
/** A gear outline: n trapezoid teeth between radius r and R round (cx, cy). */
|
|
356
|
+
export function gearPath(cx, cy, r, R, n) {
|
|
357
|
+
const pts = [];
|
|
358
|
+
const step = (Math.PI * 2) / n;
|
|
359
|
+
for (let i = 0; i < n; i += 1) {
|
|
360
|
+
const a = i * step;
|
|
361
|
+
for (const [rad, off] of [[r, -0.32], [R, -0.18], [R, 0.18], [r, 0.32]]) {
|
|
362
|
+
pts.push(`${r1(cx + rad * Math.cos(a + off * step))},${r1(cy + rad * Math.sin(a + off * step))}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return `M${pts.join('L')}Z`;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** Where the code scene's caret sits after step `s` (the newest line at the bottom slot): its x. */
|
|
369
|
+
export function codeCaretX(s) {
|
|
370
|
+
const [indent, key, rest] = CODE_LINES[(4 + s) % CODE_LINES.length];
|
|
371
|
+
return 4 + indent + key + 3 + rest + 2;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function codeFull() {
|
|
375
|
+
let lines = '';
|
|
376
|
+
for (let i = 0; i < CODE_LINES.length * 2; i += 1) {
|
|
377
|
+
const [indent, key, rest] = CODE_LINES[i % CODE_LINES.length];
|
|
378
|
+
const y = 5 + CODE_STEP * i;
|
|
379
|
+
lines += `<path class="sc-mid" d="M${indent} ${y}h${key}"/><path class="sc-dim" d="M${indent + key + 3} ${y}h${rest}"/>`;
|
|
380
|
+
}
|
|
381
|
+
return '<rect class="sc-dim" x="1" y="1.5" width="118" height="37" rx="5"/>'
|
|
382
|
+
+ `<svg x="4" y="4" width="112" height="32" overflow="hidden"><g class="sc-code-scroll">${lines}</g></svg>`
|
|
383
|
+
+ `<g class="sc-code-caret" style="transform:translateX(${codeCaretX(0)}px)"><rect class="sc-gold sc-fill sc-caret" x="0" y="30.5" width="2" height="5" rx="1"/></g>`;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const GEAR_BIG = gearPath(66, 20, 9, 12.5, 8);
|
|
387
|
+
const GEAR_SMALL = gearPath(86.5, 12.5, 5.5, 8, 6);
|
|
388
|
+
|
|
389
|
+
function complexFull() {
|
|
390
|
+
return '<path class="sc-dim" d="M14 7h13l5 5v21H14z"/><path class="sc-mid" d="M8 11h13l5 5v21H8zM21 11v5h5M12 23h9M12 28h11"/>'
|
|
391
|
+
+ `<g class="sc-gear-big sc-box"><path class="sc-mid" d="${GEAR_BIG}"/><circle class="sc-dim" cx="66" cy="20" r="3.2"/></g>`
|
|
392
|
+
+ `<g class="sc-gear-small sc-box"><path class="sc-gold" d="${GEAR_SMALL}"/><circle class="sc-gold" cx="86.5" cy="12.5" r="2"/></g>`
|
|
393
|
+
+ '<path class="sc-dim" d="M98 30h14M102 25h10"/>';
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function reviewFull() {
|
|
397
|
+
const rows = [[9, '+', 52], [16, '-', 64], [23, '+', 40], [30, '+', 58]];
|
|
398
|
+
let out = '<rect class="sc-dim" x="1" y="1.5" width="118" height="37" rx="5"/>';
|
|
399
|
+
rows.forEach(([y, sign, len], i) => {
|
|
400
|
+
out += sign === '+' ? `<path class="sc-mid" d="M6 ${y}h4M8 ${y - 2}v4"/>` : `<path class="sc-mid" d="M6 ${y}h4"/>`;
|
|
401
|
+
out += `<path class="sc-dim" d="M15 ${y}h${len}"/>`;
|
|
402
|
+
out += `<path class="sc-gold sc-tick sc-box" style="--i:${i}" d="M${95} ${y}l2.2 2.2 4.4-4.6"/>`;
|
|
403
|
+
});
|
|
404
|
+
return out;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function researchFull() {
|
|
408
|
+
const page = (x) => `<rect class="sc-dim" x="${x}" y="4" width="40" height="32" rx="3"/><path class="sc-dim" d="M${x + 6} 11h26M${x + 6} 17h22M${x + 6} 23h28M${x + 6} 29h16"/>`;
|
|
409
|
+
return page(8) + page(56)
|
|
410
|
+
+ '<g class="sc-lens"><circle class="sc-gold" cx="24" cy="17" r="7"/><path class="sc-gold" d="M29.2 22.2l5 5"/></g>';
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const POINTER = 'M0 0v10.5l2.8-2.6 2 4.4 2-.9-2-4.3h3.9z';
|
|
414
|
+
|
|
415
|
+
function browserFull() {
|
|
416
|
+
return '<rect class="sc-dim" x="1" y="1.5" width="118" height="37" rx="5"/><path class="sc-dim" d="M1 9.5h118"/>'
|
|
417
|
+
+ '<circle class="sc-mid sc-fill" cx="6" cy="5.5" r="1"/><circle class="sc-mid sc-fill" cx="10" cy="5.5" r="1"/><circle class="sc-mid sc-fill" cx="14" cy="5.5" r="1"/>'
|
|
418
|
+
+ '<rect class="sc-dim" x="22" y="3.5" width="56" height="4" rx="2"/>'
|
|
419
|
+
+ '<path class="sc-mid" d="M8 16h36"/><path class="sc-dim" d="M8 22h54M8 27h44M8 32h30"/><rect class="sc-mid" x="78" y="25" width="28" height="8" rx="2"/>'
|
|
420
|
+
+ '<circle class="sc-gold sc-ring sc-ripple-browser sc-box" cx="92" cy="29" r="5"/>'
|
|
421
|
+
+ `<g class="sc-point-browser" style="transform:translate(92px,29px)"><path class="sc-gold sc-fill" d="${POINTER}"/></g>`;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function computerFull() {
|
|
425
|
+
return '<rect class="sc-dim" x="10" y="1.5" width="100" height="30" rx="3"/><path class="sc-dim" d="M60 31.5v4M48 37.5h24"/>'
|
|
426
|
+
+ '<rect class="sc-mid sc-shade" x="16" y="6" width="44" height="20" rx="2"/><path class="sc-dim" d="M16 10h44M21 15h20M21 20h28"/>'
|
|
427
|
+
+ '<rect class="sc-mid sc-shade" x="52" y="11" width="50" height="17" rx="2"/><path class="sc-dim" d="M52 15h50"/><rect class="sc-mid" x="84" y="20" width="13" height="5" rx="1.5"/>'
|
|
428
|
+
+ '<circle class="sc-gold sc-ring sc-ripple-computer sc-box" cx="90" cy="22.5" r="4.5"/>'
|
|
429
|
+
+ `<g class="sc-point-computer" style="transform:translate(90px,22.5px)"><path class="sc-gold sc-fill" d="${POINTER}"/></g>`;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function automationFull() {
|
|
433
|
+
return '<circle class="sc-mid" cx="18" cy="20" r="13"/><path class="sc-dim" d="M18 9v2M18 29v2M7 20h2M27 20h2"/>'
|
|
434
|
+
+ '<path class="sc-mid" d="M18 20l5-4"/>'
|
|
435
|
+
+ '<g class="sc-hand sc-vb" style="transform-origin:18px 20px"><path class="sc-gold" d="M18 20v-9"/></g><circle class="sc-gold sc-fill" cx="18" cy="20" r="1.6"/>'
|
|
436
|
+
+ '<path class="sc-dim" d="M52 24h14M76 24h14"/><rect class="sc-mid" x="44" y="20" width="8" height="8" rx="2"/><rect class="sc-mid" x="66" y="20" width="10" height="8" rx="2"/><rect class="sc-mid" x="90" y="20" width="8" height="8" rx="2"/>'
|
|
437
|
+
+ '<path class="sc-dim" d="M94 17c0-9-46-9-46 0M48 17l-2.5-3M48 17l3-2"/>'
|
|
438
|
+
+ '<g class="sc-run-dot"><circle class="sc-gold sc-fill" cx="48" cy="24" r="2.2"/></g>';
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function designFull() {
|
|
442
|
+
return '<rect class="sc-gold sc-fill sc-swatch" x="4" y="5" width="9" height="9" rx="2"/><rect class="sc-mid sc-fill sc-swatch-b" x="4" y="16" width="9" height="9" rx="2"/><rect class="sc-dim sc-fill sc-swatch-c" x="4" y="27" width="9" height="9" rx="2"/>'
|
|
443
|
+
+ '<rect class="sc-dim" x="20" y="2.5" width="96" height="35" rx="4"/>'
|
|
444
|
+
+ '<circle class="sc-mid sc-shape sc-box" style="--i:0" cx="40" cy="20" r="8"/>'
|
|
445
|
+
+ '<rect class="sc-mid sc-shape sc-box" style="--i:1" x="58" y="12" width="16" height="16" rx="3"/>'
|
|
446
|
+
+ '<path class="sc-mid sc-shape sc-box" style="--i:2" d="M86 28l9-16 9 16z"/>'
|
|
447
|
+
+ '<g class="sc-pen" style="transform:translate(40px,20px)"><path class="sc-gold" d="M0 0l6-6M6-6l2.5 2.5M0 0l-1.2 3.7L2.5 2.5z"/></g>';
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function imageFull() {
|
|
451
|
+
let tiles = '';
|
|
452
|
+
for (let row = 0; row < 3; row += 1) {
|
|
453
|
+
for (let col = 0; col < 4; col += 1) {
|
|
454
|
+
const gold = (row === 1 && col === 2) || (row === 2 && col === 0);
|
|
455
|
+
tiles += `<rect class="${gold ? 'sc-gold' : 'sc-mid'} sc-fill sc-tile" style="--i:${row + col}" x="${34 + col * 13.5}" y="${6 + row * 10}" width="11.5" height="8" rx="1.5"/>`;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return `<rect class="sc-dim" x="30" y="2.5" width="61" height="35" rx="3"/>${tiles}`
|
|
459
|
+
+ '<g class="sc-sparkle sc-box"><path class="sc-gold sc-fill" d="M104 6l1.6 4.4L110 12l-4.4 1.6L104 18l-1.6-4.4L98 12l4.4-1.6z"/></g>'
|
|
460
|
+
+ '<path class="sc-dim" d="M100 26h12M100 31h8"/>';
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function filmFrames(width, y, h, frameW, count) {
|
|
464
|
+
let out = `<rect class="sc-dim" x="0" y="${y}" width="${width}" height="${h}" rx="2"/>`;
|
|
465
|
+
for (let i = 0; i < count; i += 1) out += `<rect class="sc-mid" x="${i * frameW + 3}" y="${y + 5}" width="${frameW - 6}" height="${h - 10}" rx="1.5"/>`;
|
|
466
|
+
for (let x = 2; x < width; x += 6) out += `<rect class="sc-dim sc-fill" x="${x}" y="${y + 1.5}" width="2.4" height="2" rx=".6"/><rect class="sc-dim sc-fill" x="${x}" y="${y + h - 3.5}" width="2.4" height="2" rx=".6"/>`;
|
|
467
|
+
return out;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function videoFull() {
|
|
471
|
+
return `<svg x="4" y="4" width="112" height="32" overflow="hidden"><g class="sc-film">${filmFrames(160, 2, 28, 24, 7)}</g></svg>`
|
|
472
|
+
+ '<path class="sc-gold" d="M58 2v36M55 2h6l-3 3z"/>';
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** An open-end wrench, horizontal, its jaw round (0, 0): place it with translate(bolt) rotate(a) translate(3.5 0). */
|
|
476
|
+
const WRENCH = 'M-4.6 -3.86L-1 -2V2L-4.6 3.86A6 6 0 0 0 5.5 2.4H24A2.4 2.4 0 0 0 24 -2.4H5.5A6 6 0 0 0 -4.6 -3.86Z';
|
|
477
|
+
const hexagon = (cx, cy, r) => `M${[0, 1, 2, 3, 4, 5].map(i => `${r1(cx + r * Math.cos(i * Math.PI / 3))} ${r1(cy + r * Math.sin(i * Math.PI / 3))}`).join('L')}Z`;
|
|
478
|
+
|
|
479
|
+
function quickFull() {
|
|
480
|
+
return `<path class="sc-mid" d="${hexagon(38, 24, 3.4)}"/>`
|
|
481
|
+
+ `<g class="sc-wrench sc-vb" style="transform-origin:38px 24px"><path class="sc-gold" transform="translate(38 24) rotate(-32) translate(3.5 0)" d="${WRENCH}"/></g>`
|
|
482
|
+
+ '<path class="sc-gold sc-spark" style="--i:0" d="M30.5 19.5l-3-2"/><path class="sc-gold sc-spark" style="--i:1" d="M29.5 24.5h-3.5"/><path class="sc-gold sc-spark" style="--i:2" d="M30.5 29.5l-3 2"/>'
|
|
483
|
+
+ '<g class="sc-zap sc-box"><path class="sc-gold" d="M92 5l-8 15h7l-3 14 11-18h-7.5z"/></g>';
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function genericFull() {
|
|
487
|
+
return '<path class="sc-dim" d="M14 20h92"/><circle class="sc-mid" cx="14" cy="20" r="3"/><circle class="sc-mid" cx="60" cy="20" r="3"/><circle class="sc-mid" cx="106" cy="20" r="3"/>'
|
|
488
|
+
+ '<g class="sc-slide"><rect class="sc-gold sc-fill" x="14" y="18.5" width="24" height="3" rx="1.5"/></g>';
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Minis (40×20, the tray at 32×16): one gesture each.
|
|
492
|
+
const MINI = {
|
|
493
|
+
code: () => '<path class="sc-mid" d="M5 5h20M9 10h24M5 15h14"/><rect class="sc-gold sc-fill sc-caret" x="21.5" y="12.5" width="1.8" height="5" rx=".9"/>',
|
|
494
|
+
complex: () => `<g class="sc-gear-big sc-box"><path class="sc-mid" d="${gearPath(14, 11, 4.5, 6.6, 6)}"/></g><g class="sc-gear-small sc-box"><path class="sc-gold" d="${gearPath(26.5, 7.5, 3, 4.6, 6)}"/></g>`,
|
|
495
|
+
review: () => '<path class="sc-dim" d="M4 5h20M4 10h24M4 15h18"/><path class="sc-gold sc-tick sc-box" style="--i:0" d="M30 5l1.6 1.6 3.2-3.4"/><path class="sc-gold sc-tick sc-box" style="--i:1" d="M32 10l1.6 1.6 3.2-3.4"/>',
|
|
496
|
+
research: () => '<rect class="sc-dim" x="3" y="2.5" width="26" height="15" rx="2"/><path class="sc-dim" d="M7 7h16M7 11h12M7 15h14"/><g class="sc-lens-mini"><circle class="sc-gold" cx="12" cy="9" r="3.8"/><path class="sc-gold" d="M14.8 11.8l2.8 2.8"/></g>',
|
|
497
|
+
browser: () => `<rect class="sc-dim" x="2" y="2" width="36" height="16" rx="2.5"/><path class="sc-dim" d="M2 6h36"/><rect class="sc-mid" x="24" y="11" width="10" height="4" rx="1.2"/><g class="sc-point-mini" style="transform:translate(29px,13px) scale(.6)"><path class="sc-gold sc-fill" d="${POINTER}"/></g>`,
|
|
498
|
+
computer: () => `<rect class="sc-dim" x="5" y="1.5" width="30" height="14" rx="2"/><path class="sc-dim" d="M20 15.5v2M15 18.5h10"/><rect class="sc-mid" x="8" y="4.5" width="13" height="8" rx="1"/><g class="sc-point-mini" style="transform:translate(29px,13px) scale(.6)"><path class="sc-gold sc-fill" d="${POINTER}"/></g>`,
|
|
499
|
+
automation: () => '<circle class="sc-mid" cx="11" cy="10" r="7.5"/><path class="sc-dim" d="M11 10l3-2.5"/><g class="sc-hand sc-vb" style="transform-origin:11px 10px"><path class="sc-gold" d="M11 10V4.5"/></g>'
|
|
500
|
+
+ '<path class="sc-mid" d="M33.5 10a5 5 0 1 1-1.5-3.6M32 3.6v2.8h-2.8"/>',
|
|
501
|
+
design: () => '<rect class="sc-mid sc-fill" x="3" y="3" width="6" height="6" rx="1.5"/><rect class="sc-dim sc-fill" x="3" y="11" width="6" height="6" rx="1.5"/><circle class="sc-gold sc-shape sc-box" style="--i:0" cx="21" cy="10" r="5"/><path class="sc-mid sc-shape sc-box" style="--i:1" d="M29 15l4.5-8 4.5 8z"/>',
|
|
502
|
+
image_gen: () => {
|
|
503
|
+
let tiles = '';
|
|
504
|
+
for (let row = 0; row < 2; row += 1) for (let col = 0; col < 3; col += 1) tiles += `<rect class="${row === 1 && col === 2 ? 'sc-gold' : 'sc-mid'} sc-fill sc-tile" style="--i:${row + col}" x="${11 + col * 6.4}" y="${5 + row * 5.6}" width="5" height="4.2" rx="1"/>`;
|
|
505
|
+
return `<rect class="sc-dim" x="9" y="2.5" width="22" height="15" rx="2"/>${tiles}`;
|
|
506
|
+
},
|
|
507
|
+
video_gen: () => `<svg x="2" y="2" width="36" height="16" overflow="hidden"><g class="sc-film-mini">${filmFrames(60, 1, 14, 12, 5)}</g></svg><path class="sc-gold" d="M20 1v18"/>`,
|
|
508
|
+
quick: () => `<path class="sc-mid" d="${hexagon(11, 11, 2.6)}"/><g class="sc-wrench sc-vb" style="transform-origin:11px 11px"><path class="sc-gold" stroke-width="2.4" transform="translate(11 11) rotate(-32) scale(.62) translate(3.5 0)" d="${WRENCH}"/></g>`
|
|
509
|
+
+ '<path class="sc-gold sc-spark" style="--i:0" d="M5.5 7.5l-2-1.3"/><path class="sc-gold sc-spark" style="--i:1" d="M5 11.5H2.6"/>',
|
|
510
|
+
generic: () => '<circle class="sc-gold sc-fill sc-dot" style="--i:0" cx="11" cy="10" r="2.4"/><circle class="sc-gold sc-fill sc-dot" style="--i:1" cx="20" cy="10" r="2.4"/><circle class="sc-gold sc-fill sc-dot" style="--i:2" cx="29" cy="10" r="2.4"/>',
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
const FULL = {
|
|
514
|
+
quick: quickFull, code: codeFull, complex: complexFull, review: reviewFull, research: researchFull, browser: browserFull,
|
|
515
|
+
computer: computerFull, automation: automationFull, design: designFull, image_gen: imageFull, video_gen: videoFull, generic: genericFull,
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* A scene's SVG (decorative: aria-hidden). `mini` draws the tray's 40×20
|
|
520
|
+
* version. `live` starts it moving (the stage and tray set data-live
|
|
521
|
+
* themselves later; this is only the first state).
|
|
522
|
+
*/
|
|
523
|
+
export function sceneSvg(scene, { mini = false, live = false, className = '' } = {}) {
|
|
524
|
+
const id = Object.hasOwn(FULL, scene) ? scene : 'generic';
|
|
525
|
+
const [w, h] = mini ? [40, 20] : [120, 40];
|
|
526
|
+
const body = (mini ? MINI[id] : FULL[id])();
|
|
527
|
+
return `<svg class="asst-scene${mini ? ' is-mini' : ''}${className ? ` ${className}` : ''}" data-scene="${id}"${live ? ' data-live=""' : ''} viewBox="0 0 ${w} ${h}" width="${w}" height="${h}" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${body}</svg>`;
|
|
528
|
+
}
|
|
@@ -450,21 +450,9 @@ export function injectAssistantSidepanelStyles() {
|
|
|
450
450
|
.assistant-panel .asst-send[data-state="ready"]::before { transform: scaleX(1); }
|
|
451
451
|
.assistant-panel .asst-send[data-state="ready"]:hover { box-shadow: inset 0 0 0 1px var(--asp-gold); }
|
|
452
452
|
|
|
453
|
-
/*
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
icon · name · ✕, no geometry of its own. Only the identity is
|
|
457
|
-
SynaBun's: the two-pill mark, and the cameo in its place while working
|
|
458
|
-
(gold, with a gold hairline); a session that needs you tints the mark
|
|
459
|
-
and the hairline. It is a button (Enter/Space) with the panel's focus
|
|
460
|
-
ring, and its ✕ keeps the tray's 24px target. */
|
|
461
|
-
.asp-session-pill .term-minimized-pill-icon .syna-cameo { display: none; }
|
|
462
|
-
.asp-session-pill.asp-pill-running { border-color: var(--asst-pill-on-ring); }
|
|
463
|
-
.asp-session-pill.asp-pill-running .term-minimized-pill-icon { color: var(--asst-brand); }
|
|
464
|
-
.asp-session-pill.asp-pill-running .term-minimized-pill-icon > svg:not(.syna-cameo) { display: none; }
|
|
465
|
-
.asp-session-pill.asp-pill-running .term-minimized-pill-icon .syna-cameo { display: inline-flex; }
|
|
466
|
-
.asp-session-pill.asp-pill-attention { border-color: var(--asst-pill-warn-ring); }
|
|
467
|
-
.asp-session-pill.asp-pill-attention .term-minimized-pill-icon { color: var(--asst-warn); }
|
|
453
|
+
/* The tray pill (#term-minimized-tray, outside the panel) is the
|
|
454
|
+
component's (asst-styles.js "Tray pill"): the terminal tab minimises to
|
|
455
|
+
the same one, so its states load with the component in either host. */
|
|
468
456
|
|
|
469
457
|
/* ── Motion ─────────────────────────────────────────────────────── */
|
|
470
458
|
@keyframes asp-sweep { from { transform: translateX(-100%); } to { transform: translateX(270%); } }
|
|
@@ -429,6 +429,20 @@ export function runTone(run) {
|
|
|
429
429
|
return 'running';
|
|
430
430
|
}
|
|
431
431
|
|
|
432
|
+
/**
|
|
433
|
+
* What a session's status is (the tray pill, the sidepanel header, the terminal tab's badge):
|
|
434
|
+
* 'action' while anything waits on you (a card of its own, or a worker's permission, question or
|
|
435
|
+
* model choice), 'working' while its own turn runs or any worker it dispatched works (queued for a
|
|
436
|
+
* free slot, starting, in a turn), else what its own last turn left ('done' when it ended out of
|
|
437
|
+
* sight, else 'idle'). A worker outlives the turn that dispatched it, and so does the gold.
|
|
438
|
+
* `own` is the brain's own status; `workers` the agents tray's counts (asst-agents-dock.js counts()).
|
|
439
|
+
*/
|
|
440
|
+
export function sessionStatus(own, workers = {}) {
|
|
441
|
+
if (own === 'action' || Number(workers?.waiting) > 0) return 'action';
|
|
442
|
+
if (own === 'working' || Number(workers?.working) > 0) return 'working';
|
|
443
|
+
return own === 'done' ? 'done' : 'idle';
|
|
444
|
+
}
|
|
445
|
+
|
|
432
446
|
function toMs(value) {
|
|
433
447
|
if (value == null || value === '') return 0;
|
|
434
448
|
if (typeof value === 'number') return Number.isFinite(value) ? value : 0;
|