synabun 2.0.0-beta → 2.0.5
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 +65 -0
- package/NOTICE +5 -0
- package/README.md +1 -1
- package/THIRD-PARTY-LICENSES.md +51 -0
- package/benchmarks/fixtures/browser/README.md +1 -1
- package/benchmarks/fixtures/desktop/README.md +1 -1
- package/docs/whatsapp.md +2 -2
- 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 +20 -0
- package/hooks/claude-code/stop.mjs +5 -5
- package/launcher.mjs +40 -0
- package/lib/claude-hooks.js +61 -8
- package/lib/client-config-repair.js +4 -3
- package/lib/data-home-migration.js +4 -0
- package/lib/desktop-pwa.js +206 -0
- package/lib/external-tools.js +221 -0
- package/lib/first-launch-protection.js +5 -0
- package/lib/packaged-runtime.js +110 -0
- package/lib/start-launcher.js +1396 -0
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -3
- package/neural-interface/i18n/en.json +1540 -154
- package/neural-interface/i18n/pt-BR.json +1538 -153
- package/neural-interface/lib/assistant-api.js +62 -6
- package/neural-interface/lib/assistant-brains/claude.js +4 -0
- package/neural-interface/lib/assistant-catalog.js +179 -27
- package/neural-interface/lib/assistant-config.js +31 -2
- package/neural-interface/lib/assistant-dispatch.js +62 -13
- package/neural-interface/lib/assistant-envelope.js +9 -6
- package/neural-interface/lib/assistant-hidden-models.js +393 -66
- package/neural-interface/lib/assistant-memory.js +24 -10
- package/neural-interface/lib/assistant-persona.js +6 -2
- package/neural-interface/lib/assistant-pricing.js +21 -6
- package/neural-interface/lib/assistant-runtime.js +181 -12
- 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 +181 -0
- package/neural-interface/lib/augmented-path.js +23 -3
- package/neural-interface/lib/browser-background-tab.js +134 -0
- package/neural-interface/lib/browser-language.js +83 -0
- package/neural-interface/lib/browser-screenshot.js +678 -61
- package/neural-interface/lib/claude-agent-bridge.js +87 -153
- package/neural-interface/lib/claude-executable.js +241 -0
- package/neural-interface/lib/claude-model-catalog.js +82 -93
- package/neural-interface/lib/claude-temporary.js +46 -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/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-diff-api.js +103 -0
- package/neural-interface/lib/git-read.js +202 -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/machine-names.js +88 -0
- package/neural-interface/lib/memory-api.js +31 -7
- package/neural-interface/lib/native-binary-runtime.js +69 -337
- package/neural-interface/lib/native-loop-providers.js +40 -49
- package/neural-interface/lib/offline-page.js +54 -0
- package/neural-interface/lib/plugin-installer.js +4 -2
- package/neural-interface/lib/project-storage.js +5 -7
- package/neural-interface/lib/request-gate.js +589 -0
- package/neural-interface/lib/session-title-generator.js +5 -0
- package/neural-interface/lib/synabun-update-plan.js +19 -0
- package/neural-interface/lib/ui-blob-api.js +108 -0
- package/neural-interface/lib/ui-blob-store.js +68 -0
- package/neural-interface/package-lock.json +701 -253
- package/neural-interface/package.json +13 -2
- package/neural-interface/public/install-app.html +34 -0
- package/neural-interface/public/manifest.json +2 -0
- package/neural-interface/public/offline.html +402 -66
- package/neural-interface/public/onboarding.html +264 -147
- package/neural-interface/public/shared/agent-runtime-options.js +22 -6
- package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +312 -62
- package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
- package/neural-interface/public/shared/assistant/asst-mascot.js +26 -64
- package/neural-interface/public/shared/assistant/asst-menu.js +12 -8
- package/neural-interface/public/shared/assistant/asst-panel.js +150 -28
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +0 -3
- package/neural-interface/public/shared/assistant/asst-render.js +219 -67
- package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
- package/neural-interface/public/shared/assistant/asst-route.js +23 -329
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +495 -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-state.js +185 -1
- package/neural-interface/public/shared/assistant/asst-styles.js +162 -6
- package/neural-interface/public/shared/blob-store.js +111 -22
- package/neural-interface/public/shared/cdx/cdx-panel.js +32 -11
- package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
- package/neural-interface/public/shared/cdx/cdx-styles.js +36 -0
- package/neural-interface/public/shared/cdx/cdx-tabs.js +87 -4
- package/neural-interface/public/shared/command-runner-model.js +30 -0
- package/neural-interface/public/shared/constants.js +6 -1
- package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
- package/neural-interface/public/shared/cp/cp-styles.js +15 -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/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 +169 -170
- 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 +99 -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 +5 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +40 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
- package/neural-interface/public/shared/pwa-install-page.js +62 -0
- package/neural-interface/public/shared/pwa-install.css +12 -0
- package/neural-interface/public/shared/pwa-install.js +127 -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 +18 -4
- package/neural-interface/public/shared/settings/settings-rules.js +160 -0
- package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
- package/neural-interface/public/shared/start-bridge.js +802 -0
- package/neural-interface/public/shared/styleguide/sg-colors.js +5 -2
- package/neural-interface/public/shared/styleguide/sg-import-export.js +4 -3
- package/neural-interface/public/shared/styleguide/sg-kit.js +4 -1
- package/neural-interface/public/shared/styleguide/sg-panel.js +9 -1
- package/neural-interface/public/shared/styleguide/sg-typography.js +1 -0
- package/neural-interface/public/shared/styles.css +2219 -1117
- package/neural-interface/public/shared/synabun-mascot.js +20 -56
- package/neural-interface/public/shared/term-ready.js +307 -0
- package/neural-interface/public/shared/tunnel-view.js +167 -0
- package/neural-interface/public/shared/ui-claude-panel.js +160 -19
- package/neural-interface/public/shared/ui-command-runner.js +251 -468
- 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-help.js +26 -0
- package/neural-interface/public/shared/ui-invite.js +126 -116
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +4 -0
- package/neural-interface/public/shared/ui-loading.js +367 -12
- package/neural-interface/public/shared/ui-menubar.js +21 -55
- 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 +45 -21
- package/neural-interface/public/shared/ui-settings.js +491 -547
- package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
- package/neural-interface/public/shared/ui-sync.js +16 -0
- package/neural-interface/public/shared/ui-terminal.js +153 -149
- 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-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/worker-end.js +251 -0
- package/neural-interface/public/sw.js +3 -1
- package/neural-interface/public/variant/2d/main.js +2 -1
- package/neural-interface/public/variant/3d/main.js +2 -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/rebuild-pty.js +15 -12
- package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
- package/neural-interface/server.js +1092 -1212
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/package.json +13 -7
- package/postinstall.js +11 -81
- package/setup.js +111 -6
- package/benchmarks/browser-live-results.json +0 -79
- package/benchmarks/browser-v2-results.json +0 -258
- package/docs/browser-v2.md +0 -109
- package/docs/hook-integrity.md +0 -89
- package/docs/judgments.md +0 -182
- package/docs/style-guide.md +0 -246
- 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/scripts/audit-claude-hook-usage.mjs +0 -12
- package/scripts/audit-memory-duplicates.mjs +0 -44
- package/scripts/measure-claude-hook-overhead.mjs +0 -77
- package/scripts/recover-user-config.mjs +0 -254
- package/skills/synabun/synabunicon.png +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Neural Interface — Code editor: the command palette and go-to-file
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Two lists under a search field, at the top of the editor panel: the
|
|
6
|
+
// editor's commands (F1 or Mod-Shift-P), and the files of the project
|
|
7
|
+
// (Mod-P; with nothing typed, the open tabs). Enter runs or opens what is
|
|
8
|
+
// selected, Escape closes the list and nothing else happens. Both are the
|
|
9
|
+
// panel's one popup (editor-menu.js); what they list and in which order is
|
|
10
|
+
// decided in editor-palette-logic.js.
|
|
11
|
+
// Takes its words, the menu and what a choice does as arguments.
|
|
12
|
+
|
|
13
|
+
import { FILE_SEARCH_DELAY_MS, fileListEmpty, fileRows, fileSearchParams, paletteCommands, queryTerms, rankRows, tabRows } from './editor-palette-logic.js';
|
|
14
|
+
import { formatKey } from './editor-commands.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {object} o
|
|
18
|
+
* @param {(key: string, params?: object) => string} o.t
|
|
19
|
+
* @param {(menu: object) => { close: Function, setItems: Function }} o.openMenu editor-menu.js, already given the panel as its host
|
|
20
|
+
* @param {() => { x: number, y: number }} o.position where a list opens: its top-left corner, in page coordinates
|
|
21
|
+
* @param {boolean} o.mac
|
|
22
|
+
* @param {object[]} o.commands editor-commands.js
|
|
23
|
+
* @param {() => string[]} o.features the features this server has ('ai', 'git')
|
|
24
|
+
* @param {(id: string) => void} o.run run a command by its id
|
|
25
|
+
* @param {() => string | null | Promise<string | null>} o.project the folder files are searched in (it may have to be asked for)
|
|
26
|
+
* @param {() => { path: string, name: string }[]} o.tabs the open files, the one used last first
|
|
27
|
+
* @param {(path: string) => void} o.openFile
|
|
28
|
+
* @param {() => void} [o.onClose] a list closed (the keyboard goes back to the text)
|
|
29
|
+
* @param {typeof fetch} [o.fetchImpl]
|
|
30
|
+
*/
|
|
31
|
+
export function createPalette({ t, openMenu, position, mac, commands, features, run, project, tabs, openFile, onClose = () => {}, fetchImpl = (...args) => fetch(...args) }) {
|
|
32
|
+
const item = (row, hint) => ({ id: row.id, label: row.label, ...(hint ? { hint } : {}) });
|
|
33
|
+
|
|
34
|
+
function openCommands() {
|
|
35
|
+
const rows = paletteCommands(commands, { features: features() }).map((row) => ({ id: row.id, label: t(row.titleKey), key: row.key }));
|
|
36
|
+
return openMenu({
|
|
37
|
+
className: 'fe-editor-palette',
|
|
38
|
+
at: position(),
|
|
39
|
+
label: t('editor.palette.commands'),
|
|
40
|
+
items: [],
|
|
41
|
+
search: {
|
|
42
|
+
label: t('editor.palette.commands'),
|
|
43
|
+
placeholder: t('editor.palette.commandsPlaceholder'),
|
|
44
|
+
empty: t('editor.palette.noCommand'),
|
|
45
|
+
filter: (query) => rankRows(rows, query, { limit: rows.length }).map((row) => item(row, row.key ? formatKey(row.key, mac) : '')),
|
|
46
|
+
},
|
|
47
|
+
onSelect: (id) => run(id),
|
|
48
|
+
onClose,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function openFiles() {
|
|
53
|
+
let root = null; // the folder that is searched, once it is known
|
|
54
|
+
let rootKnown = false;
|
|
55
|
+
let found = []; // the files of the last answer
|
|
56
|
+
let typed = '';
|
|
57
|
+
let asked = ''; // the query string of the request that was last sent
|
|
58
|
+
let timer = 0;
|
|
59
|
+
let request = null;
|
|
60
|
+
let failed = false;
|
|
61
|
+
let pending = false; // a search for what is typed is waiting to be sent, or has not answered yet
|
|
62
|
+
let handle = null;
|
|
63
|
+
|
|
64
|
+
const list = (query) => {
|
|
65
|
+
const rows = queryTerms(query).length ? rankRows(found, query) : tabRows(tabs(), root);
|
|
66
|
+
return rows.map((row) => item(row, row.detail));
|
|
67
|
+
};
|
|
68
|
+
// Still searching, failed, nothing found and nothing asked yet are four different things to say.
|
|
69
|
+
const empty = () => t(fileListEmpty({ rootKnown, root, failed, pending, typed }));
|
|
70
|
+
|
|
71
|
+
async function search(params) {
|
|
72
|
+
request?.abort();
|
|
73
|
+
const mine = new AbortController();
|
|
74
|
+
request = mine;
|
|
75
|
+
let rows = [];
|
|
76
|
+
let ok = false;
|
|
77
|
+
try {
|
|
78
|
+
const res = await fetchImpl(`/api/project-files?${params}`, { signal: mine.signal });
|
|
79
|
+
if (res.ok) { rows = fileRows(await res.json()); ok = true; }
|
|
80
|
+
} catch { /* aborted, or no answer */ }
|
|
81
|
+
if (request !== mine) return; // a newer search is on its way
|
|
82
|
+
request = null;
|
|
83
|
+
pending = false;
|
|
84
|
+
found = rows;
|
|
85
|
+
failed = !ok;
|
|
86
|
+
handle?.setItems(list(typed));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function schedule(query) {
|
|
90
|
+
const params = fileSearchParams(root, query);
|
|
91
|
+
if (params === asked) return;
|
|
92
|
+
asked = params;
|
|
93
|
+
clearTimeout(timer);
|
|
94
|
+
if (!params) { request?.abort(); request = null; found = []; failed = false; pending = false; return; }
|
|
95
|
+
pending = true;
|
|
96
|
+
timer = setTimeout(() => search(params), FILE_SEARCH_DELAY_MS);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
handle = openMenu({
|
|
100
|
+
className: 'fe-editor-palette',
|
|
101
|
+
at: position(),
|
|
102
|
+
label: t('editor.palette.files'),
|
|
103
|
+
items: [],
|
|
104
|
+
search: {
|
|
105
|
+
label: t('editor.palette.files'),
|
|
106
|
+
placeholder: t('editor.palette.filesPlaceholder'),
|
|
107
|
+
empty,
|
|
108
|
+
filter: (query) => { typed = query; schedule(query); return list(query); },
|
|
109
|
+
},
|
|
110
|
+
onSelect: (path) => openFile(path),
|
|
111
|
+
onClose: () => { clearTimeout(timer); request?.abort(); request = null; handle = null; onClose(); },
|
|
112
|
+
});
|
|
113
|
+
// The folder may have to be asked for: what was typed meanwhile is searched as soon as it is known.
|
|
114
|
+
Promise.resolve().then(project).catch(() => null).then((folder) => {
|
|
115
|
+
root = folder || null;
|
|
116
|
+
rootKnown = true;
|
|
117
|
+
if (!handle) return;
|
|
118
|
+
schedule(typed);
|
|
119
|
+
handle.setItems(list(typed));
|
|
120
|
+
});
|
|
121
|
+
return handle;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return { openCommands, openFiles };
|
|
125
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Neural Interface — Code editor: the panel's decisions
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// What the editor panel decides without touching the page: the path it shows,
|
|
6
|
+
// the state of its buttons, the events of a plan being edited, and what a
|
|
7
|
+
// refused file means. editor-panel.js renders from these. No DOM and no
|
|
8
|
+
// imports: loaded by `node --test` as it is.
|
|
9
|
+
|
|
10
|
+
/** A file size the way the status bar writes it. */
|
|
11
|
+
export function formatSize(bytes) {
|
|
12
|
+
const n = Number(bytes) || 0;
|
|
13
|
+
if (n < 1024) return `${n} B`;
|
|
14
|
+
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
|
|
15
|
+
return `${(n / (1024 * 1024)).toFixed(1)} MB`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The path the header shows: relative to the selected project, or the whole path without its leading slash
|
|
20
|
+
* when no project is selected (or the file is not in it).
|
|
21
|
+
*/
|
|
22
|
+
export function displayPath(path, projectRoot) {
|
|
23
|
+
const full = String(path ?? '');
|
|
24
|
+
const rel = projectRoot ? full.replace(String(projectRoot).replace(/\\/g, '/'), '') : full;
|
|
25
|
+
return rel.startsWith('/') ? rel.slice(1) : rel;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The name a plan's banner uses for the panel that opened it. */
|
|
29
|
+
export function planSourceLabel(source) {
|
|
30
|
+
if (source === 'codex') return 'Codex';
|
|
31
|
+
if (source === 'opencode') return 'OpenCode';
|
|
32
|
+
return 'Claude';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The identity every plan event carries, from the contract `open-plan-editor` delivered.
|
|
37
|
+
* @param {{ source?: string, tabId?: any, planId?: any, revision?: any, accountId?: any, threadId?: any, sidepanelWindowId?: any }} contract
|
|
38
|
+
* @param {object} [extra] the fields of the particular event
|
|
39
|
+
*/
|
|
40
|
+
export function planEvent(contract, extra = {}) {
|
|
41
|
+
const { source = 'claude', tabId = null, planId, revision, accountId, threadId, sidepanelWindowId = null } = contract || {};
|
|
42
|
+
return { source, tabId, planId, revision, accountId, threadId, sidepanelWindowId: sidepanelWindowId || null, ...extra };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** What tells one plan request from another: the panel and tab that asked, the plan and its revision. */
|
|
46
|
+
export function planIdentityKey(contract) {
|
|
47
|
+
const { source = 'claude', tabId = null, planId, revision, sidepanelWindowId = null } = contract || {};
|
|
48
|
+
return [source, tabId ?? '', planId ?? '', revision ?? '', sidepanelWindowId || ''].join('|');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Whether two plan requests come from the same place: the same tab of the same panel. That place follows one
|
|
53
|
+
* plan editor at a time, so a second plan of its own takes the first one's tab.
|
|
54
|
+
*/
|
|
55
|
+
export function isSamePlanOwner(a, b) {
|
|
56
|
+
if (!a || !b) return false;
|
|
57
|
+
return (a.source ?? 'claude') === (b.source ?? 'claude')
|
|
58
|
+
&& (a.tabId ?? null) === (b.tabId ?? null)
|
|
59
|
+
&& (a.sidepanelWindowId || null) === (b.sidepanelWindowId || null);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Whether `contract` asks for the plan revision that is already open (the editor is then only focused). */
|
|
63
|
+
export function isSamePlan(open, contract) {
|
|
64
|
+
if (!open || !contract) return false;
|
|
65
|
+
return open.filePath === contract.filePath
|
|
66
|
+
&& (open.source ?? 'claude') === (contract.source ?? 'claude')
|
|
67
|
+
&& (open.tabId ?? null) === (contract.tabId ?? null)
|
|
68
|
+
&& open.planId === contract.planId
|
|
69
|
+
&& open.revision === contract.revision;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Whether the file on disk still holds the plan revision the panel asked to edit. Line endings are not part of
|
|
74
|
+
* a revision: both sides are compared with "\n".
|
|
75
|
+
* @param {string} content the file as read
|
|
76
|
+
* @param {string | undefined} expected the contract's `expectedMarkdown`; anything but a string means no check
|
|
77
|
+
*/
|
|
78
|
+
export function matchesExpectedMarkdown(content, expected) {
|
|
79
|
+
if (typeof expected !== 'string') return true;
|
|
80
|
+
return String(content).replace(/\r\n/g, '\n') === expected.replace(/\r\n/g, '\n');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Whether a path is the user's OpenCode configuration file. */
|
|
84
|
+
export function isOpencodeConfigPath(path) {
|
|
85
|
+
return String(path || '').replace(/\\/g, '/').endsWith('/.config/opencode/config.json');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const OUTSIDE_ROOTS = 'Path outside registered project roots';
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* What a failed `GET /api/file-content` means for the panel.
|
|
92
|
+
* @param {{ status: number, body?: object, path?: string }} failure
|
|
93
|
+
* @returns {{ kind: 'toast' | 'refused', key: string, params?: object, text?: string }}
|
|
94
|
+
* `toast`: nothing opens; `text` (the server's own words) wins over the translation of `key` when present.
|
|
95
|
+
* `refused`: the panel opens with the message of `key` in place of an editor.
|
|
96
|
+
*/
|
|
97
|
+
export function describeOpenFailure({ status, body, path } = {}) {
|
|
98
|
+
const error = typeof body?.error === 'string' ? body.error : '';
|
|
99
|
+
if (status === 403 && error === OUTSIDE_ROOTS && isOpencodeConfigPath(path)) {
|
|
100
|
+
return { kind: 'toast', key: 'editor.toast.restartForOpencodeConfig' };
|
|
101
|
+
}
|
|
102
|
+
if (status === 415) {
|
|
103
|
+
return body?.reason === 'encoding'
|
|
104
|
+
? { kind: 'refused', key: 'editor.refused.encoding' }
|
|
105
|
+
: { kind: 'refused', key: 'editor.refused.binary' };
|
|
106
|
+
}
|
|
107
|
+
if (status === 413) {
|
|
108
|
+
const max = Number(body?.maxBytes);
|
|
109
|
+
return Number.isFinite(max) && max > 0
|
|
110
|
+
? { kind: 'toast', key: 'editor.toast.tooLargeOver', params: { size: formatSize(max) } }
|
|
111
|
+
: { kind: 'toast', key: 'editor.toast.tooLarge' };
|
|
112
|
+
}
|
|
113
|
+
return { kind: 'toast', key: 'editor.toast.cannotOpen', text: error };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The state of the header's buttons.
|
|
118
|
+
* @param {{ ready: boolean, dirty: boolean, saving: boolean, plan: boolean, changelog?: boolean }} s `ready`: a
|
|
119
|
+
* document is open; `plan`, `changelog`: a plan or a changelog draft is being edited (either can be saved
|
|
120
|
+
* unchanged, which approves it as it is)
|
|
121
|
+
*/
|
|
122
|
+
export function controlsState({ ready, dirty, saving, plan, changelog = false }) {
|
|
123
|
+
return {
|
|
124
|
+
saveDisabled: !ready || saving || (!dirty && !plan && !changelog),
|
|
125
|
+
discardDisabled: !ready || saving || !dirty,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The status bar's indentation item.
|
|
131
|
+
* @param {{ kind: 'spaces' | 'tabs', tabSize: number }} indent from resolveIndentation()
|
|
132
|
+
* @returns {{ key: string, params: { n: number } }}
|
|
133
|
+
*/
|
|
134
|
+
export function indentStatus(indent) {
|
|
135
|
+
return { key: indent?.kind === 'tabs' ? 'editor.status.tabSize' : 'editor.status.spaces', params: { n: indent?.tabSize ?? 2 } };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The status bar's line-ending item: the style, or what a save turns a mixed file into.
|
|
140
|
+
* @param {{ eol: 'LF' | 'CRLF', mixed: boolean }} ending from detectLineEnding()
|
|
141
|
+
* @returns {{ key: string | null, params?: { eol: string }, text?: string }} `key: null` → show `text` as it is
|
|
142
|
+
*/
|
|
143
|
+
export function eolStatus(ending) {
|
|
144
|
+
const eol = ending?.eol === 'CRLF' ? 'CRLF' : 'LF';
|
|
145
|
+
return ending?.mixed ? { key: 'editor.status.eolMixed', params: { eol } } : { key: null, text: eol };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The status bar's position item.
|
|
150
|
+
* @param {{ line: number, column: number, selected: number, cursors: number }} at
|
|
151
|
+
* @returns {{ key: string, params: object }}
|
|
152
|
+
*/
|
|
153
|
+
export function positionStatus({ line, column, selected = 0, cursors = 1 }) {
|
|
154
|
+
// Several carets: the place of the main one, how many there are, and what they select together.
|
|
155
|
+
if (cursors > 1) {
|
|
156
|
+
return selected > 0
|
|
157
|
+
? { key: 'editor.status.cursorsSelected', params: { line, column, count: cursors, selected } }
|
|
158
|
+
: { key: 'editor.status.cursors', params: { line, column, count: cursors } };
|
|
159
|
+
}
|
|
160
|
+
if (selected > 0) return { key: 'editor.status.positionSelected', params: { line, column, selected } };
|
|
161
|
+
return { key: 'editor.status.position', params: { line, column } };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The question asked before tabs with unsaved changes are closed.
|
|
166
|
+
* @param {string[]} unsaved the names of the files that have unsaved changes
|
|
167
|
+
* @param {{ only?: boolean }} [o] `only`: the one tab that is open is being closed (the question the editor
|
|
168
|
+
* asked before it had tabs)
|
|
169
|
+
* @returns {{ key: string, params?: object } | null} null: nothing is unsaved, nothing is asked
|
|
170
|
+
*/
|
|
171
|
+
export function closeConfirm(unsaved, { only = false } = {}) {
|
|
172
|
+
const names = Array.isArray(unsaved) ? unsaved : [];
|
|
173
|
+
if (!names.length) return null;
|
|
174
|
+
if (only) return { key: 'editor.confirm.close' };
|
|
175
|
+
if (names.length === 1) return { key: 'editor.confirm.closeOne', params: { name: names[0] } };
|
|
176
|
+
return { key: 'editor.confirm.closeMany', params: { count: names.length, files: names.map((name) => `\u2022 ${name}`).join('\n') } };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** The indentations the status bar offers, beside "Detect". */
|
|
180
|
+
export const INDENT_CHOICES = Object.freeze([
|
|
181
|
+
Object.freeze({ id: 'spaces-2', kind: 'spaces', size: 2 }),
|
|
182
|
+
Object.freeze({ id: 'spaces-4', kind: 'spaces', size: 4 }),
|
|
183
|
+
Object.freeze({ id: 'spaces-8', kind: 'spaces', size: 8 }),
|
|
184
|
+
Object.freeze({ id: 'tabs', kind: 'tabs' }),
|
|
185
|
+
]);
|
|
186
|
+
|
|
187
|
+
/** The choice an id of the indentation menu stands for; null for "detect" (and for anything else). */
|
|
188
|
+
export function indentChoice(id) {
|
|
189
|
+
const found = INDENT_CHOICES.find((choice) => choice.id === id);
|
|
190
|
+
return found ? { kind: found.kind, ...(found.size ? { size: found.size } : {}) } : null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** The id of the menu item that is in force: the user's choice, or 'detect' when there is none. */
|
|
194
|
+
export function indentChoiceId(choice) {
|
|
195
|
+
if (!choice) return 'detect';
|
|
196
|
+
return choice.kind === 'tabs' ? 'tabs' : `spaces-${choice.size}`;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The languages a search of the status bar's list finds: those whose name or other names hold the words typed,
|
|
201
|
+
* the ones whose name starts with them first.
|
|
202
|
+
* @param {{ name: string, alias?: readonly string[] }[]} languages
|
|
203
|
+
* @param {string} query
|
|
204
|
+
* @returns {string[]} names
|
|
205
|
+
*/
|
|
206
|
+
export function filterLanguages(languages, query) {
|
|
207
|
+
const list = (languages || []).filter((language) => language && typeof language.name === 'string');
|
|
208
|
+
const wanted = String(query ?? '').trim().toLowerCase();
|
|
209
|
+
const byName = (a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' });
|
|
210
|
+
if (!wanted) return list.map((language) => language.name).sort(byName);
|
|
211
|
+
const starts = []; const holds = [];
|
|
212
|
+
for (const language of list) {
|
|
213
|
+
const name = language.name.toLowerCase();
|
|
214
|
+
if (name.startsWith(wanted)) starts.push(language.name);
|
|
215
|
+
else if (name.includes(wanted) || (language.alias || []).some((alias) => String(alias).toLowerCase().includes(wanted))) holds.push(language.name);
|
|
216
|
+
}
|
|
217
|
+
return [...starts.sort(byName), ...holds.sort(byName)];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ── The View menu ──
|
|
221
|
+
|
|
222
|
+
/** The sizes the text can have, as the preferences allow them (editor-prefs.js keeps the same numbers). */
|
|
223
|
+
export const VIEW_FONT = Object.freeze({ min: 10, max: 18, base: 12 });
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The View menu's entries for the preferences in force.
|
|
227
|
+
* @param {{ wordWrap: boolean, minimap: boolean, indentGuides: boolean, renderWhitespace: string, fontSize: number }} editing
|
|
228
|
+
* @returns {({ separator: true } | { id: string, labelKey: string, checked?: boolean, toggle?: boolean,
|
|
229
|
+
* disabled?: boolean, hintKey?: string, hintParams?: object })[]} `toggle`: a switch (the others with `checked`
|
|
230
|
+
* are one choice among several)
|
|
231
|
+
*/
|
|
232
|
+
export function viewMenuItems(editing = {}) {
|
|
233
|
+
const size = Number(editing.fontSize) || VIEW_FONT.base;
|
|
234
|
+
const whitespace = ['none', 'selection', 'all'].includes(editing.renderWhitespace) ? editing.renderWhitespace : 'none';
|
|
235
|
+
return [
|
|
236
|
+
{ id: 'wordWrap', labelKey: 'editor.view.wordWrap', checked: editing.wordWrap !== false, toggle: true },
|
|
237
|
+
{ id: 'minimap', labelKey: 'editor.view.minimap', checked: editing.minimap !== false, toggle: true },
|
|
238
|
+
{ id: 'indentGuides', labelKey: 'editor.view.indentGuides', checked: editing.indentGuides !== false, toggle: true },
|
|
239
|
+
{ separator: true },
|
|
240
|
+
{ id: 'whitespace:none', labelKey: 'editor.view.whitespaceNone', checked: whitespace === 'none' },
|
|
241
|
+
{ id: 'whitespace:selection', labelKey: 'editor.view.whitespaceSelection', checked: whitespace === 'selection' },
|
|
242
|
+
{ id: 'whitespace:all', labelKey: 'editor.view.whitespaceAll', checked: whitespace === 'all' },
|
|
243
|
+
{ separator: true },
|
|
244
|
+
{ id: 'font:larger', labelKey: 'editor.view.fontLarger', disabled: size >= VIEW_FONT.max, hintKey: 'editor.view.fontSize', hintParams: { size } },
|
|
245
|
+
{ id: 'font:smaller', labelKey: 'editor.view.fontSmaller', disabled: size <= VIEW_FONT.min },
|
|
246
|
+
{ id: 'font:reset', labelKey: 'editor.view.fontReset', disabled: size === VIEW_FONT.base },
|
|
247
|
+
];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* What choosing an entry of the View menu changes.
|
|
252
|
+
* @param {string} id an entry's id
|
|
253
|
+
* @param {object} editing the preferences in force
|
|
254
|
+
* @returns {object | null} the part of the `editing` preferences to store, or null for an entry that changes nothing
|
|
255
|
+
*/
|
|
256
|
+
export function viewMenuChange(id, editing = {}) {
|
|
257
|
+
const size = Number(editing.fontSize) || VIEW_FONT.base;
|
|
258
|
+
switch (id) {
|
|
259
|
+
case 'wordWrap': return { wordWrap: editing.wordWrap === false };
|
|
260
|
+
case 'minimap': return { minimap: editing.minimap === false };
|
|
261
|
+
case 'indentGuides': return { indentGuides: editing.indentGuides === false };
|
|
262
|
+
case 'whitespace:none': return editing.renderWhitespace === 'none' ? null : { renderWhitespace: 'none' };
|
|
263
|
+
case 'whitespace:selection': return editing.renderWhitespace === 'selection' ? null : { renderWhitespace: 'selection' };
|
|
264
|
+
case 'whitespace:all': return editing.renderWhitespace === 'all' ? null : { renderWhitespace: 'all' };
|
|
265
|
+
case 'font:larger': return size >= VIEW_FONT.max ? null : { fontSize: size + 1 };
|
|
266
|
+
case 'font:smaller': return size <= VIEW_FONT.min ? null : { fontSize: size - 1 };
|
|
267
|
+
case 'font:reset': return size === VIEW_FONT.base ? null : { fontSize: VIEW_FONT.base };
|
|
268
|
+
default: return null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** The next way of drawing whitespace, for a command that goes through them: none → selection → all → none. */
|
|
273
|
+
export function nextWhitespace(current) {
|
|
274
|
+
const order = ['none', 'selection', 'all'];
|
|
275
|
+
return order[(order.indexOf(current) + 1) % order.length] || 'none';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Narrower than this, the editor has no room for a minimap. */
|
|
279
|
+
export const MINIMAP_MIN_WIDTH = 760;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Whether a document shows the minimap.
|
|
283
|
+
* @param {{ preference: boolean, width: number, large: boolean }} o `width`: the editor's, in pixels; `large`: the
|
|
284
|
+
* document is over the size the minimap is drawn for (editor-doc.js: isLargeDocument)
|
|
285
|
+
*/
|
|
286
|
+
export function minimapShown({ preference, width, large }) {
|
|
287
|
+
return preference !== false && !large && Number(width) >= MINIMAP_MIN_WIDTH;
|
|
288
|
+
}
|