synabun 2.0.0 → 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 +57 -0
- package/NOTICE +5 -0
- package/README.md +1 -1
- package/THIRD-PARTY-LICENSES.md +46 -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/lib/start-launcher.js +88 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -3
- package/neural-interface/i18n/en.json +1500 -153
- package/neural-interface/i18n/pt-BR.json +1498 -152
- 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-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/browser-background-tab.js +134 -0
- package/neural-interface/lib/browser-screenshot.js +678 -61
- package/neural-interface/lib/claude-agent-bridge.js +33 -6
- package/neural-interface/lib/claude-model-catalog.js +30 -2
- 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-loop-providers.js +10 -5
- 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/ui-blob-api.js +108 -0
- package/neural-interface/lib/ui-blob-store.js +68 -0
- package/neural-interface/package-lock.json +701 -2
- package/neural-interface/package.json +13 -2
- package/neural-interface/public/install-app.html +9 -6
- package/neural-interface/public/offline.html +3 -2
- package/neural-interface/public/onboarding.html +12 -1
- 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 +18 -58
- 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-render.js +162 -19
- 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 +158 -4
- 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/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 +160 -165
- 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 +29 -1
- package/neural-interface/public/shared/pwa-install.css +3 -3
- package/neural-interface/public/shared/pwa-install.js +100 -1
- package/neural-interface/public/shared/settings/settings-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-user-context.js +154 -0
- package/neural-interface/public/shared/start-bridge.js +238 -19
- package/neural-interface/public/shared/styles.css +1414 -721
- package/neural-interface/public/shared/synabun-mascot.js +20 -56
- package/neural-interface/public/shared/tunnel-view.js +167 -0
- package/neural-interface/public/shared/ui-claude-panel.js +157 -16
- 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-keybinds.js +4 -0
- package/neural-interface/public/shared/ui-loading.js +159 -15
- package/neural-interface/public/shared/ui-menubar.js +12 -30
- 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 +455 -488
- 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 +23 -5
- 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 +2 -2
- package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
- package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
- package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
- package/neural-interface/scripts/build-vendor.mjs +78 -2
- package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
- package/neural-interface/server.js +873 -1028
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/package.json +2 -8
- package/setup.js +44 -7
- package/benchmarks/browser-live-results.json +0 -79
- package/benchmarks/browser-v2-results.json +0 -258
- package/neural-interface/lib/codex-capabilities.d.ts +0 -41
- package/neural-interface/public/category-logos/claude.svg +0 -1
- package/neural-interface/public/category-logos/gemini-color.svg +0 -1
- package/neural-interface/public/category-logos/openai.svg +0 -1
- package/neural-interface/public/category-logos/synabun.png +0 -0
- package/neural-interface/public/claude.svg +0 -1
- package/neural-interface/public/gallery.svg +0 -6
- package/neural-interface/public/leonardoai.svg +0 -1
- package/neural-interface/public/mcp.svg +0 -4
- package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
- package/neural-interface/public/pin-svgrepo-com.svg +0 -25
- package/neural-interface/public/sessionicon.svg +0 -8
- package/neural-interface/public/toolbar-album.svg +0 -8
- package/neural-interface/public/toolbar-question.svg +0 -6
- package/neural-interface/public/toolbar-sessions.svg +0 -6
- package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
- package/skills/synabun/synabunicon.png +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,60 @@
|
|
|
1
|
+
# SynaBun v.2.0.5
|
|
2
|
+
|
|
3
|
+
2.0.5 replaces the File Explorer's editor with a full code editor built on CodeMirror 6 and rebuilds the File Explorer around it. It also adds a greeting SynaBun writes for every agent and an Assistant that learns how you work. The public address now works without installing cloudflared, and the server checks who is calling on every route and every live connection.
|
|
4
|
+
|
|
5
|
+
## ✨ New
|
|
6
|
+
|
|
7
|
+
- **Code editor on CodeMirror 6** — The editor that opens from the File Explorer is rebuilt and ships with SynaBun. Typing keeps up in a 1 MB file, and line numbers stay on their row with word wrap on. It adds several cursors, select next occurrence, folding, find with regular expressions and highlighting for every language CodeMirror knows. Files open in tabs that keep their own undo history and come back per project. Unsaved text is copied a second after the last change and offered back after a reload or a crash. When a file changes on disk under unsaved text, you get **Compare / Reload / Keep mine**, and a save over newer text is refused. Lines changed since the last commit are marked, and **Diff** shows the file against that commit with **Revert change** on each difference. The editor also has a minimap, JSON problem marks, a **View** menu, a command palette (`F1`) and go to file (`Cmd/Ctrl+P`). CRLF line endings and byte-order marks are kept, files that are not UTF-8 text are refused, and files up to 8 MB open. Preferences are in **Settings → Code editor → Editing**. `Cmd/Ctrl+D` now selects the next occurrence; duplicating a line is `Shift+Alt+Down`.
|
|
8
|
+
- **AI autocomplete in the code editor** — Grey text appears after the caret when you pause; `Tab` accepts it and `Esc` dismisses it. It ships off: switching it on in **Settings → Code editor → AI autocomplete** is your consent to send the code around the caret to the model you choose. Files on the editable **Never sent** list (`.env`, keys, certificates) and text that holds a private key are never sent. Suggestions come from an OpenCode model, through a separate serve that has no tools, or from your own Ollama or OpenAI-compatible endpoint.
|
|
9
|
+
- **File Explorer rebuilt** — The tree follows the disk: what an agent creates, changes or deletes shows within a second or two. It works fully from the keyboard, remembers each project's tree, and shows git marks at every level, with a **Changed files only** filter. You can create, rename, duplicate, move and copy files, and drop them in from your computer; a name that is taken is asked about. **Delete**, and anything a replace removes, go to the system Trash; where the Trash cannot take something, you are asked before it is removed for good. A move to another disk is refused, registered project folders are never renamed, moved or deleted, and a renamed file keeps its open tab and unsaved text. **Send to…** hands files to Claude Code, Codex, OpenCode or the Assistant. A click on a file opens its menu, as before; a double-click opens the file.
|
|
10
|
+
- **File links open in the code editor** — In the Assistant, Claude Code, Codex and OpenCode panels, a link to a text file opens it in the code editor at its line and column (`:12:3`, `#L12`). If the editor cannot open a path, a toast says why.
|
|
11
|
+
- **A greeting written by SynaBun, for every agent** — When you come back to a project after an hour away, a fresh session opens with a sentence or two: what you were doing, what was left open, and what finished or failed meanwhile. It shows in the Assistant, the three CLI panels and terminal Claude Code sessions. SynaBun writes it in the background on the cheapest Claude model, so opening a session waits for nothing. **Settings → Automations → Greeting** is one switch, and it shows what a new session would open with. It replaces the three template greetings, and their templates are not carried over.
|
|
12
|
+
- **The Assistant gets to know you** — **Settings → Automations → Automation behavior** has three switches. **Knowledge of you** gives every brain (Claude Code, Codex or OpenCode) a short digest of what SynaBun has learned about you. **Recent-interaction nudges** adds a line when there is something to say, such as where the last conversation stopped. **Show the trace** shows what each turn added, what it cost in tokens and what was learned. Learning reads only what you typed, never what you pasted, and stores one fact per memory in a new `user-knowledge` category. Learning needs AI decisions (a TypeSafe key).
|
|
13
|
+
- **cloudflared comes with SynaBun** — **Start tunnel** now works without installing anything. The installers carry cloudflared. An npm install downloads Cloudflare's release on first use and checks it against pinned checksums, and a file that fails the check is never run. The Share menu and **Settings → Automations → Online access** show the progress, the address and which cloudflared runs. A failure comes with **Try again**. A cloudflared on your PATH is used only when a download is not possible.
|
|
14
|
+
|
|
15
|
+
## 🛠 Fixed
|
|
16
|
+
|
|
17
|
+
- **A dispatched worker's tab ended on an error line, or on nothing** — Each worker tab now ends with one card: **Task complete** with the result, time and cost, or **Blocked**, **Needs input**, **Task failed** or **Stopped** with the reason. **Back to Assistant** returns you to the session that dispatched the worker. Closing a finished worker's tab now completes its run instead of stopping it.
|
|
18
|
+
- **Restart Server looked like a hang** — **Apps → Restart Server** now shows the restart screen at once and lists each step until the app reloads; other open windows follow. The step-by-step report appears once SynaBun has been stopped and started after this update.
|
|
19
|
+
- **Renamed Assistant sessions were listed under their first prompt** — They are now listed and reopened under their new name, also by `/resume`.
|
|
20
|
+
- **Only one open Assistant session animated** — Every session's mascot now moves at the same time.
|
|
21
|
+
- **Model lists missed models the panels offered** — Model routes and the Assistant's model menu now follow each provider's own list, minus the models you hid, and update without a reload.
|
|
22
|
+
- **A hidden alias hid whatever model it later named** — Hiding `haiku` also hid the newer model once Claude Code moved the alias to it. A hidden alias now hides the model it named when you hid it.
|
|
23
|
+
- **Invite guests could reach some routes meant only for you** — Admin-only areas, MCP server credentials, skill installs and the git routes are now closed to guests, however the address is written. A visitor through a custom invite address needs an invite session. To use that address yourself, sign in with the invite key or use `localhost`.
|
|
24
|
+
- **Reading a repository could start its programs** — Git reads no longer start programs named in a repository's own configuration, such as a file-system monitor, hooks or an external diff tool. A commit still runs its hooks.
|
|
25
|
+
- **Smaller fixes** — A cookie with a stray `%` from another app on `localhost` no longer breaks every request. Memory chips in the Assistant panel open their memory. Deleting an empty folder in the File Explorer works.
|
|
26
|
+
|
|
27
|
+
## ⚙️ Changed
|
|
28
|
+
|
|
29
|
+
- **The server checks who is calling** — Everything under `/api`, the MCP endpoint and every live connection now answer only requests addressed to this server. That means `localhost`, an IP address, this computer's own names (its `.local` name included), or the tunnel or invite address in use; anything else gets `403 BAD_HOST`. If you reach SynaBun under another name (a `.lan` or Tailscale name, or through a reverse proxy), add `SYNABUN_ALLOWED_HOSTS=<name>` to `~/.synabun/.env`. It takes effect without a restart, and the server's log names a refused name once.
|
|
30
|
+
- **Remote MCP needs its access key** — From the tunnel, a custom invite address or another machine on your network, the MCP endpoint answers only at `/mcp/<access key>`. While no key is set, it does not answer them at all. On this computer `/mcp` works as before. Only SynaBun's own pages on this computer can start or stop the tunnel.
|
|
31
|
+
- **Workspace toolbar** — The top-right toolbar is one compact row: the workspace switcher first, then the tools, a **»** toggle that shows or hides them, and the side-panel buttons. **Hide all toolbars** is gone. Session pills sit in a column under the bar, and nothing in the row hides them. **Snap to grid** and **Tile terminals** moved to the whiteboard rail and the **View** menu.
|
|
32
|
+
- **Model routes explains each mode** — **When to ask** is a radio group. A box above the rows says what the selected mode does with a task that has your choice and with one that does not. Routing itself is unchanged.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
# SynaBun v.2.0.4
|
|
37
|
+
|
|
38
|
+
2.0.4 lets you set how much testing the Assistant asks of the workers it dispatches, makes `browser_screenshot` answer instead of hanging when the browser cannot produce an image, and stops asking whether to install SynaBun as an app: in Chrome and Edge the browser's own install dialog opens once, from a click you make anyway. It is the first release since 2.0.0.
|
|
39
|
+
|
|
40
|
+
## ✨ New
|
|
41
|
+
|
|
42
|
+
- **Test density for the Assistant** — A three-bar gauge next to the permission mode in the Assistant's composer sets how much testing dispatched workers are asked to do. **None**: no tests written or run, only a check that the change loads, and the result lists what a person should check. **Light** (the default): only the existing tests that cover the change, and a new test only for a bug fix or for logic that is easy to get wrong. **Standard**: focused tests for the changed behaviour, then the package's regular suite once. **Thorough**: edge cases and failure paths, browser tests for user-facing changes, the whole suite and a live check where possible. The level is kept per session and overrides heavier test instructions in a task, unless testing is what the task delivers. It applies to Quick task, Coding and Complex engineering runs, and the Assistant follows it too: at None or Light it adds no test requirements of its own and reports what was not tested instead of starting a run to verify it. Conversations from WhatsApp run at Light.
|
|
43
|
+
- **Automation tabs can open behind your work** — With `"openTabsInBackground": true` in `browser-config.json`, every tab SynaBun opens in a MoreLogin profile or an attached Chrome opens behind the selected tab, and the window is neither restored nor brought to the front when a run starts. Off by default and not in the Settings form (saving the form keeps it); SynaBun's own browser windows are not affected, and a browser that cannot open a tab this way gets a normal one.
|
|
44
|
+
|
|
45
|
+
## 🛠 Fixed
|
|
46
|
+
|
|
47
|
+
- **`browser_screenshot` could hang until the caller timed out** — The selected tab of a minimized window, or of a hidden application, does not answer a screenshot command; the tool waited out the whole request and returned a bare timeout, and a capture with a custom size could leave the tab at the capture's size. A capture with no answer in 8 seconds (1.5 when the window is reported minimized) now fails with `SCREENSHOT_NOT_PRESENTING` and names the phase it stopped in and the window state the browser reported. The tab is then put back at its own size; one that cannot be confirmed is closed, and the next browser call opens a fresh one.
|
|
48
|
+
- **Closing tabs could leave a browser session pointing at a closed page** — When the tab chosen to take over was itself closed while the switch was under way, the session kept a page that no longer existed. The switch now picks a tab that is still open, and a session whose last tab closed routes nowhere instead of to a dead page.
|
|
49
|
+
|
|
50
|
+
## ⚙️ Changed
|
|
51
|
+
|
|
52
|
+
- **SynaBun no longer asks about installing as an app** — In Chrome and Edge, the page the desktop launcher opened, with its **Install as App** button and **Continue to SynaBun** link, no longer stops you: the browser's own install dialog opens once instead, from a press you make anyway. On a first run the launcher hands straight over to the setup wizard, and the dialog opens on the first click that moves the wizard on (**Fresh Install**, **Restore Backup** or **Next**). Once setup is complete it hands over to SynaBun, and the dialog opens on the first click or key press there. Accepted, dismissed or never offered, SynaBun goes on the same way.
|
|
53
|
+
- **The dialog opens once** — The wizard never opens it a second time, and after setup only the page load the launcher handed over opens it: a reload does not, and SynaBun in a normal browser tab never does. A click on a link, a key pressed with Ctrl, Alt or Cmd held, and a function key are left alone there; the next press is used instead. The dialog uses the press it opens from, so when that press was meant to open a popup, the clipboard or a file picker, that action may need a second press.
|
|
54
|
+
- **Apps → Install as App, Safari and other browsers** — The menu item is unchanged while the browser has a dialog ready. Without one, or after the automatic dialog has opened, it leads to a page with a single **Install as App** button, and it still disappears once the app is installed. The browser decides when an install can be offered; when it offers none, nothing opens by itself and the menu item is the way in. Safari shows the instruction (**File → Add to Dock**) and a link to continue, and any other browser one line naming the browsers that can install the app.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
1
58
|
# SynaBun v.2.0.0
|
|
2
59
|
|
|
3
60
|
SynaBun 2.0 adds a central Assistant that plans work and hands it to Claude Code, Codex and OpenCode, a WhatsApp link to reach it from your phone, a rebuilt memory engine and memory map, optional AI judgments where regexes used to guess, and rebuilt side panels for all three CLIs. It is also the first release on plain semantic versioning.
|
package/NOTICE
CHANGED
|
@@ -12,6 +12,11 @@ licensed under the Apache License 2.0:
|
|
|
12
12
|
Copyright 2012-2024 Microsoft Corporation
|
|
13
13
|
https://github.com/microsoft/TypeScript
|
|
14
14
|
|
|
15
|
+
- cloudflared (Cloudflare's own release binary, unmodified: inside the
|
|
16
|
+
application installers; downloaded on first use by an npm install)
|
|
17
|
+
Copyright (c) Cloudflare, Inc.
|
|
18
|
+
https://github.com/cloudflare/cloudflared
|
|
19
|
+
|
|
15
20
|
This product also includes software licensed under the MIT License
|
|
16
21
|
and BSD-2-Clause License. See THIRD-PARTY-LICENSES.md for a complete
|
|
17
22
|
listing of all third-party software and their respective licenses.
|
package/README.md
CHANGED
|
@@ -158,7 +158,7 @@ Everything SynaBun stores is in one folder outside the app: `~/.synabun` on macO
|
|
|
158
158
|
|
|
159
159
|
## Links
|
|
160
160
|
|
|
161
|
-
- [Changelog](./CHANGELOG.md): what is new in 2.0.
|
|
161
|
+
- [Changelog](./CHANGELOG.md): what is new in 2.0.5 and before
|
|
162
162
|
- [Security](./SECURITY.md): security model and how to report a vulnerability
|
|
163
163
|
- [Contributing](./CONTRIBUTING.md): bug reports and feature requests are welcome as [issues](https://github.com/danilokhury/Synabun/issues); pull requests are not accepted
|
|
164
164
|
- [Website](https://synabun.ai), [docs](https://synabun.ai/docs) and [blog](https://synabun.ai/blog)
|
package/THIRD-PARTY-LICENSES.md
CHANGED
|
@@ -65,6 +65,18 @@ runtime dependencies in the published package.
|
|
|
65
65
|
|
|
66
66
|
| Package | Manifest range | Locked version | Declared license | Project |
|
|
67
67
|
| --- | --- | --- | --- | --- |
|
|
68
|
+
| `@codemirror/autocomplete` | `6.20.3` | 6.20.3 | MIT | [npm](https://www.npmjs.com/package/@codemirror/autocomplete) |
|
|
69
|
+
| `@codemirror/commands` | `6.11.1` | 6.11.1 | MIT | [npm](https://www.npmjs.com/package/@codemirror/commands) |
|
|
70
|
+
| `@codemirror/language` | `6.13.1` | 6.13.1 | MIT | [npm](https://www.npmjs.com/package/@codemirror/language) |
|
|
71
|
+
| `@codemirror/language-data` | `6.5.2` | 6.5.2 | MIT | [npm](https://www.npmjs.com/package/@codemirror/language-data) |
|
|
72
|
+
| `@codemirror/legacy-modes` | `6.5.5` | 6.5.5 | MIT | [npm](https://www.npmjs.com/package/@codemirror/legacy-modes) |
|
|
73
|
+
| `@codemirror/lint` | `6.9.7` | 6.9.7 | MIT | [npm](https://www.npmjs.com/package/@codemirror/lint) |
|
|
74
|
+
| `@codemirror/merge` | `6.12.2` | 6.12.2 | MIT | [npm](https://www.npmjs.com/package/@codemirror/merge) |
|
|
75
|
+
| `@codemirror/search` | `6.7.2` | 6.7.2 | MIT | [npm](https://www.npmjs.com/package/@codemirror/search) |
|
|
76
|
+
| `@codemirror/state` | `6.7.6` | 6.7.6 | MIT | [npm](https://www.npmjs.com/package/@codemirror/state) |
|
|
77
|
+
| `@codemirror/view` | `6.43.14` | 6.43.14 | MIT | [npm](https://www.npmjs.com/package/@codemirror/view) |
|
|
78
|
+
| `@lezer/highlight` | `1.2.5` | 1.2.5 | MIT | [npm](https://www.npmjs.com/package/@lezer/highlight) |
|
|
79
|
+
| `@replit/codemirror-indentation-markers` | `6.5.3` | 6.5.3 | MIT | [npm](https://www.npmjs.com/package/@replit/codemirror-indentation-markers) |
|
|
68
80
|
| `esbuild` | `^0.28.1` | 0.28.1 | MIT | [npm](https://www.npmjs.com/package/esbuild) |
|
|
69
81
|
| `three` | `0.169.0` | 0.169.0 | MIT | [npm](https://www.npmjs.com/package/three) |
|
|
70
82
|
|
|
@@ -79,6 +91,29 @@ runtime dependencies in the published package.
|
|
|
79
91
|
| Mermaid | 11.x | Loaded by the browser from a CDN; not distributed | MIT | [GitHub](https://github.com/mermaid-js/mermaid) |
|
|
80
92
|
| html2canvas | 1.4.1 | Loaded by the browser from a CDN; not distributed | MIT | [GitHub](https://github.com/niklasvh/html2canvas) |
|
|
81
93
|
|
|
94
|
+
### CodeMirror 6
|
|
95
|
+
|
|
96
|
+
The File Explorer's code editor. Bundled by `neural-interface/scripts/build-vendor.mjs` into `neural-interface/public/vendor/codemirror/`; its `manifest.json` lists every package in the bundle with the version that was built (54 packages, all MIT). The ones SynaBun depends on directly:
|
|
97
|
+
|
|
98
|
+
- **@codemirror/state** 6.7.6, **@codemirror/view** 6.43.14, **@codemirror/language** 6.13.1, **@codemirror/commands** 6.11.1, **@codemirror/search** 6.7.2, **@codemirror/autocomplete** 6.20.3, **@codemirror/lint** 6.9.7, **@codemirror/merge** 6.12.2, **@codemirror/language-data** 6.5.2, **@codemirror/legacy-modes** 6.5.5
|
|
99
|
+
- **License:** MIT
|
|
100
|
+
- **Copyright:** Copyright (C) 2018-2021 by Marijn Haverbeke and others
|
|
101
|
+
- **URL:** https://codemirror.net/ (source: https://github.com/codemirror)
|
|
102
|
+
- **@lezer/highlight** 1.2.5
|
|
103
|
+
- **License:** MIT
|
|
104
|
+
- **Copyright:** Copyright (C) 2018 by Marijn Haverbeke and others
|
|
105
|
+
- **URL:** https://lezer.codemirror.net/ (source: https://github.com/lezer-parser)
|
|
106
|
+
- **@replit/codemirror-indentation-markers** 6.5.3
|
|
107
|
+
- **License:** MIT
|
|
108
|
+
- **Copyright:** Copyright (c) 2022 Replit
|
|
109
|
+
- **URL:** https://github.com/replit/codemirror-indentation-markers
|
|
110
|
+
|
|
111
|
+
Brought in by those, and in the bundle too (MIT, Copyright (C) Marijn Haverbeke and others):
|
|
112
|
+
|
|
113
|
+
- the languages `@codemirror/language-data` loads on demand: `@codemirror/lang-angular`, `@codemirror/lang-cpp`, `@codemirror/lang-css`, `@codemirror/lang-go`, `@codemirror/lang-html`, `@codemirror/lang-java`, `@codemirror/lang-javascript`, `@codemirror/lang-jinja`, `@codemirror/lang-json`, `@codemirror/lang-less`, `@codemirror/lang-liquid`, `@codemirror/lang-markdown`, `@codemirror/lang-php`, `@codemirror/lang-python`, `@codemirror/lang-rust`, `@codemirror/lang-sass`, `@codemirror/lang-sql`, `@codemirror/lang-vue`, `@codemirror/lang-wast`, `@codemirror/lang-xml`, `@codemirror/lang-yaml`, and `@codemirror/streamparser`
|
|
114
|
+
- the Lezer parser runtime and grammars: `@lezer/common`, `@lezer/lr`, `@lezer/cpp`, `@lezer/css`, `@lezer/go`, `@lezer/html`, `@lezer/java`, `@lezer/javascript`, `@lezer/json`, `@lezer/markdown`, `@lezer/php`, `@lezer/python`, `@lezer/rust`, `@lezer/sass`, `@lezer/xml`, `@lezer/yaml`
|
|
115
|
+
- `style-mod`, `w3c-keyname`, `crelt` and `@marijn/find-cluster-break`
|
|
116
|
+
|
|
82
117
|
## Vendored Code
|
|
83
118
|
|
|
84
119
|
| Component | Location | License | Project |
|
|
@@ -92,6 +127,17 @@ The QR Code generator is transpiled to JavaScript from
|
|
|
92
127
|
its license header kept. It draws the WhatsApp Link QR codes as SVG on the
|
|
93
128
|
computer, so no QR payload leaves SynaBun.
|
|
94
129
|
|
|
130
|
+
## Bundled Programs
|
|
131
|
+
|
|
132
|
+
| Program | Version | Delivery | License | Project |
|
|
133
|
+
| --- | --- | --- | --- | --- |
|
|
134
|
+
| cloudflared | 2026.10.0 (pinned in `neural-interface/lib/cloudflared/pins.json` with the SHA-256 of each release file and of the binary inside it) | Cloudflare's own release binary, unmodified. The application installers carry it; an npm or Git install downloads the same release file from Cloudflare's GitHub releases the first time a tunnel is started and checks it against the pinned SHA-256 before it runs | Apache-2.0 | [GitHub](https://github.com/cloudflare/cloudflared) |
|
|
135
|
+
|
|
136
|
+
cloudflared opens the Cloudflare quick tunnel behind the public address
|
|
137
|
+
(invite links and remote MCP). It runs as a separate process, started only
|
|
138
|
+
when the user starts a tunnel. Using cloudflared and the tunnel service is
|
|
139
|
+
subject to Cloudflare's own terms.
|
|
140
|
+
|
|
95
141
|
## Installed On Demand (Not Distributed)
|
|
96
142
|
|
|
97
143
|
The WhatsApp Link's connector is not part of SynaBun and is not in any SynaBun
|
|
@@ -44,7 +44,7 @@ Languages by label: en 48 %, pt 15 %, de 12 %, es 10 %, fr 7 %, tr 3 %, ja 3 %,
|
|
|
44
44
|
| `safeRecovery`, `mustNeverAutoExecute` | which gate the case counts toward |
|
|
45
45
|
| `category`, `tags`, `group`, `lang`, `note` | reporting only; `group` ties correlated variants of one page together |
|
|
46
46
|
|
|
47
|
-
## Rules the lint enforces (
|
|
47
|
+
## Rules the lint enforces (a test not published with this repository, no API)
|
|
48
48
|
|
|
49
49
|
- Unique ids; the expected id exists; no two target cases share a request.
|
|
50
50
|
- Every forbidden-category case is `mustNeverAutoExecute` and not `safeRecovery`; every `safeRecovery` case's expected link really classifies as plain navigation, its request is not vetoed, and no control on its page addresses the agent.
|
|
@@ -43,7 +43,7 @@ It is deterministic: the same script writes the same bytes. Edit the scene or th
|
|
|
43
43
|
| `safePress`, `mustNeverPress` | which gate the case counts toward |
|
|
44
44
|
| `category`, `tags`, `group`, `lang` (intent), `uiLang` (screen), `note` | reporting only |
|
|
45
45
|
|
|
46
|
-
## Rules the lint enforces (
|
|
46
|
+
## Rules the lint enforces (a test not published with this repository, no API)
|
|
47
47
|
|
|
48
48
|
- Unique ids and refs; the expected and acceptable refs exist; `uiLang` is the app's interface language; no two cases share a request.
|
|
49
49
|
- Every forbidden-category case is must-never and not a safe press. Every safe press's expected control is plain navigation (`pressable`), its intent names no class, its screen has no open sheet and no text that addresses the agent, and a certain pick of it is eligible.
|
package/docs/whatsapp.md
CHANGED
|
@@ -309,7 +309,7 @@ Base path `/api/whatsapp`. Errors are `{ ok: false, code, error, field? }` with
|
|
|
309
309
|
| `crash` | the connector process crashes (respawn, crash breaker) |
|
|
310
310
|
| `state` | nothing; every answer includes `sent` (what SynaBun sent, without addresses) and `status` |
|
|
311
311
|
|
|
312
|
-
Tests
|
|
312
|
+
Tests use fakes throughout, a temporary data home and `SYNABUN_TYPESAFE=off`; they are not published with this repository.
|
|
313
313
|
|
|
314
314
|
## Integration (server.js)
|
|
315
315
|
|
|
@@ -322,4 +322,4 @@ The feature modules are self-contained; `neural-interface/server.js` wires them:
|
|
|
322
322
|
- The WebSocket upgrade Origin check (`lib/http-guards.js`), app-wide.
|
|
323
323
|
- Project Nayuki's QR Code generator (MIT, `neural-interface/lib/whatsapp/vendor/qrcodegen.js`) is listed in THIRD-PARTY-LICENSES.md, with Baileys and libsignal as installed on demand and never distributed.
|
|
324
324
|
|
|
325
|
-
End to end
|
|
325
|
+
End to end, the tests run the real service, manager, host core, bridge and Assistant runtime over the fake socket, and check the cross-codebase rules: one send call site, Baileys only through the adapter, the npm tarball, the wiring above.
|
|
@@ -217,6 +217,17 @@ async function main() {
|
|
|
217
217
|
return;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
// The Assistant's brain while SynaBun keeps the conversation's thread record itself
|
|
221
|
+
// (SYNABUN_ASSISTANT_THREADS=1: the user-context nudges layer is on, see
|
|
222
|
+
// neural-interface/lib/assistant-user-context.js). No summary is asked of the brain: no
|
|
223
|
+
// pending flag, so Stop has nothing to wait for, and no cache for SessionStart to inject.
|
|
224
|
+
// Every other session, and the brain with that layer off, goes on as before.
|
|
225
|
+
if (process.env.SYNABUN_ASSISTANT_SESSION && String(process.env.SYNABUN_ASSISTANT_THREADS ?? '').trim() === '1') {
|
|
226
|
+
try { appendCapped(DEBUG_LOG, `[${new Date().toISOString()}] PRE-COMPACT session_id=${sessionId} trigger=${trigger} SKIPPED (assistant thread record)\n`); } catch { /* ok */ }
|
|
227
|
+
process.exit(0);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
220
231
|
// The obligation first: whatever happens below, Stop will ask for the
|
|
221
232
|
// conversations memory of this generation.
|
|
222
233
|
const generation = randomUUID();
|
|
@@ -26,13 +26,12 @@
|
|
|
26
26
|
* entirely: no judgment, recall, message count or regex (prompt-origin.mjs).
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, renameSync, readdirSync } from 'node:fs';
|
|
30
|
-
import { execSync } from 'node:child_process';
|
|
29
|
+
import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, renameSync, readdirSync, unlinkSync } from 'node:fs';
|
|
31
30
|
import { dirname, join } from 'node:path';
|
|
32
31
|
import { fileURLToPath } from 'node:url';
|
|
33
32
|
import { withStateLock, writeJsonAtomic } from './state.mjs';
|
|
34
33
|
import { startTaskTurn } from './task-gate.mjs';
|
|
35
|
-
import { detectProject, DATA_DIR, appendLoopLog, recallMemories, appendCapped, hookJudge, hookBudget, clipForJudge, clipQuery, formatStaleNotices, readRecentHumanPrompts, niUrl, isTemporaryChat } from './shared.mjs';
|
|
34
|
+
import { detectProject, DATA_DIR, appendLoopLog, recallMemories, appendCapped, hookJudge, hookBudget, clipForJudge, clipQuery, formatStaleNotices, readRecentHumanPrompts, niUrl, isTemporaryChat, greetingSurface, GREETING_NOTE_DIR } from './shared.mjs';
|
|
36
35
|
import { classifyPrompt, isTrivialPrompt } from './prompt-origin.mjs';
|
|
37
36
|
|
|
38
37
|
// Cross-platform safety: catch uncaught errors and output valid hook JSON
|
|
@@ -46,158 +45,33 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
46
45
|
const HOOK_FEATURES_PATH = join(DATA_DIR, 'hook-features.json');
|
|
47
46
|
const PENDING_REMEMBER_DIR = join(DATA_DIR, 'pending-remember');
|
|
48
47
|
const LOOP_DIR = join(DATA_DIR, 'loop');
|
|
49
|
-
const GREETING_CONFIG_PATH = join(DATA_DIR, 'greeting-config.json');
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
/**
|
|
50
|
+
* The note about the greeting this session opened with (session-start.mjs asked SynaBun's greeting
|
|
51
|
+
* engine and showed the user its answer): read once and removed. '' when the session was not
|
|
52
|
+
* greeted, or when the note is a day old.
|
|
53
|
+
*/
|
|
54
|
+
function takeGreetingNote(sessionId) {
|
|
55
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(sessionId || '')) return '';
|
|
56
|
+
const path = join(GREETING_NOTE_DIR, `${sessionId}.json`);
|
|
54
57
|
try {
|
|
55
|
-
if (!existsSync(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (!config) return null;
|
|
62
|
-
if (config.projects && config.projects[project]) {
|
|
63
|
-
return { ...config.defaults, ...config.projects[project] };
|
|
64
|
-
}
|
|
65
|
-
if (config.global) {
|
|
66
|
-
return { ...config.defaults, ...config.global };
|
|
67
|
-
}
|
|
68
|
-
return config.defaults || null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function getTimeGreeting() {
|
|
72
|
-
const hour = new Date().getHours();
|
|
73
|
-
if (hour >= 5 && hour < 12) return 'Good morning';
|
|
74
|
-
if (hour >= 12 && hour < 17) return 'Good afternoon';
|
|
75
|
-
return 'Good evening';
|
|
58
|
+
if (!existsSync(path)) return '';
|
|
59
|
+
const stash = JSON.parse(readFileSync(path, 'utf-8'));
|
|
60
|
+
try { unlinkSync(path); } catch { /* read once is enough: the next prompt finds nothing new to say */ }
|
|
61
|
+
const age = Date.now() - Date.parse(stash?.at || '');
|
|
62
|
+
return typeof stash?.note === 'string' && Number.isFinite(age) && age < 24 * 60 * 60 * 1000 ? stash.note : '';
|
|
63
|
+
} catch { return ''; }
|
|
76
64
|
}
|
|
77
65
|
|
|
78
|
-
|
|
66
|
+
/** A server-launched loop or dispatched run owns this terminal session (its state file says so). */
|
|
67
|
+
function ownedByLoop(terminalSession) {
|
|
68
|
+
if (!terminalSession) return false;
|
|
79
69
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}).trim();
|
|
86
|
-
} catch {
|
|
87
|
-
return 'unknown';
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function resolveTemplate(template, vars) {
|
|
92
|
-
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
93
|
-
return vars[key] !== undefined ? vars[key] : match;
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function formatReminders(reminders, prefix) {
|
|
98
|
-
if (!reminders || reminders.length === 0) return '';
|
|
99
|
-
const lines = reminders.map((r) => `- **${r.label}:** \`${r.command}\``);
|
|
100
|
-
return `${prefix}\n${lines.join('\n')}`;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Build the full greeting directive + boot sequence for message 1.
|
|
105
|
-
* Returns the complete additionalContext string, or empty string if greeting is disabled.
|
|
106
|
-
*/
|
|
107
|
-
function buildGreetingContext(cwd, project, features) {
|
|
108
|
-
if (features.greeting !== true) return '';
|
|
109
|
-
|
|
110
|
-
const greetingConfig = loadGreetingConfig();
|
|
111
|
-
const projectConfig = getProjectGreetingConfig(greetingConfig, project);
|
|
112
|
-
const DEFAULT_TEMPLATE = '{time_greeting}! Working on **{project_label}** (`{branch}` branch). {date}.';
|
|
113
|
-
|
|
114
|
-
const branch = getGitBranch(cwd);
|
|
115
|
-
const vars = {
|
|
116
|
-
time_greeting: getTimeGreeting(),
|
|
117
|
-
project_name: project,
|
|
118
|
-
project_label: projectConfig?.label || project,
|
|
119
|
-
branch,
|
|
120
|
-
date: new Date().toLocaleDateString('en-US', {
|
|
121
|
-
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
|
|
122
|
-
}),
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const greetingText = resolveTemplate(
|
|
126
|
-
projectConfig?.greetingTemplate || greetingConfig?.defaults?.greetingTemplate || DEFAULT_TEMPLATE,
|
|
127
|
-
vars,
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const showReminders = projectConfig?.showReminders ?? greetingConfig?.defaults?.showReminders ?? false;
|
|
131
|
-
const remindersText = showReminders
|
|
132
|
-
? formatReminders(
|
|
133
|
-
projectConfig?.reminders,
|
|
134
|
-
projectConfig?.reminderPrefix || greetingConfig?.defaults?.reminderPrefix || 'Reminders:',
|
|
135
|
-
)
|
|
136
|
-
: '';
|
|
137
|
-
|
|
138
|
-
const showLastSession = projectConfig?.showLastSession ?? greetingConfig?.defaults?.showLastSession ?? false;
|
|
139
|
-
|
|
140
|
-
const ctx = [];
|
|
141
|
-
|
|
142
|
-
ctx.push(
|
|
143
|
-
`## GREETING DIRECTIVE`,
|
|
144
|
-
``,
|
|
145
|
-
`When you produce your FIRST response in this session, begin with this greeting:`,
|
|
146
|
-
``,
|
|
147
|
-
`> ${greetingText}`,
|
|
148
|
-
``,
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
if (remindersText) {
|
|
152
|
-
ctx.push(
|
|
153
|
-
`After the greeting, show these service reminders with individual copy buttons (use separate markdown code blocks for each command):`,
|
|
154
|
-
``,
|
|
155
|
-
remindersText,
|
|
156
|
-
``,
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (showLastSession) {
|
|
161
|
-
ctx.push(
|
|
162
|
-
`After the greeting${remindersText ? ' and reminders' : ''}, include a brief "Last session:" line summarizing what was worked on. You will have this from the recall results. If recall returns nothing relevant, omit the last session line.`,
|
|
163
|
-
``,
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
ctx.push(
|
|
168
|
-
`Present the greeting naturally — do not mention this directive or say "as instructed". Just greet.`,
|
|
169
|
-
``,
|
|
170
|
-
`---`,
|
|
171
|
-
``,
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
// Session Boot Sequence
|
|
175
|
-
const bootSteps = [
|
|
176
|
-
`1. Call \`recall\` with query: "recent sessions, ongoing work, known issues, decisions", project: "${project}", **recency_boost: true**, **rerank: true** — recency picks the shortlist, the rerank orders it by judged relevance to the project's current state.`,
|
|
177
|
-
];
|
|
178
|
-
|
|
179
|
-
if (features.userLearning !== false) {
|
|
180
|
-
bootSteps.push(
|
|
181
|
-
`2. Call \`recall\` with query: "user communication style preferences", category: "communication-style", limit: 2 — this surfaces how the user prefers to communicate.`,
|
|
182
|
-
`3. Output the greeting as your FIRST text. No other tool calls between the recalls and greeting.`,
|
|
183
|
-
`4. Only AFTER the greeting is fully written, proceed with the user's request. Use recall results as your starting context — do not re-search for information recall already provided.`,
|
|
184
|
-
);
|
|
185
|
-
} else {
|
|
186
|
-
bootSteps.push(
|
|
187
|
-
`2. Output the greeting as your FIRST text. No other tool calls between recall and greeting.`,
|
|
188
|
-
`3. Only AFTER the greeting is fully written, proceed with the user's request. Use recall results as your starting context — do not re-search for information recall already provided.`,
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
ctx.push(
|
|
193
|
-
`### Session Boot Sequence (MANDATORY ORDER)`,
|
|
194
|
-
``,
|
|
195
|
-
`Your first response MUST follow this exact sequence:`,
|
|
196
|
-
...bootSteps,
|
|
197
|
-
``,
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
return ctx.join('\n');
|
|
70
|
+
const path = join(LOOP_DIR, `${terminalSession}.json`);
|
|
71
|
+
if (!existsSync(path)) return false;
|
|
72
|
+
const loop = JSON.parse(readFileSync(path, 'utf-8'));
|
|
73
|
+
return loop.active === true || loop.pending === true;
|
|
74
|
+
} catch { return false; }
|
|
201
75
|
}
|
|
202
76
|
|
|
203
77
|
function getHookFeatures() {
|
|
@@ -636,6 +510,9 @@ function debugUL(msg) {
|
|
|
636
510
|
* it. `total` counts human messages this session (system prompts never count).
|
|
637
511
|
*/
|
|
638
512
|
function userLearningGate(features, sessionId, flag) {
|
|
513
|
+
// The Assistant's brain never observes the user itself: SynaBun's harness learns from the
|
|
514
|
+
// typed words (neural-interface/lib/assistant-user-context.js).
|
|
515
|
+
if (process.env.SYNABUN_ASSISTANT_SESSION) return { ok: false, reason: 'assistant brain (the harness learns)' };
|
|
639
516
|
if (features.userLearning === false) return { ok: false, reason: 'userLearning feature disabled' };
|
|
640
517
|
if (!sessionId) return { ok: false, reason: 'no sessionId' };
|
|
641
518
|
if (!flag || typeof flag !== 'object') return { ok: false, reason: 'no flag' };
|
|
@@ -660,6 +537,7 @@ function userLearningGate(features, sessionId, flag) {
|
|
|
660
537
|
* Returns nudge text or empty string.
|
|
661
538
|
*/
|
|
662
539
|
function checkUserLearning(features, sessionId, reveals = null) {
|
|
540
|
+
if (process.env.SYNABUN_ASSISTANT_SESSION) return '';
|
|
663
541
|
if (features.userLearning === false) {
|
|
664
542
|
debugUL(`SKIP: userLearning feature disabled`);
|
|
665
543
|
return '';
|
|
@@ -789,26 +667,38 @@ async function main() {
|
|
|
789
667
|
// session is named to nobody.
|
|
790
668
|
if (isTemporaryChat()) { await temporaryChatPrompt(prompt, project); return; }
|
|
791
669
|
|
|
792
|
-
// Reset before
|
|
670
|
+
// Reset before the trivial-message and loop early returns.
|
|
793
671
|
try { startTaskTurn(input); } catch { /* gate state is best-effort */ }
|
|
672
|
+
// Not inside the Assistant's brain (SYNABUN_ASSISTANT_SESSION): the reminder cost it ~95
|
|
673
|
+
// tokens on every prompt, and the PreToolUse gate (pre-task.mjs) enforces the recall anyway.
|
|
794
674
|
if (!input.agent_id && /^[a-zA-Z0-9_-]+$/.test(sessionId) && typeof input.prompt === 'string'
|
|
675
|
+
&& !process.env.SYNABUN_ASSISTANT_SESSION
|
|
795
676
|
&& getHookFeatures().taskRecallGate !== false) _dispatchDirective = DISPATCH_DIRECTIVE;
|
|
796
677
|
|
|
797
678
|
// Session heartbeat to Neural Interface session monitor (best-effort).
|
|
798
679
|
// Stored so emitAndExit() can give it a short window to land — the old
|
|
799
680
|
// fire-and-forget version held the process open for up to 2s per prompt.
|
|
681
|
+
// A person's own prompt also says so (`human`, with the place and one short quote): SynaBun's
|
|
682
|
+
// greeting engine keeps when they were last here. Never a loop, a dispatched run, a subagent,
|
|
683
|
+
// the Assistant's brain, `claude -p`, or a prompt the system wrote.
|
|
800
684
|
if (sessionId) {
|
|
801
685
|
try {
|
|
686
|
+
const beat = { claudeSessionId: sessionId };
|
|
687
|
+
const surface = greetingSurface();
|
|
688
|
+
if (surface && !input.agent_id && !/^\[SynaBun Loop\]/i.test(trimmed) && !ownedByLoop(process.env.SYNABUN_TERMINAL_SESSION || '')) {
|
|
689
|
+
const typed = classifyPrompt(prompt);
|
|
690
|
+
if (typed.origin !== 'system' && typed.text.trim()) Object.assign(beat, { human: true, surface, cwd: cwd || undefined, words: typed.text.trim().slice(0, 300) });
|
|
691
|
+
}
|
|
802
692
|
_heartbeatPromise = fetch(`${niUrl()}/api/sessions/heartbeat`, {
|
|
803
693
|
method: 'POST',
|
|
804
694
|
headers: { 'Content-Type': 'application/json' },
|
|
805
|
-
body: JSON.stringify(
|
|
695
|
+
body: JSON.stringify(beat),
|
|
806
696
|
signal: AbortSignal.timeout(600),
|
|
807
697
|
}).catch(() => {});
|
|
808
698
|
} catch { /* ok */ }
|
|
809
699
|
}
|
|
810
700
|
|
|
811
|
-
// --- Loop marker detection (
|
|
701
|
+
// --- Loop marker detection (first: a loop takes none of what follows) ---
|
|
812
702
|
const terminalSessionEnv = process.env.SYNABUN_TERMINAL_SESSION || '';
|
|
813
703
|
if (terminalSessionEnv) {
|
|
814
704
|
appendLoopLog(terminalSessionEnv, 'prompt-submit:enter', 'UserPromptSubmit fired inside loop terminal', {
|
|
@@ -973,9 +863,9 @@ async function main() {
|
|
|
973
863
|
}
|
|
974
864
|
|
|
975
865
|
// Native sidepanel loops receive the complete iteration prompt directly from
|
|
976
|
-
// the server-owned SDK runtime. Bypass the legacy marker claim
|
|
977
|
-
//
|
|
978
|
-
//
|
|
866
|
+
// the server-owned SDK runtime. Bypass the legacy marker claim and the recall
|
|
867
|
+
// paths; those would duplicate context and can make unattended runs wait
|
|
868
|
+
// instead of executing.
|
|
979
869
|
if (terminalSessionEnv && !/^\[SynaBun Loop\]/i.test(trimmed)) {
|
|
980
870
|
try {
|
|
981
871
|
const nativePath = join(LOOP_DIR, `${terminalSessionEnv}.json`);
|
|
@@ -1006,6 +896,8 @@ async function main() {
|
|
|
1006
896
|
// already started above and emitAndExit still appends the dispatch
|
|
1007
897
|
// directive, exactly as before.
|
|
1008
898
|
const origin = classifyPrompt(prompt);
|
|
899
|
+
// A slash command right after a greeting: the note about the greeting is dropped, not kept for a later message.
|
|
900
|
+
if (origin.marker === 'skill-instructions' || /^\s*\//.test(prompt)) takeGreetingNote(sessionId);
|
|
1009
901
|
if (origin.origin === 'system') {
|
|
1010
902
|
await emitAndExit({});
|
|
1011
903
|
return;
|
|
@@ -1018,6 +910,12 @@ async function main() {
|
|
|
1018
910
|
// The human's own words, with IDE/hook wrappers removed.
|
|
1019
911
|
const text = origin.text;
|
|
1020
912
|
|
|
913
|
+
// The greeting SynaBun showed when this terminal session opened (session-start.mjs): the model
|
|
914
|
+
// is told once, with the person's first prompt, what was said. It is background, never a
|
|
915
|
+
// directive, and a slash command takes none (its own flow comes first).
|
|
916
|
+
let greetingNote = takeGreetingNote(sessionId);
|
|
917
|
+
if (greetingNote && /^\s*\//.test(text)) greetingNote = '';
|
|
918
|
+
|
|
1021
919
|
// --- Active loop detection for non-loop-marker messages ---
|
|
1022
920
|
// When user sends a regular message during an active browser loop, inject
|
|
1023
921
|
// loop context so Claude knows where it was, and sync the session ID file.
|
|
@@ -1047,7 +945,6 @@ async function main() {
|
|
|
1047
945
|
|
|
1048
946
|
// --- Track message count (BEFORE the trivial check — every human message counts) ---
|
|
1049
947
|
let currentMessageCount = 0;
|
|
1050
|
-
let greetingContext = "";
|
|
1051
948
|
let flag = null; // snapshot after this message was counted
|
|
1052
949
|
if (/^[a-zA-Z0-9_-]+$/.test(sessionId) && text.length > 0) {
|
|
1053
950
|
try {
|
|
@@ -1064,33 +961,15 @@ async function main() {
|
|
|
1064
961
|
if (!current.firstMessageAt) current.firstMessageAt = new Date().toISOString();
|
|
1065
962
|
current.lastMessageAt = new Date().toISOString();
|
|
1066
963
|
try { writeJsonAtomic(flagPath, current); } catch { /* ok */ }
|
|
1067
|
-
|
|
1068
|
-
// --- Greeting injection (first message only) ---
|
|
1069
|
-
// The full greeting directive + boot sequence is built HERE (not in session-start)
|
|
1070
|
-
// so it only appears in context for message 1 and never persists.
|
|
1071
|
-
if (current.messageCount === 1 && !current.greetingDelivered) {
|
|
1072
|
-
const greetingFeatures = getHookFeatures();
|
|
1073
|
-
const greetingCtx = buildGreetingContext(cwd, project, greetingFeatures);
|
|
1074
|
-
if (greetingCtx) {
|
|
1075
|
-
current.greetingDelivered = true;
|
|
1076
|
-
try { writeJsonAtomic(flagPath, current); } catch { /* ok */ }
|
|
1077
|
-
greetingContext = greetingCtx;
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
964
|
flag = { ...current };
|
|
1081
965
|
}, { timeoutMs: 500 });
|
|
1082
966
|
} catch { flag = readFlag(sessionId); /* contended: judge with what is on disk */ }
|
|
1083
967
|
}
|
|
1084
968
|
|
|
1085
|
-
if (greetingContext) {
|
|
1086
|
-
await emitAndExit({ hookSpecificOutput: { hookEventName: 'UserPromptSubmit',
|
|
1087
|
-
additionalContext: greetingContext + '\nIf the user message is just a greeting, the greeting is your full response.' } });
|
|
1088
|
-
return;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
969
|
// Skip trivial messages first (fastest path). Whole-string patterns only.
|
|
970
|
+
// ("yes, continue that" after a greeting still carries the note about it.)
|
|
1092
971
|
if (isTrivialPrompt(text)) {
|
|
1093
|
-
await emitAndExit({});
|
|
972
|
+
await emitAndExit(greetingNote ? { hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext: greetingNote } } : {});
|
|
1094
973
|
return;
|
|
1095
974
|
}
|
|
1096
975
|
|
|
@@ -1123,10 +1002,9 @@ async function main() {
|
|
|
1123
1002
|
unsaved_work: unsavedWork,
|
|
1124
1003
|
}, { timeoutMs: callMs });
|
|
1125
1004
|
|
|
1126
|
-
//
|
|
1127
|
-
//
|
|
1128
|
-
const
|
|
1129
|
-
const autoRecallMinMessage = greetingEnabled ? 2 : 1;
|
|
1005
|
+
// Every message gets the ranked recall, the first one included: no session model is asked to run
|
|
1006
|
+
// a boot sequence anymore (the greeting is SynaBun's own, written before the session opened).
|
|
1007
|
+
const autoRecallMinMessage = 1;
|
|
1130
1008
|
const staleShown = Array.isArray(flag?.staleShown) ? flag.staleShown.filter((id) => typeof id === 'string') : [];
|
|
1131
1009
|
const recallRequest = (!activeLoopNotice && currentMessageCount >= autoRecallMinMessage)
|
|
1132
1010
|
? recallMemories({
|
|
@@ -1223,9 +1101,7 @@ async function main() {
|
|
|
1223
1101
|
} catch { /* best effort */ }
|
|
1224
1102
|
|
|
1225
1103
|
// --- Emit combined output ---
|
|
1226
|
-
|
|
1227
|
-
// via buildGreetingContext(), so it never persists in session context.
|
|
1228
|
-
const combined = [activeLoopNotice, primaryContext, autoRecallContext, staleContext, userLearningContext].filter(Boolean).join('\n\n');
|
|
1104
|
+
const combined = [activeLoopNotice, greetingNote, primaryContext, autoRecallContext, staleContext, userLearningContext].filter(Boolean).join('\n\n');
|
|
1229
1105
|
|
|
1230
1106
|
if (combined) {
|
|
1231
1107
|
await emitAndExit({
|