synabun 2.0.7 → 2.0.9

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 (346) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +1 -1
  3. package/hooks/claude-code/post-plan.mjs +6 -30
  4. package/hooks/claude-code/session-start.mjs +1 -4
  5. package/hooks/claude-code/shared.mjs +106 -72
  6. package/lib/package-processes.js +670 -0
  7. package/lib/runtime-dependencies.js +225 -0
  8. package/mcp-server/dist/services/browser-bench.d.ts +1 -1
  9. package/mcp-server/dist/services/browser-bench.d.ts.map +1 -1
  10. package/mcp-server/dist/services/browser-bench.js +1 -1
  11. package/mcp-server/dist/services/browser-bench.js.map +1 -1
  12. package/mcp-server/dist/services/categories.d.ts +35 -2
  13. package/mcp-server/dist/services/categories.d.ts.map +1 -1
  14. package/mcp-server/dist/services/categories.js +77 -33
  15. package/mcp-server/dist/services/categories.js.map +1 -1
  16. package/mcp-server/dist/services/desktop-bench.d.ts +7 -7
  17. package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -1
  18. package/mcp-server/dist/services/desktop-bench.js +1 -1
  19. package/mcp-server/dist/services/desktop-bench.js.map +1 -1
  20. package/mcp-server/dist/tools/agents.d.ts +1 -1
  21. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  22. package/mcp-server/dist/tools/agents.js +1 -1
  23. package/mcp-server/dist/tools/agents.js.map +1 -1
  24. package/mcp-server/dist/tools/bluesky.js +1 -1
  25. package/mcp-server/dist/tools/bluesky.js.map +1 -1
  26. package/mcp-server/dist/tools/browser-advanced.d.ts +1 -1
  27. package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -1
  28. package/mcp-server/dist/tools/browser-advanced.js +1 -1
  29. package/mcp-server/dist/tools/browser-advanced.js.map +1 -1
  30. package/mcp-server/dist/tools/browser-batch.d.ts +1 -1
  31. package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -1
  32. package/mcp-server/dist/tools/browser-batch.js +1 -1
  33. package/mcp-server/dist/tools/browser-batch.js.map +1 -1
  34. package/mcp-server/dist/tools/browser-cheatsheet.d.ts +1 -1
  35. package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -1
  36. package/mcp-server/dist/tools/browser-cheatsheet.js +1 -1
  37. package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -1
  38. package/mcp-server/dist/tools/browser-interact.d.ts +1 -1
  39. package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -1
  40. package/mcp-server/dist/tools/browser-interact.js +1 -1
  41. package/mcp-server/dist/tools/browser-interact.js.map +1 -1
  42. package/mcp-server/dist/tools/browser-navigate.d.ts +1 -1
  43. package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -1
  44. package/mcp-server/dist/tools/browser-navigate.js +1 -1
  45. package/mcp-server/dist/tools/browser-navigate.js.map +1 -1
  46. package/mcp-server/dist/tools/browser-observe.d.ts +1 -1
  47. package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -1
  48. package/mcp-server/dist/tools/browser-observe.js +1 -1
  49. package/mcp-server/dist/tools/browser-observe.js.map +1 -1
  50. package/mcp-server/dist/tools/card-tools.d.ts +1 -1
  51. package/mcp-server/dist/tools/card-tools.d.ts.map +1 -1
  52. package/mcp-server/dist/tools/card-tools.js +1 -1
  53. package/mcp-server/dist/tools/card-tools.js.map +1 -1
  54. package/mcp-server/dist/tools/category.d.ts +1 -1
  55. package/mcp-server/dist/tools/category.d.ts.map +1 -1
  56. package/mcp-server/dist/tools/category.js +5 -1
  57. package/mcp-server/dist/tools/category.js.map +1 -1
  58. package/mcp-server/dist/tools/choice.d.ts +1 -1
  59. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  60. package/mcp-server/dist/tools/choice.js +1 -1
  61. package/mcp-server/dist/tools/choice.js.map +1 -1
  62. package/mcp-server/dist/tools/computer.d.ts +1 -1
  63. package/mcp-server/dist/tools/computer.d.ts.map +1 -1
  64. package/mcp-server/dist/tools/computer.js +1 -1
  65. package/mcp-server/dist/tools/computer.js.map +1 -1
  66. package/mcp-server/dist/tools/discord-channel.d.ts +1 -1
  67. package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -1
  68. package/mcp-server/dist/tools/discord-channel.js +1 -1
  69. package/mcp-server/dist/tools/discord-channel.js.map +1 -1
  70. package/mcp-server/dist/tools/discord-guild.d.ts +1 -1
  71. package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -1
  72. package/mcp-server/dist/tools/discord-guild.js +1 -1
  73. package/mcp-server/dist/tools/discord-guild.js.map +1 -1
  74. package/mcp-server/dist/tools/discord-member.d.ts +1 -1
  75. package/mcp-server/dist/tools/discord-member.d.ts.map +1 -1
  76. package/mcp-server/dist/tools/discord-member.js +1 -1
  77. package/mcp-server/dist/tools/discord-member.js.map +1 -1
  78. package/mcp-server/dist/tools/discord-message.d.ts +1 -1
  79. package/mcp-server/dist/tools/discord-message.d.ts.map +1 -1
  80. package/mcp-server/dist/tools/discord-message.js +1 -1
  81. package/mcp-server/dist/tools/discord-message.js.map +1 -1
  82. package/mcp-server/dist/tools/discord-onboarding.d.ts +1 -1
  83. package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -1
  84. package/mcp-server/dist/tools/discord-onboarding.js +1 -1
  85. package/mcp-server/dist/tools/discord-onboarding.js.map +1 -1
  86. package/mcp-server/dist/tools/discord-role.d.ts +1 -1
  87. package/mcp-server/dist/tools/discord-role.d.ts.map +1 -1
  88. package/mcp-server/dist/tools/discord-role.js +1 -1
  89. package/mcp-server/dist/tools/discord-role.js.map +1 -1
  90. package/mcp-server/dist/tools/discord-thread.d.ts +1 -1
  91. package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -1
  92. package/mcp-server/dist/tools/discord-thread.js +1 -1
  93. package/mcp-server/dist/tools/discord-thread.js.map +1 -1
  94. package/mcp-server/dist/tools/discord-webhook.d.ts +1 -1
  95. package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -1
  96. package/mcp-server/dist/tools/discord-webhook.js +1 -1
  97. package/mcp-server/dist/tools/discord-webhook.js.map +1 -1
  98. package/mcp-server/dist/tools/fb-groups.d.ts +1 -1
  99. package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -1
  100. package/mcp-server/dist/tools/fb-groups.js +1 -1
  101. package/mcp-server/dist/tools/fb-groups.js.map +1 -1
  102. package/mcp-server/dist/tools/forget.d.ts +1 -1
  103. package/mcp-server/dist/tools/forget.d.ts.map +1 -1
  104. package/mcp-server/dist/tools/forget.js +1 -1
  105. package/mcp-server/dist/tools/forget.js.map +1 -1
  106. package/mcp-server/dist/tools/git-tools.d.ts +1 -1
  107. package/mcp-server/dist/tools/git-tools.d.ts.map +1 -1
  108. package/mcp-server/dist/tools/git-tools.js +1 -1
  109. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  110. package/mcp-server/dist/tools/gsc/experience.d.ts +1 -1
  111. package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -1
  112. package/mcp-server/dist/tools/gsc/experience.js +1 -1
  113. package/mcp-server/dist/tools/gsc/experience.js.map +1 -1
  114. package/mcp-server/dist/tools/gsc/indexing.d.ts +1 -1
  115. package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -1
  116. package/mcp-server/dist/tools/gsc/indexing.js +1 -1
  117. package/mcp-server/dist/tools/gsc/indexing.js.map +1 -1
  118. package/mcp-server/dist/tools/gsc/inspect.d.ts +1 -1
  119. package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -1
  120. package/mcp-server/dist/tools/gsc/inspect.js +1 -1
  121. package/mcp-server/dist/tools/gsc/inspect.js.map +1 -1
  122. package/mcp-server/dist/tools/gsc/navigate.d.ts +1 -1
  123. package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -1
  124. package/mcp-server/dist/tools/gsc/navigate.js +1 -1
  125. package/mcp-server/dist/tools/gsc/navigate.js.map +1 -1
  126. package/mcp-server/dist/tools/gsc/performance.d.ts +1 -1
  127. package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -1
  128. package/mcp-server/dist/tools/gsc/performance.js +1 -1
  129. package/mcp-server/dist/tools/gsc/performance.js.map +1 -1
  130. package/mcp-server/dist/tools/gsc/settings.d.ts +1 -1
  131. package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -1
  132. package/mcp-server/dist/tools/gsc/settings.js +1 -1
  133. package/mcp-server/dist/tools/gsc/settings.js.map +1 -1
  134. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  135. package/mcp-server/dist/tools/image-tools.d.ts.map +1 -1
  136. package/mcp-server/dist/tools/image-tools.js +1 -1
  137. package/mcp-server/dist/tools/image-tools.js.map +1 -1
  138. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +1 -1
  139. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -1
  140. package/mcp-server/dist/tools/leonardo-browser-tools.js +1 -1
  141. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -1
  142. package/mcp-server/dist/tools/loop.d.ts +1 -1
  143. package/mcp-server/dist/tools/loop.d.ts.map +1 -1
  144. package/mcp-server/dist/tools/loop.js +1 -1
  145. package/mcp-server/dist/tools/loop.js.map +1 -1
  146. package/mcp-server/dist/tools/memories.d.ts +1 -1
  147. package/mcp-server/dist/tools/memories.d.ts.map +1 -1
  148. package/mcp-server/dist/tools/memories.js +1 -1
  149. package/mcp-server/dist/tools/memories.js.map +1 -1
  150. package/mcp-server/dist/tools/morelogin.d.ts +1 -1
  151. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  152. package/mcp-server/dist/tools/morelogin.js +1 -1
  153. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  154. package/mcp-server/dist/tools/profile.d.ts +1 -1
  155. package/mcp-server/dist/tools/profile.d.ts.map +1 -1
  156. package/mcp-server/dist/tools/profile.js +1 -1
  157. package/mcp-server/dist/tools/profile.js.map +1 -1
  158. package/mcp-server/dist/tools/recall.d.ts +1 -1
  159. package/mcp-server/dist/tools/recall.d.ts.map +1 -1
  160. package/mcp-server/dist/tools/recall.js +1 -1
  161. package/mcp-server/dist/tools/recall.js.map +1 -1
  162. package/mcp-server/dist/tools/reflect.d.ts +1 -1
  163. package/mcp-server/dist/tools/reflect.d.ts.map +1 -1
  164. package/mcp-server/dist/tools/reflect.js +1 -1
  165. package/mcp-server/dist/tools/reflect.js.map +1 -1
  166. package/mcp-server/dist/tools/remember.d.ts +1 -1
  167. package/mcp-server/dist/tools/remember.d.ts.map +1 -1
  168. package/mcp-server/dist/tools/remember.js +13 -11
  169. package/mcp-server/dist/tools/remember.js.map +1 -1
  170. package/mcp-server/dist/tools/restore.d.ts +1 -1
  171. package/mcp-server/dist/tools/restore.d.ts.map +1 -1
  172. package/mcp-server/dist/tools/restore.js +1 -1
  173. package/mcp-server/dist/tools/restore.js.map +1 -1
  174. package/mcp-server/dist/tools/style-guide-tools.d.ts +1 -1
  175. package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -1
  176. package/mcp-server/dist/tools/style-guide-tools.js +1 -1
  177. package/mcp-server/dist/tools/style-guide-tools.js.map +1 -1
  178. package/mcp-server/dist/tools/sync.d.ts +1 -1
  179. package/mcp-server/dist/tools/sync.d.ts.map +1 -1
  180. package/mcp-server/dist/tools/sync.js +1 -1
  181. package/mcp-server/dist/tools/sync.js.map +1 -1
  182. package/mcp-server/dist/tools/tictactoe-tools.d.ts +1 -1
  183. package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -1
  184. package/mcp-server/dist/tools/tictactoe-tools.js +1 -1
  185. package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -1
  186. package/mcp-server/dist/tools/utils.d.ts +1 -1
  187. package/mcp-server/dist/tools/utils.d.ts.map +1 -1
  188. package/mcp-server/dist/tools/utils.js +1 -1
  189. package/mcp-server/dist/tools/utils.js.map +1 -1
  190. package/mcp-server/dist/tools/whatsapp-send-file.d.ts +1 -1
  191. package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -1
  192. package/mcp-server/dist/tools/whatsapp-send-file.js +1 -1
  193. package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -1
  194. package/mcp-server/dist/tools/whiteboard-tools.d.ts +3 -3
  195. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  196. package/mcp-server/dist/tools/whiteboard-tools.js +1 -1
  197. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  198. package/mcp-server/dist/tools/youtube/analytics.d.ts +1 -1
  199. package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -1
  200. package/mcp-server/dist/tools/youtube/analytics.js +1 -1
  201. package/mcp-server/dist/tools/youtube/analytics.js.map +1 -1
  202. package/mcp-server/dist/tools/youtube/download.d.ts +1 -1
  203. package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -1
  204. package/mcp-server/dist/tools/youtube/download.js +1 -1
  205. package/mcp-server/dist/tools/youtube/download.js.map +1 -1
  206. package/mcp-server/dist/tools/youtube/media.d.ts +1 -1
  207. package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -1
  208. package/mcp-server/dist/tools/youtube/media.js +1 -1
  209. package/mcp-server/dist/tools/youtube/media.js.map +1 -1
  210. package/mcp-server/dist/tools/youtube/metadata.d.ts +1 -1
  211. package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -1
  212. package/mcp-server/dist/tools/youtube/metadata.js +1 -1
  213. package/mcp-server/dist/tools/youtube/metadata.js.map +1 -1
  214. package/mcp-server/dist/tools/youtube/navigate.d.ts +1 -1
  215. package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -1
  216. package/mcp-server/dist/tools/youtube/navigate.js +1 -1
  217. package/mcp-server/dist/tools/youtube/navigate.js.map +1 -1
  218. package/mcp-server/dist/tools/youtube/playlist.d.ts +1 -1
  219. package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -1
  220. package/mcp-server/dist/tools/youtube/playlist.js +1 -1
  221. package/mcp-server/dist/tools/youtube/playlist.js.map +1 -1
  222. package/mcp-server/dist/tools/youtube/schedule.d.ts +1 -1
  223. package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -1
  224. package/mcp-server/dist/tools/youtube/schedule.js +1 -1
  225. package/mcp-server/dist/tools/youtube/schedule.js.map +1 -1
  226. package/mcp-server/dist/tools/youtube/source.d.ts +1 -1
  227. package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -1
  228. package/mcp-server/dist/tools/youtube/source.js +1 -1
  229. package/mcp-server/dist/tools/youtube/source.js.map +1 -1
  230. package/mcp-server/dist/tools/youtube/upload.d.ts +1 -1
  231. package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -1
  232. package/mcp-server/dist/tools/youtube/upload.js +4 -9
  233. package/mcp-server/dist/tools/youtube/upload.js.map +1 -1
  234. package/mcp-server/dist/tui.js +16 -4
  235. package/mcp-server/dist/tui.js.map +1 -1
  236. package/mcp-server/package-lock.json +3 -3
  237. package/mcp-server/package.json +3 -3
  238. package/mcp-server/src/services/browser-bench.ts +1 -1
  239. package/mcp-server/src/services/categories.ts +77 -32
  240. package/mcp-server/src/services/desktop-bench.ts +1 -1
  241. package/mcp-server/src/tools/agents.ts +1 -1
  242. package/mcp-server/src/tools/bluesky.ts +1 -1
  243. package/mcp-server/src/tools/browser-advanced.ts +1 -1
  244. package/mcp-server/src/tools/browser-batch.ts +1 -1
  245. package/mcp-server/src/tools/browser-cheatsheet.ts +1 -1
  246. package/mcp-server/src/tools/browser-interact.ts +1 -1
  247. package/mcp-server/src/tools/browser-navigate.ts +1 -1
  248. package/mcp-server/src/tools/browser-observe.ts +1 -1
  249. package/mcp-server/src/tools/card-tools.ts +1 -1
  250. package/mcp-server/src/tools/category.ts +6 -1
  251. package/mcp-server/src/tools/choice.ts +1 -1
  252. package/mcp-server/src/tools/computer.ts +1 -1
  253. package/mcp-server/src/tools/discord-channel.ts +1 -1
  254. package/mcp-server/src/tools/discord-guild.ts +1 -1
  255. package/mcp-server/src/tools/discord-member.ts +1 -1
  256. package/mcp-server/src/tools/discord-message.ts +1 -1
  257. package/mcp-server/src/tools/discord-onboarding.ts +1 -1
  258. package/mcp-server/src/tools/discord-role.ts +1 -1
  259. package/mcp-server/src/tools/discord-thread.ts +1 -1
  260. package/mcp-server/src/tools/discord-webhook.ts +1 -1
  261. package/mcp-server/src/tools/fb-groups.ts +1 -1
  262. package/mcp-server/src/tools/forget.ts +1 -1
  263. package/mcp-server/src/tools/git-tools.ts +1 -1
  264. package/mcp-server/src/tools/gsc/experience.ts +1 -1
  265. package/mcp-server/src/tools/gsc/indexing.ts +1 -1
  266. package/mcp-server/src/tools/gsc/inspect.ts +1 -1
  267. package/mcp-server/src/tools/gsc/navigate.ts +1 -1
  268. package/mcp-server/src/tools/gsc/performance.ts +1 -1
  269. package/mcp-server/src/tools/gsc/settings.ts +1 -1
  270. package/mcp-server/src/tools/image-tools.ts +1 -1
  271. package/mcp-server/src/tools/leonardo-browser-tools.ts +1 -1
  272. package/mcp-server/src/tools/loop.ts +1 -1
  273. package/mcp-server/src/tools/memories.ts +1 -1
  274. package/mcp-server/src/tools/morelogin.ts +1 -1
  275. package/mcp-server/src/tools/profile.ts +1 -1
  276. package/mcp-server/src/tools/recall.ts +1 -1
  277. package/mcp-server/src/tools/reflect.ts +1 -1
  278. package/mcp-server/src/tools/remember.ts +13 -12
  279. package/mcp-server/src/tools/restore.ts +1 -1
  280. package/mcp-server/src/tools/style-guide-tools.ts +1 -1
  281. package/mcp-server/src/tools/sync.ts +1 -1
  282. package/mcp-server/src/tools/tictactoe-tools.ts +1 -1
  283. package/mcp-server/src/tools/utils.ts +1 -1
  284. package/mcp-server/src/tools/whatsapp-send-file.ts +1 -1
  285. package/mcp-server/src/tools/whiteboard-tools.ts +1 -1
  286. package/mcp-server/src/tools/youtube/analytics.ts +1 -1
  287. package/mcp-server/src/tools/youtube/download.ts +1 -1
  288. package/mcp-server/src/tools/youtube/media.ts +1 -1
  289. package/mcp-server/src/tools/youtube/metadata.ts +1 -1
  290. package/mcp-server/src/tools/youtube/navigate.ts +1 -1
  291. package/mcp-server/src/tools/youtube/playlist.ts +1 -1
  292. package/mcp-server/src/tools/youtube/schedule.ts +1 -1
  293. package/mcp-server/src/tools/youtube/source.ts +1 -1
  294. package/mcp-server/src/tools/youtube/upload.ts +4 -12
  295. package/mcp-server/src/tui.ts +22 -9
  296. package/neural-interface/i18n/en.json +18 -0
  297. package/neural-interface/i18n/pt-BR.json +18 -0
  298. package/neural-interface/lib/agent-sandbox-elevation.js +102 -0
  299. package/neural-interface/lib/agent-sandbox-setting.js +57 -0
  300. package/neural-interface/lib/assistant-api.js +19 -0
  301. package/neural-interface/lib/assistant-route-gate-codex.js +3 -1
  302. package/neural-interface/lib/assistant-runtime.js +5 -1
  303. package/neural-interface/lib/codex-account-auth.js +4 -2
  304. package/neural-interface/lib/codex-accounts.js +14 -1
  305. package/neural-interface/lib/codex-settings-schema.js +5 -3
  306. package/neural-interface/lib/exec-loop-command.js +3 -1
  307. package/neural-interface/lib/install-details.js +23 -5
  308. package/neural-interface/lib/native-loop-providers.js +6 -1
  309. package/neural-interface/lib/provider-panel-terminal-auth.js +3 -2
  310. package/neural-interface/lib/session-indexer.js +3 -1
  311. package/neural-interface/lib/session-title-generator.js +2 -0
  312. package/neural-interface/package-lock.json +2 -2
  313. package/neural-interface/package.json +1 -1
  314. package/neural-interface/public/shared/account-menu.js +4 -1
  315. package/neural-interface/public/shared/account-usage.js +62 -2
  316. package/neural-interface/public/shared/account-view.js +2 -1
  317. package/neural-interface/public/shared/assistant/asst-account-menu.js +298 -0
  318. package/neural-interface/public/shared/assistant/asst-api.js +7 -0
  319. package/neural-interface/public/shared/assistant/asst-brain-picker.js +232 -75
  320. package/neural-interface/public/shared/assistant/asst-menu.js +204 -77
  321. package/neural-interface/public/shared/assistant/asst-model-chip.js +135 -0
  322. package/neural-interface/public/shared/assistant/asst-panel.js +39 -2
  323. package/neural-interface/public/shared/assistant/asst-styles.js +66 -17
  324. package/neural-interface/public/shared/cdx/cdx-panel.js +1 -1
  325. package/neural-interface/public/shared/cdx/cdx-styles.js +45 -5
  326. package/neural-interface/public/shared/cdx/cdx-tabs.js +3 -0
  327. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -1
  328. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +4 -1
  329. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +51 -2
  330. package/neural-interface/public/shared/showcase-privacy.js +2 -1
  331. package/neural-interface/public/shared/styles.css +3 -1
  332. package/neural-interface/public/shared/ui-claude-panel.js +50 -4
  333. package/neural-interface/public/shared/ui-explorer.js +2 -0
  334. package/neural-interface/public/shared/ui-sync.js +2 -0
  335. package/neural-interface/public/shared/ui-update.js +4 -2
  336. package/neural-interface/scripts/rebuild-pty.js +14 -2
  337. package/neural-interface/server.js +180 -86
  338. package/npm-shrinkwrap.json +4424 -0
  339. package/package.json +54 -2
  340. package/postinstall.js +61 -47
  341. package/preuninstall.js +8 -35
  342. package/setup.js +76 -44
  343. package/skills/synabun/modules/idea.md +1 -1
  344. package/skills/synabun/modules/schedule.md +1 -1
  345. package/updater.cmd +2 -2
  346. package/updater.mjs +97 -3
@@ -12,6 +12,8 @@ import { createClaudeAccounts as createPanelClaudeAccounts } from './lib/claude-
12
12
  import { createClaudePanelAuth } from './lib/claude-panel-auth.js';
13
13
  import { createCodexPanelAuth } from './lib/codex-panel-auth.js';
14
14
  import { createCodexAccounts, applyCodexLaunchEnv, codexAppServerArgs, codexExecEnv } from './lib/codex-accounts.js';
15
+ import { codexWindowsSandbox, codexWindowsSandboxArgs } from './lib/agent-sandbox-elevation.js';
16
+ import { createAdminSandboxSetting } from './lib/agent-sandbox-setting.js';
15
17
  import { createCodexAccountAuth } from './lib/codex-account-auth.js';
16
18
  import { registerProviderPanelApiKeyAuthRoutes, redactProviderSecrets, providerApiKeyBodyError, providerDiagnosticSink } from './lib/provider-panel-api-key-auth.js';
17
19
  import { createProviderPanelTerminalAuth, providerLoginSpec, registerProviderPanelTerminalAuthRoutes } from './lib/provider-panel-terminal-auth.js';
@@ -272,11 +274,12 @@ import {
272
274
  clampPointsToRect as wbClampPointsToRect,
273
275
  convertPctInPlace as wbConvertPctInPlace,
274
276
  } from '../mcp-server/dist/services/whiteboard-geometry.js';
275
- import { ensureProjectCategories } from '../hooks/claude-code/shared.mjs';
277
+ import { ensureProjectCategories as ensureProjectCategoriesInFile, ensureCategories as ensureCategoriesInFile, FEATURE_CATEGORIES } from '../hooks/claude-code/shared.mjs';
276
278
  import { getDataHome, getDataHomeDiagnostics, isGlobalInstall, pathIsInside } from '../lib/paths.js';
277
279
  import { launcherLogPath } from '../lib/first-launch-protection.js';
278
280
  import { registerStartLauncher, startLauncherState } from '../lib/start-launcher.js';
279
281
  import { effectiveNpmPrefix } from '../lib/child-path.js';
282
+ import { checkRuntimeDependencies, fallbackInstallArgs, fallbackInstallEnv, findInstalled, mcpCompiler, npmCommand, npmInvocation } from '../lib/runtime-dependencies.js';
280
283
  import { redactDeep, redactSecrets } from '../lib/log-redact.js';
281
284
  import { applyPackagedChildPath, durableEntry, mcpStdioCommand, npmGlobalBinFor, packagedNpmPrefix, packagedPathFolders, packagedRuntime } from '../lib/packaged-runtime.js';
282
285
  import { dataHomeId } from '../lib/desktop-app.js';
@@ -328,11 +331,15 @@ const __dirname = dirname(__filename);
328
331
  // This sweeps ALL platform directories, not just this host's: a vendored
329
332
  // checkout can carry several, and repairing only the current one left e.g.
330
333
  // prebuilds/darwin-x64/spawn-helper broken for Intel Macs.
334
+ // Both node_modules an install can have: the package root's (`npm i -g synabun` puts every dependency there) and
335
+ // the Neural Interface's own (a development checkout, a desktop build).
331
336
  try {
332
- const sweep = ensureVendoredExecutables({ root: __dirname, log: (msg) => console.log(msg) });
333
- for (const failure of sweep.failed) {
334
- console.warn(`[binaries] ${failure.path} is not launchable (${failure.state}).`
335
- + (failure.repairCommand ? ` Try: ${failure.repairCommand}` : ''));
337
+ for (const root of new Set([__dirname, resolve(__dirname, '..')])) {
338
+ const sweep = ensureVendoredExecutables({ root, log: (msg) => console.log(msg) });
339
+ for (const failure of sweep.failed) {
340
+ console.warn(`[binaries] ${failure.path} is not launchable (${failure.state}).`
341
+ + (failure.repairCommand ? ` Try: ${failure.repairCommand}` : ''));
342
+ }
336
343
  }
337
344
  } catch (err) {
338
345
  console.warn('[binaries] Could not verify vendored binary permissions:', err.message);
@@ -538,49 +545,31 @@ const GLOBAL_CATEGORIES_PATH = resolve(CATEGORIES_DATA_DIR, 'custom-categories.j
538
545
  const NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
539
546
  const CATEGORIES_POINT_ID = '00000000-0000-0000-0000-000000000000';
540
547
 
541
- // Default categories seeded on first startup (new connection)
542
- // Must stay in sync with hooks/claude-code/shared.mjs STANDALONE_DEFAULTS
543
- const DEFAULT_CATEGORIES = [
544
- {
545
- name: 'uncategorized',
546
- description: 'Fallback category for memories stored without an explicit category. Any memory whose category is null, undefined, or empty is automatically assigned here during data normalization. Ensures every memory is always categorized for filtering, sidebar visibility toggling, and graph rendering.',
547
- color: '#6b7280',
548
- },
549
- {
550
- name: 'conversations',
551
- description: 'Indexed conversation sessions with compacted summaries for cross-session recall. Stores session metadata (date, branch, session ID, file path) and topic summaries so users can search and retrieve past conversations naturally — e.g. "what did we work on yesterday?" or "remember that conversation about auth?"',
552
- color: '#a855f7',
553
- is_parent: true,
554
- },
555
- {
556
- name: 'communication-style',
557
- description: 'User communication patterns and preferences.',
558
- },
559
- {
560
- name: 'plans',
561
- description: 'Implementation plans stored after plan mode approval.',
562
- color: '#06d6a0',
563
- is_parent: true,
564
- },
565
- {
566
- name: 'ideas',
567
- description: 'Feature ideas, product concepts, brainstorms, and future plans. A general-purpose category for capturing forward-looking thoughts that haven\'t been implemented yet — new features to build, architectural experiments to try, UX improvements to explore, or any creative concept worth revisiting later.',
568
- color: '#f59e0b',
569
- },
570
- ];
571
-
548
+ // No default categories: a fresh install has none. A project's defaults are made
549
+ // when the project is added (ensureProjectCategories), a feature's category the
550
+ // first time the feature saves into it.
572
551
  function getCategoriesPath() {
573
552
  // Single categories file — no per-connection paths needed with SQLite
574
- if (!existsSync(GLOBAL_CATEGORIES_PATH)) {
575
- const dir = resolve(GLOBAL_CATEGORIES_PATH, '..');
576
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
577
- writeFileSync(GLOBAL_CATEGORIES_PATH, JSON.stringify({ version: 1, categories: DEFAULT_CATEGORIES }, null, 2), 'utf-8');
578
- }
579
-
580
553
  return GLOBAL_CATEGORIES_PATH;
581
554
  }
582
555
 
556
+ // The file not written yet: what SQLite (the source of truth) holds, which is nothing on a fresh install.
557
+ function categoriesFromDb() {
558
+ try {
559
+ return dbGetCategories().map((row) => {
560
+ const category = { name: row.name, description: row.description || '', created_at: row.created_at };
561
+ if (row.parent) category.parent = row.parent;
562
+ if (row.color) category.color = row.color;
563
+ if (row.is_parent) category.is_parent = true;
564
+ return category;
565
+ });
566
+ } catch {
567
+ return [];
568
+ }
569
+ }
570
+
583
571
  function loadCategories() {
572
+ if (!existsSync(GLOBAL_CATEGORIES_PATH)) return categoriesFromDb();
584
573
  try {
585
574
  const raw = readFileSync(getCategoriesPath(), 'utf-8');
586
575
  const data = JSON.parse(raw);
@@ -593,6 +582,27 @@ function loadCategories() {
593
582
  }
594
583
  }
595
584
 
585
+ // The categories file is written by the hooks' helpers (the file the MCP server watches); SQLite gets a copy, as with every other category write.
586
+ function syncCategoriesToDb(created) {
587
+ if (!created?.length) return created || [];
588
+ try { dbSaveCategories(loadCategories()); } catch (err) { console.error('Failed to sync categories to SQLite:', err.message); }
589
+ return created;
590
+ }
591
+
592
+ // A project's default categories (parent + project / architecture / bugs / config), made once, when the project is
593
+ // registered; never for a project already in the registry. Adds what is missing only.
594
+ function ensureProjectCategories(projects) {
595
+ return syncCategoriesToDb(ensureProjectCategoriesInFile(projects).created);
596
+ }
597
+
598
+ // A feature's own category (FEATURE_CATEGORIES: conversations, communication-style, plans, uncategorized), made the
599
+ // first time the feature saves into it; a fresh install has none. Adds it only when it is missing.
600
+ function ensureFeatureCategory(name) {
601
+ const feature = Object.prototype.hasOwnProperty.call(FEATURE_CATEGORIES, name) ? FEATURE_CATEGORIES[name] : null;
602
+ if (!feature) return [];
603
+ return syncCategoriesToDb(ensureCategoriesInFile([{ name, description: feature.description, is_parent: feature.is_parent }]).created);
604
+ }
605
+
596
606
  function saveCategories(categories) {
597
607
  const filePath = getCategoriesPath();
598
608
  const dir = resolve(filePath, '..');
@@ -2391,6 +2401,18 @@ function cleanupOldUpdaterStages(baseDir) {
2391
2401
  } catch {}
2392
2402
  }
2393
2403
 
2404
+ // lib/package-processes.js and the module it imports (only node: modules in either).
2405
+ const UPDATER_STAGED_LIBS = ['package-processes.js', 'runtime-dependencies.js'];
2406
+
2407
+ // The forms of the package folder this server knows: as it resolved it, and as it was started
2408
+ // (`node <prefix>\node_modules\synabun\neural-interface\server.js` through a junction or a link).
2409
+ function updaterPackageRoots() {
2410
+ const roots = [PACKAGE_ROOT];
2411
+ const started = process.argv[1] ? resolve(process.argv[1]) : '';
2412
+ if (basename(started) === 'server.js' && basename(dirname(started)) === 'neural-interface') roots.push(resolve(started, '..', '..'));
2413
+ return [...new Set(roots)];
2414
+ }
2415
+
2394
2416
  function stageSynabunUpdater({ installPlan, serverPid, autoRestart, cleanupPids = [], safetySnapshot = null, handoffPath = null }) {
2395
2417
  const sourceUpdater = resolve(PACKAGE_ROOT, 'updater.mjs');
2396
2418
  if (!existsSync(sourceUpdater)) {
@@ -2408,6 +2430,16 @@ function stageSynabunUpdater({ installPlan, serverPid, autoRestart, cleanupPids
2408
2430
  const payloadPath = resolve(stageDir, 'payload.json');
2409
2431
  const runnerPath = resolve(stageDir, process.platform === 'win32' ? 'run-update.cmd' : 'run-update.sh');
2410
2432
  copyFileSync(sourceUpdater, stagedUpdater);
2433
+ // What updater.mjs imports on Windows to stop the processes AI clients started from this folder: staged as lib/
2434
+ // next to it, with a package.json that makes those .js files ES modules on every Node SynaBun runs on. One that
2435
+ // cannot be copied leaves the updater without that step, never without the update.
2436
+ try {
2437
+ mkdirSync(resolve(stageDir, 'lib'), { recursive: true });
2438
+ writeFileSync(resolve(stageDir, 'lib', 'package.json'), '{ "type": "module" }\n', 'utf8');
2439
+ for (const file of UPDATER_STAGED_LIBS) copyFileSync(resolve(PACKAGE_ROOT, 'lib', file), resolve(stageDir, 'lib', file));
2440
+ } catch (err) {
2441
+ console.warn(`[server] could not stage lib/ for the updater: ${err?.message}`);
2442
+ }
2411
2443
 
2412
2444
  const payload = {
2413
2445
  serverPid,
@@ -2419,6 +2451,9 @@ function stageSynabunUpdater({ installPlan, serverPid, autoRestart, cleanupPids
2419
2451
  target: installPlan.target,
2420
2452
  channel: installPlan.channel,
2421
2453
  cleanupPids,
2454
+ // The folder `npm i -g` replaces, in every form known here: on Windows the updater stops what still runs from it.
2455
+ packageRoot: PACKAGE_ROOT,
2456
+ packageRoots: updaterPackageRoots(),
2422
2457
  safetySnapshot,
2423
2458
  handoffPath,
2424
2459
  // Where the relaunched launcher leaves its reason if it stops.
@@ -3708,6 +3743,25 @@ function readCodexRuntimeModelCatalog(codexHome = CODEX_DEFAULT_HOME) {
3708
3743
  }
3709
3744
  const CODEX_ACCOUNTS_PATH = resolve(DATA_HOME, 'data', 'codex-accounts.json');
3710
3745
 
3746
+ // Admin sandbox (lib/agent-sandbox-setting.js, lib/agent-sandbox-elevation.js): one global value,
3747
+ // off by default, for every agent SynaBun starts: may it use a sandbox whose setup needs Windows
3748
+ // administrator approval. Codex is the provider it changes (windows.sandbox, a launch override on
3749
+ // every Codex process, never written into config.toml). Changed from the Assistant panel only; idle
3750
+ // Codex app-servers (panel tabs, the Assistant's brain) restart under it, busy ones keep theirs.
3751
+ const _agentSandbox = createAdminSandboxSetting({
3752
+ path: resolve(DATA_HOME, 'data', 'agent-sandbox.json'),
3753
+ broadcast: (message) => broadcastSync(message),
3754
+ log: (tag, message) => console.log(`[${tag}]`, message),
3755
+ });
3756
+ function adminSandboxOn() { return _agentSandbox.enabled(); }
3757
+ /** The `-c` words every Codex SynaBun starts gets for the setting (outside an account's launch plan). */
3758
+ function codexSandboxArgs() { return codexWindowsSandboxArgs(adminSandboxOn()); }
3759
+ _agentSandbox.subscribe(() => {
3760
+ for (const connection of [..._codexLiveConnections]) {
3761
+ if (!connection.busy()) { try { connection.credentialsChanged(); } catch {} }
3762
+ }
3763
+ });
3764
+
3711
3765
  // The Codex accounts registry (lib/codex-accounts.js): one instance for the
3712
3766
  // sidepanel, the Assistant (brain, workers, catalog), loops and every route, so
3713
3767
  // one account state is shown everywhere. Its ChatGPT half is Codex's own
@@ -3721,6 +3775,8 @@ function _codexAccounts() {
3721
3775
  dataHome: DATA_HOME, homeDir: getHomePath(), accountsRoot: CODEX_ACCOUNTS_ROOT,
3722
3776
  readNativeStatus: (accountId) => codexAccountAuth().nativeStatus(accountId),
3723
3777
  prepareDefaultConfig: () => ensureCanonicalCodexConfig({ strict: true }),
3778
+ // Every launch plan carries the Windows sandbox the Admin sandbox setting allows.
3779
+ adminSandbox: () => adminSandboxOn(),
3724
3780
  log: (tag, message) => console.log(`[${tag}]`, message),
3725
3781
  });
3726
3782
  _codexAccountsInstance.subscribe((event) => {
@@ -3850,6 +3906,8 @@ function handleCodexSkinWebSocket(ws) {
3850
3906
  let childUsesHeldKey = false;
3851
3907
  // Which credential the running app-server started with (launchFor().credential).
3852
3908
  let childCredential = null;
3909
+ // Which Windows sandbox it started with (launchFor().windowsSandbox, the Admin sandbox setting).
3910
+ let childWindowsSandbox = null;
3853
3911
  const CODEX_GREETING_MARKER_START = '[SYNABUN_CODEX_GREETING_START]';
3854
3912
  const CODEX_GREETING_MARKER_END = '[SYNABUN_CODEX_GREETING_END]';
3855
3913
  const CODEX_PLAN_MODE_PREFIXES = [
@@ -4092,12 +4150,12 @@ CRITICAL — When you need clarification during planning:
4092
4150
  sendToClient({ type: 'account_state', accountId: activeAccountId, account: _codexAccounts().describeForClient(activeAccountId), accounts: listCodexAccountsForClient() });
4093
4151
  }
4094
4152
 
4095
- // The account's credential or mode changed (withCodexAccountCredentialChange): an idle
4096
- // app-server is retired, and the next request starts one under the new credential; the
4097
- // conversation resumes from its thread then. The transcript stays.
4153
+ // The account's credential or mode changed (withCodexAccountCredentialChange), or the Admin
4154
+ // sandbox setting did: an idle app-server is retired, and the next request starts one under
4155
+ // the new launch plan; the conversation resumes from its thread then. The transcript stays.
4098
4156
  function retireForCredentialChange() {
4099
4157
  const next = _codexAccounts().launchFor(activeAccountId);
4100
- if (child && !activeTurnId && !pendingServerRequests.size && (!next.ok || next.credential !== childCredential)) {
4158
+ if (child && !activeTurnId && !pendingServerRequests.size && (!next.ok || next.credential !== childCredential || next.windowsSandbox !== childWindowsSandbox)) {
4101
4159
  const old = child;
4102
4160
  const oldHome = activeCodexHome;
4103
4161
  const oldThreadIds = ownedWriterThreadIds();
@@ -4118,6 +4176,7 @@ CRITICAL — When you need clarification during planning:
4118
4176
  unregisterCodexMcpProfileRuntime();
4119
4177
  child = null;
4120
4178
  childCredential = null;
4179
+ childWindowsSandbox = null;
4121
4180
  retireCodexProcess(old, { codexHome: oldHome, threadIds: oldThreadIds, reason: 'Codex account sign-in changed' });
4122
4181
  }
4123
4182
  sendAccountState();
@@ -5183,7 +5242,8 @@ CRITICAL — When you need clarification during planning:
5183
5242
  args.unshift(codexBin);
5184
5243
  codexBin = process.execPath;
5185
5244
  }
5186
- // API-key mode with a key SynaBun holds: an ephemeral credential store, before the subcommand.
5245
+ // The Windows sandbox the Admin sandbox setting allows and, in API-key mode with a key SynaBun
5246
+ // holds, an ephemeral credential store: before the subcommand.
5187
5247
  args.splice(args.length - 1, 0, ...codexAppServerArgs(launch));
5188
5248
  const useShell = !codexBin.includes(sep)
5189
5249
  || (process.platform === 'win32' && /\.(cmd|bat)$/i.test(codexBin));
@@ -5212,10 +5272,11 @@ CRITICAL — When you need clarification during planning:
5212
5272
  childApiKeyLogin = launch.apiKey || null;
5213
5273
  childUsesHeldKey = !!launch.apiKey;
5214
5274
  childCredential = launch.credential;
5275
+ childWindowsSandbox = launch.windowsSandbox;
5215
5276
  childRetirementPromise = null;
5216
5277
  writerLifecycleState.releaseRequested = false;
5217
5278
  registerCodexMcpProfileRuntime();
5218
- console.log(`[codex-skin] Spawned app-server pid ${proc.pid || '?'} account=${activeAccountId} mode=${launch.mode || 'none'} profile=${codexMcpProfileState.value} runtime=${codexMcpRuntimeId} CODEX_HOME=${activeCodexHome}`);
5279
+ console.log(`[codex-skin] Spawned app-server pid ${proc.pid || '?'} account=${activeAccountId} mode=${launch.mode || 'none'} windowsSandbox=${launch.windowsSandbox} profile=${codexMcpProfileState.value} runtime=${codexMcpRuntimeId} CODEX_HOME=${activeCodexHome}`);
5219
5280
  proc.stdout.setEncoding('utf-8');
5220
5281
  proc.stdout.on('data', (chunk) => {
5221
5282
  if (child !== proc) return; // stale process from a previous account
@@ -5485,7 +5546,7 @@ CRITICAL — When you need clarification during planning:
5485
5546
  const versionResult = spawnSync(codexBin, ['--version'], { encoding: 'utf-8', timeout: 5000, windowsHide: true });
5486
5547
  cliVersion = parseCodexVersion(versionResult.stdout);
5487
5548
  } catch {}
5488
- try { sdkVersion = JSON.parse(readFileSync(join(__dirname, 'node_modules', '@openai', 'codex-sdk', 'package.json'), 'utf-8')).version; } catch {}
5549
+ sdkVersion = findInstalled(__dirname, '@openai/codex-sdk', { stopAt: PACKAGE_ROOT })?.version || null;
5489
5550
  codexCapabilities.reset({ codexBin, codexBinSource: _codexBinSource, cliVersion, sdkVersion });
5490
5551
  startChild();
5491
5552
  bootPromise = request('initialize', {
@@ -7382,7 +7443,8 @@ async function queryCodexAppServerModels(codexHome = CODEX_DEFAULT_HOME, launch
7382
7443
  ensureCanonicalCodexConfig({ strict: true, codexHome: launch?.home || codexHome });
7383
7444
  // The Codex the resolver found (Settings' path first); a command line in Settings ("wsl codex") as written.
7384
7445
  let codexBin = configuredCommandLine('codex') || getCodexBin();
7385
- const args = [...(launch?.ok ? codexAppServerArgs(launch) : []), 'app-server'];
7446
+ // Without an account's launch plan, still the Windows sandbox the Admin sandbox setting allows.
7447
+ const args = [...(launch?.ok ? codexAppServerArgs(launch) : codexSandboxArgs()), 'app-server'];
7386
7448
  if (!/\s/.test(codexBin) && /\.js$/i.test(codexBin)) {
7387
7449
  args.unshift(codexBin);
7388
7450
  codexBin = process.execPath;
@@ -9067,6 +9129,7 @@ app.post('/api/sidepanel/session-title', async (req, res) => {
9067
9129
  execFile: execFileAsync,
9068
9130
  getCodexBin,
9069
9131
  getCodexAccountHome,
9132
+ codexConfigArgs: codexSandboxArgs,
9070
9133
  getAugmentedPath,
9071
9134
  ensureOpenCode: ensureOpencodeServer,
9072
9135
  openCodeClient: opencodeV2Client,
@@ -13497,6 +13560,8 @@ app.post('/api/loop/launch', async (req, res) => {
13497
13560
  mcpProfile: cliMcpProfile,
13498
13561
  codexAccountId: codexAccount?.id || null,
13499
13562
  codexHome: codexAccount ? (codexAccount.home || CODEX_DEFAULT_HOME) : null,
13563
+ // A Codex exec loop keeps the Admin sandbox setting it started with (every iteration is its own `codex exec`).
13564
+ adminSandbox: cliProfile === 'codex' ? adminSandboxOn() : undefined,
13500
13565
  // Continuation mechanism. 'hook': Claude Code ONLY — the Stop/UserPromptSubmit hooks in
13501
13566
  // .claude/ set awaitingNext and attachLoopDriver() drives /clear + re-prompt; if those
13502
13567
  // hooks are absent (e.g. a claude-code task run under a hookless harness) the loop STALLS.
@@ -14495,6 +14560,8 @@ async function launchScheduledLoop(schedule) {
14495
14560
  mcpProfile: cliMcpProfile || null,
14496
14561
  codexAccountId: codexAccount?.id || null,
14497
14562
  codexHome: codexAccount ? (codexAccount.home || CODEX_DEFAULT_HOME) : null,
14563
+ // A Codex exec loop keeps the Admin sandbox setting it started with (every iteration is its own `codex exec`).
14564
+ adminSandbox: cliProfile === 'codex' ? adminSandboxOn() : undefined,
14498
14565
  driverType: nativeRuntime ? 'native' : (cliProfile === 'claude-code' ? 'hook' : 'exec'),
14499
14566
  runtimeType: nativeRuntime ? 'native' : 'pty',
14500
14567
  surface: nativeRuntime ? 'sidepanel' : 'terminal',
@@ -17150,12 +17217,13 @@ app.post('/api/system/restore', async (req, res) => {
17150
17217
  const mcpDistCheck = resolve(PACKAGE_ROOT, 'mcp-server', 'dist', 'index.js');
17151
17218
  if (!existsSync(mcpDistCheck)) {
17152
17219
  try {
17153
- // Ensure dev deps are installed for TypeScript
17220
+ // TypeScript is a devDependency of the package root (a development checkout also has it in mcp-server/).
17154
17221
  const mcpDir = resolve(PACKAGE_ROOT, 'mcp-server');
17155
- if (!existsSync(resolve(mcpDir, 'node_modules', 'typescript'))) {
17156
- execSync('npm install', { cwd: mcpDir, stdio: 'pipe', timeout: 180_000, env: withPackagedPathLast({ ...process.env, NODE_ENV: 'development' }) });
17222
+ if (!mcpCompiler(PACKAGE_ROOT)) {
17223
+ const npm = npmCommand(npmInvocation(), fallbackInstallArgs({ includeDev: true }));
17224
+ await execFileAsync(npm.file, npm.args, { cwd: PACKAGE_ROOT, timeout: 600_000, maxBuffer: 16 * 1024 * 1024, shell: npm.shell, windowsHide: true, env: withPackagedPathLast(fallbackInstallEnv({ ...process.env, NODE_ENV: 'development' })) });
17157
17225
  }
17158
- execSync('npm run build', { cwd: mcpDir, stdio: 'pipe', timeout: 60_000, env: withPackagedPathLast(process.env) });
17226
+ await execFileAsync(process.execPath, [mcpCompiler(PACKAGE_ROOT), '-p', mcpDir], { cwd: mcpDir, timeout: 120_000, maxBuffer: 16 * 1024 * 1024, windowsHide: true });
17159
17227
  results.files.push('(auto-built MCP server)');
17160
17228
  } catch (buildErr) {
17161
17229
  results.errors.push(`MCP server auto-build failed: ${buildErr.message}`);
@@ -18421,29 +18489,34 @@ app.post('/api/setup/build', async (req, res) => {
18421
18489
  const mcpDist = resolve(PACKAGE_ROOT, 'mcp-server', 'dist', 'index.js');
18422
18490
  const mcpNeedsBuild = !existsSync(mcpDist);
18423
18491
 
18424
- // Phase 1: npm install for each directory
18425
- for (const dir of dirs) {
18426
- const hasModules = existsSync(resolve(dir.path, 'node_modules'));
18427
- // If MCP server needs building, reinstall with dev deps even if node_modules exists
18428
- const isMcp = dir.name === 'MCP Server';
18429
- const needsDevDeps = isMcp && mcpNeedsBuild && !existsSync(resolve(dir.path, 'node_modules', 'typescript'));
18430
- if (hasModules && !needsDevDeps) {
18431
- send('install', { dir: dir.name, status: 'skipped', output: 'node_modules already present' });
18432
- continue;
18433
- }
18434
-
18435
- send('install', { dir: dir.name, status: 'start' });
18492
+ // Phase 1: the dependencies. `npm i -g synabun` installed them at the package root (lib/runtime-dependencies.js
18493
+ // checks that Node finds them from both parts); only what is missing is installed, once, at the package root,
18494
+ // and never inside a packaged application. A fresh checkout also needs the TypeScript that builds the MCP server.
18495
+ const report = checkRuntimeDependencies({ packageRoot: PACKAGE_ROOT });
18496
+ const compilerMissing = mcpNeedsBuild && !mcpCompiler(PACKAGE_ROOT);
18497
+ if (report.ok && !compilerMissing) {
18498
+ for (const dir of dirs) send('install', { dir: dir.name, status: 'skipped', output: 'dependencies already installed' });
18499
+ } else if (PACKAGED_RUNTIME) {
18500
+ for (const dir of dirs) send('install', { dir: dir.name, status: 'error', output: 'This application is incomplete: reinstall SynaBun.' });
18501
+ send('complete', { ok: false, error: 'The application is incomplete' });
18502
+ return res.end();
18503
+ } else {
18504
+ for (const dir of dirs) send('install', { dir: dir.name, status: 'start' });
18436
18505
  try {
18437
- // The user's own npm when they have one, a packaged application's after it (withPackagedPathLast).
18438
- const { stdout, stderr } = await execAsync('npm install', {
18439
- cwd: dir.path,
18440
- timeout: 180_000,
18441
- env: withPackagedPathLast({ ...process.env, NODE_ENV: 'development' }),
18506
+ // The npm that started SynaBun, else the user's own on PATH, else the one next to this Node (npmInvocation).
18507
+ const npm = npmCommand(npmInvocation(), fallbackInstallArgs({ includeDev: mcpNeedsBuild }));
18508
+ const { stdout } = await execFileAsync(npm.file, npm.args, {
18509
+ cwd: PACKAGE_ROOT,
18510
+ timeout: 600_000,
18511
+ maxBuffer: 16 * 1024 * 1024,
18512
+ shell: npm.shell,
18513
+ windowsHide: true,
18514
+ env: withPackagedPathLast(fallbackInstallEnv({ ...process.env, NODE_ENV: 'development' })),
18442
18515
  });
18443
- send('install', { dir: dir.name, status: 'done', output: tail(stdout) });
18516
+ for (const dir of dirs) send('install', { dir: dir.name, status: 'done', output: tail(stdout) });
18444
18517
  } catch (err) {
18445
- send('install', { dir: dir.name, status: 'error', output: tail(err.stderr || err.message) });
18446
- send('complete', { ok: false, error: `npm install failed for ${dir.name}` });
18518
+ for (const dir of dirs) send('install', { dir: dir.name, status: 'error', output: tail(err.stderr || err.message) });
18519
+ send('complete', { ok: false, error: 'npm install failed in the package root' });
18447
18520
  return res.end();
18448
18521
  }
18449
18522
  }
@@ -18460,10 +18533,14 @@ app.post('/api/setup/build', async (req, res) => {
18460
18533
  } else {
18461
18534
  send('build', { status: 'start' });
18462
18535
  try {
18463
- const { stdout, stderr } = await execAsync('npm run build', {
18536
+ // The TypeScript Node finds from mcp-server/ (the root's devDependency in a fresh checkout), by this Node.
18537
+ const tsc = mcpCompiler(PACKAGE_ROOT);
18538
+ if (!tsc) throw new Error('TypeScript is not installed: npm install in the package root installs it');
18539
+ const { stdout } = await execFileAsync(process.execPath, [tsc, '-p', resolve(PACKAGE_ROOT, 'mcp-server')], {
18464
18540
  cwd: resolve(PACKAGE_ROOT, 'mcp-server'),
18465
- timeout: 60_000,
18466
- env: withPackagedPathLast(process.env),
18541
+ timeout: 120_000,
18542
+ maxBuffer: 16 * 1024 * 1024,
18543
+ windowsHide: true,
18467
18544
  });
18468
18545
  send('build', { status: 'done', output: tail(stdout) });
18469
18546
  } catch (err) {
@@ -20547,7 +20624,7 @@ app.post('/api/session-indexing/mirror', async (req, res) => {
20547
20624
  try {
20548
20625
  await mirrorExistingChunks((event) => {
20549
20626
  try { broadcastSync(event); } catch {}
20550
- });
20627
+ }, { ensureCategory: () => ensureFeatureCategory('conversations') });
20551
20628
  } catch (err) {
20552
20629
  console.error('Mirror error:', err);
20553
20630
  try { broadcastSync({ type: 'mirror:error', error: err.message }); } catch {}
@@ -20686,16 +20763,15 @@ app.post('/api/claude-code/integrations', (req, res) => {
20686
20763
  writeClaudeSettings(filePath, settings);
20687
20764
  }
20688
20765
 
20689
- // Save to registered projects list
20766
+ // Save to registered projects list, and create the new project's default category tree (parent + children)
20767
+ // then, once: a project already registered gets nothing, so a default the user deleted stays deleted
20690
20768
  const projectLabel = label || basename(normalized);
20691
20769
  if (!registered) {
20692
20770
  projects.push({ path: normalized, label: projectLabel });
20693
20771
  saveHookProjects(projects);
20772
+ try { ensureProjectCategories([{ path: normalized, label: projectLabel }]); } catch {}
20694
20773
  }
20695
20774
 
20696
- // Create default category tree for the project (parent + children)
20697
- try { ensureProjectCategories(); } catch {}
20698
-
20699
20775
  // Probe for git "dubious ownership" — signals the UI to show an explicit trust prompt.
20700
20776
  // Only relevant on Windows when the project dir is owned by a different SID than the
20701
20777
  // account running Node (external drives, copied repos, etc.). No-op on Mac/Linux.
@@ -24299,6 +24375,11 @@ function getTerminalProfile(profileId, opts = {}) {
24299
24375
  cmd = `${cmd} -c model_reasoning_effort="${codexEffort}"`;
24300
24376
  }
24301
24377
  }
24378
+ // Every Codex terminal: the Windows sandbox the Admin sandbox setting allows. A bare value
24379
+ // (Codex reads one that is not TOML as a string), so no shell can strip a quote from it.
24380
+ if (profileId === 'codex') {
24381
+ cmd = `${cmd} -c ${terminalArgument(`windows.sandbox=${codexWindowsSandbox(adminSandboxOn())}`, DEFAULT_SHELL)}`;
24382
+ }
24302
24383
 
24303
24384
  // Loop-only: bypass permission prompts for unattended Claude Code loops.
24304
24385
  // The loop runs in a PTY with no human to answer prompts, so accessing
@@ -25194,6 +25275,8 @@ _nativeLoopRuntime = new NativeLoopRuntime({
25194
25275
  extraEnv: { ...(state.extraEnv || {}), ...codexExecEnv(launch) },
25195
25276
  unsetEnv: launch.unset,
25196
25277
  codexHome: launch.home,
25278
+ // The Admin sandbox setting as the run starts: it keeps that Windows sandbox while it lives.
25279
+ adminSandbox: adminSandboxOn(),
25197
25280
  // Native schedules use the same trusted global CLI as the interactive
25198
25281
  // sidepanel; SynaBun carries no Codex for the SDK to find by itself.
25199
25282
  codexPath: getNativeCodexBin(),
@@ -25738,6 +25821,8 @@ _nativeLoopRuntime = new NativeLoopRuntime({
25738
25821
  userContext: assistantUserContext,
25739
25822
  // The greeting a conversation opened with (told to the brain once) and when the person was last here.
25740
25823
  greeting: _greeting,
25824
+ // The Admin sandbox setting: every session view shows it (features.adminSandbox gates the panel's control).
25825
+ adminSandbox: _agentSandbox,
25741
25826
  });
25742
25827
  assistantDesktop?.attach?.({ runtime: _assistantRuntime, dispatcher: _assistantDispatcher });
25743
25828
  // Warm the catalog so brain capabilities (vision, tier) are known on first attach,
@@ -25794,6 +25879,8 @@ _nativeLoopRuntime = new NativeLoopRuntime({
25794
25879
  // router (startWhatsAppLink), and the port for that route's localhost Host check.
25795
25880
  whatsapp: () => _whatsapp,
25796
25881
  port: () => Number(PORT),
25882
+ // GET / PUT /api/assistant/admin-sandbox (the PUT answers UI_ONLY to agents).
25883
+ adminSandbox: _agentSandbox,
25797
25884
  }));
25798
25885
  const shutdownAssistant = () => {
25799
25886
  try { assistantRouter.shutdown(); } catch {}
@@ -26056,6 +26143,8 @@ function prepareExecWrapperFile(terminalSessionId, loopState, taskFile, sentinel
26056
26143
  model: loopState.model,
26057
26144
  effort: loopState.effort,
26058
26145
  mcpEnvOverrides,
26146
+ // The Admin sandbox setting the loop started with (a loop file from before it: the current one).
26147
+ codexConfigArgs: codexWindowsSandboxArgs(typeof loopState.adminSandbox === 'boolean' ? loopState.adminSandbox : adminSandboxOn()),
26059
26148
  });
26060
26149
  const wrapperFile = join(
26061
26150
  os.tmpdir(),
@@ -26781,6 +26870,7 @@ const providerPanelTerminalAuth = createProviderPanelTerminalAuth({
26781
26870
  provider, accountId, claudeAccounts: _panelClaudeAccounts(), codexAccount: findCodexAccount,
26782
26871
  claudeExecutable: getClaudeSdkExecutable, codexExecutable: getCodexBin,
26783
26872
  env: withPathEnv(process.env, getAugmentedPath()),
26873
+ codexConfigArgs: codexSandboxArgs(),
26784
26874
  }),
26785
26875
  createSession: createTerminalSession,
26786
26876
  whenSpawned: id => terminalHost.whenSpawned(id),
@@ -26855,7 +26945,8 @@ app.post('/api/terminal/sessions', async (req, res) => {
26855
26945
  } catch (err) {
26856
26946
  let msg = err.message;
26857
26947
  if (process.platform !== 'win32' && (msg.includes('posix_spawn') || msg.includes('EACCES'))) {
26858
- msg = `Terminal failed: spawn-helper lacks execute permission. Try: chmod +x neural-interface/node_modules/node-pty/prebuilds/${process.platform}-${process.arch}/spawn-helper`;
26948
+ const ptyDir = findInstalled(__dirname, 'node-pty', { stopAt: PACKAGE_ROOT })?.path || join(__dirname, 'node_modules', 'node-pty');
26949
+ msg = `Terminal failed: spawn-helper lacks execute permission. Try: chmod +x "${join(ptyDir, 'prebuilds', `${process.platform}-${process.arch}`, 'spawn-helper')}"`;
26859
26950
  }
26860
26951
  return res.status(500).json({ error: msg });
26861
26952
  }
@@ -27897,7 +27988,9 @@ function spawnSidecarProcess(linkId, sessionId, message) {
27897
27988
  const found = CLI_DEFAULTS[profile] && command === CLI_DEFAULTS[profile].command ? cliResolver.launcher(profile) : null;
27898
27989
  const direct = found?.spec?.kind === 'direct' ? found.launchPath : null;
27899
27990
  let spawnCmd = direct || command;
27900
- let spawnArgs = [...sidecarConfig.args];
27991
+ // Codex: the Windows sandbox the Admin sandbox setting allows, before its flag (a bare value: no quote for a shell to lose).
27992
+ const leadArgs = profile === 'codex' ? ['-c', `windows.sandbox=${codexWindowsSandbox(adminSandboxOn())}`] : [];
27993
+ let spawnArgs = [...leadArgs, ...sidecarConfig.args];
27901
27994
  let useShell = IS_WIN && !direct;
27902
27995
  let tmpFile = null;
27903
27996
 
@@ -27909,10 +28002,11 @@ function spawnSidecarProcess(linkId, sessionId, message) {
27909
28002
  // Use PowerShell which correctly passes $msg as a single argument value.
27910
28003
  tmpFile = join(os.tmpdir(), `synabun-relay-${randomBytes(4).toString('hex')}.txt`);
27911
28004
  writeFileSync(tmpFile, message, 'utf-8');
27912
- const flag = spawnArgs[0]; // e.g. '-p', '-q'
28005
+ const flag = sidecarConfig.args[0]; // e.g. '-p', '-q'
28006
+ const lead = leadArgs.map((word) => ` '${word}'`).join('');
27913
28007
  spawnCmd = 'powershell.exe';
27914
28008
  spawnArgs = ['-NoProfile', '-NonInteractive', '-Command',
27915
- `$msg = Get-Content -Raw '${tmpFile}'; & '${String(direct || command).replace(/'/g, "''")}' ${flag} $msg`];
28009
+ `$msg = Get-Content -Raw '${tmpFile}'; & '${String(direct || command).replace(/'/g, "''")}'${lead} ${flag} $msg`];
27916
28010
  useShell = false;
27917
28011
  } else {
27918
28012
  // Unix: pass directly as the flag's value arg (no shell quoting issues)