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,216 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Neural Interface — File Explorer: the server
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Every request the explorer makes. The page reloads at any time and the
|
|
6
|
+
// server only on a restart, so it works against an older server with what that
|
|
7
|
+
// has: the listing and search of /api/project-files, git from /api/git/status,
|
|
8
|
+
// a new file or folder and a delete through the editor's routes. Whether the
|
|
9
|
+
// server has the explorer's own routes (lib/file-explorer-api.js) it is told
|
|
10
|
+
// by the answer of GET /api/projects, which the panel asks for anyway
|
|
11
|
+
// (`serverSays`): an older server lists nothing there, and nothing of
|
|
12
|
+
// /api/explorer is ever asked of it. What it cannot do answers
|
|
13
|
+
// `{ ok: false, code: 'unsupported' }` here, without a request.
|
|
14
|
+
// Nothing in this file throws: a call resolves to `{ ok: true, … }` or to
|
|
15
|
+
// `{ ok: false, code, … }` (`offline` when the server did not answer).
|
|
16
|
+
|
|
17
|
+
import { fromLegacyListing, fromLegacySearch, trimSlash } from './fx-logic.js';
|
|
18
|
+
|
|
19
|
+
const JSON_HEADERS = { 'Content-Type': 'application/json' };
|
|
20
|
+
const RECONNECT_MS = [1500, 3000, 6000, 12000, 30000];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {{ fetchImpl?: typeof fetch, EventSourceImpl?: typeof EventSource }} [o]
|
|
24
|
+
*/
|
|
25
|
+
export function createExplorerApi({ fetchImpl = (...args) => fetch(...args), EventSourceImpl = globalThis.EventSource } = {}) {
|
|
26
|
+
let asked = null; // the one question about what the server has
|
|
27
|
+
let listed = null; // what GET /api/projects said this server has
|
|
28
|
+
let caps = { known: false, explorer: false, info: null };
|
|
29
|
+
|
|
30
|
+
async function request(url, init) {
|
|
31
|
+
let res;
|
|
32
|
+
try { res = await fetchImpl(url, init); } catch (error) { return { ok: false, code: error?.name === 'AbortError' ? 'aborted' : 'offline' }; }
|
|
33
|
+
let body = null;
|
|
34
|
+
try { body = await res.json(); } catch { body = null; }
|
|
35
|
+
if (res.ok && body && body.ok !== false) return { ok: true, ...body };
|
|
36
|
+
// The server's first gate answers an invited guest 403 "Admin only", without a code of its own.
|
|
37
|
+
const guest = res.status === 403 && body?.error === 'Admin only';
|
|
38
|
+
return { ...(body && typeof body === 'object' ? body : {}), ok: false, code: body?.code || (guest ? 'GUEST_FORBIDDEN' : res.status === 403 ? 'denied' : res.status === 404 ? 'gone' : 'failed'), status: res.status };
|
|
39
|
+
}
|
|
40
|
+
const post = (path, body) => request(`/api/explorer${path}`, { method: 'POST', headers: JSON_HEADERS, body: JSON.stringify(body) });
|
|
41
|
+
const unsupported = () => Promise.resolve({ ok: false, code: 'unsupported' });
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* What GET /api/projects listed as this server's capabilities (null when it did not answer). Called by the panel
|
|
45
|
+
* each time it reads the projects: a server that was restarted since is found out by the next read.
|
|
46
|
+
*/
|
|
47
|
+
function serverSays(list) {
|
|
48
|
+
const has = Array.isArray(list) && list.includes('explorer');
|
|
49
|
+
if (listed !== null && has === caps.explorer && caps.known) return;
|
|
50
|
+
listed = Array.isArray(list) ? list : (list === null ? null : []);
|
|
51
|
+
asked = null;
|
|
52
|
+
caps = { known: false, explorer: false, info: null };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** What the server can do: its own word on the explorer's routes, asked for once it says it has them. */
|
|
56
|
+
function capabilities() {
|
|
57
|
+
if (!asked) {
|
|
58
|
+
asked = (async () => {
|
|
59
|
+
if (listed === null) { asked = null; return caps; } // not told yet: the next call looks again
|
|
60
|
+
const has = listed.includes('explorer');
|
|
61
|
+
const info = has ? await request('/api/explorer/info') : null;
|
|
62
|
+
if (has && !info.ok && info.code === 'offline') { asked = null; return caps; }
|
|
63
|
+
caps = { known: true, explorer: !!(has && info?.ok), info: info?.ok ? info : null };
|
|
64
|
+
return caps;
|
|
65
|
+
})();
|
|
66
|
+
}
|
|
67
|
+
return asked;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** What is known of the server right now (after `capabilities()` answered). */
|
|
71
|
+
const abilities = () => ({
|
|
72
|
+
known: caps.known,
|
|
73
|
+
ops: caps.explorer,
|
|
74
|
+
watch: caps.explorer,
|
|
75
|
+
trash: caps.explorer && !!caps.info?.trash,
|
|
76
|
+
reveal: caps.explorer && !!caps.info?.reveal,
|
|
77
|
+
preview: caps.explorer,
|
|
78
|
+
platform: caps.info?.platform || null,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
async function list(path) {
|
|
82
|
+
await capabilities();
|
|
83
|
+
if (caps.explorer) return request(`/api/explorer/list?path=${encodeURIComponent(path)}`);
|
|
84
|
+
const old = await request(`/api/project-files?path=${encodeURIComponent(path)}`);
|
|
85
|
+
if (!old.ok) {
|
|
86
|
+
// The older route words its failures itself: a folder that is not there, a path that is not allowed.
|
|
87
|
+
return { ok: false, code: old.code === 'offline' ? 'offline' : old.status === 403 ? (old.code === 'GUEST_FORBIDDEN' ? old.code : 'outside') : old.status === 400 ? 'gone' : 'failed' };
|
|
88
|
+
}
|
|
89
|
+
return fromLegacyListing(old);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function search(root, query, signal) {
|
|
93
|
+
await capabilities();
|
|
94
|
+
if (caps.explorer) return request(`/api/explorer/search?root=${encodeURIComponent(root)}&q=${encodeURIComponent(query)}`, { signal });
|
|
95
|
+
const old = await request(`/api/project-files?${new URLSearchParams({ path: root, search: query, recursive: '1' })}`, { signal });
|
|
96
|
+
return old.ok ? fromLegacySearch(old) : old;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function git(root) {
|
|
100
|
+
await capabilities();
|
|
101
|
+
if (caps.explorer) return request(`/api/explorer/git?root=${encodeURIComponent(root)}`);
|
|
102
|
+
const old = await request(`/api/git/status?path=${encodeURIComponent(root)}`);
|
|
103
|
+
if (!old.ok) return old;
|
|
104
|
+
if (!old.isGit) return { ok: true, isGit: false };
|
|
105
|
+
const changes = {};
|
|
106
|
+
for (const change of old.changes || []) if (change?.path) changes[change.path] = change.status;
|
|
107
|
+
return { ok: true, isGit: true, branch: old.branch || '', changes, ignored: [], legacy: true };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function create(parent, name, type) {
|
|
111
|
+
await capabilities();
|
|
112
|
+
if (caps.explorer) return post('/create', { parent, name, type });
|
|
113
|
+
// An older server: its own two routes. It would write over a file, or take a folder that is there for a new
|
|
114
|
+
// one, so the folder is read first and a name that is taken is refused here.
|
|
115
|
+
const there = await list(parent);
|
|
116
|
+
if (!there.ok) return there;
|
|
117
|
+
if (there.items.some((item) => item.name.toLowerCase() === name.toLowerCase())) return { ok: false, code: 'exists', name };
|
|
118
|
+
const path = `${trimSlash(parent)}/${name}`;
|
|
119
|
+
const made = type === 'dir'
|
|
120
|
+
? await request('/api/file-mkdir', { method: 'POST', headers: JSON_HEADERS, body: JSON.stringify({ path }) })
|
|
121
|
+
: await request('/api/file-content', { method: 'POST', headers: JSON_HEADERS, body: JSON.stringify({ path, content: '', create: true, expectAbsent: true }) });
|
|
122
|
+
if (made.ok) return { ok: true, path, type };
|
|
123
|
+
return { ok: false, code: made.status === 409 ? 'exists' : made.status === 403 ? 'denied' : made.code === 'offline' ? 'offline' : 'failed', name };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function remove(paths, { permanent = false } = {}) {
|
|
127
|
+
await capabilities();
|
|
128
|
+
if (caps.explorer) return post('/delete', { paths, permanent });
|
|
129
|
+
// An older server deletes for good, one entry at a time, and a folder only when it is empty.
|
|
130
|
+
if (!permanent) return { ok: false, code: 'no-trash' };
|
|
131
|
+
const deleted = [];
|
|
132
|
+
for (const path of paths) {
|
|
133
|
+
const done = await request(`/api/file-content?path=${encodeURIComponent(path)}`, { method: 'DELETE' });
|
|
134
|
+
if (done.ok || done.status === 404) { deleted.push(path); continue; }
|
|
135
|
+
const notEmpty = done.status === 400 && /not empty/i.test(String(done.error || ''));
|
|
136
|
+
return { ok: false, code: notEmpty ? 'not-empty' : done.status === 403 ? 'denied' : done.code === 'offline' ? 'offline' : 'failed', deleted, failed: path };
|
|
137
|
+
}
|
|
138
|
+
return { ok: true, deleted, trashed: false };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const guarded = (call) => async (...args) => { await capabilities(); return caps.explorer ? call(...args) : unsupported(); };
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Follow a project on disk. `onChange({ dirs, git })` names the shown folders that changed; `onReady(again)` says
|
|
145
|
+
* the stream is up (`again`: after it was down, so anything may have changed meanwhile). A stream is not a watch
|
|
146
|
+
* that works: `onState({ live, scope })` says what the server really watches, at the start and when it changes
|
|
147
|
+
* (`live`: 'full', 'partial' when some folders could not be watched, 'none' when the project is not watched at
|
|
148
|
+
* all; `scope`: 'tree', or 'folders' where only the shown folders are watched). `onResync()`: the server lost
|
|
149
|
+
* its watch on the project; it tries for it again by itself, and nothing is sent back for the report (what is
|
|
150
|
+
* shown may be stale, the folders that are shown are the ones it was told). Null on a server that has no
|
|
151
|
+
* watch. The connection is tried again by itself, ever more slowly, until `close()`.
|
|
152
|
+
*/
|
|
153
|
+
function watch(root, { onChange, onReady = () => {}, onDown = () => {}, onState = () => {}, onResync = () => {} }) {
|
|
154
|
+
if (!caps.explorer || typeof EventSourceImpl !== 'function') return null;
|
|
155
|
+
let source = null; let id = null; let dirs = []; let closed = false; let attempt = 0; let timer = 0; let pushTimer = 0; let wasUp = false;
|
|
156
|
+
const push = () => {
|
|
157
|
+
clearTimeout(pushTimer);
|
|
158
|
+
pushTimer = setTimeout(() => { if (id && !closed) post(`/watch/${id}`, { dirs }); }, 120);
|
|
159
|
+
};
|
|
160
|
+
const connect = () => {
|
|
161
|
+
if (closed) return;
|
|
162
|
+
source = new EventSourceImpl(`/api/explorer/watch?root=${encodeURIComponent(root)}`);
|
|
163
|
+
const say = (data) => onState({ live: ['partial', 'none'].includes(data?.live) ? data.live : 'full', scope: data?.scope === 'folders' ? 'folders' : 'tree' });
|
|
164
|
+
source.addEventListener('ready', (event) => {
|
|
165
|
+
let said = null;
|
|
166
|
+
try { said = JSON.parse(event.data); } catch { said = null; }
|
|
167
|
+
id = said?.id || null;
|
|
168
|
+
attempt = 0;
|
|
169
|
+
push();
|
|
170
|
+
say(said);
|
|
171
|
+
onReady(wasUp);
|
|
172
|
+
wasUp = true;
|
|
173
|
+
});
|
|
174
|
+
source.addEventListener('state', (event) => { try { say(JSON.parse(event.data)); } catch { /* skipped, as below */ } });
|
|
175
|
+
source.addEventListener('change', (event) => { try { onChange(JSON.parse(event.data)); } catch { /* a report that cannot be read is skipped */ } });
|
|
176
|
+
source.addEventListener('resync', () => onResync());
|
|
177
|
+
source.onerror = () => {
|
|
178
|
+
// The browser would try again every three seconds for as long as the page lives: tried here, more slowly.
|
|
179
|
+
try { source.close(); } catch { /* closed */ }
|
|
180
|
+
id = null;
|
|
181
|
+
if (closed) return;
|
|
182
|
+
onDown();
|
|
183
|
+
timer = setTimeout(connect, RECONNECT_MS[Math.min(attempt++, RECONNECT_MS.length - 1)]);
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
connect();
|
|
187
|
+
return {
|
|
188
|
+
setDirs(list) { dirs = [...list]; push(); },
|
|
189
|
+
close() { closed = true; clearTimeout(timer); clearTimeout(pushTimer); try { source?.close(); } catch { /* closed */ } },
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
serverSays,
|
|
195
|
+
capabilities,
|
|
196
|
+
abilities,
|
|
197
|
+
list,
|
|
198
|
+
search,
|
|
199
|
+
git,
|
|
200
|
+
create,
|
|
201
|
+
remove,
|
|
202
|
+
rename: guarded((path, name) => post('/rename', { path, name })),
|
|
203
|
+
// `permanent`: what a replace clears may be removed for good when the Trash cannot take it (the user was asked).
|
|
204
|
+
// `replace`: the names that may be replaced (the ones the user was asked about), or false.
|
|
205
|
+
move: guarded((paths, into, { replace = false, permanent = false } = {}) => post('/move', { paths, into, replace, permanent })),
|
|
206
|
+
copy: guarded((paths, into, { replace = false, permanent = false } = {}) => post('/copy', { paths, into, replace, permanent })),
|
|
207
|
+
reveal: guarded((path) => post('/reveal', { path })),
|
|
208
|
+
upload: guarded((file, into, { name = file.name, rel = '', replace = false, permanent = false } = {}) => request(
|
|
209
|
+
`/api/explorer/upload?${new URLSearchParams({ into, name, ...(rel ? { rel } : {}), ...(replace ? { replace: '1' } : {}), ...(replace && permanent ? { permanent: '1' } : {}) })}`,
|
|
210
|
+
{ method: 'POST', headers: { 'Content-Type': 'application/octet-stream' }, body: file },
|
|
211
|
+
)),
|
|
212
|
+
/** Where the bytes of an image are (null on a server that has no preview). */
|
|
213
|
+
rawUrl: (path) => (caps.explorer ? `/api/explorer/raw?path=${encodeURIComponent(path)}` : null),
|
|
214
|
+
watch,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Neural Interface — File Explorer: the editor and the agents
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// The two neighbours the tree talks to.
|
|
6
|
+
//
|
|
7
|
+
// The code editor (shared/editor/) says which files are open, which have
|
|
8
|
+
// unsaved text and which one is showing (`getEditorTabs()`, and the
|
|
9
|
+
// `editor-tabs-changed` event when that changes), and re-points the tab of a
|
|
10
|
+
// file that was renamed or moved (`repointEditorTab()`): the tab stays, with its
|
|
11
|
+
// text, caret, scroll position and undo history. The controller hands those
|
|
12
|
+
// in; nothing of the editor is read from the page or changed here.
|
|
13
|
+
//
|
|
14
|
+
// The agents: a path is handed to a side panel through the function each panel
|
|
15
|
+
// already has for it. What goes where, and the words for it, are decided here.
|
|
16
|
+
|
|
17
|
+
import { isWithin, trimSlash } from './fx-logic.js';
|
|
18
|
+
|
|
19
|
+
const wait = (ms) => new Promise((done) => setTimeout(done, ms));
|
|
20
|
+
async function until(check, ms) {
|
|
21
|
+
const end = Date.now() + ms;
|
|
22
|
+
for (;;) {
|
|
23
|
+
if (check()) return true;
|
|
24
|
+
if (Date.now() > end) return false;
|
|
25
|
+
await wait(40);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const sameSet = (a, b) => a.size === b.size && [...a].every((entry) => b.has(entry));
|
|
29
|
+
const laterFrame = (work) => (typeof requestAnimationFrame === 'function' ? requestAnimationFrame(work) : setTimeout(work, 16));
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {object} o
|
|
33
|
+
* @param {(path: string, at?: { pin?: boolean }) => void} o.openFile editor-panel.js openFileInEditor
|
|
34
|
+
* @param {() => any} o.save editor-panel.js saveEditorPanel (the showing tab)
|
|
35
|
+
* @param {() => { open: { path: string, dirty: boolean }[], active: string | null }} o.tabs editor-panel.js getEditorTabs
|
|
36
|
+
* @param {(from: string, to: string) => { moved: object[], kept: string[] }} o.repoint editor-panel.js repointEditorTab
|
|
37
|
+
* @param {(listener: (tabs: object) => void) => (() => void)} o.subscribe hears `editor-tabs-changed`; gives back how to stop
|
|
38
|
+
* @param {(state: { open: Set<string>, dirty: Set<string>, active: string | null }) => void} o.onChange
|
|
39
|
+
* @param {(work: () => void) => any} [o.later] runs `work` soon (a frame): several changes are one redraw
|
|
40
|
+
*/
|
|
41
|
+
export function createEditorLink({ openFile, save, tabs, repoint, subscribe, onChange, later = laterFrame }) {
|
|
42
|
+
let state = { open: new Set(), dirty: new Set(), active: null };
|
|
43
|
+
let stopHearing = null;
|
|
44
|
+
let due = false;
|
|
45
|
+
|
|
46
|
+
const shape = (said) => {
|
|
47
|
+
const next = { open: new Set(), dirty: new Set(), active: null };
|
|
48
|
+
for (const tab of said?.open || []) {
|
|
49
|
+
const path = trimSlash(tab?.path || '');
|
|
50
|
+
if (!path) continue;
|
|
51
|
+
next.open.add(path);
|
|
52
|
+
if (tab.dirty) next.dirty.add(path);
|
|
53
|
+
}
|
|
54
|
+
if (said?.active) next.active = trimSlash(said.active);
|
|
55
|
+
return next;
|
|
56
|
+
};
|
|
57
|
+
/** What the editor has open right now. */
|
|
58
|
+
const read = () => { try { return shape(tabs()); } catch { return shape(null); } };
|
|
59
|
+
|
|
60
|
+
function refresh() {
|
|
61
|
+
due = false;
|
|
62
|
+
if (!stopHearing) return;
|
|
63
|
+
const next = read();
|
|
64
|
+
if (next.active === state.active && sameSet(next.open, state.open) && sameSet(next.dirty, state.dirty)) return;
|
|
65
|
+
state = next;
|
|
66
|
+
onChange(state);
|
|
67
|
+
}
|
|
68
|
+
// The editor says so while it works (a first letter typed, a tab closed): the tree is drawn after it, once.
|
|
69
|
+
const schedule = () => { if (!due) { due = true; later(refresh); } };
|
|
70
|
+
|
|
71
|
+
/** Start following what the editor has open. */
|
|
72
|
+
function start() {
|
|
73
|
+
if (stopHearing) return;
|
|
74
|
+
stopHearing = subscribe(schedule) || (() => {});
|
|
75
|
+
schedule();
|
|
76
|
+
}
|
|
77
|
+
function stop() {
|
|
78
|
+
stopHearing?.();
|
|
79
|
+
stopHearing = null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The open files with unsaved text that are one of `paths`, or inside one of them. */
|
|
83
|
+
const unsavedIn = (paths) => [...read().dirty].filter((file) => paths.some((path) => isWithin(path, file)));
|
|
84
|
+
|
|
85
|
+
/** Save one open file: its tab is shown, saved, and checked. False when it still has unsaved text after that. */
|
|
86
|
+
async function saveFile(path) {
|
|
87
|
+
const file = trimSlash(path);
|
|
88
|
+
openFile(file);
|
|
89
|
+
if (!(await until(() => read().active === file, 4000))) return false;
|
|
90
|
+
try { await save(); } catch { return false; }
|
|
91
|
+
return until(() => { const now = read(); return now.active === file && !now.dirty.has(file); }, 6000);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Entries were renamed or moved: the tabs of the files among them, or inside them, follow, each as it is.
|
|
96
|
+
* @param {{ from: string, to: string }[]} moves
|
|
97
|
+
* @returns {string[]} the open files that could not follow (the path each would take is open with unsaved text)
|
|
98
|
+
*/
|
|
99
|
+
function follow(moves) {
|
|
100
|
+
const kept = [];
|
|
101
|
+
for (const move of moves) {
|
|
102
|
+
try { kept.push(...(repoint(move.from, move.to)?.kept || [])); }
|
|
103
|
+
catch (error) { console.warn('[file-explorer] the editor could not follow', move.from, error); }
|
|
104
|
+
}
|
|
105
|
+
return kept;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { start, stop, state: () => state, read, unsavedIn, saveFile, follow };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── The agents ──
|
|
112
|
+
|
|
113
|
+
export const SEND_TARGETS = Object.freeze(['claude', 'codex', 'opencode', 'assistant']);
|
|
114
|
+
const TARGET_NAMES = { claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode' };
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @param {object} o
|
|
118
|
+
* @param {object} o.deps what each panel offers: `sendToFocusedSession(kind, data)`, `claude(path)`, `codex(path)`,
|
|
119
|
+
* `opencode(path)`, `assistant(path)`, and `lastActive()` (the panel used last)
|
|
120
|
+
* @param {(key: string, params?: object) => string} o.t
|
|
121
|
+
*/
|
|
122
|
+
export function createSender({ deps, t }) {
|
|
123
|
+
const nameOf = (target) => (target === 'session' ? t('fileExplorer.send.session') : TARGET_NAMES[target] || t('fileExplorer.send.assistant'));
|
|
124
|
+
/** Where "Send to AI" goes when nothing else is said: the panel that was used last. */
|
|
125
|
+
const current = () => { let last = null; try { last = deps.lastActive(); } catch { last = null; } return SEND_TARGETS.includes(last) ? last : 'claude'; };
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Hand paths to an agent, each as a file reference of that panel. Only what a panel took counts as sent: a
|
|
129
|
+
* panel answers `false` for a path it did not take (the Assistant when it is switched off); anything else it
|
|
130
|
+
* answers, or nothing, is a path that was taken.
|
|
131
|
+
* @param {string[]} paths @param {string | null} [target] one of SEND_TARGETS; without it, the session window
|
|
132
|
+
* that has the focus, else the panel used last
|
|
133
|
+
* @returns {Promise<{ ok: boolean, target: string, name: string, count: number }>} `count`: how many were taken;
|
|
134
|
+
* `ok`: at least one was, and nothing failed
|
|
135
|
+
*/
|
|
136
|
+
async function send(paths, target = null) {
|
|
137
|
+
const list = paths.filter(Boolean);
|
|
138
|
+
let to = target;
|
|
139
|
+
let taken = 0;
|
|
140
|
+
try {
|
|
141
|
+
if (!to) {
|
|
142
|
+
// A detached session that has the focus takes it: all of it, or none.
|
|
143
|
+
if (list.length && deps.sendToFocusedSession('path', list[0])) {
|
|
144
|
+
for (const path of list.slice(1)) deps.sendToFocusedSession('path', path);
|
|
145
|
+
return { ok: true, target: 'session', name: nameOf('session'), count: list.length };
|
|
146
|
+
}
|
|
147
|
+
to = current();
|
|
148
|
+
}
|
|
149
|
+
for (const path of list) if ((await deps[to](path)) !== false) taken++;
|
|
150
|
+
return { ok: taken > 0, target: to, name: nameOf(to), count: taken };
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.warn('[file-explorer] could not send to', to, error);
|
|
153
|
+
return { ok: false, target: to || current(), name: nameOf(to || current()), count: taken };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Rows dragged out of the tree onto a side panel: the panel takes them as it takes "Send to AI".
|
|
158
|
+
let dragged = null; let marked = null; let onSent = () => {};
|
|
159
|
+
const surfaceOf = (event) => event.target?.closest?.('[data-sidepanel-provider]') || null;
|
|
160
|
+
const mark = (surface) => {
|
|
161
|
+
if (marked === surface) return;
|
|
162
|
+
marked?.classList.remove('fe-drop-agent');
|
|
163
|
+
marked = surface;
|
|
164
|
+
marked?.classList.add('fe-drop-agent');
|
|
165
|
+
};
|
|
166
|
+
const over = (event) => {
|
|
167
|
+
const surface = surfaceOf(event);
|
|
168
|
+
mark(surface && SEND_TARGETS.includes(surface.dataset.sidepanelProvider) ? surface : null);
|
|
169
|
+
if (!marked) return;
|
|
170
|
+
event.preventDefault();
|
|
171
|
+
event.stopPropagation();
|
|
172
|
+
event.dataTransfer.dropEffect = 'copy';
|
|
173
|
+
};
|
|
174
|
+
const drop = (event) => {
|
|
175
|
+
const surface = surfaceOf(event);
|
|
176
|
+
const target = surface?.dataset.sidepanelProvider;
|
|
177
|
+
const paths = dragged;
|
|
178
|
+
mark(null);
|
|
179
|
+
if (!paths || !SEND_TARGETS.includes(target)) return;
|
|
180
|
+
event.preventDefault();
|
|
181
|
+
event.stopPropagation();
|
|
182
|
+
send(paths, target).then(onSent);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
targets: () => SEND_TARGETS.map((id) => ({ id, name: nameOf(id) })),
|
|
187
|
+
current,
|
|
188
|
+
nameOf,
|
|
189
|
+
send,
|
|
190
|
+
/** Rows are being dragged: side panels take them until `dragEnd()`. */
|
|
191
|
+
dragStart(paths, sent) {
|
|
192
|
+
dragged = [...paths];
|
|
193
|
+
onSent = sent || (() => {});
|
|
194
|
+
document.addEventListener('dragover', over, true);
|
|
195
|
+
document.addEventListener('drop', drop, true);
|
|
196
|
+
},
|
|
197
|
+
dragEnd() {
|
|
198
|
+
dragged = null;
|
|
199
|
+
mark(null);
|
|
200
|
+
document.removeEventListener('dragover', over, true);
|
|
201
|
+
document.removeEventListener('drop', drop, true);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|