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.
Files changed (334) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/THIRD-PARTY-LICENSES.md +46 -0
  5. package/benchmarks/fixtures/browser/README.md +1 -1
  6. package/benchmarks/fixtures/desktop/README.md +1 -1
  7. package/docs/whatsapp.md +2 -2
  8. package/hooks/claude-code/pre-compact.mjs +11 -0
  9. package/hooks/claude-code/prompt-submit.mjs +60 -184
  10. package/hooks/claude-code/session-start.mjs +73 -16
  11. package/hooks/claude-code/shared.mjs +20 -0
  12. package/hooks/claude-code/stop.mjs +5 -5
  13. package/lib/start-launcher.js +88 -1
  14. package/mcp-server/package-lock.json +2 -2
  15. package/mcp-server/package.json +1 -3
  16. package/neural-interface/i18n/en.json +1500 -153
  17. package/neural-interface/i18n/pt-BR.json +1498 -152
  18. package/neural-interface/lib/assistant-api.js +62 -6
  19. package/neural-interface/lib/assistant-brains/claude.js +4 -0
  20. package/neural-interface/lib/assistant-catalog.js +179 -27
  21. package/neural-interface/lib/assistant-config.js +31 -2
  22. package/neural-interface/lib/assistant-dispatch.js +62 -13
  23. package/neural-interface/lib/assistant-hidden-models.js +393 -66
  24. package/neural-interface/lib/assistant-memory.js +24 -10
  25. package/neural-interface/lib/assistant-persona.js +6 -2
  26. package/neural-interface/lib/assistant-pricing.js +21 -6
  27. package/neural-interface/lib/assistant-runtime.js +181 -12
  28. package/neural-interface/lib/assistant-task-prompt.js +13 -3
  29. package/neural-interface/lib/assistant-test-density.js +142 -0
  30. package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
  31. package/neural-interface/lib/assistant-user-context.js +908 -0
  32. package/neural-interface/lib/assistant-user-knowledge.js +328 -0
  33. package/neural-interface/lib/assistant-user-learn.js +404 -0
  34. package/neural-interface/lib/assistant-user-threads.js +226 -0
  35. package/neural-interface/lib/assistant-user-writer.js +181 -0
  36. package/neural-interface/lib/browser-background-tab.js +134 -0
  37. package/neural-interface/lib/browser-screenshot.js +678 -61
  38. package/neural-interface/lib/claude-agent-bridge.js +33 -6
  39. package/neural-interface/lib/claude-model-catalog.js +30 -2
  40. package/neural-interface/lib/claude-temporary.js +46 -7
  41. package/neural-interface/lib/cloudflared/install.js +533 -0
  42. package/neural-interface/lib/cloudflared/manager.js +545 -0
  43. package/neural-interface/lib/cloudflared/pins.js +115 -0
  44. package/neural-interface/lib/cloudflared/pins.json +63 -0
  45. package/neural-interface/lib/cloudflared/tunnel.js +265 -0
  46. package/neural-interface/lib/editor-completion-endpoint.js +264 -0
  47. package/neural-interface/lib/editor-completion-opencode.js +436 -0
  48. package/neural-interface/lib/editor-completion.js +714 -0
  49. package/neural-interface/lib/editor-config.js +149 -0
  50. package/neural-interface/lib/editor-files-api.js +268 -0
  51. package/neural-interface/lib/editor-git-api.js +134 -0
  52. package/neural-interface/lib/file-explorer-api.js +1039 -0
  53. package/neural-interface/lib/file-explorer-system.js +355 -0
  54. package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
  55. package/neural-interface/lib/file-explorer-watch.js +239 -0
  56. package/neural-interface/lib/git-diff-api.js +103 -0
  57. package/neural-interface/lib/git-read.js +202 -0
  58. package/neural-interface/lib/greeting/api.js +89 -0
  59. package/neural-interface/lib/greeting/budgets.js +90 -0
  60. package/neural-interface/lib/greeting/engine.js +461 -0
  61. package/neural-interface/lib/greeting/facts.js +320 -0
  62. package/neural-interface/lib/greeting/sources.js +252 -0
  63. package/neural-interface/lib/greeting/writer.js +139 -0
  64. package/neural-interface/lib/http-guards.js +189 -13
  65. package/neural-interface/lib/machine-names.js +88 -0
  66. package/neural-interface/lib/memory-api.js +31 -7
  67. package/neural-interface/lib/native-loop-providers.js +10 -5
  68. package/neural-interface/lib/plugin-installer.js +4 -2
  69. package/neural-interface/lib/project-storage.js +5 -7
  70. package/neural-interface/lib/request-gate.js +589 -0
  71. package/neural-interface/lib/ui-blob-api.js +108 -0
  72. package/neural-interface/lib/ui-blob-store.js +68 -0
  73. package/neural-interface/package-lock.json +701 -2
  74. package/neural-interface/package.json +13 -2
  75. package/neural-interface/public/install-app.html +9 -6
  76. package/neural-interface/public/offline.html +3 -2
  77. package/neural-interface/public/onboarding.html +12 -1
  78. package/neural-interface/public/shared/agent-runtime-options.js +22 -6
  79. package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
  80. package/neural-interface/public/shared/assistant/asst-brain-picker.js +312 -62
  81. package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
  82. package/neural-interface/public/shared/assistant/asst-mascot.js +18 -58
  83. package/neural-interface/public/shared/assistant/asst-menu.js +12 -8
  84. package/neural-interface/public/shared/assistant/asst-panel.js +150 -28
  85. package/neural-interface/public/shared/assistant/asst-render.js +162 -19
  86. package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
  87. package/neural-interface/public/shared/assistant/asst-route.js +23 -329
  88. package/neural-interface/public/shared/assistant/asst-routes-editor.js +495 -0
  89. package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
  90. package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
  91. package/neural-interface/public/shared/assistant/asst-state.js +185 -1
  92. package/neural-interface/public/shared/assistant/asst-styles.js +158 -4
  93. package/neural-interface/public/shared/blob-store.js +111 -22
  94. package/neural-interface/public/shared/cdx/cdx-panel.js +32 -11
  95. package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
  96. package/neural-interface/public/shared/cdx/cdx-styles.js +36 -0
  97. package/neural-interface/public/shared/cdx/cdx-tabs.js +87 -4
  98. package/neural-interface/public/shared/constants.js +6 -1
  99. package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
  100. package/neural-interface/public/shared/cp/cp-styles.js +15 -0
  101. package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
  102. package/neural-interface/public/shared/editor/editor-ai.js +619 -0
  103. package/neural-interface/public/shared/editor/editor-commands.js +212 -0
  104. package/neural-interface/public/shared/editor/editor-compare.js +103 -0
  105. package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
  106. package/neural-interface/public/shared/editor/editor-doc.js +257 -0
  107. package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
  108. package/neural-interface/public/shared/editor/editor-git.js +95 -0
  109. package/neural-interface/public/shared/editor/editor-languages.js +156 -0
  110. package/neural-interface/public/shared/editor/editor-lint.js +229 -0
  111. package/neural-interface/public/shared/editor/editor-loader.js +51 -0
  112. package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
  113. package/neural-interface/public/shared/editor/editor-menu.js +233 -0
  114. package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
  115. package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
  116. package/neural-interface/public/shared/editor/editor-palette.js +125 -0
  117. package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
  118. package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
  119. package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
  120. package/neural-interface/public/shared/editor/editor-safety.js +500 -0
  121. package/neural-interface/public/shared/editor/editor-search.js +352 -0
  122. package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
  123. package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
  124. package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
  125. package/neural-interface/public/shared/editor/editor-theme.js +244 -0
  126. package/neural-interface/public/shared/editor/editor-view.js +332 -0
  127. package/neural-interface/public/shared/explorer/fx-api.js +216 -0
  128. package/neural-interface/public/shared/explorer/fx-links.js +204 -0
  129. package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
  130. package/neural-interface/public/shared/explorer/fx-main.js +865 -0
  131. package/neural-interface/public/shared/explorer/fx-names.js +87 -0
  132. package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
  133. package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
  134. package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
  135. package/neural-interface/public/shared/file-links.js +339 -0
  136. package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
  137. package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
  138. package/neural-interface/public/shared/html-shell.js +160 -165
  139. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
  140. package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
  141. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +99 -17
  142. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  143. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +5 -0
  144. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +40 -0
  145. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
  146. package/neural-interface/public/shared/pwa-install-page.js +29 -1
  147. package/neural-interface/public/shared/pwa-install.css +3 -3
  148. package/neural-interface/public/shared/pwa-install.js +100 -1
  149. package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
  150. package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
  151. package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
  152. package/neural-interface/public/shared/settings/settings-ia.js +18 -4
  153. package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
  154. package/neural-interface/public/shared/start-bridge.js +238 -19
  155. package/neural-interface/public/shared/styles.css +1414 -721
  156. package/neural-interface/public/shared/synabun-mascot.js +20 -56
  157. package/neural-interface/public/shared/tunnel-view.js +167 -0
  158. package/neural-interface/public/shared/ui-claude-panel.js +157 -16
  159. package/neural-interface/public/shared/ui-detail.js +15 -0
  160. package/neural-interface/public/shared/ui-explorer.js +22 -0
  161. package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
  162. package/neural-interface/public/shared/ui-file-links.js +103 -0
  163. package/neural-interface/public/shared/ui-help.js +26 -0
  164. package/neural-interface/public/shared/ui-invite.js +126 -116
  165. package/neural-interface/public/shared/ui-keybinds.js +4 -0
  166. package/neural-interface/public/shared/ui-loading.js +159 -15
  167. package/neural-interface/public/shared/ui-menubar.js +12 -30
  168. package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
  169. package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
  170. package/neural-interface/public/shared/ui-navbar.js +45 -21
  171. package/neural-interface/public/shared/ui-settings.js +455 -488
  172. package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
  173. package/neural-interface/public/shared/ui-sync.js +16 -0
  174. package/neural-interface/public/shared/ui-terminal.js +23 -5
  175. package/neural-interface/public/shared/ui-tunnel.js +130 -0
  176. package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
  177. package/neural-interface/public/shared/ui-whiteboard.js +12 -0
  178. package/neural-interface/public/shared/ui-worker-end.js +245 -0
  179. package/neural-interface/public/shared/ui-workspaces.js +41 -27
  180. package/neural-interface/public/shared/worker-end.js +251 -0
  181. package/neural-interface/public/sw.js +2 -2
  182. package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
  183. package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
  184. package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
  185. package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
  186. package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
  187. package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
  188. package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
  189. package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
  190. package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
  191. package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
  192. package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
  193. package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
  194. package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
  195. package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
  196. package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
  197. package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
  198. package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
  199. package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
  200. package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
  201. package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
  202. package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
  203. package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
  204. package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
  205. package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
  206. package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
  207. package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
  208. package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
  209. package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
  210. package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
  211. package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
  212. package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
  213. package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
  214. package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
  215. package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
  216. package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
  217. package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
  218. package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
  219. package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
  220. package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
  221. package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
  222. package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
  223. package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
  224. package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
  225. package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
  226. package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
  227. package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
  228. package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
  229. package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
  230. package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
  231. package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
  232. package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
  233. package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
  234. package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
  235. package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
  236. package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
  237. package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
  238. package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
  239. package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
  240. package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
  241. package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
  242. package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
  243. package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
  244. package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
  245. package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
  246. package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
  247. package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
  248. package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
  249. package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
  250. package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
  251. package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
  252. package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
  253. package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
  254. package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
  255. package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
  256. package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
  257. package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
  258. package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
  259. package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
  260. package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
  261. package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
  262. package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
  263. package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
  264. package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
  265. package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
  266. package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
  267. package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
  268. package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
  269. package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
  270. package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
  271. package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
  272. package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
  273. package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
  274. package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
  275. package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
  276. package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
  277. package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
  278. package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
  279. package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
  280. package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
  281. package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
  282. package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
  283. package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
  284. package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
  285. package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
  286. package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
  287. package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
  288. package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
  289. package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
  290. package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
  291. package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
  292. package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
  293. package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
  294. package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
  295. package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
  296. package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
  297. package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
  298. package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
  299. package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
  300. package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
  301. package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
  302. package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
  303. package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
  304. package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
  305. package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
  306. package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
  307. package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
  308. package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
  309. package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
  310. package/neural-interface/scripts/build-vendor.mjs +78 -2
  311. package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
  312. package/neural-interface/server.js +873 -1028
  313. package/neural-interface/templates/rulesets/README.md +1 -1
  314. package/package.json +2 -8
  315. package/setup.js +44 -7
  316. package/benchmarks/browser-live-results.json +0 -79
  317. package/benchmarks/browser-v2-results.json +0 -258
  318. package/neural-interface/lib/codex-capabilities.d.ts +0 -41
  319. package/neural-interface/public/category-logos/claude.svg +0 -1
  320. package/neural-interface/public/category-logos/gemini-color.svg +0 -1
  321. package/neural-interface/public/category-logos/openai.svg +0 -1
  322. package/neural-interface/public/category-logos/synabun.png +0 -0
  323. package/neural-interface/public/claude.svg +0 -1
  324. package/neural-interface/public/gallery.svg +0 -6
  325. package/neural-interface/public/leonardoai.svg +0 -1
  326. package/neural-interface/public/mcp.svg +0 -4
  327. package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
  328. package/neural-interface/public/pin-svgrepo-com.svg +0 -25
  329. package/neural-interface/public/sessionicon.svg +0 -8
  330. package/neural-interface/public/toolbar-album.svg +0 -8
  331. package/neural-interface/public/toolbar-question.svg +0 -6
  332. package/neural-interface/public/toolbar-sessions.svg +0 -6
  333. package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
  334. package/skills/synabun/synabunicon.png +0 -0
@@ -0,0 +1,355 @@
1
+ // ── The File Explorer's system programs ──
2
+ // The three things the explorer asks the operating system for: move something
3
+ // to the Trash, show something in the file manager, and (for "Add project")
4
+ // the folder picker. Every path is handed over as an argument of its own
5
+ // (execFile, never a shell), so nothing in a file name is ever read as a command.
6
+ //
7
+ // Trash, per system:
8
+ // macOS /usr/bin/trash (macOS 14 and later), else a move into ~/.Trash
9
+ // Windows the Recycle Bin, through lib/file-explorer-trash.ps1, and only
10
+ // where the bin is sure to keep the item (recycleVerdict)
11
+ // Linux `gio trash`, else the FreeDesktop Trash of the home folder
12
+ // A path that has no Trash (another volume, a system without one) throws
13
+ // TrashUnavailable and nothing is removed: the caller asks before deleting for good.
14
+
15
+ import { execFile } from 'node:child_process';
16
+ import {
17
+ closeSync, existsSync, lstatSync, mkdirSync, openSync, renameSync, rmdirSync, unlinkSync, writeFileSync,
18
+ } from 'node:fs';
19
+ import { lstat, readdir } from 'node:fs/promises';
20
+ import { homedir } from 'node:os';
21
+ import { basename, dirname, join } from 'node:path';
22
+ import { fileURLToPath, pathToFileURL } from 'node:url';
23
+ import { splitName } from '../public/shared/explorer/fx-names.js';
24
+
25
+ const HERE = dirname(fileURLToPath(import.meta.url));
26
+ export const TRASH_SCRIPT = join(HERE, 'file-explorer-trash.ps1');
27
+ export const MAC_TRASH = '/usr/bin/trash';
28
+ const SYSTEM_TIMEOUT_MS = 20000;
29
+
30
+ /** There is no Trash for that path on this system. Nothing was removed. */
31
+ export class TrashUnavailable extends Error {
32
+ constructor(message = 'No Trash is available for that path.') {
33
+ super(message);
34
+ this.name = 'TrashUnavailable';
35
+ this.code = 'no-trash';
36
+ }
37
+ }
38
+
39
+ /** Run a program with its arguments, without a shell. Rejects with the error (its `code` is the errno or exit code). */
40
+ export function runProgram(file, args, { timeoutMs = SYSTEM_TIMEOUT_MS, env = process.env } = {}) {
41
+ return new Promise((done, failed) => {
42
+ try {
43
+ execFile(file, args, { timeout: timeoutMs, windowsHide: true, shell: false, env, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
44
+ if (error) { error.stderr = String(stderr || ''); failed(error); } else done({ stdout: String(stdout || ''), stderr: String(stderr || '') });
45
+ });
46
+ } catch (error) { failed(error); }
47
+ });
48
+ }
49
+
50
+ const two = (n) => String(n).padStart(2, '0');
51
+
52
+ /**
53
+ * Move `path` into the folder `dir` without ever replacing something that is there. The name is reserved first by
54
+ * making an empty placeholder exclusively (a file, or a folder for a folder): `rename` then replaces only what
55
+ * was just made here. A second entry of one name gets the time appended, as the Finder does.
56
+ * @returns {string} where it is now
57
+ */
58
+ export function moveIntoFolder(path, dir, { now = new Date() } = {}) {
59
+ const st = lstatSync(path);
60
+ const isDir = st.isDirectory();
61
+ const name = basename(path);
62
+ const { stem, ext } = isDir ? { stem: name, ext: '' } : splitName(name);
63
+ const stamp = `${two(now.getHours())}.${two(now.getMinutes())}.${two(now.getSeconds())}`;
64
+ for (let n = 0; n < 500; n++) {
65
+ const candidate = n === 0 ? name : `${stem} ${stamp}${n > 1 ? ` ${n}` : ''}${ext}`;
66
+ const dest = join(dir, candidate);
67
+ try {
68
+ if (isDir) mkdirSync(dest);
69
+ else closeSync(openSync(dest, 'wx'));
70
+ } catch (error) {
71
+ if (error?.code === 'EEXIST') continue;
72
+ throw error;
73
+ }
74
+ try {
75
+ renameSync(path, dest);
76
+ return dest;
77
+ } catch (error) {
78
+ try { if (isDir) rmdirSync(dest); else unlinkSync(dest); } catch { /* the placeholder stays: an empty entry in the Trash */ }
79
+ throw error;
80
+ }
81
+ }
82
+ throw new Error('No free name in the Trash.');
83
+ }
84
+
85
+ /**
86
+ * Give `path` the name `dest` only when nothing is there: a file or a folder that is under that name, or turns up
87
+ * under it while a request waits, is never replaced. The name is reserved first by an empty placeholder made
88
+ * exclusively (a file, or a folder for a folder), and `rename` then replaces only what was just made here. Throws
89
+ * EEXIST when the name is taken; a rename that fails leaves nothing under the name.
90
+ *
91
+ * The window that is left, and why it is accepted. Between the two calls (making the placeholder, renaming onto
92
+ * it) another writer can put something of its own in the placeholder's place, and the rename replaces it. That
93
+ * takes another program writing to the very same name in the instant between two system calls that follow one
94
+ * another; for a folder the system closes most of it (a rename onto a folder that got content fails by itself).
95
+ * The one way to close it for a file is to give the file its new name as a hard link, which replaces nothing; it
96
+ * was tried and taken out again, because macOS does not report the later deletion of a file that ever had a
97
+ * second hard link (APFS, macOS 26.6: not to a recursive watch, not to a watch on its folder). A file placed
98
+ * that way and deleted by something else kept its row in the tree: the explorer no longer followed the disk for
99
+ * every file it had renamed, moved or taken in. A window that needs a second writer on the same name in the same
100
+ * instant is the smaller cost. (tests/file-explorer-safety.test.mjs asks the real disk.)
101
+ * @param {string} path @param {string} dest
102
+ * @param {{ isDir?: boolean, platform?: string, rename?: typeof renameSync }} [o]
103
+ */
104
+ export function renameExclusive(path, dest, { isDir = false, platform = process.platform, rename = renameSync } = {}) {
105
+ if (isDir && platform === 'win32') {
106
+ // Windows renames a folder over nothing at all, and not onto a placeholder either: the name is looked at,
107
+ // and the system's own refusal is what holds.
108
+ let there = true;
109
+ try { lstatSync(dest); } catch { there = false; }
110
+ if (there) throw Object.assign(new Error(`EEXIST: file already exists, rename '${path}' -> '${dest}'`), { code: 'EEXIST' });
111
+ rename(path, dest);
112
+ return;
113
+ }
114
+ if (isDir) mkdirSync(dest);
115
+ else closeSync(openSync(dest, 'wx'));
116
+ try {
117
+ rename(path, dest);
118
+ } catch (error) {
119
+ try { if (isDir) rmdirSync(dest); else unlinkSync(dest); } catch { /* the placeholder stays: an empty entry */ }
120
+ throw error;
121
+ }
122
+ }
123
+
124
+ // ── The Recycle Bin (Windows) ──
125
+ // The Shell deletes for good, without a word, what its bin cannot keep: an item on a network or a removable
126
+ // drive, on a drive whose bin is switched off, or larger than the bin. So the bin is asked about first
127
+ // (file-explorer-trash.ps1 -Probe gives the facts) and the item is handed to the Shell only when the rule
128
+ // below says it will be kept. The rule is here, not in the script, so that it is tested without Windows.
129
+
130
+ const MB = 1024 * 1024;
131
+ /** The Win32 drive type of a local disk (Win32_Volume.DriveType): the only kind whose bin keeps what it is given. */
132
+ export const FIXED_DRIVE = 3;
133
+ /** A bin that was never set up has the system's own limit: taken at its smallest. */
134
+ export const DEFAULT_BIN_SHARE = 0.05;
135
+ export const BIN_PROBE_TTL_MS = 5000;
136
+ export const MEASURE_MAX_ENTRIES = 200000;
137
+
138
+ /**
139
+ * Whether an item is sure to be kept by the Recycle Bin. Each of the two switches is `true` (off), `false` (on:
140
+ * also what the probe says of a setting that is not there, which is Windows' default) or anything else, which is
141
+ * "it could not be read": then nothing is known, and the answer is no.
142
+ * @param {{ driveType?: number | string, volumeBytes?: number | null, maxCapacityMB?: number | null, nukeOnDelete?: boolean | null, policyOff?: boolean | null, error?: string } | null} facts
143
+ * what the probe said of the bin that serves the item's folder
144
+ * @param {number | null} sizeBytes how large the item is (`Infinity`: past the limit it was measured to; null: not known)
145
+ * @returns {{ ok: true } | { ok: false, reason: 'unknown' | 'drive' | 'off' | 'too-large' }} `unknown`: the bin could
146
+ * not be asked, one of its switches could not be read, or the item was not measured; `drive`: not a local disk;
147
+ * `off`: the bin is switched off, for the drive or by policy; `too-large`: the item is larger than the bin
148
+ */
149
+ export function recycleVerdict(facts, sizeBytes) {
150
+ const no = (reason) => ({ ok: false, reason });
151
+ if (!facts || typeof facts !== 'object' || facts.error) return no('unknown');
152
+ if (facts.policyOff === true) return no('off');
153
+ if (facts.policyOff !== false) return no('unknown');
154
+ if (Number(facts.driveType) !== FIXED_DRIVE) return no('drive');
155
+ if (facts.nukeOnDelete === true) return no('off');
156
+ if (facts.nukeOnDelete !== false) return no('unknown');
157
+ const own = facts.maxCapacityMB;
158
+ const capacity = typeof own === 'number' && Number.isFinite(own) && own >= 0 ? own * MB
159
+ : typeof facts.volumeBytes === 'number' && Number.isFinite(facts.volumeBytes) && facts.volumeBytes > 0 ? facts.volumeBytes * DEFAULT_BIN_SHARE
160
+ : null;
161
+ if (capacity === null) return no('unknown');
162
+ if (typeof sizeBytes !== 'number' || Number.isNaN(sizeBytes) || sizeBytes < 0) return no('unknown');
163
+ return sizeBytes > capacity ? no('too-large') : { ok: true };
164
+ }
165
+
166
+ /**
167
+ * How large an entry is: a file's size, or everything below a folder (a link counts as the link it is).
168
+ * @param {string} path
169
+ * @param {{ stopAt?: number, maxEntries?: number }} [o] past `stopAt` bytes the answer is `Infinity` and the rest
170
+ * is not walked; a folder of more than `maxEntries` entries is not measured
171
+ * @returns {Promise<number | null>} null when it cannot be said
172
+ */
173
+ export async function entryBytes(path, { stopAt = Infinity, maxEntries = MEASURE_MAX_ENTRIES } = {}) {
174
+ let total = 0; let seen = 0;
175
+ const queue = [path];
176
+ try {
177
+ while (queue.length) {
178
+ const at = queue.pop();
179
+ if (++seen > maxEntries) return null;
180
+ const st = await lstat(at);
181
+ total += st.size;
182
+ if (total > stopAt) return Infinity;
183
+ if (st.isDirectory()) for (const name of await readdir(at)) queue.push(join(at, name));
184
+ }
185
+ } catch { return null; }
186
+ return total;
187
+ }
188
+
189
+ const BIN_REASONS = {
190
+ unknown: 'The Recycle Bin of that drive could not be asked about.',
191
+ drive: 'That drive has no Recycle Bin (a network or a removable drive).',
192
+ off: 'The Recycle Bin is switched off for that drive.',
193
+ 'too-large': 'That is larger than the Recycle Bin of its drive.',
194
+ };
195
+
196
+ /** The FreeDesktop Trash of the home folder: `files/` holds the entry, `info/<name>.trashinfo` where it came from. */
197
+ export function trashFreeDesktop(path, { trashDir, now = new Date() } = {}) {
198
+ const files = join(trashDir, 'files');
199
+ const info = join(trashDir, 'info');
200
+ mkdirSync(files, { recursive: true, mode: 0o700 });
201
+ mkdirSync(info, { recursive: true, mode: 0o700 });
202
+ const name = basename(path);
203
+ const isDir = lstatSync(path).isDirectory();
204
+ const { stem, ext } = isDir ? { stem: name, ext: '' } : splitName(name);
205
+ const when = `${now.getFullYear()}-${two(now.getMonth() + 1)}-${two(now.getDate())}T${two(now.getHours())}:${two(now.getMinutes())}:${two(now.getSeconds())}`;
206
+ const record = `[Trash Info]\nPath=${pathToFileURL(path).pathname}\nDeletionDate=${when}\n`;
207
+ for (let n = 1; n < 1000; n++) {
208
+ const candidate = n === 1 ? name : `${stem}.${n}${ext}`;
209
+ const infoFile = join(info, `${candidate}.trashinfo`);
210
+ if (existsSync(join(files, candidate))) continue;
211
+ // The record is written first, exclusively: that is what reserves the name (the Trash specification).
212
+ try { writeFileSync(infoFile, record, { flag: 'wx', mode: 0o600 }); }
213
+ catch (error) { if (error?.code === 'EEXIST') continue; throw error; }
214
+ try {
215
+ renameSync(path, join(files, candidate));
216
+ return join(files, candidate);
217
+ } catch (error) {
218
+ try { unlinkSync(infoFile); } catch { /* nothing to undo */ }
219
+ throw error;
220
+ }
221
+ }
222
+ throw new Error('No free name in the Trash.');
223
+ }
224
+
225
+ /**
226
+ * @param {object} [o]
227
+ * @param {string} [o.platform]
228
+ * @param {(file: string, args: string[]) => Promise<any>} [o.run] runs a program (tests hand in a recorder)
229
+ * @param {object} [o.env] @param {string} [o.home]
230
+ * @param {(path: string) => boolean} [o.exists]
231
+ * @param {typeof entryBytes} [o.measure] @param {() => number} [o.now] Windows: how an item is measured, and the clock
232
+ * @returns {{ kind: string, available: () => boolean, trash: (path: string) => Promise<void> }} `path` is a
233
+ * canonical absolute path that exists; `trash` rejects with TrashUnavailable when it has nowhere to go
234
+ */
235
+ export function createTrash({
236
+ platform = process.platform, run = runProgram, env = process.env, home = homedir(), exists = existsSync,
237
+ measure = entryBytes, now = () => Date.now(),
238
+ } = {}) {
239
+ // A cross-device move, or a Trash that cannot be written, is "no Trash here", not a failure of the delete.
240
+ const noTrashHere = (error) => ['EXDEV', 'EACCES', 'EPERM', 'ENOENT', 'EROFS'].includes(error?.code);
241
+
242
+ if (platform === 'darwin') {
243
+ const fallback = (path) => {
244
+ try { moveIntoFolder(path, join(home, '.Trash')); }
245
+ catch (error) { if (noTrashHere(error)) throw new TrashUnavailable(); throw error; }
246
+ };
247
+ return {
248
+ kind: 'macos',
249
+ available: () => true,
250
+ async trash(path) {
251
+ if (exists(MAC_TRASH)) {
252
+ try { await run(MAC_TRASH, [path]); return; }
253
+ catch { if (!exists(path)) return; /* it went all the same */ }
254
+ }
255
+ fallback(path);
256
+ },
257
+ };
258
+ }
259
+
260
+ if (platform === 'win32') {
261
+ const script = ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', TRASH_SCRIPT];
262
+ const asked = new Map(); // folder → { at, facts }: the rows of one delete are mostly of one folder
263
+ // What is known of the bin that serves a folder, or null when it could not be asked.
264
+ async function binOf(folder) {
265
+ const known = asked.get(folder);
266
+ if (known && now() - known.at < BIN_PROBE_TTL_MS) return known.facts;
267
+ let facts = null;
268
+ try { facts = JSON.parse(String((await run('powershell.exe', [...script, '-Probe', folder]))?.stdout || '').trim()); } catch { facts = null; }
269
+ asked.set(folder, { at: now(), facts });
270
+ if (asked.size > 64) asked.delete(asked.keys().next().value);
271
+ return facts;
272
+ }
273
+ return {
274
+ kind: 'windows',
275
+ available: () => true,
276
+ async trash(path) {
277
+ // Asked first, and nothing is handed to the Shell unless the bin is sure to keep it: what it cannot keep
278
+ // it deletes for good without a word. Refused here, the item stays and the caller asks its own question.
279
+ const facts = await binOf(dirname(path));
280
+ const limit = typeof facts?.maxCapacityMB === 'number' ? facts.maxCapacityMB * MB : typeof facts?.volumeBytes === 'number' ? facts.volumeBytes * DEFAULT_BIN_SHARE : 0;
281
+ const verdict = recycleVerdict(facts, recycleVerdict(facts, 0).ok ? await measure(path, { stopAt: limit }) : null);
282
+ if (!verdict.ok) throw new TrashUnavailable(BIN_REASONS[verdict.reason]);
283
+ try {
284
+ await run('powershell.exe', [...script, path]);
285
+ } catch (error) {
286
+ if (!exists(path)) return;
287
+ // The script could not be run at all (no PowerShell), or the Shell refused the item.
288
+ throw new TrashUnavailable(String(error?.stderr || error?.message || '').trim() || undefined);
289
+ }
290
+ },
291
+ };
292
+ }
293
+
294
+ const trashDir = join(env.XDG_DATA_HOME || join(home, '.local', 'share'), 'Trash');
295
+ return {
296
+ kind: 'freedesktop',
297
+ available: () => true,
298
+ async trash(path) {
299
+ try { await run('gio', ['trash', '--', path]); return; }
300
+ catch { if (!exists(path)) return; /* no gio, or it refused: the home Trash is tried by hand */ }
301
+ try { trashFreeDesktop(path, { trashDir }); }
302
+ catch (error) { if (noTrashHere(error)) throw new TrashUnavailable(); throw error; }
303
+ },
304
+ };
305
+ }
306
+
307
+ /**
308
+ * The program that shows `path` selected in the system's file manager, as `{ file, args }` lists (the first that
309
+ * runs is used), or an empty list when this system has none.
310
+ */
311
+ export function revealCommands(platform, path, { env = process.env } = {}) {
312
+ if (platform === 'darwin') return [{ file: 'open', args: ['-R', path] }];
313
+ // explorer.exe takes "/select," and the path as one argument, and answers 1 even when it worked.
314
+ if (platform === 'win32') return [{ file: 'explorer.exe', args: [`/select,${path}`], anyExit: true }];
315
+ if (!env.DISPLAY && !env.WAYLAND_DISPLAY) return [];
316
+ // dbus-send splits the items of an array at commas: one in the path is written as its escape, which a file
317
+ // manager reads back as the comma.
318
+ const url = pathToFileURL(path).href.replace(/,/g, '%2C');
319
+ return [
320
+ { file: 'dbus-send', args: ['--session', '--dest=org.freedesktop.FileManager1', '--type=method_call', '/org/freedesktop/FileManager1',
321
+ 'org.freedesktop.FileManager1.ShowItems', `array:string:${url}`, 'string:'] },
322
+ { file: 'xdg-open', args: [dirname(path)] },
323
+ ];
324
+ }
325
+
326
+ /** @returns {{ available: () => boolean, reveal: (path: string) => Promise<boolean> }} */
327
+ export function createRevealer({ platform = process.platform, run = runProgram, env = process.env } = {}) {
328
+ return {
329
+ available: () => revealCommands(platform, '/', { env }).length > 0,
330
+ async reveal(path) {
331
+ for (const command of revealCommands(platform, path, { env })) {
332
+ try { await run(command.file, command.args); return true; }
333
+ catch (error) { if (command.anyExit && error?.code !== 'ENOENT') return true; }
334
+ }
335
+ return false;
336
+ },
337
+ };
338
+ }
339
+
340
+ /**
341
+ * The system's folder picker as a program and its arguments. The prompt is an argument: it is never part of a
342
+ * script or a command line that is parsed again.
343
+ * @param {string} platform @param {string} prompt
344
+ * @param {{ scriptPath?: string }} [o] Windows: lib/folder-picker.ps1
345
+ */
346
+ export function folderPickerCommand(platform, prompt, { scriptPath = join(HERE, 'folder-picker.ps1') } = {}) {
347
+ const title = String(prompt || 'Select a folder').replace(/[\r\n]+/g, ' ').slice(0, 200);
348
+ if (platform === 'win32') {
349
+ return { file: 'powershell.exe', args: ['-NoProfile', '-STA', '-WindowStyle', 'Hidden', '-ExecutionPolicy', 'Bypass', '-File', scriptPath, '-Title', title] };
350
+ }
351
+ if (platform === 'darwin') {
352
+ return { file: 'osascript', args: ['-e', 'on run argv', '-e', 'POSIX path of (choose folder with prompt (item 1 of argv))', '-e', 'end run', title] };
353
+ }
354
+ return { file: 'zenity', args: ['--file-selection', '--directory', `--title=${title}`] };
355
+ }
@@ -0,0 +1,85 @@
1
+ # The Recycle Bin, for lib/file-explorer-system.js. Two uses, and a path is always the script's argument (it is
2
+ # never part of a command line that is parsed again):
3
+ #
4
+ # file-explorer-trash.ps1 -Probe <folder> says what is known of the bin that serves that folder, as one line
5
+ # of JSON, and removes nothing
6
+ # file-explorer-trash.ps1 <path> moves that file or folder to the Recycle Bin
7
+ #
8
+ # Nothing is decided here. The Shell deletes for good, without a word, what its bin cannot keep (a network or a
9
+ # removable drive, a bin that is switched off, an item larger than the bin), so the server asks first and applies
10
+ # its rule, recycleVerdict() in lib/file-explorer-system.js, which is tested without Windows. It runs the second
11
+ # form only for an item that rule says the bin will keep. Nobody has run this script on Windows yet.
12
+ param([Parameter(Mandatory = $true, Position = 0)][string]$LiteralPath, [switch]$Probe)
13
+ $ErrorActionPreference = 'Stop'
14
+
15
+ if ($Probe) {
16
+ # The facts. A setting that is not there and a setting that could not be read are told apart: the first is
17
+ # Windows' default (the bin is on, with the system's own limit), the second is nothing known, and the rule
18
+ # takes "not known" for "not sure" and hands the bin nothing.
19
+ # driveType Win32_Volume.DriveType of the volume the folder is on (3 is a local disk); 0 when no volume
20
+ # is found for it (a network drive, a drive made by subst)
21
+ # volumeBytes how large that volume is
22
+ # maxCapacityMB the bin's own limit on that volume; $null when it was never set up
23
+ # nukeOnDelete "Don't move files to the Recycle Bin" is chosen for that volume: $true, $false (also when
24
+ # the setting is not there), or $null when it could not be read
25
+ # policyOff the same, by policy: $true, $false (also when there is no such policy), or $null when a
26
+ # policy key could not be read
27
+ $facts = @{ driveType = 0; volumeBytes = $null; maxCapacityMB = $null; nukeOnDelete = $null; policyOff = $null }
28
+
29
+ # The values of one registry key: a table (empty when the key is not there), or $null when it could not be read.
30
+ function Read-Key([string]$Key) {
31
+ try {
32
+ $values = @{}
33
+ $item = Get-ItemProperty -LiteralPath $Key -ErrorAction Stop
34
+ if ($null -ne $item) { foreach ($property in $item.PSObject.Properties) { $values[$property.Name] = $property.Value } }
35
+ return $values
36
+ } catch [System.Management.Automation.ItemNotFoundException] {
37
+ return @{}
38
+ } catch {
39
+ return $null
40
+ }
41
+ }
42
+
43
+ try {
44
+ $folder = [System.IO.Path]::GetFullPath($LiteralPath).TrimEnd('\') + '\'
45
+ # The volume whose mount point is the longest beginning of the folder: a volume mounted in a folder is found too.
46
+ $volume = Get-CimInstance -ClassName Win32_Volume |
47
+ Where-Object { $_.Name -and $folder.StartsWith($_.Name, [System.StringComparison]::OrdinalIgnoreCase) } |
48
+ Sort-Object -Property { $_.Name.Length } -Descending |
49
+ Select-Object -First 1
50
+ if ($volume) {
51
+ $facts.driveType = [int]$volume.DriveType
52
+ if ($volume.Capacity) { $facts.volumeBytes = [double]$volume.Capacity }
53
+ $id = [regex]::Match([string]$volume.DeviceID, '\{[0-9A-Fa-f-]{36}\}').Value
54
+ if ($id) {
55
+ $bin = Read-Key "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\BitBucket\Volume\$id"
56
+ if ($null -ne $bin) {
57
+ if ($bin.ContainsKey('MaxCapacity') -and $null -ne $bin['MaxCapacity']) { $facts.maxCapacityMB = [double]$bin['MaxCapacity'] }
58
+ $facts.nukeOnDelete = ($bin.ContainsKey('NukeOnDelete') -and $bin['NukeOnDelete'] -eq 1)
59
+ }
60
+ }
61
+ }
62
+ $off = $false
63
+ $read = $true
64
+ foreach ($hive in 'HKCU:', 'HKLM:') {
65
+ $policy = Read-Key "$hive\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer"
66
+ if ($null -eq $policy) { $read = $false }
67
+ elseif ($policy.ContainsKey('NoRecycleFiles') -and $policy['NoRecycleFiles'] -eq 1) { $off = $true }
68
+ }
69
+ # Switched off by one hive is off, whatever the other says; otherwise both must have been read to say "on".
70
+ if ($off) { $facts.policyOff = $true } elseif ($read) { $facts.policyOff = $false }
71
+ } catch {
72
+ $facts.error = [string]$_.Exception.Message
73
+ }
74
+ [Console]::Out.WriteLine(($facts | ConvertTo-Json -Compress))
75
+ exit 0
76
+ }
77
+
78
+ Add-Type -AssemblyName Microsoft.VisualBasic
79
+ if (Test-Path -LiteralPath $LiteralPath -PathType Container) {
80
+ [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteDirectory($LiteralPath, 'OnlyErrorDialogs', 'SendToRecycleBin')
81
+ } elseif (Test-Path -LiteralPath $LiteralPath) {
82
+ [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($LiteralPath, 'OnlyErrorDialogs', 'SendToRecycleBin')
83
+ } else {
84
+ exit 3
85
+ }