synabun 2.0.0 → 2.0.7
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 +97 -0
- package/NOTICE +5 -0
- package/README.md +2 -1
- package/THIRD-PARTY-LICENSES.md +59 -0
- package/benchmarks/fixtures/browser/README.md +1 -1
- package/benchmarks/fixtures/desktop/README.md +1 -1
- package/docs/whatsapp.md +153 -18
- package/hooks/claude-code/pre-compact.mjs +11 -0
- package/hooks/claude-code/prompt-submit.mjs +60 -184
- package/hooks/claude-code/session-start.mjs +73 -16
- package/hooks/claude-code/shared.mjs +26 -3
- package/hooks/claude-code/stop.mjs +5 -5
- package/lib/child-path.js +303 -0
- package/lib/claude-hooks.js +2 -1
- package/lib/data-home-migration.js +2 -0
- package/lib/desktop-app.js +265 -0
- package/lib/external-tools.js +7 -3
- package/lib/log-redact.js +102 -0
- package/lib/packaged-runtime.js +138 -11
- package/lib/start-launcher.js +88 -1
- package/mcp-server/dist/http.d.ts +3 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +15 -4
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +9 -6
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +108 -0
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/budget-judgments.js +153 -0
- package/mcp-server/dist/services/budget-judgments.js.map +1 -0
- package/mcp-server/dist/services/codex-config-heal.d.ts +5 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +41 -4
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +11 -0
- package/mcp-server/dist/services/identity.d.ts.map +1 -1
- package/mcp-server/dist/services/identity.js +24 -0
- package/mcp-server/dist/services/identity.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +13 -0
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +34 -2
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/typesafe-config.d.ts +1 -1
- package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -1
- package/mcp-server/dist/services/typesafe-config.js +4 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +10 -7
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +34 -13
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts +17 -0
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -0
- package/mcp-server/dist/tools/whatsapp-send-file.js +44 -0
- package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -0
- package/mcp-server/dist/tui.js +2 -1
- package/mcp-server/dist/tui.js.map +1 -1
- package/mcp-server/dist/version.d.ts +5 -0
- package/mcp-server/dist/version.d.ts.map +1 -0
- package/mcp-server/dist/version.js +21 -0
- package/mcp-server/dist/version.js.map +1 -0
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -3
- package/mcp-server/run.mjs +15 -9
- package/mcp-server/src/http.ts +18 -3
- package/mcp-server/src/index.ts +9 -6
- package/mcp-server/src/services/budget-judgments.ts +183 -0
- package/mcp-server/src/services/codex-config-heal.ts +35 -4
- package/mcp-server/src/services/identity.ts +27 -0
- package/mcp-server/src/services/neural-interface.ts +34 -2
- package/mcp-server/src/services/typesafe-config.ts +4 -1
- package/mcp-server/src/tools/agents.ts +33 -14
- package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
- package/mcp-server/src/tui.ts +2 -1
- package/mcp-server/src/version.ts +22 -0
- package/neural-interface/i18n/en.json +2126 -209
- package/neural-interface/i18n/pt-BR.json +2123 -207
- package/neural-interface/lib/account-usage.js +163 -0
- package/neural-interface/lib/assistant-api.js +316 -57
- package/neural-interface/lib/assistant-brains/claude.js +19 -2
- package/neural-interface/lib/assistant-brains/codex.js +3 -0
- package/neural-interface/lib/assistant-brains/opencode.js +17 -4
- package/neural-interface/lib/assistant-budget-planner.js +390 -0
- package/neural-interface/lib/assistant-budget-split.js +408 -0
- package/neural-interface/lib/assistant-budget.js +94 -95
- package/neural-interface/lib/assistant-catalog.js +179 -27
- package/neural-interface/lib/assistant-config.js +91 -14
- package/neural-interface/lib/assistant-dispatch.js +494 -138
- package/neural-interface/lib/assistant-hidden-models.js +393 -66
- package/neural-interface/lib/assistant-jev.js +26 -3
- package/neural-interface/lib/assistant-memory.js +24 -10
- package/neural-interface/lib/assistant-persona.js +73 -12
- package/neural-interface/lib/assistant-plan-permissions.js +8 -1
- package/neural-interface/lib/assistant-pricing.js +21 -6
- package/neural-interface/lib/assistant-route-accounts.js +14 -0
- package/neural-interface/lib/assistant-route-gate.js +19 -3
- package/neural-interface/lib/assistant-router.js +373 -42
- package/neural-interface/lib/assistant-runtime.js +488 -59
- package/neural-interface/lib/assistant-task-prompt.js +13 -3
- package/neural-interface/lib/assistant-test-density.js +142 -0
- package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
- package/neural-interface/lib/assistant-user-context.js +908 -0
- package/neural-interface/lib/assistant-user-knowledge.js +328 -0
- package/neural-interface/lib/assistant-user-learn.js +404 -0
- package/neural-interface/lib/assistant-user-threads.js +226 -0
- package/neural-interface/lib/assistant-user-writer.js +183 -0
- package/neural-interface/lib/augmented-path.js +317 -53
- package/neural-interface/lib/browser-background-tab.js +134 -0
- package/neural-interface/lib/browser-screenshot.js +678 -61
- package/neural-interface/lib/claude-accounts.js +342 -31
- package/neural-interface/lib/claude-agent-bridge.js +123 -9
- package/neural-interface/lib/claude-executable.js +6 -1
- package/neural-interface/lib/claude-model-catalog.js +33 -5
- package/neural-interface/lib/claude-panel-auth.js +221 -0
- package/neural-interface/lib/claude-profile-api-key.js +62 -0
- package/neural-interface/lib/claude-temporary.js +46 -7
- package/neural-interface/lib/cli-install-api.js +137 -0
- package/neural-interface/lib/cli-install.js +797 -0
- package/neural-interface/lib/cli-path.js +130 -0
- package/neural-interface/lib/cli-resolver.js +744 -0
- package/neural-interface/lib/cli-update-planner.js +143 -7
- package/neural-interface/lib/cloudflared/install.js +533 -0
- package/neural-interface/lib/cloudflared/manager.js +545 -0
- package/neural-interface/lib/cloudflared/pins.js +115 -0
- package/neural-interface/lib/cloudflared/pins.json +63 -0
- package/neural-interface/lib/cloudflared/tunnel.js +265 -0
- package/neural-interface/lib/codex-account-auth.js +178 -0
- package/neural-interface/lib/codex-accounts.js +489 -0
- package/neural-interface/lib/codex-capabilities.js +2 -1
- package/neural-interface/lib/codex-compat-rpc.js +8 -2
- package/neural-interface/lib/codex-mcp-approvals.js +5 -1
- package/neural-interface/lib/codex-panel-auth.js +62 -0
- package/neural-interface/lib/codex-session-settings.js +1 -1
- package/neural-interface/lib/codex-settings-schema.js +120 -0
- package/neural-interface/lib/desktop/config.js +3 -0
- package/neural-interface/lib/editor-completion-endpoint.js +264 -0
- package/neural-interface/lib/editor-completion-opencode.js +436 -0
- package/neural-interface/lib/editor-completion.js +714 -0
- package/neural-interface/lib/editor-config.js +149 -0
- package/neural-interface/lib/editor-files-api.js +268 -0
- package/neural-interface/lib/editor-git-api.js +134 -0
- package/neural-interface/lib/file-explorer-api.js +1039 -0
- package/neural-interface/lib/file-explorer-system.js +355 -0
- package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
- package/neural-interface/lib/file-explorer-watch.js +239 -0
- package/neural-interface/lib/git-bash/bzip2.js +339 -0
- package/neural-interface/lib/git-bash/claude-settings.js +73 -0
- package/neural-interface/lib/git-bash/extract-worker.js +34 -0
- package/neural-interface/lib/git-bash/install.js +529 -0
- package/neural-interface/lib/git-bash/licenses/COPYING +360 -0
- package/neural-interface/lib/git-bash/licenses/LGPL-2.1 +511 -0
- package/neural-interface/lib/git-bash/manager.js +268 -0
- package/neural-interface/lib/git-bash/pins.js +206 -0
- package/neural-interface/lib/git-bash/pins.json +34 -0
- package/neural-interface/lib/git-bash/resolver.js +194 -0
- package/neural-interface/lib/git-diff-api.js +103 -0
- package/neural-interface/lib/git-read.js +234 -0
- package/neural-interface/lib/greeting/api.js +89 -0
- package/neural-interface/lib/greeting/budgets.js +90 -0
- package/neural-interface/lib/greeting/engine.js +461 -0
- package/neural-interface/lib/greeting/facts.js +320 -0
- package/neural-interface/lib/greeting/sources.js +252 -0
- package/neural-interface/lib/greeting/writer.js +139 -0
- package/neural-interface/lib/http-guards.js +189 -13
- package/neural-interface/lib/install-details.js +145 -0
- package/neural-interface/lib/machine-names.js +88 -0
- package/neural-interface/lib/mcp-installer.js +14 -2
- package/neural-interface/lib/memory-api.js +31 -7
- package/neural-interface/lib/native-loop-providers.js +26 -8
- package/neural-interface/lib/native-loop-runtime.js +9 -4
- package/neural-interface/lib/os-path.js +319 -0
- package/neural-interface/lib/plugin-installer.js +4 -2
- package/neural-interface/lib/project-storage.js +5 -7
- package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
- package/neural-interface/lib/provider-panel-terminal-auth.js +95 -0
- package/neural-interface/lib/pty-host/core.js +2 -1
- package/neural-interface/lib/pty-host/manager.js +27 -2
- package/neural-interface/lib/remote-policy.js +20 -11
- package/neural-interface/lib/request-gate.js +589 -0
- package/neural-interface/lib/session-title-generator.js +4 -3
- package/neural-interface/lib/system-about.js +340 -0
- package/neural-interface/lib/system-activity.js +66 -0
- package/neural-interface/lib/terminal-env.js +11 -3
- package/neural-interface/lib/terminal-path.js +55 -0
- package/neural-interface/lib/ui-blob-api.js +108 -0
- package/neural-interface/lib/ui-blob-store.js +68 -0
- package/neural-interface/lib/virtual-socket.js +12 -1
- package/neural-interface/lib/whatsapp/baileys-adapter.js +165 -45
- package/neural-interface/lib/whatsapp/bridge.js +78 -34
- package/neural-interface/lib/whatsapp/commands.js +13 -14
- package/neural-interface/lib/whatsapp/config.js +134 -20
- package/neural-interface/lib/whatsapp/fake-baileys.js +99 -14
- package/neural-interface/lib/whatsapp/host-core.js +168 -35
- package/neural-interface/lib/whatsapp/inbound.js +5 -3
- package/neural-interface/lib/whatsapp/local-file.js +524 -0
- package/neural-interface/lib/whatsapp/manager.js +92 -32
- package/neural-interface/lib/whatsapp/paths.js +11 -1
- package/neural-interface/lib/whatsapp/protocol.js +65 -5
- package/neural-interface/lib/whatsapp/redact.js +63 -0
- package/neural-interface/lib/whatsapp/service.js +343 -91
- package/neural-interface/lib/whatsapp/transcription.js +463 -0
- package/neural-interface/package-lock.json +701 -2
- package/neural-interface/package.json +13 -2
- package/neural-interface/public/index.html +2 -0
- package/neural-interface/public/index2d.html +2 -0
- package/neural-interface/public/install-app.html +9 -6
- package/neural-interface/public/offline.html +19 -3
- package/neural-interface/public/onboarding.html +107 -2
- package/neural-interface/public/shared/account-i18n.js +7 -0
- package/neural-interface/public/shared/account-menu.js +539 -0
- package/neural-interface/public/shared/account-usage.js +19 -0
- package/neural-interface/public/shared/account-view.js +335 -0
- package/neural-interface/public/shared/agent-runtime-options.js +50 -14
- package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
- package/neural-interface/public/shared/assistant/asst-api.js +32 -2
- package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +430 -81
- package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
- package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
- package/neural-interface/public/shared/assistant/asst-mascot.js +140 -61
- package/neural-interface/public/shared/assistant/asst-menu.js +27 -11
- package/neural-interface/public/shared/assistant/asst-panel.js +198 -42
- package/neural-interface/public/shared/assistant/asst-render.js +197 -23
- package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
- package/neural-interface/public/shared/assistant/asst-route.js +95 -343
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +534 -0
- package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
- package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
- package/neural-interface/public/shared/assistant/asst-state.js +186 -2
- package/neural-interface/public/shared/assistant/asst-styles.js +247 -11
- package/neural-interface/public/shared/blob-store.js +111 -22
- package/neural-interface/public/shared/cdx/cdx-commands.js +4 -1
- package/neural-interface/public/shared/cdx/cdx-features.js +22 -14
- package/neural-interface/public/shared/cdx/cdx-icons.js +2 -0
- package/neural-interface/public/shared/cdx/cdx-panel.js +80 -118
- package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
- package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +164 -107
- package/neural-interface/public/shared/cdx/cdx-tabs.js +348 -668
- package/neural-interface/public/shared/cdx/cdx-ws.js +2 -0
- package/neural-interface/public/shared/claude-account-view.js +3 -0
- package/neural-interface/public/shared/cli-install-view.js +392 -0
- package/neural-interface/public/shared/cli-status.js +282 -22
- package/neural-interface/public/shared/constants.js +6 -1
- package/neural-interface/public/shared/cp/cp-events.js +2 -1
- package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
- package/neural-interface/public/shared/cp/cp-styles.js +61 -0
- package/neural-interface/public/shared/desktop-bridge.js +39 -0
- package/neural-interface/public/shared/desktop-titlebar-page.js +59 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +122 -0
- package/neural-interface/public/shared/desktop-titlebar.js +153 -0
- package/neural-interface/public/shared/desktop-update-view.js +462 -0
- package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
- package/neural-interface/public/shared/editor/editor-ai.js +619 -0
- package/neural-interface/public/shared/editor/editor-commands.js +212 -0
- package/neural-interface/public/shared/editor/editor-compare.js +103 -0
- package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
- package/neural-interface/public/shared/editor/editor-doc.js +257 -0
- package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
- package/neural-interface/public/shared/editor/editor-git.js +95 -0
- package/neural-interface/public/shared/editor/editor-languages.js +156 -0
- package/neural-interface/public/shared/editor/editor-lint.js +229 -0
- package/neural-interface/public/shared/editor/editor-loader.js +51 -0
- package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
- package/neural-interface/public/shared/editor/editor-menu.js +233 -0
- package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
- package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
- package/neural-interface/public/shared/editor/editor-palette.js +125 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
- package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
- package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
- package/neural-interface/public/shared/editor/editor-safety.js +500 -0
- package/neural-interface/public/shared/editor/editor-search.js +352 -0
- package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
- package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
- package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
- package/neural-interface/public/shared/editor/editor-theme.js +244 -0
- package/neural-interface/public/shared/editor/editor-view.js +332 -0
- package/neural-interface/public/shared/explorer/fx-api.js +216 -0
- package/neural-interface/public/shared/explorer/fx-links.js +204 -0
- package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
- package/neural-interface/public/shared/explorer/fx-main.js +865 -0
- package/neural-interface/public/shared/explorer/fx-names.js +87 -0
- package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
- package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
- package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
- package/neural-interface/public/shared/file-links.js +339 -0
- package/neural-interface/public/shared/git-bash-view.js +145 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
- package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
- package/neural-interface/public/shared/html-shell.js +161 -165
- package/neural-interface/public/shared/i18n.js +19 -1
- package/neural-interface/public/shared/install-details-view.js +86 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +131 -17
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +22 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +158 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
- package/neural-interface/public/shared/pwa-install-page.js +32 -2
- package/neural-interface/public/shared/pwa-install.css +3 -3
- package/neural-interface/public/shared/pwa-install.js +100 -1
- package/neural-interface/public/shared/settings/settings-about-pane.js +271 -0
- package/neural-interface/public/shared/settings/settings-about.js +254 -0
- package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
- package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
- package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
- package/neural-interface/public/shared/settings/settings-ia.js +33 -4
- package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
- package/neural-interface/public/shared/showcase-privacy.js +489 -0
- package/neural-interface/public/shared/start-bridge.js +238 -19
- package/neural-interface/public/shared/storage.js +30 -3
- package/neural-interface/public/shared/styles.css +1710 -770
- package/neural-interface/public/shared/synabun-mascot.js +68 -58
- package/neural-interface/public/shared/tunnel-view.js +167 -0
- package/neural-interface/public/shared/ui-claude-panel.js +369 -229
- package/neural-interface/public/shared/ui-cli-banner.js +355 -0
- package/neural-interface/public/shared/ui-detail.js +15 -0
- package/neural-interface/public/shared/ui-explorer.js +22 -0
- package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
- package/neural-interface/public/shared/ui-file-links.js +103 -0
- package/neural-interface/public/shared/ui-git-bash.js +124 -0
- package/neural-interface/public/shared/ui-help.js +26 -0
- package/neural-interface/public/shared/ui-invite.js +126 -116
- package/neural-interface/public/shared/ui-judgments.js +10 -1
- package/neural-interface/public/shared/ui-keybinds.js +4 -0
- package/neural-interface/public/shared/ui-loading.js +187 -19
- package/neural-interface/public/shared/ui-menubar.js +25 -33
- package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
- package/neural-interface/public/shared/ui-navbar.js +48 -22
- package/neural-interface/public/shared/ui-provider-auth.js +104 -0
- package/neural-interface/public/shared/ui-provider-terminal-auth.js +223 -0
- package/neural-interface/public/shared/ui-sessions.js +9 -3
- package/neural-interface/public/shared/ui-settings.js +509 -490
- package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
- package/neural-interface/public/shared/ui-sync.js +22 -0
- package/neural-interface/public/shared/ui-terminal.js +40 -5
- package/neural-interface/public/shared/ui-tool-updates.js +5 -0
- package/neural-interface/public/shared/ui-tunnel.js +130 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
- package/neural-interface/public/shared/ui-update.js +594 -5
- package/neural-interface/public/shared/ui-whatsapp.js +21 -6
- package/neural-interface/public/shared/ui-whiteboard.js +12 -0
- package/neural-interface/public/shared/ui-worker-end.js +245 -0
- package/neural-interface/public/shared/ui-workspaces.js +41 -27
- package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
- package/neural-interface/public/shared/worker-end.js +253 -0
- package/neural-interface/public/sw.js +2 -2
- package/neural-interface/public/variant/2d/main.js +10 -1
- package/neural-interface/public/variant/3d/main.js +10 -1
- package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
- package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
- package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
- package/neural-interface/scripts/build-vendor.mjs +78 -2
- package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
- package/neural-interface/server.js +2085 -1629
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/package.json +5 -8
- package/setup.js +53 -15
- package/benchmarks/browser-live-results.json +0 -79
- package/benchmarks/browser-v2-results.json +0 -258
- package/neural-interface/lib/codex-capabilities.d.ts +0 -41
- package/neural-interface/public/category-logos/claude.svg +0 -1
- package/neural-interface/public/category-logos/gemini-color.svg +0 -1
- package/neural-interface/public/category-logos/openai.svg +0 -1
- package/neural-interface/public/category-logos/synabun.png +0 -0
- package/neural-interface/public/claude.svg +0 -1
- package/neural-interface/public/gallery.svg +0 -6
- package/neural-interface/public/leonardoai.svg +0 -1
- package/neural-interface/public/mcp.svg +0 -4
- package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
- package/neural-interface/public/pin-svgrepo-com.svg +0 -25
- package/neural-interface/public/sessionicon.svg +0 -8
- package/neural-interface/public/toolbar-album.svg +0 -8
- package/neural-interface/public/toolbar-question.svg +0 -6
- package/neural-interface/public/toolbar-sessions.svg +0 -6
- package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
- package/skills/synabun/synabunicon.png +0 -0
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import { assistantEventKey, fmtCost, fmtElapsed, isRemovableRun, isRunIdle, isTerminalRunStatus, modelShortName, providerShortLabel, routeTargetLabel, runTone, summarizeMailbox } from './asst-state.js';
|
|
22
22
|
import { createRouteLine } from './asst-route.js';
|
|
23
|
+
import { closeMenu, isMenuOpen } from './asst-menu.js';
|
|
23
24
|
import { computerToolName, describeComputerAction, frameUrls, markerPercent, openFrameLightbox, parseComputerResult, swapImage } from './asst-computer.js';
|
|
24
25
|
import * as mascotLib from '../synabun-mascot.js';
|
|
25
26
|
import { isReducedMotion, subscribe } from '../synabun-ticker.js';
|
|
@@ -27,6 +28,7 @@ import { KIND_SPECS, callOutcome, commandOf, editDiff, editPaths, fmtDuration, g
|
|
|
27
28
|
import { injectRackStyles } from './asst-rack-styles.js';
|
|
28
29
|
import { formatRunTokens } from './asst-usage.js';
|
|
29
30
|
import { sanitizeHtmlString, sanitizeInto } from './asst-sanitize.js';
|
|
31
|
+
import { automationView } from './asst-automation.js';
|
|
30
32
|
|
|
31
33
|
// ── Markdown (lazy marked, same CDN build as the sidepanels) ───────────────
|
|
32
34
|
let _marked = null;
|
|
@@ -226,8 +228,9 @@ export function updateRunCard(card, run, opts = {}) {
|
|
|
226
228
|
const r = run.route;
|
|
227
229
|
const routeBits = [r.taskClassLabel || r.taskClass || t('assistant.routes.task', 'task')];
|
|
228
230
|
if (r.status === 'pending') routeBits.push(t('assistant.routes.state.pending', 'waiting for your choice'));
|
|
231
|
+
else if (r.decidedBy === 'budget' || r.source === 'budget') routeBits.push(t('assistant.routes.budgetDecision', 'budget re-route'));
|
|
229
232
|
else if (r.decidedBy === 'user') routeBits.push(t('assistant.routes.youChose', 'you chose'));
|
|
230
|
-
else if (r.remembered || r.decidedBy === 'remembered') routeBits.push(t('assistant.routes.remembered', '
|
|
233
|
+
else if (r.remembered || r.decidedBy === 'remembered') routeBits.push(t('assistant.routes.remembered', 'your saved choice'));
|
|
231
234
|
else if (Number.isFinite(Number(r.confidence))) routeBits.push(`${Math.round(Number(r.confidence) <= 1 ? Number(r.confidence) * 100 : Number(r.confidence))}%`);
|
|
232
235
|
const tip = r.target ? `${t('assistant.routes.routedTo', 'Routed to')} ${routeTargetLabel(r.target, { effort: true })}` : t('assistant.routes.title', 'Model routing');
|
|
233
236
|
bits.push(`<span class="asst-run-route" data-tooltip="${esc(tip)}">⇄ ${esc(routeBits.join(', '))}</span>`);
|
|
@@ -434,12 +437,12 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
434
437
|
const scopes = new Map(); // parent_tool_use_id → { container, stream, key }
|
|
435
438
|
const runCards = new Map(); // runId → card element
|
|
436
439
|
const routeLines = new Map(); // routeId → line handle
|
|
440
|
+
const autoRows = new Map(); // traceId → the turn's automation trace row
|
|
437
441
|
let working = null;
|
|
438
442
|
let workingFace = null; // the "Thinking" row's character: { still, rig?, el, target? } (syncWorkingFace)
|
|
439
443
|
let followTail = true;
|
|
440
444
|
let emptyEl = null;
|
|
441
445
|
let hero = null; // the empty state's character: { rig, el, box, parked, leaving, held, dock, egg, target }
|
|
442
|
-
let rigsOn = true; // this panel's rigs may animate (asst-mascot.js lets one panel at a time)
|
|
443
446
|
const mcpWarned = new Set();
|
|
444
447
|
let lastErrorText = ''; // a synthetic API-error message's text, so the result does not repeat it
|
|
445
448
|
let turnFrames = []; // computer cards with inline thumbnails in the current turn
|
|
@@ -539,10 +542,19 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
539
542
|
function hideEmpty({ park = false } = {}) {
|
|
540
543
|
if (!emptyEl) return;
|
|
541
544
|
if (!(park && parkHero())) dropHero();
|
|
545
|
+
closeEmptyMenu();
|
|
542
546
|
emptyEl.remove();
|
|
543
547
|
emptyEl = null;
|
|
544
548
|
}
|
|
545
549
|
|
|
550
|
+
/** A menu opened from the empty state's project picker does not outlive it. */
|
|
551
|
+
function closeEmptyMenu() {
|
|
552
|
+
for (const btn of emptyEl?.querySelectorAll('.asst-empty-project-btn') || []) {
|
|
553
|
+
if (isMenuOpen(btn)) closeMenu();
|
|
554
|
+
}
|
|
555
|
+
hooks.unmountEmptyControls?.();
|
|
556
|
+
}
|
|
557
|
+
|
|
546
558
|
// ── The hero ──
|
|
547
559
|
const cssEase = (name, fallback) => {
|
|
548
560
|
try { return getComputedStyle($msgs).getPropertyValue(name).trim() || fallback; } catch { return fallback; }
|
|
@@ -698,13 +710,6 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
698
710
|
try { hooks.onMascotChange?.(); } catch { /* the director is gone */ }
|
|
699
711
|
}
|
|
700
712
|
|
|
701
|
-
/** Whether this panel's rigs animate (another panel may lead); still frames otherwise. */
|
|
702
|
-
function setRigsEnabled(on) {
|
|
703
|
-
if (rigsOn === !!on) return;
|
|
704
|
-
rigsOn = !!on;
|
|
705
|
-
activateRigs();
|
|
706
|
-
}
|
|
707
|
-
|
|
708
713
|
function prune() {
|
|
709
714
|
const rows = $msgs.children;
|
|
710
715
|
while (rows.length > MAX_MESSAGES && rows[0] !== working) rows[0].remove();
|
|
@@ -757,8 +762,8 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
757
762
|
const a = el('a', 'file-link', match[0]);
|
|
758
763
|
a.href = '#';
|
|
759
764
|
a.title = t('assistant.copyPath', 'Click to copy path');
|
|
760
|
-
|
|
761
|
-
|
|
765
|
+
// The click is taken on the transcript (asst-panel.js → ui-file-links.js): the code editor when it
|
|
766
|
+
// can open the path, else the copy a click has always made.
|
|
762
767
|
frag.appendChild(a);
|
|
763
768
|
last = match.index + match[0].length;
|
|
764
769
|
}
|
|
@@ -1502,7 +1507,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
1502
1507
|
rack.clearTimer = 0;
|
|
1503
1508
|
rack.row.classList.add('is-staged');
|
|
1504
1509
|
if (!rack.rig) {
|
|
1505
|
-
try { rack.rig = mascotLib.createMascot(rack.stage.face, { width: 72, height: 36, rangeX: 10, rangeY: 7,
|
|
1510
|
+
try { rack.rig = mascotLib.createMascot(rack.stage.face, { width: 72, height: 36, rangeX: 10, rangeY: 7, pose: 'idle' }); } catch { rack.rig = null; }
|
|
1506
1511
|
rack.pose = null;
|
|
1507
1512
|
rack.target = rack.rig ? stageTarget(rack) : null;
|
|
1508
1513
|
if (hero?.parked) dropHero(); // the stage is the character now: a hero still on its way out goes at once
|
|
@@ -1564,12 +1569,16 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
1564
1569
|
rack.bubble = { step: null, since: 0, key: '', open: false };
|
|
1565
1570
|
}
|
|
1566
1571
|
|
|
1567
|
-
/**
|
|
1572
|
+
/**
|
|
1573
|
+
* One rig of this transcript animates: the hero, else the newest stage, else
|
|
1574
|
+
* the "Thinking" row's. The rule ends at this renderer: every other panel
|
|
1575
|
+
* runs its own, so N live sessions show N moving characters.
|
|
1576
|
+
*/
|
|
1568
1577
|
function activateRigs() {
|
|
1569
1578
|
const newest = hero?.rig ? null : newestStage();
|
|
1570
|
-
for (const rack of racks) if (rack.rig) rack.rig.setActive?.(
|
|
1571
|
-
hero?.rig?.setActive?.(
|
|
1572
|
-
workingFace?.rig?.setActive?.(
|
|
1579
|
+
for (const rack of racks) if (rack.rig) rack.rig.setActive?.(rack === newest);
|
|
1580
|
+
hero?.rig?.setActive?.(true);
|
|
1581
|
+
workingFace?.rig?.setActive?.(!hero?.rig && !newest);
|
|
1573
1582
|
}
|
|
1574
1583
|
|
|
1575
1584
|
/** The bubble's call: the awake one, else the newest; it holds 900 ms (3 s for thinking) before the next wins. */
|
|
@@ -2634,7 +2643,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
2634
2643
|
return;
|
|
2635
2644
|
}
|
|
2636
2645
|
try {
|
|
2637
|
-
const rig = mascotLib.createMascot(host, { width: 56, height: 28,
|
|
2646
|
+
const rig = mascotLib.createMascot(host, { width: 56, height: 28, pose: 'think' });
|
|
2638
2647
|
const face = { still: false, rig, el: rig.el, held: false };
|
|
2639
2648
|
face.target = { kind: 'working', rig, el: rig.el, hold(on) { face.held = !!on; }, restore() { if (workingFace === face) rig.setPose('think'); } };
|
|
2640
2649
|
workingFace = face;
|
|
@@ -2683,7 +2692,12 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
2683
2692
|
|
|
2684
2693
|
function upsertRunCard(run, { result = null } = {}) {
|
|
2685
2694
|
if (!run?.runId) return null;
|
|
2686
|
-
|
|
2695
|
+
const prev = runInfo.get(run.runId);
|
|
2696
|
+
const status = run.status || prev?.state;
|
|
2697
|
+
const tone = status ? runTone({ ...run, status }) : '';
|
|
2698
|
+
const routeId = run.route?.routeId || prev?.routeId || '';
|
|
2699
|
+
runInfo.set(run.runId, { ...prev, title: run.title || run.task || prev?.title, state: status, provider: run.provider, routeId, working: tone === 'running' || tone === 'queued' });
|
|
2700
|
+
if (routeId) syncRouteLive(routeId);
|
|
2687
2701
|
const cardOpts = runCardOpts(result);
|
|
2688
2702
|
let card = runCards.get(run.runId);
|
|
2689
2703
|
if (card && card.isConnected) {
|
|
@@ -2739,21 +2753,42 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
2739
2753
|
return { phase, t: hooks.t, providerIcon: hooks.providerIcon, brainLabel: hooks.brainLabel, onChangeRoutes: hooks.onChangeRoutes };
|
|
2740
2754
|
}
|
|
2741
2755
|
|
|
2742
|
-
/** Create or update the line for `route.routeId` in place. */
|
|
2756
|
+
/** Create or update the line for `route.routeId` in place. Only a new line enters (never on replay). */
|
|
2743
2757
|
function upsertRouteLine(route, phase = 'decided') {
|
|
2744
2758
|
const routeId = route?.routeId;
|
|
2745
2759
|
if (!routeId) return null;
|
|
2746
2760
|
const existing = routeLines.get(routeId);
|
|
2747
|
-
if (existing && existing.el.isConnected) { existing.update(route, phase); return existing; }
|
|
2761
|
+
if (existing && existing.el.isConnected) { existing.update(route, phase); syncRouteLive(routeId); return existing; }
|
|
2748
2762
|
const line = createRouteLine(route, routeLineOpts(phase));
|
|
2749
2763
|
routeLines.set(routeId, line);
|
|
2750
2764
|
append(line.el);
|
|
2765
|
+
syncRouteLive(routeId);
|
|
2766
|
+
enterRow(line.el);
|
|
2751
2767
|
return line;
|
|
2752
2768
|
}
|
|
2753
2769
|
|
|
2754
2770
|
/** Adopt a line created by a collapsing route card so later events update it. */
|
|
2755
2771
|
function registerRouteLine(routeId, line) {
|
|
2756
|
-
if (routeId
|
|
2772
|
+
if (!routeId || !line) return;
|
|
2773
|
+
const fresh = routeLines.get(routeId) !== line;
|
|
2774
|
+
routeLines.set(routeId, line);
|
|
2775
|
+
syncRouteLive(routeId);
|
|
2776
|
+
if (fresh && line.el?.isConnected) enterRow(line.el);
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
/** The line is live while a run it dispatched is queued or working (run cards keep runInfo current). */
|
|
2780
|
+
function syncRouteLive(routeId) {
|
|
2781
|
+
const line = routeLines.get(routeId);
|
|
2782
|
+
if (!line?.setRunning) return;
|
|
2783
|
+
let working = false;
|
|
2784
|
+
for (const info of runInfo.values()) if (info.routeId === routeId && info.working) { working = true; break; }
|
|
2785
|
+
line.setRunning(working);
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
/** A new row's entrance: the rack ledger's (4px rise and fade, --asst-dur-fast, --asst-ease-enter); none when calm. */
|
|
2789
|
+
function enterRow(node) {
|
|
2790
|
+
if (calm() || typeof node?.animate !== 'function') return;
|
|
2791
|
+
node.animate([{ opacity: 0, transform: 'translateY(4px)' }, { opacity: 1, transform: 'none' }], { duration: 140, easing: cssEase('--asst-ease-enter', 'cubic-bezier(0,0,.38,.9)') });
|
|
2757
2792
|
}
|
|
2758
2793
|
|
|
2759
2794
|
function removeRouteLine(routeId) {
|
|
@@ -2761,6 +2796,115 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
2761
2796
|
if (line) { line.el.remove(); routeLines.delete(routeId); }
|
|
2762
2797
|
}
|
|
2763
2798
|
|
|
2799
|
+
// ── The automation trace ──
|
|
2800
|
+
// What the harness did for a turn (`synabun.automation`, asst-automation.js):
|
|
2801
|
+
// one disclosure row per turn, upserted by its traceId. It appears where the
|
|
2802
|
+
// turn was sent, moves under the reply when the turn ends and updates in
|
|
2803
|
+
// place when learning finishes. Drawn from the event alone, so the live row
|
|
2804
|
+
// and the replayed one are the same. Opening one keeps the next ones open.
|
|
2805
|
+
let autoUid = 0;
|
|
2806
|
+
const TRACE_OPEN_KEY = 'synabun-asst-trace-open';
|
|
2807
|
+
const traceOpenPref = () => { try { return localStorage.getItem(TRACE_OPEN_KEY) === '1'; } catch { return false; } };
|
|
2808
|
+
|
|
2809
|
+
function buildAutoRow() {
|
|
2810
|
+
const node = el('div', 'asst-route-line asst-auto');
|
|
2811
|
+
const detailId = `asst-auto-detail-${++autoUid}`;
|
|
2812
|
+
node.innerHTML = `
|
|
2813
|
+
<button type="button" class="asst-route-line-head asst-auto-head" aria-expanded="false" aria-controls="${detailId}">
|
|
2814
|
+
<span class="asst-route-glyph asst-icon" aria-hidden="true">${ICON_MEMORY}</span>
|
|
2815
|
+
<span class="asst-route-class asst-auto-title"></span>
|
|
2816
|
+
<span class="asst-route-meta asst-auto-summary"></span>
|
|
2817
|
+
<span class="asst-route-state asst-auto-state"></span>
|
|
2818
|
+
<span class="asst-route-chev" aria-hidden="true">›</span>
|
|
2819
|
+
</button>
|
|
2820
|
+
<div class="asst-route-detail asst-auto-detail" id="${detailId}" hidden></div>`;
|
|
2821
|
+
const head = node.querySelector('.asst-auto-head');
|
|
2822
|
+
const detail = node.querySelector('.asst-auto-detail');
|
|
2823
|
+
const setOpen = (open) => {
|
|
2824
|
+
head.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
2825
|
+
detail.hidden = !open;
|
|
2826
|
+
node.classList.toggle('open', open);
|
|
2827
|
+
};
|
|
2828
|
+
head.addEventListener('click', () => {
|
|
2829
|
+
const open = head.getAttribute('aria-expanded') !== 'true';
|
|
2830
|
+
setOpen(open);
|
|
2831
|
+
try { localStorage.setItem(TRACE_OPEN_KEY, open ? '1' : '0'); } catch { /* no storage: this row only */ }
|
|
2832
|
+
});
|
|
2833
|
+
setOpen(traceOpenPref());
|
|
2834
|
+
return { el: node, detail, atEnd: false };
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
function paintAutoRow(row, ev) {
|
|
2838
|
+
const view = automationView(ev, { t: hooks.t });
|
|
2839
|
+
row.el.dataset.traceId = view.traceId;
|
|
2840
|
+
row.el.dataset.phase = view.phase;
|
|
2841
|
+
row.el.classList.toggle('busy', view.tone === 'busy');
|
|
2842
|
+
row.el.classList.toggle('learned', view.tone === 'learned');
|
|
2843
|
+
row.el.querySelector('.asst-auto-title').textContent = view.title;
|
|
2844
|
+
row.el.querySelector('.asst-auto-summary').textContent = view.summary;
|
|
2845
|
+
const state = row.el.querySelector('.asst-auto-state');
|
|
2846
|
+
state.textContent = view.state;
|
|
2847
|
+
state.hidden = !view.state;
|
|
2848
|
+
row.detail.replaceChildren();
|
|
2849
|
+
for (const group of view.groups) {
|
|
2850
|
+
const box = el('div', 'asst-auto-group');
|
|
2851
|
+
box.dataset.group = group.key;
|
|
2852
|
+
box.appendChild(el('div', 'asst-auto-h', group.title));
|
|
2853
|
+
for (const item of group.rows) {
|
|
2854
|
+
const line = el('div', `asst-auto-row${item.tone ? ` ${item.tone}` : ''}`);
|
|
2855
|
+
if (item.label || item.meta) {
|
|
2856
|
+
const lead = el('div', 'asst-auto-row-head');
|
|
2857
|
+
if (item.label) lead.appendChild(el('span', 'asst-auto-tier', item.label));
|
|
2858
|
+
if (item.meta) lead.appendChild(el('span', 'asst-auto-meta', item.meta));
|
|
2859
|
+
line.appendChild(lead);
|
|
2860
|
+
}
|
|
2861
|
+
// Memory text and the user's own words: always as text, never as markup.
|
|
2862
|
+
if (item.text) line.appendChild(el(item.pre ? 'pre' : 'div', 'asst-auto-text', item.text));
|
|
2863
|
+
if (item.ids.length) {
|
|
2864
|
+
const ids = el('div', 'asst-auto-ids');
|
|
2865
|
+
for (const id of item.ids) {
|
|
2866
|
+
const link = el('button', 'asst-link', String(id).slice(0, 8));
|
|
2867
|
+
link.type = 'button';
|
|
2868
|
+
link.dataset.memoryId = id;
|
|
2869
|
+
link.title = `${t('assistant.automation.open', 'Open memory')} ${id}`;
|
|
2870
|
+
link.setAttribute('aria-label', link.title);
|
|
2871
|
+
link.addEventListener('click', () => hooks.onMemoryClick?.(id, { id }));
|
|
2872
|
+
ids.appendChild(link);
|
|
2873
|
+
}
|
|
2874
|
+
line.appendChild(ids);
|
|
2875
|
+
}
|
|
2876
|
+
box.appendChild(line);
|
|
2877
|
+
}
|
|
2878
|
+
row.detail.appendChild(box);
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
/** Create or update the trace row for `ev.traceId`. */
|
|
2883
|
+
function upsertAutomation(ev) {
|
|
2884
|
+
const id = String(ev?.traceId || '');
|
|
2885
|
+
if (!id) return null;
|
|
2886
|
+
let row = autoRows.get(id);
|
|
2887
|
+
const fresh = !row || !row.el.isConnected;
|
|
2888
|
+
if (fresh) {
|
|
2889
|
+
row = buildAutoRow();
|
|
2890
|
+
autoRows.set(id, row);
|
|
2891
|
+
while (autoRows.size > 200) autoRows.delete(autoRows.keys().next().value);
|
|
2892
|
+
}
|
|
2893
|
+
paintAutoRow(row, ev);
|
|
2894
|
+
// Under the reply once the turn has ended; a later snapshot (learning) never moves it again.
|
|
2895
|
+
const ended = ev.phase !== 'sent';
|
|
2896
|
+
if (fresh || (ended && !row.atEnd)) {
|
|
2897
|
+
// Placed like any row (before "Working…"), but a status line of the harness never dismisses the hero.
|
|
2898
|
+
if (working && working.parentNode === $msgs) $msgs.insertBefore(row.el, working);
|
|
2899
|
+
else $msgs.appendChild(row.el);
|
|
2900
|
+
if (ended) row.atEnd = true;
|
|
2901
|
+
prune();
|
|
2902
|
+
if (racks.size) syncRacks();
|
|
2903
|
+
scrollEnd();
|
|
2904
|
+
}
|
|
2905
|
+
return row.el;
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2764
2908
|
// ── Empty state ──
|
|
2765
2909
|
function showEmpty() {
|
|
2766
2910
|
if (emptyEl || $msgs.querySelector(':scope > :not(.asst-working)')) return;
|
|
@@ -2769,14 +2913,24 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
2769
2913
|
<div class="asst-empty-mascot" aria-hidden="true"></div>
|
|
2770
2914
|
<div class="asst-empty-title" role="heading" aria-level="2">${esc(t('assistant.empty.heading', 'What should we do?'))}</div>
|
|
2771
2915
|
<div class="asst-empty-body">${esc(t('assistant.empty.lead', 'I can use your Mac, look things up on the web, edit files and run commands, and remember or schedule things.'))}</div>
|
|
2916
|
+
<div class="asst-empty-greet"></div>
|
|
2917
|
+
<div class="asst-empty-project" hidden></div>
|
|
2772
2918
|
<div class="asst-suggestions" role="list"></div>`;
|
|
2773
2919
|
const box = emptyEl.querySelector('.asst-empty-mascot');
|
|
2774
2920
|
try {
|
|
2775
|
-
const rig = mascotLib.createMascot(box, { width: 120, height: 60
|
|
2921
|
+
const rig = mascotLib.createMascot(box, { width: 120, height: 60 });
|
|
2776
2922
|
hero = { rig, el: rig.el, box, parked: false, leaving: false, held: false, dock: null, egg: false, leaveTimer: 0 };
|
|
2777
2923
|
hero.target = heroTarget(hero);
|
|
2778
2924
|
wireEgg(hero);
|
|
2779
2925
|
} catch { hero = null; }
|
|
2926
|
+
// The project the conversation works in, under the lead: the host draws the picker (the brain
|
|
2927
|
+
// picker's project field), so it and the toolbar's Working project are one control.
|
|
2928
|
+
const projectSlot = emptyEl.querySelector('.asst-empty-project');
|
|
2929
|
+
let picker = null;
|
|
2930
|
+
try { picker = typeof hooks.mountEmptyProject === 'function' ? hooks.mountEmptyProject(projectSlot) : null; } catch { picker = null; }
|
|
2931
|
+
let budget = null;
|
|
2932
|
+
try { budget = hooks.mountEmptyBudget?.(projectSlot); } catch { /* unavailable */ }
|
|
2933
|
+
projectSlot.hidden = !picker && !budget;
|
|
2780
2934
|
renderSuggestions();
|
|
2781
2935
|
$msgs.appendChild(emptyEl);
|
|
2782
2936
|
// The host's "Starting…" character flies into place (not on replay or reduced motion).
|
|
@@ -2786,6 +2940,20 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
2786
2940
|
mascotChanged();
|
|
2787
2941
|
}
|
|
2788
2942
|
|
|
2943
|
+
/**
|
|
2944
|
+
* The greeting SynaBun prepared for this return (public/shared/greeting/) takes the lead's place.
|
|
2945
|
+
* The panel calls it once it knows the conversation is new: a restored one is never greeted.
|
|
2946
|
+
*/
|
|
2947
|
+
function offerGreeting() {
|
|
2948
|
+
const owner = emptyEl;
|
|
2949
|
+
if (!owner || owner.dataset.greetingAsked === '1' || typeof hooks.greeting !== 'function') return;
|
|
2950
|
+
owner.dataset.greetingAsked = '1';
|
|
2951
|
+
const slot = owner.querySelector('.asst-empty-greet');
|
|
2952
|
+
Promise.resolve().then(() => hooks.greeting(slot))
|
|
2953
|
+
.then((greeting) => { if (greeting && emptyEl === owner) owner.classList.add('has-greeting'); })
|
|
2954
|
+
.catch(() => { /* no greeting: the lead stays */ });
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2789
2957
|
function renderSuggestions() {
|
|
2790
2958
|
if (!emptyEl) return;
|
|
2791
2959
|
const host = emptyEl.querySelector('.asst-suggestions');
|
|
@@ -3111,6 +3279,9 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
3111
3279
|
// The card itself arrives as a control_request; its outcome is a line (the panel's card shows it live).
|
|
3112
3280
|
if (ev.phase !== 'card') appendStatus(clarifyLine(ev), 'info');
|
|
3113
3281
|
return true;
|
|
3282
|
+
case 'synabun.automation':
|
|
3283
|
+
upsertAutomation(ev);
|
|
3284
|
+
return true;
|
|
3114
3285
|
default:
|
|
3115
3286
|
return false;
|
|
3116
3287
|
}
|
|
@@ -3233,6 +3404,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
3233
3404
|
scopes.clear();
|
|
3234
3405
|
runCards.clear();
|
|
3235
3406
|
routeLines.clear();
|
|
3407
|
+
autoRows.clear();
|
|
3236
3408
|
turnFrames = [];
|
|
3237
3409
|
rootScope.stream = null;
|
|
3238
3410
|
rootScope.kept = null;
|
|
@@ -3249,6 +3421,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
3249
3421
|
seen.clear();
|
|
3250
3422
|
snapshot = null;
|
|
3251
3423
|
waiting = null;
|
|
3424
|
+
closeEmptyMenu();
|
|
3252
3425
|
$msgs.innerHTML = '';
|
|
3253
3426
|
emptyEl = null;
|
|
3254
3427
|
followTail = true;
|
|
@@ -3273,6 +3446,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
3273
3446
|
registerRouteLine,
|
|
3274
3447
|
removeRouteLine,
|
|
3275
3448
|
getRouteLine: (routeId) => routeLines.get(routeId) || null,
|
|
3449
|
+
upsertAutomation,
|
|
3276
3450
|
getRunCard: (runId) => runCards.get(runId) || null,
|
|
3277
3451
|
handleEvent,
|
|
3278
3452
|
/** The live gate for an event (false: already drawn); registers what it lets through. */
|
|
@@ -3289,6 +3463,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
3289
3463
|
hideWorking,
|
|
3290
3464
|
isWorkingShown: () => !!working?.isConnected,
|
|
3291
3465
|
showEmpty,
|
|
3466
|
+
offerGreeting,
|
|
3292
3467
|
refreshEmpty: renderSuggestions,
|
|
3293
3468
|
isEmpty: () => !!emptyEl,
|
|
3294
3469
|
scrollEnd,
|
|
@@ -3296,7 +3471,6 @@ export function createRenderer(transcriptEl, hooks = {}) {
|
|
|
3296
3471
|
md,
|
|
3297
3472
|
/** The character on screen, for the panel's director: { kind, rig, el, hold(on), restore() } or null. */
|
|
3298
3473
|
mascot: visibleMascot,
|
|
3299
|
-
setRigsEnabled,
|
|
3300
3474
|
/** What this turn did: real calls (not the prompt-time recall), whether the last one failed, a turn error. */
|
|
3301
3475
|
turnStats: () => ({ calls: turn.calls, lastFailed: turn.last?.state === 'error', errored: turn.errored }),
|
|
3302
3476
|
/** The text of the turn's last message at the root ('' when it folded into a rack or there was none). */
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Assistant — Model routes editor: where its model lists come from
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
// The data side of the Routes editor (asst-route.js `openRoutesEditor`), kept
|
|
5
|
+
// apart from its markup. No DOM is built here.
|
|
6
|
+
//
|
|
7
|
+
// One list per provider, the one every Assistant model menu shows:
|
|
8
|
+
// loadModelCatalog() of asst-brain-picker.js, which is GET /api/assistant/catalog,
|
|
9
|
+
// itself built from the lists the Claude, Codex and OpenCode panels' own
|
|
10
|
+
// selectors read. Nothing here, and nothing in the editor, may keep a second
|
|
11
|
+
// list of models: a label, a tier, a price or an effort level is read from the
|
|
12
|
+
// catalog row each time it is drawn.
|
|
13
|
+
|
|
14
|
+
import { catalogModelRow, loadModelCatalog, modelCatalogStatus, onModelCatalogChange } from './asst-brain-picker.js';
|
|
15
|
+
import { routeTargetLabel } from './asst-state.js';
|
|
16
|
+
|
|
17
|
+
/** The catalog as the editor opens: a new build, never the copy another menu loaded a minute ago. */
|
|
18
|
+
export function loadRouteModels() {
|
|
19
|
+
return loadModelCatalog({ force: true });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Loading/partial state belongs to the same model source, without changing the catalog shape. */
|
|
23
|
+
export function routeModelsStatus() { return modelCatalogStatus(); }
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The name shown for a saved route's model. The catalog's label for that id wins:
|
|
27
|
+
* a route keeps the label it was saved with, and an alias moves ("haiku" was
|
|
28
|
+
* Haiku 4.5, then Haiku 5.5). A model the catalog no longer lists (removed by its
|
|
29
|
+
* provider, hidden, or its provider is not answering) keeps the saved label,
|
|
30
|
+
* then its id, then the provider's name: never an empty name.
|
|
31
|
+
*/
|
|
32
|
+
export function routeModelLabel(pref, catalog) {
|
|
33
|
+
if (!pref || typeof pref !== 'object') return '';
|
|
34
|
+
const row = pref.provider && pref.model ? catalogModelRow(pref.provider, pref.model, catalog) : null;
|
|
35
|
+
const live = row?.label ? String(row.label).trim() : '';
|
|
36
|
+
return live || routeTargetLabel(pref);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** What the editor draws from a catalog: when this is unchanged, there is nothing to redraw. */
|
|
40
|
+
export function catalogSignature(catalog) {
|
|
41
|
+
if (!catalog || typeof catalog !== 'object') return '';
|
|
42
|
+
return JSON.stringify(Object.keys(catalog).sort().map(provider => [
|
|
43
|
+
provider,
|
|
44
|
+
(Array.isArray(catalog[provider]) ? catalog[provider] : []).map(m => [
|
|
45
|
+
m?.id, m?.label, m?.status ?? null, m?.vision ?? null, m?.outputs?.image ?? null, m?.outputs?.video ?? null,
|
|
46
|
+
(m?.efforts || []).join(','), m?.defaultEffort || '', m?.isDefault === true,
|
|
47
|
+
]),
|
|
48
|
+
]));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Keeps an open editor on the current lists. `apply(catalog)` is called with a
|
|
53
|
+
* newly loaded catalog whenever it differs from the last one applied:
|
|
54
|
+
* - after a change event (a model hidden or shown, a provider listing other
|
|
55
|
+
* models, an OpenCode provider connected or removed): a new build is asked;
|
|
56
|
+
* - when the window is shown again: the catalog is read again, and reloaded
|
|
57
|
+
* once its copy has aged out (no event tells a window that slept).
|
|
58
|
+
* Returns { seed(catalog), stop() }: seed with the catalog the editor loaded
|
|
59
|
+
* itself, stop when it closes. No timer runs while nothing changes.
|
|
60
|
+
*/
|
|
61
|
+
export function watchRouteModels(apply, {
|
|
62
|
+
load = loadModelCatalog,
|
|
63
|
+
subscribe = onModelCatalogChange,
|
|
64
|
+
doc = typeof document !== 'undefined' ? document : null,
|
|
65
|
+
delayMs = 150,
|
|
66
|
+
setTimer = setTimeout,
|
|
67
|
+
clearTimer = clearTimeout,
|
|
68
|
+
} = {}) {
|
|
69
|
+
let stopped = false;
|
|
70
|
+
let timer = null;
|
|
71
|
+
let last = null;
|
|
72
|
+
let run = 0;
|
|
73
|
+
|
|
74
|
+
async function reload(force) {
|
|
75
|
+
const mine = ++run;
|
|
76
|
+
let catalog = null;
|
|
77
|
+
try { catalog = await load({ force }); } catch { return; }
|
|
78
|
+
if (stopped || mine !== run || !catalog) return;
|
|
79
|
+
const signature = catalogSignature(catalog);
|
|
80
|
+
if (signature === last) return;
|
|
81
|
+
last = signature;
|
|
82
|
+
try { apply(catalog); } catch { /* the editor's own failure */ }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Several events for one change (a hide broadcasts twice) become one reload.
|
|
86
|
+
let pendingForce = false;
|
|
87
|
+
function schedule(force) {
|
|
88
|
+
if (stopped) return;
|
|
89
|
+
pendingForce = pendingForce || force;
|
|
90
|
+
if (timer != null) clearTimer(timer);
|
|
91
|
+
timer = setTimer(() => { timer = null; const f = pendingForce; pendingForce = false; reload(f); }, delayMs);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const unsubscribe = subscribe(() => schedule(true));
|
|
95
|
+
const onVisible = () => { if (doc?.visibilityState !== 'hidden') schedule(false); };
|
|
96
|
+
doc?.addEventListener?.('visibilitychange', onVisible);
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
seed(catalog) { last = catalogSignature(catalog); },
|
|
100
|
+
stop() {
|
|
101
|
+
stopped = true;
|
|
102
|
+
if (timer != null) clearTimer(timer);
|
|
103
|
+
timer = null;
|
|
104
|
+
try { unsubscribe?.(); } catch { /* ignore */ }
|
|
105
|
+
doc?.removeEventListener?.('visibilitychange', onVisible);
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|