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
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Neural Interface — Code editor: AI autocomplete, the decisions
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// What AI autocomplete decides without a page: whether a request may be made at
|
|
6
|
+
// all, which text around the caret is sent, which files and texts are never
|
|
7
|
+
// sent, what is left of a suggestion while the user types it, and what the
|
|
8
|
+
// status-bar chip says. editor-ai.js acts on these; the server's
|
|
9
|
+
// lib/editor-completion.js imports the limits and the never-sent rules from
|
|
10
|
+
// here, so the two sides cannot disagree about them. No DOM and no imports:
|
|
11
|
+
// loaded by `node --test` as it is.
|
|
12
|
+
|
|
13
|
+
/** Sizes of what a request carries (docs/design/code-editor/SPEC.md, section 9.3). */
|
|
14
|
+
export const AI_LIMITS = Object.freeze({
|
|
15
|
+
prefixChars: 6000, // before the caret, cut at a line start
|
|
16
|
+
suffixChars: 1500, // after the caret, cut at a line end
|
|
17
|
+
headerLines: 40, // the file's first lines, when the prefix does not start at offset 0
|
|
18
|
+
headerChars: 4000,
|
|
19
|
+
neighborCount: 2, // snippets of other open tabs
|
|
20
|
+
neighborChars: 1200,
|
|
21
|
+
pathChars: 1000,
|
|
22
|
+
completionChars: 1200, // the most a suggestion holds
|
|
23
|
+
cacheSize: 20, // results kept
|
|
24
|
+
cacheBefore: 300, // characters before the caret in a cache key
|
|
25
|
+
cacheAfter: 100, // characters after it
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// The prefix starts on a multiple of this many characters (then at the next line start), so it stays the same
|
|
29
|
+
// text for a while as the caret moves on: a provider that caches the start of a prompt can reuse it.
|
|
30
|
+
const PREFIX_GRID = 1000;
|
|
31
|
+
|
|
32
|
+
/** What may follow the caret on its line for a suggestion to be asked for: nothing, or closing punctuation. */
|
|
33
|
+
const CLOSING_ONLY = /^[\s)\]}'"`;,]*$/;
|
|
34
|
+
|
|
35
|
+
const PRIVATE_KEY = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/;
|
|
36
|
+
|
|
37
|
+
// ── Never sent ──
|
|
38
|
+
|
|
39
|
+
/** The last part of a path, whichever slash it uses. */
|
|
40
|
+
export function fileNameOf(path) {
|
|
41
|
+
const text = String(path ?? '');
|
|
42
|
+
return text.slice(Math.max(text.lastIndexOf('/'), text.lastIndexOf('\\')) + 1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function globToRegExp(glob) {
|
|
46
|
+
const body = String(glob).replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.');
|
|
47
|
+
return new RegExp(`^${body}$`, 'i');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Whether a file is one AI autocomplete never reads. The globs (`*` any run of characters, `?` one) are matched
|
|
52
|
+
* on the file's name, not on its folder, whatever the case of its letters.
|
|
53
|
+
* @param {string} path a path or a bare file name
|
|
54
|
+
* @param {string[]} globs `ai.exclude`
|
|
55
|
+
*/
|
|
56
|
+
export function matchesExclude(path, globs) {
|
|
57
|
+
const name = fileNameOf(path);
|
|
58
|
+
if (!name || !Array.isArray(globs)) return false;
|
|
59
|
+
return globs.some((glob) => typeof glob === 'string' && glob && globToRegExp(glob).test(name));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Whether any of the texts holds the first line of a private key. */
|
|
63
|
+
export function hasPrivateKey(...texts) {
|
|
64
|
+
return texts.some((text) => typeof text === 'string' && PRIVATE_KEY.test(text));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── When to ask ──
|
|
68
|
+
|
|
69
|
+
/** Whether the rest of the caret's line lets a suggestion in: empty, or only closing punctuation. */
|
|
70
|
+
export function restOfLineAllows(after) {
|
|
71
|
+
return CLOSING_ONLY.test(String(after ?? ''));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Whether a suggestion may be asked for right now.
|
|
76
|
+
* @param {object} s
|
|
77
|
+
* @param {boolean} s.enabled `ai.enabled`
|
|
78
|
+
* @param {boolean} s.capable the server has the `complete` capability
|
|
79
|
+
* @param {boolean} [s.readOnly] the document cannot be edited (a save is under way)
|
|
80
|
+
* @param {boolean} s.focused the document has the keyboard
|
|
81
|
+
* @param {boolean} s.visible the page is visible
|
|
82
|
+
* @param {number} s.carets how many carets or selections there are
|
|
83
|
+
* @param {boolean} s.hasSelection any of them selects text
|
|
84
|
+
* @param {boolean} s.composing an IME composition is under way
|
|
85
|
+
* @param {string} s.lineAfter the text after the caret on its line
|
|
86
|
+
* @param {string} s.path the file's path
|
|
87
|
+
* @param {string[]} s.exclude `ai.exclude`
|
|
88
|
+
* @returns {{ ok: true } | { ok: false, reason: 'off' | 'read-only' | 'unfocused' | 'hidden' | 'multiple' | 'selection'
|
|
89
|
+
* | 'composing' | 'excluded' | 'mid-line' }} An open completion list is no reason to wait: the suggestion is
|
|
90
|
+
* asked for, and kept hidden until the list closes.
|
|
91
|
+
*/
|
|
92
|
+
export function shouldRequest(s = {}) {
|
|
93
|
+
const no = (reason) => ({ ok: false, reason });
|
|
94
|
+
if (!s.enabled || !s.capable) return no('off');
|
|
95
|
+
if (!s.path || matchesExclude(s.path, s.exclude)) return no('excluded');
|
|
96
|
+
if (s.readOnly) return no('read-only');
|
|
97
|
+
if (!s.focused) return no('unfocused');
|
|
98
|
+
if (!s.visible) return no('hidden');
|
|
99
|
+
if (s.carets !== 1) return no('multiple');
|
|
100
|
+
if (s.hasSelection) return no('selection');
|
|
101
|
+
if (s.composing) return no('composing');
|
|
102
|
+
if (!restOfLineAllows(s.lineAfter)) return no('mid-line');
|
|
103
|
+
return { ok: true };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Whether suggestions are expected for a document: the feature is on and the server has it, the file is not one
|
|
108
|
+
* that is never read, and there is a model to ask. While they are, the completion list leaves the words of the
|
|
109
|
+
* document out unless it is asked for them (Ctrl-Space): a list that opened for every word would cover the
|
|
110
|
+
* suggestion each time.
|
|
111
|
+
* @param {{ capable: boolean, enabled: boolean, excluded?: boolean, problem?: { kind: string } | null }} s
|
|
112
|
+
*/
|
|
113
|
+
export function suggestionsExpected({ capable, enabled, excluded = false, problem = null } = {}) {
|
|
114
|
+
if (!capable || !enabled || excluded) return false;
|
|
115
|
+
return problem?.kind !== 'no-model' && problem?.kind !== 'no-endpoint';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── What is sent ──
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The text around the caret that a request carries.
|
|
122
|
+
* @param {object} o
|
|
123
|
+
* @param {(from: number, to: number) => string} o.slice reads part of the document (line breaks as "\n")
|
|
124
|
+
* @param {number} o.length the document's length
|
|
125
|
+
* @param {number} o.pos the caret
|
|
126
|
+
* @returns {{ prefix: string, suffix: string, header: string, prefixStart: number, suffixEnd: number }}
|
|
127
|
+
* `prefix`: up to 6,000 characters before the caret, from a line start; `suffix`: up to 1,500 after it, to a
|
|
128
|
+
* line end; `header`: the file's first 40 lines when the prefix does not reach the start of the file, else ''.
|
|
129
|
+
*/
|
|
130
|
+
export function completionWindow({ slice, length, pos }) {
|
|
131
|
+
const at = Math.max(0, Math.min(length, pos));
|
|
132
|
+
let prefixStart = Math.ceil(Math.max(0, at - AI_LIMITS.prefixChars) / PREFIX_GRID) * PREFIX_GRID;
|
|
133
|
+
let prefix = slice(prefixStart, at);
|
|
134
|
+
if (prefixStart > 0) {
|
|
135
|
+
const lineStart = prefix.indexOf('\n');
|
|
136
|
+
if (lineStart >= 0) { prefixStart += lineStart + 1; prefix = prefix.slice(lineStart + 1); }
|
|
137
|
+
}
|
|
138
|
+
let suffixEnd = Math.min(length, at + AI_LIMITS.suffixChars);
|
|
139
|
+
let suffix = slice(at, suffixEnd);
|
|
140
|
+
if (suffixEnd < length) {
|
|
141
|
+
const lineEnd = suffix.lastIndexOf('\n');
|
|
142
|
+
if (lineEnd >= 0) { suffixEnd = at + lineEnd; suffix = suffix.slice(0, lineEnd); }
|
|
143
|
+
}
|
|
144
|
+
// The header stops where the prefix begins: no line is sent twice.
|
|
145
|
+
const header = prefixStart > 0 ? clampHeader(slice(0, Math.min(prefixStart, AI_LIMITS.headerChars + 1))) : '';
|
|
146
|
+
return { prefix, suffix, header, prefixStart, suffixEnd };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** At most the last 6,000 characters of a prefix, from a line start. */
|
|
150
|
+
export function clampPrefix(text) {
|
|
151
|
+
const prefix = String(text ?? '');
|
|
152
|
+
if (prefix.length <= AI_LIMITS.prefixChars) return prefix;
|
|
153
|
+
const cut = prefix.slice(prefix.length - AI_LIMITS.prefixChars);
|
|
154
|
+
const lineStart = cut.indexOf('\n');
|
|
155
|
+
return lineStart >= 0 ? cut.slice(lineStart + 1) : cut;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** At most the first 1,500 characters of a suffix, to a line end. */
|
|
159
|
+
export function clampSuffix(text) {
|
|
160
|
+
const suffix = String(text ?? '');
|
|
161
|
+
if (suffix.length <= AI_LIMITS.suffixChars) return suffix;
|
|
162
|
+
const cut = suffix.slice(0, AI_LIMITS.suffixChars);
|
|
163
|
+
const lineEnd = cut.lastIndexOf('\n');
|
|
164
|
+
return lineEnd >= 0 ? cut.slice(0, lineEnd) : cut;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** At most the first 40 lines and 4,000 characters of a header, whole lines only. */
|
|
168
|
+
export function clampHeader(text) {
|
|
169
|
+
let header = String(text ?? '').split('\n').slice(0, AI_LIMITS.headerLines).join('\n');
|
|
170
|
+
if (header.length > AI_LIMITS.headerChars) {
|
|
171
|
+
const cut = header.slice(0, AI_LIMITS.headerChars);
|
|
172
|
+
const lineEnd = cut.lastIndexOf('\n');
|
|
173
|
+
header = lineEnd >= 0 ? cut.slice(0, lineEnd) : cut;
|
|
174
|
+
}
|
|
175
|
+
return header.replace(/\n+$/, '');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The body of `POST /api/editor/complete`.
|
|
180
|
+
* @param {object} o
|
|
181
|
+
* @param {string} o.path
|
|
182
|
+
* @param {string} [o.language] the language's name as the status bar shows it
|
|
183
|
+
* @param {string} [o.indentUnit] one level of indentation (spaces, or a tab)
|
|
184
|
+
* @param {{ prefix: string, suffix: string, header: string }} o.window from completionWindow()
|
|
185
|
+
* @param {{ path: string, text: string }[]} [o.neighbors]
|
|
186
|
+
* @param {'auto' | 'manual'} [o.trigger]
|
|
187
|
+
*/
|
|
188
|
+
export function requestBody({ path, language = '', indentUnit = ' ', window, neighbors = [], trigger = 'auto' }) {
|
|
189
|
+
const body = { path, language, indentUnit, prefix: window.prefix, suffix: window.suffix, trigger: trigger === 'manual' ? 'manual' : 'auto' };
|
|
190
|
+
if (window.header) body.header = window.header;
|
|
191
|
+
if (neighbors.length) body.neighbors = neighbors.slice(0, AI_LIMITS.neighborCount).map((n) => ({ path: n.path, text: String(n.text).slice(0, AI_LIMITS.neighborChars) }));
|
|
192
|
+
return body;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The part of another open document that is sent along: the 1,200 characters around its caret (the whole text
|
|
197
|
+
* when it is shorter), whole lines where the window allows.
|
|
198
|
+
* @param {{ slice: (from: number, to: number) => string, length: number, head?: number }} doc
|
|
199
|
+
*/
|
|
200
|
+
export function neighborSnippet({ slice, length, head = 0 }) {
|
|
201
|
+
const size = AI_LIMITS.neighborChars;
|
|
202
|
+
if (length <= size) return slice(0, length);
|
|
203
|
+
const from = Math.max(0, Math.min(length - size, Math.floor(Number(head) || 0) - size / 2));
|
|
204
|
+
let text = slice(from, from + size);
|
|
205
|
+
if (from > 0) {
|
|
206
|
+
const lineStart = text.indexOf('\n');
|
|
207
|
+
if (lineStart >= 0 && lineStart < text.length - 1) text = text.slice(lineStart + 1);
|
|
208
|
+
}
|
|
209
|
+
if (from + size < length) {
|
|
210
|
+
const lineEnd = text.lastIndexOf('\n');
|
|
211
|
+
if (lineEnd > 0) text = text.slice(0, lineEnd);
|
|
212
|
+
}
|
|
213
|
+
return text;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Snippets of other open tabs for a request: up to two, of the document's own language, the tabs used last
|
|
218
|
+
* first. Never a file on the excluded list, never a text that holds a private key, never without a language
|
|
219
|
+
* (plain text is not code to learn from).
|
|
220
|
+
* @param {object} o
|
|
221
|
+
* @param {{ path: string, language: string }} o.current the document the request is for
|
|
222
|
+
* @param {{ path: string, language: string, length: number, head?: number, slice: (from: number, to: number) => string }[]} o.tabs
|
|
223
|
+
* the other open documents, the most recently used first
|
|
224
|
+
* @param {string[]} o.exclude `ai.exclude`
|
|
225
|
+
* @returns {{ path: string, text: string }[]}
|
|
226
|
+
*/
|
|
227
|
+
export function pickNeighbors({ current, tabs, exclude } = {}) {
|
|
228
|
+
const out = [];
|
|
229
|
+
if (!current?.language) return out;
|
|
230
|
+
for (const tab of tabs || []) {
|
|
231
|
+
if (out.length >= AI_LIMITS.neighborCount) break;
|
|
232
|
+
if (!tab || !tab.path || tab.path === current.path || tab.language !== current.language) continue;
|
|
233
|
+
if (matchesExclude(tab.path, exclude) || out.some((taken) => taken.path === tab.path)) continue;
|
|
234
|
+
const text = neighborSnippet(tab);
|
|
235
|
+
if (!text.trim() || hasPrivateKey(text)) continue;
|
|
236
|
+
out.push({ path: tab.path, text });
|
|
237
|
+
}
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ── Results kept ──
|
|
242
|
+
|
|
243
|
+
function fnv1a(text) {
|
|
244
|
+
let hash = 0x811c9dc5;
|
|
245
|
+
for (let i = 0; i < text.length; i++) {
|
|
246
|
+
hash ^= text.charCodeAt(i);
|
|
247
|
+
hash = Math.imul(hash, 0x01000193);
|
|
248
|
+
}
|
|
249
|
+
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** The key a result is kept under: the last 300 characters before the caret, the first 100 after it, and the path. */
|
|
253
|
+
export function cacheKey({ path, prefix, suffix }) {
|
|
254
|
+
const before = String(prefix ?? '').slice(-AI_LIMITS.cacheBefore);
|
|
255
|
+
const after = String(suffix ?? '').slice(0, AI_LIMITS.cacheAfter);
|
|
256
|
+
return `${fnv1a(`${before}\u0000${after}`)}${fnv1a(`${after}\u0000${before}\u0000${path ?? ''}`)}`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** The last results, the most recently used last. */
|
|
260
|
+
export function createSuggestionCache(max = AI_LIMITS.cacheSize) {
|
|
261
|
+
const entries = new Map();
|
|
262
|
+
return {
|
|
263
|
+
get(key) {
|
|
264
|
+
if (!entries.has(key)) return undefined;
|
|
265
|
+
const value = entries.get(key);
|
|
266
|
+
entries.delete(key);
|
|
267
|
+
entries.set(key, value);
|
|
268
|
+
return value;
|
|
269
|
+
},
|
|
270
|
+
set(key, value) {
|
|
271
|
+
entries.delete(key);
|
|
272
|
+
entries.set(key, value);
|
|
273
|
+
while (entries.size > max) entries.delete(entries.keys().next().value);
|
|
274
|
+
},
|
|
275
|
+
delete(key) { return entries.delete(key); },
|
|
276
|
+
clear() { entries.clear(); },
|
|
277
|
+
get size() { return entries.size; },
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ── A suggestion while the user types ──
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* What is left of a suggestion after a change to the document.
|
|
285
|
+
* @param {{ from: number, text: string } | null} suggestion what is shown: `text` would be inserted at `from`
|
|
286
|
+
* @param {{ from: number, to: number, insert: string, head: number }} change one change: `insert` replaced
|
|
287
|
+
* `from`..`to`, and the caret is at `head` afterwards
|
|
288
|
+
* @returns {{ typed: boolean, suggestion: { from: number, text: string } | null }} `typed`: the user typed what
|
|
289
|
+
* the suggestion begins with (no new request is needed while a remainder is left); `suggestion`: the remainder
|
|
290
|
+
*/
|
|
291
|
+
export function typeThrough(suggestion, change) {
|
|
292
|
+
const miss = { typed: false, suggestion: null };
|
|
293
|
+
if (!suggestion || !change || typeof change.insert !== 'string' || !change.insert) return miss;
|
|
294
|
+
if (change.from !== change.to || change.from !== suggestion.from) return miss;
|
|
295
|
+
if (change.head !== change.from + change.insert.length) return miss;
|
|
296
|
+
if (!suggestion.text.startsWith(change.insert)) return miss;
|
|
297
|
+
const rest = suggestion.text.slice(change.insert.length);
|
|
298
|
+
return { typed: true, suggestion: rest ? { from: change.head, text: rest } : null };
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const WORD = /^(\s*)(?:[\p{L}\p{N}_$]+|[^\s\p{L}\p{N}_$]+)/u;
|
|
302
|
+
|
|
303
|
+
/** The part of a suggestion "accept one word" takes: the white space in front of the next word, and that word (or run of punctuation). */
|
|
304
|
+
export function nextWord(text) {
|
|
305
|
+
const value = String(text ?? '');
|
|
306
|
+
const match = WORD.exec(value);
|
|
307
|
+
return match ? match[0] : value;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ── The chip ──
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* What the status-bar chip shows.
|
|
314
|
+
* @param {object} s
|
|
315
|
+
* @param {boolean} s.capable the server has the `complete` capability (without it there is no chip)
|
|
316
|
+
* @param {boolean} s.enabled `ai.enabled`
|
|
317
|
+
* @param {boolean} [s.excluded] the open file is one that is never read
|
|
318
|
+
* @param {boolean} [s.busy] a request is under way
|
|
319
|
+
* @param {{ kind: string } | null} [s.problem] the last request's failure, until one succeeds
|
|
320
|
+
* @returns {'hidden' | 'off' | 'ready' | 'thinking' | 'problem'}
|
|
321
|
+
*/
|
|
322
|
+
export function chipState({ capable, enabled, excluded = false, busy = false, problem = null } = {}) {
|
|
323
|
+
if (!capable) return 'hidden';
|
|
324
|
+
if (!enabled || excluded) return 'off';
|
|
325
|
+
if (busy) return 'thinking';
|
|
326
|
+
if (problem) return 'problem';
|
|
327
|
+
return 'ready';
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* What a failed request means.
|
|
332
|
+
* @param {{ status?: number, body?: object | null, error?: string | null }} failure what the server answered, or
|
|
333
|
+
* why there was no answer
|
|
334
|
+
* @returns {{ kind: 'disabled' | 'excluded' | 'rate' | 'engine' | 'no-model' | 'no-endpoint' | 'timeout' | 'network' | 'server',
|
|
335
|
+
* retryAfterMs: number, message: string }} `disabled` and `excluded` are not problems: the feature is off, or
|
|
336
|
+
* off for this file. `message` is the engine's own words when it gave any.
|
|
337
|
+
*/
|
|
338
|
+
export function describeFailure({ status = 0, body = null, error = null } = {}) {
|
|
339
|
+
const message = typeof body?.message === 'string' ? body.message.replace(/\s+/g, ' ').trim().slice(0, 300) : '';
|
|
340
|
+
const out = (kind, retryAfterMs = 0) => ({ kind, retryAfterMs, message });
|
|
341
|
+
if (status === 409 && body?.code === 'disabled') return out('disabled');
|
|
342
|
+
if (status === 403 && body?.code === 'excluded') return out('excluded');
|
|
343
|
+
if (status === 429) {
|
|
344
|
+
const wait = Number(body?.retryAfterMs);
|
|
345
|
+
return out('rate', Number.isFinite(wait) && wait > 0 ? Math.min(wait, 120_000) : 5000);
|
|
346
|
+
}
|
|
347
|
+
if (status === 502 && body?.code === 'engine') {
|
|
348
|
+
if (body.reason === 'no-model') return out('no-model');
|
|
349
|
+
if (body.reason === 'no-endpoint') return out('no-endpoint');
|
|
350
|
+
if (body.reason === 'timeout') return out('timeout');
|
|
351
|
+
return out('engine');
|
|
352
|
+
}
|
|
353
|
+
if (!status) return { kind: 'network', retryAfterMs: 0, message: String(error ?? '').slice(0, 300) };
|
|
354
|
+
return out('server');
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** The i18n key of a failure's sentence (parameters: `message`, `seconds`). */
|
|
358
|
+
export function failureKey(failure) {
|
|
359
|
+
switch (failure?.kind) {
|
|
360
|
+
case 'rate': return 'editor.ai.problem.rate';
|
|
361
|
+
case 'no-model': return 'editor.ai.problem.noModel';
|
|
362
|
+
case 'no-endpoint': return 'editor.ai.problem.noEndpoint';
|
|
363
|
+
case 'timeout': return 'editor.ai.problem.timeout';
|
|
364
|
+
case 'network': return 'editor.ai.problem.network';
|
|
365
|
+
case 'engine': return failure.message ? 'editor.ai.problem.engine' : 'editor.ai.problem.engineUnknown';
|
|
366
|
+
default: return 'editor.ai.problem.server';
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* The popover's line about today's use, from the answer of `GET /api/editor/complete/usage`.
|
|
372
|
+
* "No requests today" is said only for an answer that says so: no answer, or one that is not one, is a read
|
|
373
|
+
* that failed.
|
|
374
|
+
* @param {{ ok?: boolean, today?: { requests: number, tokensIn: number, tokensOut: number } } | null} answer
|
|
375
|
+
* @returns {{ key: string, params: object }}
|
|
376
|
+
*/
|
|
377
|
+
export function usageLine(answer) {
|
|
378
|
+
const day = answer && answer.ok === true && answer.today && typeof answer.today === 'object' ? answer.today : null;
|
|
379
|
+
if (!day) return { key: 'editor.ai.todayFailed', params: {} };
|
|
380
|
+
const requests = Math.round(Number(day.requests) || 0);
|
|
381
|
+
if (requests <= 0) return { key: 'editor.ai.todayNone', params: {} };
|
|
382
|
+
return {
|
|
383
|
+
key: requests === 1 ? 'editor.ai.today.one' : 'editor.ai.today.other',
|
|
384
|
+
params: { count: formatCount(requests), input: formatCount(day.tokensIn), output: formatCount(day.tokensOut) },
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Whether the popover's read of the models failed. They are asked for with the OpenCode engine only; an answer
|
|
390
|
+
* that says OpenCode is not running is an answer (it has a sentence of its own).
|
|
391
|
+
* @param {{ engine: string, models: object | null }} s `models`: the answer of `GET /api/editor/complete/models`
|
|
392
|
+
*/
|
|
393
|
+
export function modelsReadFailed({ engine, models } = {}) {
|
|
394
|
+
return engine !== 'endpoint' && !(models && models.ok === true);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/** A count the way the popover writes it: 950, 1.2k, 3.4M. */
|
|
398
|
+
export function formatCount(value) {
|
|
399
|
+
const n = Math.max(0, Math.round(Number(value) || 0));
|
|
400
|
+
if (n < 1000) return String(n);
|
|
401
|
+
if (n < 1_000_000) return `${(n / 1000).toFixed(n < 10_000 ? 1 : 0).replace(/\.0$/, '')}k`;
|
|
402
|
+
return `${(n / 1_000_000).toFixed(1).replace(/\.0$/, '')}M`;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** A duration the way a model's test result is written: 640 ms, 1.2 s. */
|
|
406
|
+
export function formatMs(value) {
|
|
407
|
+
const ms = Math.max(0, Math.round(Number(value) || 0));
|
|
408
|
+
return ms < 1000 ? `${ms} ms` : `${(ms / 1000).toFixed(1)} s`;
|
|
409
|
+
}
|