synabun 2.0.5 → 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 (527) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +2 -1
  3. package/THIRD-PARTY-LICENSES.md +13 -0
  4. package/docs/whatsapp.md +151 -16
  5. package/hooks/claude-code/post-plan.mjs +6 -30
  6. package/hooks/claude-code/session-start.mjs +1 -4
  7. package/hooks/claude-code/shared.mjs +112 -75
  8. package/lib/child-path.js +303 -0
  9. package/lib/claude-hooks.js +2 -1
  10. package/lib/data-home-migration.js +2 -0
  11. package/lib/desktop-app.js +265 -0
  12. package/lib/external-tools.js +7 -3
  13. package/lib/log-redact.js +102 -0
  14. package/lib/package-processes.js +670 -0
  15. package/lib/packaged-runtime.js +138 -11
  16. package/lib/runtime-dependencies.js +225 -0
  17. package/mcp-server/dist/http.d.ts +3 -1
  18. package/mcp-server/dist/http.d.ts.map +1 -1
  19. package/mcp-server/dist/http.js +15 -4
  20. package/mcp-server/dist/http.js.map +1 -1
  21. package/mcp-server/dist/index.d.ts.map +1 -1
  22. package/mcp-server/dist/index.js +9 -6
  23. package/mcp-server/dist/index.js.map +1 -1
  24. package/mcp-server/dist/services/browser-bench.d.ts +1 -1
  25. package/mcp-server/dist/services/browser-bench.d.ts.map +1 -1
  26. package/mcp-server/dist/services/browser-bench.js +1 -1
  27. package/mcp-server/dist/services/browser-bench.js.map +1 -1
  28. package/mcp-server/dist/services/budget-judgments.d.ts +108 -0
  29. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -0
  30. package/mcp-server/dist/services/budget-judgments.js +153 -0
  31. package/mcp-server/dist/services/budget-judgments.js.map +1 -0
  32. package/mcp-server/dist/services/categories.d.ts +35 -2
  33. package/mcp-server/dist/services/categories.d.ts.map +1 -1
  34. package/mcp-server/dist/services/categories.js +77 -33
  35. package/mcp-server/dist/services/categories.js.map +1 -1
  36. package/mcp-server/dist/services/codex-config-heal.d.ts +5 -1
  37. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  38. package/mcp-server/dist/services/codex-config-heal.js +41 -4
  39. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  40. package/mcp-server/dist/services/desktop-bench.d.ts +7 -7
  41. package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -1
  42. package/mcp-server/dist/services/desktop-bench.js +1 -1
  43. package/mcp-server/dist/services/desktop-bench.js.map +1 -1
  44. package/mcp-server/dist/services/identity.d.ts +11 -0
  45. package/mcp-server/dist/services/identity.d.ts.map +1 -1
  46. package/mcp-server/dist/services/identity.js +24 -0
  47. package/mcp-server/dist/services/identity.js.map +1 -1
  48. package/mcp-server/dist/services/neural-interface.d.ts +13 -0
  49. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  50. package/mcp-server/dist/services/neural-interface.js +34 -2
  51. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  52. package/mcp-server/dist/services/typesafe-config.d.ts +1 -1
  53. package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -1
  54. package/mcp-server/dist/services/typesafe-config.js +4 -1
  55. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  56. package/mcp-server/dist/tools/agents.d.ts +11 -8
  57. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  58. package/mcp-server/dist/tools/agents.js +35 -14
  59. package/mcp-server/dist/tools/agents.js.map +1 -1
  60. package/mcp-server/dist/tools/bluesky.js +1 -1
  61. package/mcp-server/dist/tools/bluesky.js.map +1 -1
  62. package/mcp-server/dist/tools/browser-advanced.d.ts +1 -1
  63. package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -1
  64. package/mcp-server/dist/tools/browser-advanced.js +1 -1
  65. package/mcp-server/dist/tools/browser-advanced.js.map +1 -1
  66. package/mcp-server/dist/tools/browser-batch.d.ts +1 -1
  67. package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -1
  68. package/mcp-server/dist/tools/browser-batch.js +1 -1
  69. package/mcp-server/dist/tools/browser-batch.js.map +1 -1
  70. package/mcp-server/dist/tools/browser-cheatsheet.d.ts +1 -1
  71. package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -1
  72. package/mcp-server/dist/tools/browser-cheatsheet.js +1 -1
  73. package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -1
  74. package/mcp-server/dist/tools/browser-interact.d.ts +1 -1
  75. package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -1
  76. package/mcp-server/dist/tools/browser-interact.js +1 -1
  77. package/mcp-server/dist/tools/browser-interact.js.map +1 -1
  78. package/mcp-server/dist/tools/browser-navigate.d.ts +1 -1
  79. package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -1
  80. package/mcp-server/dist/tools/browser-navigate.js +1 -1
  81. package/mcp-server/dist/tools/browser-navigate.js.map +1 -1
  82. package/mcp-server/dist/tools/browser-observe.d.ts +1 -1
  83. package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -1
  84. package/mcp-server/dist/tools/browser-observe.js +1 -1
  85. package/mcp-server/dist/tools/browser-observe.js.map +1 -1
  86. package/mcp-server/dist/tools/card-tools.d.ts +1 -1
  87. package/mcp-server/dist/tools/card-tools.d.ts.map +1 -1
  88. package/mcp-server/dist/tools/card-tools.js +1 -1
  89. package/mcp-server/dist/tools/card-tools.js.map +1 -1
  90. package/mcp-server/dist/tools/category.d.ts +1 -1
  91. package/mcp-server/dist/tools/category.d.ts.map +1 -1
  92. package/mcp-server/dist/tools/category.js +5 -1
  93. package/mcp-server/dist/tools/category.js.map +1 -1
  94. package/mcp-server/dist/tools/choice.d.ts +1 -1
  95. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  96. package/mcp-server/dist/tools/choice.js +1 -1
  97. package/mcp-server/dist/tools/choice.js.map +1 -1
  98. package/mcp-server/dist/tools/computer.d.ts +1 -1
  99. package/mcp-server/dist/tools/computer.d.ts.map +1 -1
  100. package/mcp-server/dist/tools/computer.js +1 -1
  101. package/mcp-server/dist/tools/computer.js.map +1 -1
  102. package/mcp-server/dist/tools/discord-channel.d.ts +1 -1
  103. package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -1
  104. package/mcp-server/dist/tools/discord-channel.js +1 -1
  105. package/mcp-server/dist/tools/discord-channel.js.map +1 -1
  106. package/mcp-server/dist/tools/discord-guild.d.ts +1 -1
  107. package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -1
  108. package/mcp-server/dist/tools/discord-guild.js +1 -1
  109. package/mcp-server/dist/tools/discord-guild.js.map +1 -1
  110. package/mcp-server/dist/tools/discord-member.d.ts +1 -1
  111. package/mcp-server/dist/tools/discord-member.d.ts.map +1 -1
  112. package/mcp-server/dist/tools/discord-member.js +1 -1
  113. package/mcp-server/dist/tools/discord-member.js.map +1 -1
  114. package/mcp-server/dist/tools/discord-message.d.ts +1 -1
  115. package/mcp-server/dist/tools/discord-message.d.ts.map +1 -1
  116. package/mcp-server/dist/tools/discord-message.js +1 -1
  117. package/mcp-server/dist/tools/discord-message.js.map +1 -1
  118. package/mcp-server/dist/tools/discord-onboarding.d.ts +1 -1
  119. package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -1
  120. package/mcp-server/dist/tools/discord-onboarding.js +1 -1
  121. package/mcp-server/dist/tools/discord-onboarding.js.map +1 -1
  122. package/mcp-server/dist/tools/discord-role.d.ts +1 -1
  123. package/mcp-server/dist/tools/discord-role.d.ts.map +1 -1
  124. package/mcp-server/dist/tools/discord-role.js +1 -1
  125. package/mcp-server/dist/tools/discord-role.js.map +1 -1
  126. package/mcp-server/dist/tools/discord-thread.d.ts +1 -1
  127. package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -1
  128. package/mcp-server/dist/tools/discord-thread.js +1 -1
  129. package/mcp-server/dist/tools/discord-thread.js.map +1 -1
  130. package/mcp-server/dist/tools/discord-webhook.d.ts +1 -1
  131. package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -1
  132. package/mcp-server/dist/tools/discord-webhook.js +1 -1
  133. package/mcp-server/dist/tools/discord-webhook.js.map +1 -1
  134. package/mcp-server/dist/tools/fb-groups.d.ts +1 -1
  135. package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -1
  136. package/mcp-server/dist/tools/fb-groups.js +1 -1
  137. package/mcp-server/dist/tools/fb-groups.js.map +1 -1
  138. package/mcp-server/dist/tools/forget.d.ts +1 -1
  139. package/mcp-server/dist/tools/forget.d.ts.map +1 -1
  140. package/mcp-server/dist/tools/forget.js +1 -1
  141. package/mcp-server/dist/tools/forget.js.map +1 -1
  142. package/mcp-server/dist/tools/git-tools.d.ts +1 -1
  143. package/mcp-server/dist/tools/git-tools.d.ts.map +1 -1
  144. package/mcp-server/dist/tools/git-tools.js +1 -1
  145. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  146. package/mcp-server/dist/tools/gsc/experience.d.ts +1 -1
  147. package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -1
  148. package/mcp-server/dist/tools/gsc/experience.js +1 -1
  149. package/mcp-server/dist/tools/gsc/experience.js.map +1 -1
  150. package/mcp-server/dist/tools/gsc/indexing.d.ts +1 -1
  151. package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -1
  152. package/mcp-server/dist/tools/gsc/indexing.js +1 -1
  153. package/mcp-server/dist/tools/gsc/indexing.js.map +1 -1
  154. package/mcp-server/dist/tools/gsc/inspect.d.ts +1 -1
  155. package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -1
  156. package/mcp-server/dist/tools/gsc/inspect.js +1 -1
  157. package/mcp-server/dist/tools/gsc/inspect.js.map +1 -1
  158. package/mcp-server/dist/tools/gsc/navigate.d.ts +1 -1
  159. package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -1
  160. package/mcp-server/dist/tools/gsc/navigate.js +1 -1
  161. package/mcp-server/dist/tools/gsc/navigate.js.map +1 -1
  162. package/mcp-server/dist/tools/gsc/performance.d.ts +1 -1
  163. package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -1
  164. package/mcp-server/dist/tools/gsc/performance.js +1 -1
  165. package/mcp-server/dist/tools/gsc/performance.js.map +1 -1
  166. package/mcp-server/dist/tools/gsc/settings.d.ts +1 -1
  167. package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -1
  168. package/mcp-server/dist/tools/gsc/settings.js +1 -1
  169. package/mcp-server/dist/tools/gsc/settings.js.map +1 -1
  170. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  171. package/mcp-server/dist/tools/image-tools.d.ts.map +1 -1
  172. package/mcp-server/dist/tools/image-tools.js +1 -1
  173. package/mcp-server/dist/tools/image-tools.js.map +1 -1
  174. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +1 -1
  175. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -1
  176. package/mcp-server/dist/tools/leonardo-browser-tools.js +1 -1
  177. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -1
  178. package/mcp-server/dist/tools/loop.d.ts +1 -1
  179. package/mcp-server/dist/tools/loop.d.ts.map +1 -1
  180. package/mcp-server/dist/tools/loop.js +1 -1
  181. package/mcp-server/dist/tools/loop.js.map +1 -1
  182. package/mcp-server/dist/tools/memories.d.ts +1 -1
  183. package/mcp-server/dist/tools/memories.d.ts.map +1 -1
  184. package/mcp-server/dist/tools/memories.js +1 -1
  185. package/mcp-server/dist/tools/memories.js.map +1 -1
  186. package/mcp-server/dist/tools/morelogin.d.ts +1 -1
  187. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  188. package/mcp-server/dist/tools/morelogin.js +1 -1
  189. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  190. package/mcp-server/dist/tools/profile.d.ts +1 -1
  191. package/mcp-server/dist/tools/profile.d.ts.map +1 -1
  192. package/mcp-server/dist/tools/profile.js +1 -1
  193. package/mcp-server/dist/tools/profile.js.map +1 -1
  194. package/mcp-server/dist/tools/recall.d.ts +1 -1
  195. package/mcp-server/dist/tools/recall.d.ts.map +1 -1
  196. package/mcp-server/dist/tools/recall.js +1 -1
  197. package/mcp-server/dist/tools/recall.js.map +1 -1
  198. package/mcp-server/dist/tools/reflect.d.ts +1 -1
  199. package/mcp-server/dist/tools/reflect.d.ts.map +1 -1
  200. package/mcp-server/dist/tools/reflect.js +1 -1
  201. package/mcp-server/dist/tools/reflect.js.map +1 -1
  202. package/mcp-server/dist/tools/remember.d.ts +1 -1
  203. package/mcp-server/dist/tools/remember.d.ts.map +1 -1
  204. package/mcp-server/dist/tools/remember.js +13 -11
  205. package/mcp-server/dist/tools/remember.js.map +1 -1
  206. package/mcp-server/dist/tools/restore.d.ts +1 -1
  207. package/mcp-server/dist/tools/restore.d.ts.map +1 -1
  208. package/mcp-server/dist/tools/restore.js +1 -1
  209. package/mcp-server/dist/tools/restore.js.map +1 -1
  210. package/mcp-server/dist/tools/style-guide-tools.d.ts +1 -1
  211. package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -1
  212. package/mcp-server/dist/tools/style-guide-tools.js +1 -1
  213. package/mcp-server/dist/tools/style-guide-tools.js.map +1 -1
  214. package/mcp-server/dist/tools/sync.d.ts +1 -1
  215. package/mcp-server/dist/tools/sync.d.ts.map +1 -1
  216. package/mcp-server/dist/tools/sync.js +1 -1
  217. package/mcp-server/dist/tools/sync.js.map +1 -1
  218. package/mcp-server/dist/tools/tictactoe-tools.d.ts +1 -1
  219. package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -1
  220. package/mcp-server/dist/tools/tictactoe-tools.js +1 -1
  221. package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -1
  222. package/mcp-server/dist/tools/utils.d.ts +1 -1
  223. package/mcp-server/dist/tools/utils.d.ts.map +1 -1
  224. package/mcp-server/dist/tools/utils.js +1 -1
  225. package/mcp-server/dist/tools/utils.js.map +1 -1
  226. package/mcp-server/dist/tools/whatsapp-send-file.d.ts +17 -0
  227. package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -0
  228. package/mcp-server/dist/tools/whatsapp-send-file.js +44 -0
  229. package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -0
  230. package/mcp-server/dist/tools/whiteboard-tools.d.ts +3 -3
  231. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  232. package/mcp-server/dist/tools/whiteboard-tools.js +1 -1
  233. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  234. package/mcp-server/dist/tools/youtube/analytics.d.ts +1 -1
  235. package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -1
  236. package/mcp-server/dist/tools/youtube/analytics.js +1 -1
  237. package/mcp-server/dist/tools/youtube/analytics.js.map +1 -1
  238. package/mcp-server/dist/tools/youtube/download.d.ts +1 -1
  239. package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -1
  240. package/mcp-server/dist/tools/youtube/download.js +1 -1
  241. package/mcp-server/dist/tools/youtube/download.js.map +1 -1
  242. package/mcp-server/dist/tools/youtube/media.d.ts +1 -1
  243. package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -1
  244. package/mcp-server/dist/tools/youtube/media.js +1 -1
  245. package/mcp-server/dist/tools/youtube/media.js.map +1 -1
  246. package/mcp-server/dist/tools/youtube/metadata.d.ts +1 -1
  247. package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -1
  248. package/mcp-server/dist/tools/youtube/metadata.js +1 -1
  249. package/mcp-server/dist/tools/youtube/metadata.js.map +1 -1
  250. package/mcp-server/dist/tools/youtube/navigate.d.ts +1 -1
  251. package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -1
  252. package/mcp-server/dist/tools/youtube/navigate.js +1 -1
  253. package/mcp-server/dist/tools/youtube/navigate.js.map +1 -1
  254. package/mcp-server/dist/tools/youtube/playlist.d.ts +1 -1
  255. package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -1
  256. package/mcp-server/dist/tools/youtube/playlist.js +1 -1
  257. package/mcp-server/dist/tools/youtube/playlist.js.map +1 -1
  258. package/mcp-server/dist/tools/youtube/schedule.d.ts +1 -1
  259. package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -1
  260. package/mcp-server/dist/tools/youtube/schedule.js +1 -1
  261. package/mcp-server/dist/tools/youtube/schedule.js.map +1 -1
  262. package/mcp-server/dist/tools/youtube/source.d.ts +1 -1
  263. package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -1
  264. package/mcp-server/dist/tools/youtube/source.js +1 -1
  265. package/mcp-server/dist/tools/youtube/source.js.map +1 -1
  266. package/mcp-server/dist/tools/youtube/upload.d.ts +1 -1
  267. package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -1
  268. package/mcp-server/dist/tools/youtube/upload.js +4 -9
  269. package/mcp-server/dist/tools/youtube/upload.js.map +1 -1
  270. package/mcp-server/dist/tui.js +18 -5
  271. package/mcp-server/dist/tui.js.map +1 -1
  272. package/mcp-server/dist/version.d.ts +5 -0
  273. package/mcp-server/dist/version.d.ts.map +1 -0
  274. package/mcp-server/dist/version.js +21 -0
  275. package/mcp-server/dist/version.js.map +1 -0
  276. package/mcp-server/package-lock.json +3 -3
  277. package/mcp-server/package.json +3 -3
  278. package/mcp-server/run.mjs +15 -9
  279. package/mcp-server/src/http.ts +18 -3
  280. package/mcp-server/src/index.ts +9 -6
  281. package/mcp-server/src/services/browser-bench.ts +1 -1
  282. package/mcp-server/src/services/budget-judgments.ts +183 -0
  283. package/mcp-server/src/services/categories.ts +77 -32
  284. package/mcp-server/src/services/codex-config-heal.ts +35 -4
  285. package/mcp-server/src/services/desktop-bench.ts +1 -1
  286. package/mcp-server/src/services/identity.ts +27 -0
  287. package/mcp-server/src/services/neural-interface.ts +34 -2
  288. package/mcp-server/src/services/typesafe-config.ts +4 -1
  289. package/mcp-server/src/tools/agents.ts +34 -15
  290. package/mcp-server/src/tools/bluesky.ts +1 -1
  291. package/mcp-server/src/tools/browser-advanced.ts +1 -1
  292. package/mcp-server/src/tools/browser-batch.ts +1 -1
  293. package/mcp-server/src/tools/browser-cheatsheet.ts +1 -1
  294. package/mcp-server/src/tools/browser-interact.ts +1 -1
  295. package/mcp-server/src/tools/browser-navigate.ts +1 -1
  296. package/mcp-server/src/tools/browser-observe.ts +1 -1
  297. package/mcp-server/src/tools/card-tools.ts +1 -1
  298. package/mcp-server/src/tools/category.ts +6 -1
  299. package/mcp-server/src/tools/choice.ts +1 -1
  300. package/mcp-server/src/tools/computer.ts +1 -1
  301. package/mcp-server/src/tools/discord-channel.ts +1 -1
  302. package/mcp-server/src/tools/discord-guild.ts +1 -1
  303. package/mcp-server/src/tools/discord-member.ts +1 -1
  304. package/mcp-server/src/tools/discord-message.ts +1 -1
  305. package/mcp-server/src/tools/discord-onboarding.ts +1 -1
  306. package/mcp-server/src/tools/discord-role.ts +1 -1
  307. package/mcp-server/src/tools/discord-thread.ts +1 -1
  308. package/mcp-server/src/tools/discord-webhook.ts +1 -1
  309. package/mcp-server/src/tools/fb-groups.ts +1 -1
  310. package/mcp-server/src/tools/forget.ts +1 -1
  311. package/mcp-server/src/tools/git-tools.ts +1 -1
  312. package/mcp-server/src/tools/gsc/experience.ts +1 -1
  313. package/mcp-server/src/tools/gsc/indexing.ts +1 -1
  314. package/mcp-server/src/tools/gsc/inspect.ts +1 -1
  315. package/mcp-server/src/tools/gsc/navigate.ts +1 -1
  316. package/mcp-server/src/tools/gsc/performance.ts +1 -1
  317. package/mcp-server/src/tools/gsc/settings.ts +1 -1
  318. package/mcp-server/src/tools/image-tools.ts +1 -1
  319. package/mcp-server/src/tools/leonardo-browser-tools.ts +1 -1
  320. package/mcp-server/src/tools/loop.ts +1 -1
  321. package/mcp-server/src/tools/memories.ts +1 -1
  322. package/mcp-server/src/tools/morelogin.ts +1 -1
  323. package/mcp-server/src/tools/profile.ts +1 -1
  324. package/mcp-server/src/tools/recall.ts +1 -1
  325. package/mcp-server/src/tools/reflect.ts +1 -1
  326. package/mcp-server/src/tools/remember.ts +13 -12
  327. package/mcp-server/src/tools/restore.ts +1 -1
  328. package/mcp-server/src/tools/style-guide-tools.ts +1 -1
  329. package/mcp-server/src/tools/sync.ts +1 -1
  330. package/mcp-server/src/tools/tictactoe-tools.ts +1 -1
  331. package/mcp-server/src/tools/utils.ts +1 -1
  332. package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
  333. package/mcp-server/src/tools/whiteboard-tools.ts +1 -1
  334. package/mcp-server/src/tools/youtube/analytics.ts +1 -1
  335. package/mcp-server/src/tools/youtube/download.ts +1 -1
  336. package/mcp-server/src/tools/youtube/media.ts +1 -1
  337. package/mcp-server/src/tools/youtube/metadata.ts +1 -1
  338. package/mcp-server/src/tools/youtube/navigate.ts +1 -1
  339. package/mcp-server/src/tools/youtube/playlist.ts +1 -1
  340. package/mcp-server/src/tools/youtube/schedule.ts +1 -1
  341. package/mcp-server/src/tools/youtube/source.ts +1 -1
  342. package/mcp-server/src/tools/youtube/upload.ts +4 -12
  343. package/mcp-server/src/tui.ts +24 -10
  344. package/mcp-server/src/version.ts +22 -0
  345. package/neural-interface/i18n/en.json +645 -57
  346. package/neural-interface/i18n/pt-BR.json +644 -56
  347. package/neural-interface/lib/account-usage.js +163 -0
  348. package/neural-interface/lib/agent-sandbox-elevation.js +102 -0
  349. package/neural-interface/lib/agent-sandbox-setting.js +57 -0
  350. package/neural-interface/lib/assistant-api.js +274 -52
  351. package/neural-interface/lib/assistant-brains/claude.js +15 -2
  352. package/neural-interface/lib/assistant-brains/codex.js +3 -0
  353. package/neural-interface/lib/assistant-brains/opencode.js +17 -4
  354. package/neural-interface/lib/assistant-budget-planner.js +390 -0
  355. package/neural-interface/lib/assistant-budget-split.js +408 -0
  356. package/neural-interface/lib/assistant-budget.js +94 -95
  357. package/neural-interface/lib/assistant-config.js +62 -14
  358. package/neural-interface/lib/assistant-dispatch.js +432 -125
  359. package/neural-interface/lib/assistant-jev.js +26 -3
  360. package/neural-interface/lib/assistant-persona.js +68 -11
  361. package/neural-interface/lib/assistant-plan-permissions.js +8 -1
  362. package/neural-interface/lib/assistant-route-accounts.js +14 -0
  363. package/neural-interface/lib/assistant-route-gate-codex.js +3 -1
  364. package/neural-interface/lib/assistant-route-gate.js +19 -3
  365. package/neural-interface/lib/assistant-router.js +373 -42
  366. package/neural-interface/lib/assistant-runtime.js +312 -48
  367. package/neural-interface/lib/assistant-user-writer.js +4 -2
  368. package/neural-interface/lib/augmented-path.js +317 -53
  369. package/neural-interface/lib/claude-accounts.js +342 -31
  370. package/neural-interface/lib/claude-agent-bridge.js +90 -3
  371. package/neural-interface/lib/claude-executable.js +6 -1
  372. package/neural-interface/lib/claude-model-catalog.js +3 -3
  373. package/neural-interface/lib/claude-panel-auth.js +221 -0
  374. package/neural-interface/lib/claude-profile-api-key.js +62 -0
  375. package/neural-interface/lib/cli-install-api.js +137 -0
  376. package/neural-interface/lib/cli-install.js +797 -0
  377. package/neural-interface/lib/cli-path.js +130 -0
  378. package/neural-interface/lib/cli-resolver.js +744 -0
  379. package/neural-interface/lib/cli-update-planner.js +143 -7
  380. package/neural-interface/lib/codex-account-auth.js +180 -0
  381. package/neural-interface/lib/codex-accounts.js +502 -0
  382. package/neural-interface/lib/codex-capabilities.js +2 -1
  383. package/neural-interface/lib/codex-compat-rpc.js +8 -2
  384. package/neural-interface/lib/codex-mcp-approvals.js +5 -1
  385. package/neural-interface/lib/codex-panel-auth.js +62 -0
  386. package/neural-interface/lib/codex-session-settings.js +1 -1
  387. package/neural-interface/lib/codex-settings-schema.js +122 -0
  388. package/neural-interface/lib/desktop/config.js +3 -0
  389. package/neural-interface/lib/exec-loop-command.js +3 -1
  390. package/neural-interface/lib/git-bash/bzip2.js +339 -0
  391. package/neural-interface/lib/git-bash/claude-settings.js +73 -0
  392. package/neural-interface/lib/git-bash/extract-worker.js +34 -0
  393. package/neural-interface/lib/git-bash/install.js +529 -0
  394. package/neural-interface/lib/git-bash/licenses/COPYING +360 -0
  395. package/neural-interface/lib/git-bash/licenses/LGPL-2.1 +511 -0
  396. package/neural-interface/lib/git-bash/manager.js +268 -0
  397. package/neural-interface/lib/git-bash/pins.js +206 -0
  398. package/neural-interface/lib/git-bash/pins.json +34 -0
  399. package/neural-interface/lib/git-bash/resolver.js +194 -0
  400. package/neural-interface/lib/git-read.js +34 -2
  401. package/neural-interface/lib/install-details.js +163 -0
  402. package/neural-interface/lib/mcp-installer.js +14 -2
  403. package/neural-interface/lib/native-loop-providers.js +22 -4
  404. package/neural-interface/lib/native-loop-runtime.js +9 -4
  405. package/neural-interface/lib/os-path.js +319 -0
  406. package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
  407. package/neural-interface/lib/provider-panel-terminal-auth.js +96 -0
  408. package/neural-interface/lib/pty-host/core.js +2 -1
  409. package/neural-interface/lib/pty-host/manager.js +27 -2
  410. package/neural-interface/lib/remote-policy.js +20 -11
  411. package/neural-interface/lib/session-indexer.js +3 -1
  412. package/neural-interface/lib/session-title-generator.js +6 -3
  413. package/neural-interface/lib/system-about.js +340 -0
  414. package/neural-interface/lib/system-activity.js +66 -0
  415. package/neural-interface/lib/terminal-env.js +11 -3
  416. package/neural-interface/lib/terminal-path.js +55 -0
  417. package/neural-interface/lib/virtual-socket.js +12 -1
  418. package/neural-interface/lib/whatsapp/baileys-adapter.js +165 -45
  419. package/neural-interface/lib/whatsapp/bridge.js +78 -34
  420. package/neural-interface/lib/whatsapp/commands.js +13 -14
  421. package/neural-interface/lib/whatsapp/config.js +134 -20
  422. package/neural-interface/lib/whatsapp/fake-baileys.js +99 -14
  423. package/neural-interface/lib/whatsapp/host-core.js +168 -35
  424. package/neural-interface/lib/whatsapp/inbound.js +5 -3
  425. package/neural-interface/lib/whatsapp/local-file.js +524 -0
  426. package/neural-interface/lib/whatsapp/manager.js +92 -32
  427. package/neural-interface/lib/whatsapp/paths.js +11 -1
  428. package/neural-interface/lib/whatsapp/protocol.js +65 -5
  429. package/neural-interface/lib/whatsapp/redact.js +63 -0
  430. package/neural-interface/lib/whatsapp/service.js +343 -91
  431. package/neural-interface/lib/whatsapp/transcription.js +463 -0
  432. package/neural-interface/package-lock.json +2 -2
  433. package/neural-interface/package.json +1 -1
  434. package/neural-interface/public/index.html +2 -0
  435. package/neural-interface/public/index2d.html +2 -0
  436. package/neural-interface/public/offline.html +16 -1
  437. package/neural-interface/public/onboarding.html +96 -2
  438. package/neural-interface/public/shared/account-i18n.js +7 -0
  439. package/neural-interface/public/shared/account-menu.js +542 -0
  440. package/neural-interface/public/shared/account-usage.js +79 -0
  441. package/neural-interface/public/shared/account-view.js +336 -0
  442. package/neural-interface/public/shared/agent-runtime-options.js +28 -8
  443. package/neural-interface/public/shared/assistant/asst-account-menu.js +298 -0
  444. package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
  445. package/neural-interface/public/shared/assistant/asst-api.js +39 -2
  446. package/neural-interface/public/shared/assistant/asst-brain-picker.js +288 -32
  447. package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
  448. package/neural-interface/public/shared/assistant/asst-mascot.js +126 -7
  449. package/neural-interface/public/shared/assistant/asst-menu.js +219 -80
  450. package/neural-interface/public/shared/assistant/asst-model-chip.js +135 -0
  451. package/neural-interface/public/shared/assistant/asst-panel.js +87 -16
  452. package/neural-interface/public/shared/assistant/asst-render.js +38 -7
  453. package/neural-interface/public/shared/assistant/asst-route.js +72 -14
  454. package/neural-interface/public/shared/assistant/asst-routes-editor.js +45 -6
  455. package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
  456. package/neural-interface/public/shared/assistant/asst-state.js +1 -1
  457. package/neural-interface/public/shared/assistant/asst-styles.js +160 -29
  458. package/neural-interface/public/shared/cdx/cdx-commands.js +4 -1
  459. package/neural-interface/public/shared/cdx/cdx-features.js +22 -14
  460. package/neural-interface/public/shared/cdx/cdx-icons.js +2 -0
  461. package/neural-interface/public/shared/cdx/cdx-panel.js +49 -108
  462. package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
  463. package/neural-interface/public/shared/cdx/cdx-styles.js +172 -111
  464. package/neural-interface/public/shared/cdx/cdx-tabs.js +264 -664
  465. package/neural-interface/public/shared/cdx/cdx-ws.js +2 -0
  466. package/neural-interface/public/shared/claude-account-view.js +3 -0
  467. package/neural-interface/public/shared/cli-install-view.js +392 -0
  468. package/neural-interface/public/shared/cli-status.js +282 -22
  469. package/neural-interface/public/shared/cp/cp-events.js +2 -1
  470. package/neural-interface/public/shared/cp/cp-styles.js +46 -0
  471. package/neural-interface/public/shared/desktop-bridge.js +39 -0
  472. package/neural-interface/public/shared/desktop-titlebar-page.js +59 -0
  473. package/neural-interface/public/shared/desktop-titlebar-view.js +122 -0
  474. package/neural-interface/public/shared/desktop-titlebar.js +153 -0
  475. package/neural-interface/public/shared/desktop-update-view.js +462 -0
  476. package/neural-interface/public/shared/editor/editor-panel.js +1 -1
  477. package/neural-interface/public/shared/explorer/fx-main.js +1 -1
  478. package/neural-interface/public/shared/git-bash-view.js +145 -0
  479. package/neural-interface/public/shared/html-shell.js +1 -0
  480. package/neural-interface/public/shared/i18n.js +19 -1
  481. package/neural-interface/public/shared/install-details-view.js +86 -0
  482. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -1
  483. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +36 -1
  484. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +17 -0
  485. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +169 -2
  486. package/neural-interface/public/shared/pwa-install-page.js +3 -1
  487. package/neural-interface/public/shared/settings/settings-about-pane.js +271 -0
  488. package/neural-interface/public/shared/settings/settings-about.js +254 -0
  489. package/neural-interface/public/shared/settings/settings-ia.js +15 -0
  490. package/neural-interface/public/shared/showcase-privacy.js +490 -0
  491. package/neural-interface/public/shared/storage.js +30 -3
  492. package/neural-interface/public/shared/styles.css +281 -32
  493. package/neural-interface/public/shared/synabun-mascot.js +48 -2
  494. package/neural-interface/public/shared/ui-claude-panel.js +262 -217
  495. package/neural-interface/public/shared/ui-cli-banner.js +355 -0
  496. package/neural-interface/public/shared/ui-explorer.js +2 -0
  497. package/neural-interface/public/shared/ui-git-bash.js +124 -0
  498. package/neural-interface/public/shared/ui-judgments.js +10 -1
  499. package/neural-interface/public/shared/ui-loading.js +30 -6
  500. package/neural-interface/public/shared/ui-menubar.js +13 -3
  501. package/neural-interface/public/shared/ui-navbar.js +3 -1
  502. package/neural-interface/public/shared/ui-provider-auth.js +104 -0
  503. package/neural-interface/public/shared/ui-provider-terminal-auth.js +223 -0
  504. package/neural-interface/public/shared/ui-sessions.js +9 -3
  505. package/neural-interface/public/shared/ui-settings.js +55 -3
  506. package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
  507. package/neural-interface/public/shared/ui-sync.js +8 -0
  508. package/neural-interface/public/shared/ui-terminal.js +17 -0
  509. package/neural-interface/public/shared/ui-tool-updates.js +5 -0
  510. package/neural-interface/public/shared/ui-update.js +598 -7
  511. package/neural-interface/public/shared/ui-whatsapp.js +21 -6
  512. package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
  513. package/neural-interface/public/shared/worker-end.js +2 -0
  514. package/neural-interface/public/sw.js +1 -1
  515. package/neural-interface/public/variant/2d/main.js +10 -1
  516. package/neural-interface/public/variant/3d/main.js +10 -1
  517. package/neural-interface/scripts/rebuild-pty.js +14 -2
  518. package/neural-interface/server.js +1384 -679
  519. package/npm-shrinkwrap.json +4424 -0
  520. package/package.json +57 -2
  521. package/postinstall.js +61 -47
  522. package/preuninstall.js +8 -35
  523. package/setup.js +80 -47
  524. package/skills/synabun/modules/idea.md +1 -1
  525. package/skills/synabun/modules/schedule.md +1 -1
  526. package/updater.cmd +2 -2
  527. package/updater.mjs +97 -3
@@ -1,3 +1,8 @@
1
+ import { providerAuthSnapshot } from './ui-provider-auth.js';
2
+ import { mountProviderTerminalAuth, providerApiKeyRequest, startProviderTerminalLogin } from './ui-provider-terminal-auth.js';
3
+ import { accountName, accountSwitchPlan, accountText, tabAccountId, serverAccountId } from './account-view.js';
4
+ import { mountAccountMenu } from './account-menu.js';
5
+ import './account-i18n.js';
1
6
  import { hostedSidepanelId, sidepanelHost } from './ui-sidepanel-runtime.js';
2
7
  // ═══════════════════════════════════════════
3
8
  // SynaBun — Claude Code Panel (Main Area)
@@ -12,7 +17,7 @@ import { fetchClaudeSessions, fetchBrowserSessions, searchSessions } from './api
12
17
  import { createFrameRenderer } from './utils.js';
13
18
  import { notify, NOTIF_TYPE } from './ui-notifications.js';
14
19
  import { registerSidepanel, setSidepanelVisible, syncSidepanelLayout, focusSidepanel, openAnotherSidepanelSession, isHostedSessionFocused } from './ui-sidepanel-windows.js';
15
- import { subscribeCliStatus, recheckCliStatus, getCliDocUrl, getCliInstallCommand, getCliLabel } from './cli-status.js';
20
+ import { mountCliBanner } from './ui-cli-banner.js';
16
21
  import { nativeLoopWindowId } from './ui-native-window-id.js';
17
22
  import { createStickyScrollController } from './ui-scroll-follow.js';
18
23
  import { requestGeneratedSessionTitle } from './session-title.js';
@@ -166,9 +171,8 @@ function activeTab() { return _tabs[_activeTabIdx] || null; }
166
171
  let _browserEmbed = null; // { sessionId, ws, canvas, ctx, urlBar, container }
167
172
  let _browserEmbedVisible = false;
168
173
 
169
- // ── CLI-installed status (claude binary detection) ──
170
- let _cliInstalled = null; // null = unknown / missing, version string = installed
171
- let _cliUnsub = null;
174
+ // ── CLI status (claude binary detection): the banner controller, ui-cli-banner.js ──
175
+ let _cliBanner = null;
172
176
 
173
177
  // Marked.js (lazy loaded)
174
178
  let _marked = null;
@@ -308,7 +312,7 @@ const SLASH_COMMANDS = [
308
312
  { name: 'plugin', desc: 'List active plugins and skills', kind: 'info' },
309
313
  { name: 'status', desc: 'Show session status summary', kind: 'info' },
310
314
  { name: 'cost', desc: 'Toggle the cost widget', kind: 'action' },
311
- { name: 'login', desc: 'Open Claude account login', kind: 'action' },
315
+ { name: 'login', desc: 'Sign this tab\'s Claude account in (opens the account menu)', kind: 'action' },
312
316
  { name: 'logout', desc: 'Open Claude account sign-out', kind: 'action' },
313
317
  { name: 'plan', desc: 'Toggle plan mode', kind: 'action' },
314
318
  { name: 'btw', desc: 'Add context while Claude is processing (Shift+Enter)', kind: 'info' },
@@ -322,7 +326,7 @@ const SLASH_COMMANDS = [
322
326
  { name: 'reload-plugins', desc: 'Reload plugins without restarting the session', kind: 'action', needs: 'reload_plugins' },
323
327
  { name: 'tasks', desc: 'Background work of this tab: running tasks (with stop) and scheduled wakeups', kind: 'info' },
324
328
  { name: 'usage', desc: 'This session\'s cost and the plan\'s usage limits', kind: 'info', needs: 'session_requests' },
325
- { name: 'account', desc: 'Choose the Claude account this tab runs under', kind: 'action', needs: 'accounts' },
329
+ { name: 'account', desc: 'Choose and manage the Claude account of this tab (the header account menu)', kind: 'action', needs: 'accounts' },
326
330
  { name: 'effective-settings', desc: 'The Claude Code settings in effect here, and the file each comes from', kind: 'info', needs: 'settings_view' },
327
331
  ];
328
332
 
@@ -544,72 +548,7 @@ function injectStyles() {
544
548
  .cp-messages:has(.msg) .cp-empty,
545
549
  .cp-messages:has(.msg-status) .cp-empty { display: none; }
546
550
 
547
- /* ── CLI-not-installed banner (sticky top of messages container) ── */
548
- .cp-cli-banner {
549
- flex-shrink: 0;
550
- display: grid;
551
- grid-template-columns: auto 1fr auto;
552
- gap: 10px;
553
- align-items: center;
554
- margin: 6px 8px 0;
555
- padding: 10px 12px;
556
- border: 1px solid rgba(255,180,80,0.45);
557
- border-radius: 8px;
558
- background: rgba(255,180,80,0.08);
559
- color: rgba(255,235,200,0.92);
560
- font-size: 11px;
561
- line-height: 1.4;
562
- pointer-events: auto;
563
- position: relative;
564
- z-index: 5;
565
- }
566
- .cp-cli-banner-icon {
567
- width: 22px; height: 22px;
568
- display: flex; align-items: center; justify-content: center;
569
- border-radius: 50%;
570
- background: rgba(255,180,80,0.25);
571
- color: rgba(255,210,140,1);
572
- font-weight: 700;
573
- }
574
- .cp-cli-banner-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
575
- .cp-cli-banner-title {
576
- font-size: 12px; font-weight: 600;
577
- color: rgba(255,210,140,0.95);
578
- }
579
- .cp-cli-banner-body {
580
- font-size: 11px;
581
- color: rgba(255,255,255,0.7);
582
- word-break: break-word;
583
- }
584
- .cp-cli-banner-body code {
585
- padding: 1px 5px;
586
- background: rgba(0,0,0,0.35);
587
- border-radius: 3px;
588
- font-size: 10.5px;
589
- color: rgba(255,255,255,0.85);
590
- }
591
- .cp-cli-banner-actions { display: flex; gap: 6px; }
592
- .cp-cli-banner-link, .cp-cli-banner-recheck {
593
- display: inline-flex; align-items: center; gap: 4px;
594
- padding: 4px 9px;
595
- font-size: 11px;
596
- font-weight: 500;
597
- border-radius: 4px;
598
- border: 1px solid rgba(255,255,255,0.2);
599
- background: rgba(255,255,255,0.05);
600
- color: rgba(255,255,255,0.9);
601
- text-decoration: none;
602
- cursor: pointer;
603
- user-select: none;
604
- font-family: inherit;
605
- }
606
- .cp-cli-banner-link:hover, .cp-cli-banner-recheck:hover {
607
- background: rgba(255,255,255,0.12);
608
- border-color: rgba(255,255,255,0.4);
609
- }
610
- .cp-cli-banner-recheck:disabled { opacity: 0.5; cursor: default; }
611
- .claude-panel.cp-cli-blocked .cp-send { opacity: 0.4 !important; cursor: not-allowed !important; }
612
- .claude-panel.cp-cli-blocked .cp-input { opacity: 0.7; }
551
+ /* ── CLI banner (ui-cli-banner.js): its rules are in cp/cp-styles.js ── */
613
552
 
614
553
  /* ── Browser embed (live screencast inside panel) ── */
615
554
  .cp-browser-embed {
@@ -1966,10 +1905,44 @@ function injectStyles() {
1966
1905
  background: rgba(22, 22, 26, 0.95);
1967
1906
  z-index: 3;
1968
1907
  box-shadow: var(--shadow-sm), 0 0 0 1px rgba(255,255,255,0.06);
1969
- }
1908
+ /* A query container measured in controls: 1em is one header button (24px docked, the
1909
+ window's control size when detached, which follows the font scale), so the thresholds
1910
+ below hold at any scale. Nothing in the row inherits it; the session menu takes the
1911
+ panel's back. */
1912
+ container: cp-header / inline-size;
1913
+ font-size: 24px;
1914
+ }
1915
+ .sp-sidepanel.sp-floating > .cp-header { font-size: var(--fw-header-control-size); }
1916
+ .cp-header > .cp-session-menu { font-size: 1rem; }
1970
1917
  .cp-header-actions {
1971
1918
  display: flex; align-items: center; gap: 3px; margin-left: auto; flex-shrink: 0;
1972
1919
  }
1920
+ /* The header buttons never shrink. The account menu's trigger (account-menu.js) is the one
1921
+ piece of the actions that gives way, once the session name is at its readable 88px, down to
1922
+ its compact 64px, and truncates. */
1923
+ .cp-header-actions > * { flex-shrink: 0; }
1924
+ .cp-header-actions:has(> .acct-menu-trigger) { flex-shrink: 1; min-width: 0; }
1925
+ .cp-header-actions > .acct-menu-trigger { flex-shrink: 1; }
1926
+ /* Narrow headers, in order: the trigger stays at its compact 64px and the name goes from 88px
1927
+ down to its caret; then the trigger is hidden. Room counted in controls (em) plus px: docked,
1928
+ the pencil and six buttons are 7em with 21px of gaps; detached, the move handle makes 8em,
1929
+ the window's 6px gaps 39px, the name's floor is 1em. Thresholds: name + 64px trigger + that row. */
1930
+ @container cp-header (width < calc(7em + 173px)) {
1931
+ .claude-panel:not(.sp-floating) > .cp-header .cp-session-btn { flex: 1 1 0; }
1932
+ .claude-panel:not(.sp-floating) > .cp-header > .cp-header-actions { flex-shrink: 0; }
1933
+ .claude-panel:not(.sp-floating) > .cp-header .acct-menu-trigger { flex: 0 0 64px; width: 64px; }
1934
+ }
1935
+ @container cp-header (width < calc(7em + 117px)) {
1936
+ .claude-panel:not(.sp-floating) > .cp-header .acct-menu-trigger { display: none; }
1937
+ }
1938
+ @container cp-header (width < calc(8em + 191px)) {
1939
+ .claude-panel.sp-floating > .cp-header .cp-session-btn { flex: 1 1 0; }
1940
+ .claude-panel.sp-floating > .cp-header > .cp-header-actions { flex-shrink: 0; }
1941
+ .claude-panel.sp-floating > .cp-header .acct-menu-trigger { flex: 0 0 64px; width: 64px; }
1942
+ }
1943
+ @container cp-header (width < calc(9em + 103px)) {
1944
+ .claude-panel.sp-floating > .cp-header .acct-menu-trigger { display: none; }
1945
+ }
1973
1946
  .cp-header-btn {
1974
1947
  display: flex; align-items: center; justify-content: center;
1975
1948
  width: 24px; height: 24px; border-radius: 7px;
@@ -1995,14 +1968,18 @@ function injectStyles() {
1995
1968
  font-size: 11px; font-family: 'JetBrains Mono', monospace;
1996
1969
  cursor: pointer; padding: 5px 10px; border-radius: 8px 0 0 8px;
1997
1970
  transition: background 0.15s, color 0.15s;
1998
- max-width: 100%; overflow: hidden;
1971
+ /* The session name keeps a readable 88px (about 8 characters, or its own width if shorter)
1972
+ and gives way first above that: it grows only into the room the pencil and the actions
1973
+ leave, so a long name never pushes them. Narrower, the container queries above let it go
1974
+ down to 32px (the caret). */
1975
+ flex: 1 0 88px; min-width: 32px; max-width: max-content; overflow: hidden;
1999
1976
  }
2000
1977
  .cp-session-btn:hover { background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.75); }
2001
1978
  .cp-session-btn .cp-session-label {
2002
- overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1979
+ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
2003
1980
  }
2004
1981
  .cp-session-btn .cp-dd-arrow {
2005
- font-size: 9px; padding: 4px 6px; margin: -4px -6px -4px 0;
1982
+ flex-shrink: 0; font-size: 9px; padding: 4px 6px; margin: -4px -6px -4px 0;
2006
1983
  border-radius: 0 6px 6px 0; cursor: pointer;
2007
1984
  transition: background 0.15s, color 0.2s, transform 0.2s;
2008
1985
  }
@@ -2017,6 +1994,7 @@ function injectStyles() {
2017
1994
  -webkit-tap-highlight-color: transparent;
2018
1995
  touch-action: manipulation;
2019
1996
  flex-shrink: 0;
1997
+ margin-right: 3px; /* the actions' own gap, kept when the name fills the row */
2020
1998
  }
2021
1999
  .cp-header-rename-btn:hover { color: rgba(100,160,255,0.95); background: rgba(100,160,255,0.14); }
2022
2000
  .cp-header-rename-btn:active { transform: scale(0.92); transition-duration: 0.06s; }
@@ -2975,6 +2953,7 @@ function connectTab(tab) {
2975
2953
  ws.addEventListener('open', () => {
2976
2954
  if (tab.ws !== ws) return;
2977
2955
  clearTimeout(tab.reconnectTimer);
2956
+ _ensureClaudeTerminalAuth(tab);
2978
2957
  connectionOpened(tab); // no statement of the tab's mode was made on this socket yet
2979
2958
  // Reclaim this tab's server session if it outlived the old socket — a turn in
2980
2959
  // flight, a permission card, background agents or a scheduled wakeup. The
@@ -3046,6 +3025,7 @@ function switchTab(idx) {
3046
3025
  tab.messagesEl._exitToken = (tab.messagesEl._exitToken || 0) + 1; // cancel pending exits
3047
3026
  _attachMessagesEl(tab);
3048
3027
  tab.messagesEl.style.display = '';
3028
+ _ensureClaudeTerminalAuth(tab);
3049
3029
  tab.scrollController?.setActive(true);
3050
3030
  tab.messagesEl.classList.remove('cp-tab-exit');
3051
3031
  tab.messagesEl.classList.add('cp-tab-enter');
@@ -3127,6 +3107,7 @@ function switchTab(idx) {
3127
3107
  _setCompactingUI(!!tab.compacting);
3128
3108
  populateViewDropdown(_panel?.querySelector('#cp-view'), tab);
3129
3109
  populateModeDropdown(_panel?.querySelector('#cp-mode'), tab);
3110
+ _renderAccountMenu();
3130
3111
  _paintTemporary(tab);
3131
3112
  saveTabs();
3132
3113
  }
@@ -3149,6 +3130,8 @@ function closeTab(idx, { detachAutomation = false } = {}) {
3149
3130
  if (tab.automationRunId) forgetWorkerEnd(tab.automationRunId);
3150
3131
  flushSessionSnapshotSave(tab);
3151
3132
  recordHookEvent(tab, 'SessionEnd', tab.sessionId || '(new)');
3133
+ tab.authView?.dispose();
3134
+ tab.terminalAuthView?.dispose();
3152
3135
  tab.closed = true;
3153
3136
  tab.titleRequestController?.abort();
3154
3137
  tab.titleRequestController = null;
@@ -4479,7 +4462,7 @@ function writeSessionSnapshot(tab) {
4479
4462
  const sid = tab?.sessionId || null;
4480
4463
  const $msgs = tab?.messagesEl || null;
4481
4464
  if (!sid || !$msgs) return;
4482
- const html = $msgs.innerHTML || '';
4465
+ const html = providerAuthSnapshot($msgs);
4483
4466
  if (!html.trim()) return;
4484
4467
  // Skip snapshot if the transcript only contains the empty-state placeholder
4485
4468
  if ($msgs.children.length === 1 && $msgs.firstElementChild?.classList?.contains('cp-empty')) return;
@@ -5134,7 +5117,7 @@ function _contextMenuData(tab, { full = false } = {}) {
5134
5117
  folder: tab.init?.cwd || tab.project || '',
5135
5118
  // The mode as the project bar words it (it knows Bypass and "from settings").
5136
5119
  mode: ($mode && !$mode.hidden && $mode.querySelector('.cp-dd-label')?.textContent) || tab.permissionMode || '',
5137
- account: [tab.accountInfo?.email, tab.accountInfo?.organization].filter(Boolean).join(' · '),
5120
+ account: [tab.accountInfo?.authMethod === 'apiKey' ? 'API key' : tab.accountInfo?.email, tab.accountInfo?.organization].filter(Boolean).join(' · '),
5138
5121
  flags: sessionFlags(tab.session, { toolPolicy: tab.toolPolicy, fastModeState: tab.fastModeState, account: tab.accountId }),
5139
5122
  limit: tab.rateLimit?.text || '',
5140
5123
  backgroundTasks: (tab.backgroundWork || []).length,
@@ -5323,6 +5306,7 @@ function _processTabMsg(tab, msg) {
5323
5306
  if (tab === activeTab()) {
5324
5307
  renderStatusline(tab);
5325
5308
  populateModeDropdown(_panel?.querySelector('#cp-mode'), tab);
5309
+ _renderAccountMenu();
5326
5310
  }
5327
5311
  break;
5328
5312
  }
@@ -5546,6 +5530,8 @@ function _processTabMsg(tab, msg) {
5546
5530
  break;
5547
5531
  }
5548
5532
  appendError(tab, msg.message);
5533
+ // The tab's account is gone, or belongs to another conversation: the accounts card is where to choose.
5534
+ if (msg.code === 'account_unavailable' || msg.code === 'account_change_refused') _showAccounts(tab);
5549
5535
  notify('panel', NOTIF_TYPE.ERROR, tab.label || 'Claude Code', { tabId: tab.id });
5550
5536
  if (typeof msg.message === 'string' && /Claude CLI not found|ENOENT/i.test(msg.message)) {
5551
5537
  flagClaudeCliInstallFailure(msg.message);
@@ -7567,6 +7553,7 @@ function _afterTemporary(tab, sid, label) {
7567
7553
  for (const waiting of tab._sessionRequests?.values() || []) { clearTimeout(waiting.timer); try { waiting.reject(new Error('The temporary chat has ended.')); } catch {} }
7568
7554
  // An open history search lists its prompts.
7569
7555
  if (tab === activeTab()) _panel?.querySelector('.cp-rsearch')?.remove();
7556
+ tab.terminalAuthView?.dispose();
7570
7557
  tabAfterTemporary(tab, newTabState(sid, label || 'New chat', tab.id));
7571
7558
  }
7572
7559
 
@@ -8617,47 +8604,149 @@ function _showUsage(tab) {
8617
8604
  }).catch(err => appendInfoCard(tab, { title: 'Usage', kind: 'info', body: err.message }));
8618
8605
  }
8619
8606
 
8620
- // /account: the Claude accounts set up in SynaBun, and which one this tab uses.
8607
+ // ── Claude accounts ──
8608
+ // Every account and its state come from the server (lib/claude-accounts.js
8609
+ // describe(): its mode, whether it is signed in, its identity: an email or a
8610
+ // masked key, never a key); account-view.js decides the words. One list for
8611
+ // every tab, and one place to choose and manage accounts: the account menu in
8612
+ // the header (account-menu.js, the same component as the Codex panel's).
8613
+ // /account, /login and the sign-in screen's "Other accounts…" open it.
8614
+ // `claude:accounts-changed` (any window, any surface) reloads the list.
8621
8615
  // A conversation belongs to the account it started under (its transcript lives
8622
- // in that account's config directory), so the account is chosen before the
8623
- // first message of a tab.
8624
- function _showAccounts(tab, wanted = '') {
8625
- if (!hasCapability(tab, 'accounts')) { appendStatus(tab, 'Choosing an account needs a newer SynaBun server: restart it to enable this.'); return; }
8626
- fetch('/api/claude/accounts').then(r => r.json()).then((d) => {
8627
- const accounts = Array.isArray(d?.accounts) ? d.accounts : [];
8628
- const pick = (account) => {
8629
- const id = account.isDefault ? '' : account.id;
8630
- if (id === (tab.accountId || '')) { appendStatus(tab, `This tab already uses ${account.label}.`); return; }
8631
- if (tab.sessionId) { appendStatus(tab, 'This conversation belongs to the account it started under. Start a new chat (or a new tab) to use another account.'); return; }
8632
- if (!account.loggedIn) { appendStatus(tab, `${account.label} is not signed in yet. Sign it in from Settings first.`); return; }
8633
- tab.accountId = id;
8634
- saveTabs();
8635
- if (tab === activeTab()) renderStatusline(tab);
8636
- appendStatus(tab, `This tab runs under ${account.label}${account.email ? ` (${account.email})` : ''}.`);
8637
- };
8638
- if (wanted) {
8616
+ // in that account's config directory): a tab with one opens another account in
8617
+ // a new chat, and the tab's own account changes only before its first message.
8618
+ let _claudeAccountRows = null;
8619
+ let _claudeAccountsLoad = null;
8620
+ let _claudeAccountsError = '';
8621
+ let _accountMenu = null;
8622
+ function _loadClaudeAccounts({ force = false, refresh = false } = {}) {
8623
+ if (!force && !refresh && _claudeAccountRows) return Promise.resolve(_claudeAccountRows);
8624
+ if (_claudeAccountsLoad && !refresh) return _claudeAccountsLoad;
8625
+ const load = fetch(`/api/claude/accounts${refresh ? '?refresh=true' : ''}`, { cache: 'no-store' })
8626
+ .then(r => r.ok ? r.json() : Promise.reject(new Error(accountText('readFailed'))))
8627
+ .then((d) => {
8628
+ _claudeAccountRows = Array.isArray(d?.accounts) ? d.accounts : [];
8629
+ _claudeAccountsError = '';
8630
+ _claudeAccountsChanged();
8631
+ return _claudeAccountRows;
8632
+ })
8633
+ .catch((error) => { _claudeAccountsError = accountText('readFailed'); _claudeAccountsChanged(); throw error; })
8634
+ .finally(() => { if (_claudeAccountsLoad === load) _claudeAccountsLoad = null; });
8635
+ _claudeAccountsLoad = load;
8636
+ return load;
8637
+ }
8638
+ function _claudeAccountRow(id) {
8639
+ return (_claudeAccountRows || []).find(row => row.id === serverAccountId(id)) || null;
8640
+ }
8641
+ function _claudeAccountsChanged() {
8642
+ _renderAccountMenu();
8643
+ }
8644
+
8645
+ // The header account menu: the active tab's account and what it runs on, every account, and their
8646
+ // management (add, sign in with Claude, an API key, the "Uses" switch, sign out, rename, remove).
8647
+ function _mountAccountMenu() {
8648
+ if (_accountMenu || !_panel) return _accountMenu;
8649
+ const actions = _panel.querySelector('.cp-header-actions');
8650
+ if (!actions) return null;
8651
+ const path = id => `/api/claude/accounts/${encodeURIComponent(id)}`;
8652
+ _accountMenu = mountAccountMenu({
8653
+ provider: 'claude', container: actions, before: actions.firstChild, layer: () => _panel,
8654
+ read: () => {
8655
+ const tab = activeTab();
8656
+ return {
8657
+ rows: _claudeAccountRows || [], currentId: tab?.accountId || '', hasConversation: !!tab?.sessionId,
8658
+ available: !!tab && hasCapability(tab, 'accounts') && !tab.automationActive,
8659
+ busy: !!(tab?.running || tab?.automationActive), loading: !_claudeAccountRows, error: _claudeAccountsError,
8660
+ };
8661
+ },
8662
+ actions: {
8663
+ load: ({ refresh }) => _loadClaudeAccounts({ force: true, refresh }),
8664
+ pick: (id) => { const tab = activeTab(); if (tab) _pickAccount(tab, id); },
8665
+ add: async () => (await _claudeAuthRequest('/api/claude/accounts', { method: 'POST', body: '{}' })).account,
8666
+ signIn: (id) => startProviderTerminalLogin('claude', id, `Claude sign-in · ${_claudeAccountRow(id)?.label || id}`),
8667
+ saveKey: (id, key) => providerApiKeyRequest('claude', id, key),
8668
+ setMode: (id, mode) => _claudeAuthRequest(path(id), { method: 'PATCH', body: JSON.stringify({ mode }) }),
8669
+ signOut: (id, credential) => _claudeAuthRequest(`${path(id)}/auth/logout`, { method: 'POST', body: JSON.stringify({ credential }) }),
8670
+ rename: (id, label) => _claudeAuthRequest(path(id), { method: 'PATCH', body: JSON.stringify({ label }) }),
8671
+ remove: (id) => _claudeAuthRequest(path(id), { method: 'DELETE' }),
8672
+ },
8673
+ });
8674
+ return _accountMenu;
8675
+ }
8676
+ function _renderAccountMenu() {
8677
+ if (!_accountMenu) return;
8678
+ const tab = activeTab();
8679
+ if (tab && hasCapability(tab, 'accounts') && !_claudeAccountRows && !_claudeAccountsLoad) _loadClaudeAccounts().catch(() => {});
8680
+ _accountMenu.render();
8681
+ }
8682
+
8683
+ // Pick an account for a tab: now when it has no conversation yet, else in a new chat (a new tab).
8684
+ function _pickAccount(tab, id) {
8685
+ const rows = _claudeAccountRows || [];
8686
+ const plan = accountSwitchPlan({ rows, currentId: tab.accountId || '', targetId: id, hasConversation: !!tab.sessionId });
8687
+ const target = _claudeAccountRow(id);
8688
+ if (plan.effect === 'missing' || plan.effect === 'same') { appendStatus(tab, plan.message); return; }
8689
+ if (plan.effect === 'next-chat') {
8690
+ if (_tabs.length >= MAX_TABS) { appendStatus(tab, `${plan.message} ${accountText('tooManyTabs')}`); return; }
8691
+ const fresh = createTab(null, 'New chat');
8692
+ fresh.accountId = tabAccountId(id);
8693
+ _ensureClaudeTerminalAuth(fresh);
8694
+ saveTabs();
8695
+ if (fresh === activeTab()) _renderAccountMenu();
8696
+ appendStatus(fresh, accountText('newChatUnder', { label: target ? accountName(target) : id }));
8697
+ return;
8698
+ }
8699
+ tab.accountId = tabAccountId(id);
8700
+ _ensureClaudeTerminalAuth(tab);
8701
+ saveTabs();
8702
+ if (tab === activeTab()) { renderStatusline(tab); _renderAccountMenu(); }
8703
+ appendStatus(tab, plan.message);
8704
+ }
8705
+
8706
+ // /account (and /login, and the sign-in screen's "Other accounts…"): the header account menu.
8707
+ // `/account <name>` picks that account at once; `manage` opens one account's management.
8708
+ function _showAccounts(tab, wanted = '', { manage = '' } = {}) {
8709
+ if (!hasCapability(tab, 'accounts')) { appendStatus(tab, accountText('needsServer')); return; }
8710
+ if (wanted) {
8711
+ _loadClaudeAccounts({ force: true }).then((accounts) => {
8639
8712
  const w = wanted.trim().toLowerCase();
8640
- const match = accounts.find(a => a.id.toLowerCase() === w || String(a.label || '').toLowerCase() === w || String(a.email || '').toLowerCase() === w);
8713
+ const match = accounts.find(a => a.id.toLowerCase() === w || String(a.label || '').toLowerCase() === w || String(a.subscription?.email || '').toLowerCase() === w);
8641
8714
  if (!match) { appendStatus(tab, `No account "${wanted}". Use /account to list them.`); return; }
8642
- pick(match);
8643
- return;
8644
- }
8645
- const current = tab.accountId || 'default';
8646
- const html = accounts.map(a => `<div class="cp-task-row" data-account="${esc(a.id)}"><div class="cp-task-head">
8647
- <span class="cp-task-title">${esc(a.label)}${a.id === current ? ' ✓' : ''}</span>
8648
- <span class="cp-chip ${a.loggedIn ? 'cp-chip-ok' : 'cp-chip-warn'}">${a.loggedIn ? 'signed in' : 'not signed in'}</span>
8649
- ${a.id !== current ? '<button type="button" class="cp-engine-retry" data-use>Use for this tab</button>' : ''}</div>
8650
- <div class="cp-task-stats">${esc([a.email, a.organization].filter(Boolean).join(' · ') || 'no identity yet')}</div></div>`).join('')
8651
- + '<div class="cp-info-row muted">Accounts are added and signed in from Settings. The default account is what Claude Code uses in a terminal.</div>';
8652
- const card = appendInfoCard(tab, { title: 'Claude accounts', kind: 'info', html });
8653
- card?.querySelectorAll('[data-use]').forEach((btn) => {
8654
- btn.addEventListener('click', () => {
8655
- const id = btn.closest('[data-account]')?.dataset.account;
8656
- const account = accounts.find(a => a.id === id);
8657
- if (account) pick(account);
8658
- });
8659
- });
8660
- }).catch(() => appendStatus(tab, 'Could not read the accounts.'));
8715
+ _pickAccount(tab, match.id);
8716
+ }).catch(() => appendStatus(tab, accountText('readFailed')));
8717
+ return;
8718
+ }
8719
+ if (tab !== activeTab()) return;
8720
+ _mountAccountMenu()?.open(manage ? { manage } : {});
8721
+ }
8722
+
8723
+ async function _claudeAuthRequest(url, options = {}) {
8724
+ const response = await fetch(url, { ...options, cache: 'no-store', headers: { 'Content-Type': 'application/json' } });
8725
+ const data = await response.json().catch(() => ({}));
8726
+ if (!response.ok || data.error) throw new Error(data.error || 'Claude authentication request failed.');
8727
+ return data;
8728
+ }
8729
+
8730
+ function _ensureClaudeTerminalAuth(tab) {
8731
+ const accountId = tab.accountId || 'default';
8732
+ if (tab.closed || !tab.messagesEl) return;
8733
+ if (tab.terminalAuthView && tab.terminalAuthAccount === accountId) { void tab.terminalAuthView.refresh(); return; }
8734
+ tab.terminalAuthView?.dispose();
8735
+ tab.terminalAuthAccount = accountId;
8736
+ const named = accountId !== 'default' ? _claudeAccountRow(accountId) : null;
8737
+ tab.terminalAuthView = mountProviderTerminalAuth({
8738
+ host: tab.messagesEl, provider: 'claude', accountId, logo: CLAUDE_ICON,
8739
+ ...(named ? { message: `Sign in to Claude to use ${named.label}.` } : {}),
8740
+ // Another account (or a new one) is one click away from the sign-in screen: the header account menu.
8741
+ moreAction: { label: accountText('otherAccounts'), run: () => _showAccounts(tab) },
8742
+ isCurrent: () => !tab.closed && (tab.accountId || 'default') === accountId,
8743
+ readAccount: async () => {
8744
+ const account = (await _claudeAuthRequest(`/api/claude/accounts/${encodeURIComponent(accountId)}/auth?refresh=true`)).account;
8745
+ if (!tab.closed && (tab.accountId || 'default') === accountId) tab.accountInfo = account;
8746
+ return account;
8747
+ },
8748
+ onSignedIn: () => { _loadClaudeAccounts({ force: true }).catch(() => {}); },
8749
+ });
8661
8750
  }
8662
8751
 
8663
8752
  // /mcp: every server of the session with its state, and what can be done about it.
@@ -9176,8 +9265,15 @@ function runSlashCommand(tab, raw) {
9176
9265
  return true;
9177
9266
  }
9178
9267
  case 'cost': { clearInput(); emit('cost:toggle'); return true; }
9179
- case 'login': { clearInput(); window.open('https://claude.ai/login', '_blank'); return true; }
9180
- case 'logout': { clearInput(); window.open('https://claude.ai/logout', '_blank'); return true; }
9268
+ case 'login': { clearInput(); _showAccounts(tab, '', { manage: serverAccountId(tab.accountId) }); return true; }
9269
+ case 'logout': {
9270
+ clearInput();
9271
+ if (tab.running || tab.automationActive) { appendStatus(tab, 'Finish or stop the current turn before signing out.'); return true; }
9272
+ void _claudeAuthRequest(`/api/claude/accounts/${encodeURIComponent(tab.accountId || 'default')}/auth/logout`, { method: 'POST', body: '{}' })
9273
+ .then(() => { tab.accountInfo = null; tab.terminalAuthView?.update({ loggedIn: false }); })
9274
+ .catch(() => appendStatus(tab, 'Could not sign out. Try again.'));
9275
+ return true;
9276
+ }
9181
9277
  case 'plan': {
9182
9278
  clearInput();
9183
9279
  // The one path for plan mode: on is the user's pick of Plan, off goes back
@@ -9199,8 +9295,9 @@ function runSlashCommand(tab, raw) {
9199
9295
  function send({ shift = false } = {}) {
9200
9296
  const tab = activeTab();
9201
9297
  if (!tab) return;
9202
- if ((_cliInstalled === null || _cliInstallFailureForced) && !tab.automationActive) {
9203
- notify({ type: NOTIF_TYPE.WARN, title: 'Claude CLI not installed', body: 'Install the Claude Code CLI before sending a message.' });
9298
+ if (_cliBlocked() && !tab.automationActive) {
9299
+ // The banner above the transcript says why, and offers the way out.
9300
+ _cliBanner?.nudge();
9204
9301
  return;
9205
9302
  }
9206
9303
  const $input = _panel?.querySelector('#cp-input');
@@ -10094,116 +10191,50 @@ function syncReservedWidth(knownWidth) {
10094
10191
  }
10095
10192
 
10096
10193
  // ── CLI installation status (banner + send-block) ──
10097
- let _cliInstallFailureForced = false;
10098
- let _cliFailureReason = null;
10099
-
10100
- function _ensureCliBannerEl() {
10101
- if (!_panel) return null;
10102
- const container = _panel.querySelector('#cp-messages-container');
10103
- if (!container || !container.parentNode) return null;
10104
- let banner = container.parentNode.querySelector(':scope > .cp-cli-banner');
10105
- if (banner) { _renderCliBannerContent(banner); return banner; }
10106
- const url = getCliDocUrl('claude-code');
10107
- banner = document.createElement('div');
10108
- banner.className = 'cp-cli-banner';
10109
- banner.innerHTML = `
10110
- <div class="cp-cli-banner-icon">!</div>
10111
- <div class="cp-cli-banner-text">
10112
- <div class="cp-cli-banner-title"></div>
10113
- <div class="cp-cli-banner-body"></div>
10114
- </div>
10115
- <div class="cp-cli-banner-actions">
10116
- <a class="cp-cli-banner-link" href="${esc(url || '#')}" target="_blank" rel="noopener noreferrer">Install guide</a>
10117
- <button class="cp-cli-banner-recheck" type="button">Re-check</button>
10118
- </div>
10119
- `;
10120
- container.parentNode.insertBefore(banner, container);
10121
- const btn = banner.querySelector('.cp-cli-banner-recheck');
10122
- btn?.addEventListener('click', async () => {
10123
- btn.disabled = true;
10124
- btn.textContent = 'Checking…';
10125
- try { await recheckCliStatus('claude-code'); }
10126
- finally {
10127
- if (btn.isConnected) {
10128
- btn.disabled = false;
10129
- btn.textContent = 'Re-check';
10130
- }
10131
- }
10132
- });
10133
- _renderCliBannerContent(banner);
10134
- return banner;
10135
- }
10136
-
10137
- // Distinguish "never installed" from "installed but would not launch" —
10138
- // telling the user to install something already present sends them chasing a
10139
- // reinstall they do not need.
10140
- function _renderCliBannerContent(banner) {
10141
- const titleEl = banner.querySelector('.cp-cli-banner-title');
10142
- const bodyEl = banner.querySelector('.cp-cli-banner-body');
10143
- if (!titleEl || !bodyEl) return;
10144
- const label = getCliLabel('claude-code');
10145
- bodyEl.replaceChildren();
10146
-
10147
- if (_cliInstalled === null) {
10148
- titleEl.textContent = `${label} CLI not installed`;
10149
- bodyEl.append('Run ');
10150
- const code = document.createElement('code');
10151
- code.textContent = getCliInstallCommand('claude-code');
10152
- bodyEl.append(code, ' or follow the install guide.');
10153
- return;
10154
- }
10155
-
10156
- titleEl.textContent = `${label} CLI failed to start`;
10157
- bodyEl.append(`${label} v${_cliInstalled} is installed, but it could not be launched. `);
10158
- if (_cliFailureReason) {
10159
- const code = document.createElement('code');
10160
- code.textContent = _cliFailureReason;
10161
- bodyEl.append(code);
10162
- } else {
10163
- bodyEl.append('Check the CLI path in Settings, then re-check.');
10194
+ // One controller (ui-cli-banner.js) draws the banner above the transcript while
10195
+ // Claude Code is not usable: not installed (with Install, which runs Anthropic's
10196
+ // own installer on the server), being installed, failed to install, or found but
10197
+ // failed to start (with the error it gave). It also holds the class that keeps
10198
+ // sending off. What it says is cli-install-view.js (`cliInstall.*` strings).
10199
+ function _cliBannerController() {
10200
+ if (!_cliBanner) {
10201
+ _cliBanner = mountCliBanner({
10202
+ toolKey: 'claude-code',
10203
+ prefix: 'cp',
10204
+ panel: () => _panel,
10205
+ anchor: () => _panel?.querySelector('#cp-messages-container'),
10206
+ onBlockedChange: (blocked) => {
10207
+ const $send = _panel?.querySelector('#cp-send');
10208
+ if (!$send) return;
10209
+ if (blocked) { $send.disabled = true; return; }
10210
+ const tab = activeTab();
10211
+ const $input = _panel?.querySelector('#cp-input');
10212
+ if (tab?.running) $send.disabled = false;
10213
+ else $send.disabled = !$input?.value.trim() && !tab?.attachedImages?.length && !tab?.attachedFiles?.length;
10214
+ },
10215
+ });
10164
10216
  }
10217
+ return _cliBanner;
10165
10218
  }
10166
10219
 
10167
- function _removeCliBannerEl() {
10168
- if (!_panel) return;
10169
- const banner = _panel.querySelector(':scope > .cp-cli-banner');
10170
- banner?.remove();
10220
+ /** Sending is held back: Claude Code is missing, broken, failed to install, or being installed. */
10221
+ function _cliBlocked() {
10222
+ return !!_cliBanner?.blocked();
10171
10223
  }
10172
10224
 
10173
10225
  function _refreshCliBanners() {
10174
10226
  if (!_panel) return;
10175
- const missing = _cliInstalled === null || _cliInstallFailureForced;
10176
- _panel.classList.toggle('cp-cli-blocked', missing);
10177
- if (missing) _ensureCliBannerEl();
10178
- else _removeCliBannerEl();
10179
- const $send = _panel.querySelector('#cp-send');
10180
- if ($send && missing) $send.disabled = true;
10227
+ _cliBannerController().refresh();
10181
10228
  }
10182
10229
 
10230
+ // A session could not start Claude Code: "failed to start" with its words at
10231
+ // once, then the server is asked again and its answer decides what stays.
10183
10232
  export function flagClaudeCliInstallFailure(reason = null) {
10184
- _cliInstallFailureForced = true;
10185
- _cliFailureReason = reason ? String(reason).slice(0, 300) : null;
10186
- _refreshCliBanners();
10187
- // Clear from the RETURNED value, not the subscriber callback: the callback
10188
- // only fires when the version string changes, and a launch failure does not
10189
- // change it, so the banner would otherwise latch permanently.
10190
- recheckCliStatus('claude-code')
10191
- .then((info) => {
10192
- if (!info?.installed) return;
10193
- _cliInstallFailureForced = false;
10194
- _cliFailureReason = null;
10195
- _refreshCliBanners();
10196
- })
10197
- .catch(() => {});
10233
+ _cliBannerController().flagFailure(reason);
10198
10234
  }
10199
10235
 
10200
10236
  function _ensureCliSubscription() {
10201
- if (_cliUnsub) return;
10202
- _cliUnsub = subscribeCliStatus('claude-code', (info) => {
10203
- _cliInstalled = info?.installed || null;
10204
- if (_cliInstalled) { _cliInstallFailureForced = false; _cliFailureReason = null; }
10205
- _refreshCliBanners();
10206
- });
10237
+ _cliBannerController();
10207
10238
  }
10208
10239
 
10209
10240
  // ── Delegated transcript actions ──
@@ -11192,6 +11223,13 @@ function wireEvents() {
11192
11223
  const $close = _panel.querySelector('.cp-close-btn');
11193
11224
  const $minimize = _panel.querySelector('.cp-minimize-btn');
11194
11225
  const $slide = _panel.querySelector('.cp-slide-btn');
11226
+ _mountAccountMenu();
11227
+ // Any window or surface changed an account (signed in, a key saved, its mode, renamed, added,
11228
+ // removed): the account menu re-reads the list, and the tabs on it re-check sign-in.
11229
+ on('sync:claude:accounts-changed', (msg) => {
11230
+ _loadClaudeAccounts({ force: true }).catch(() => {});
11231
+ for (const t of _tabs) if (!msg?.accountId || serverAccountId(t.accountId) === msg.accountId) void t.terminalAuthView?.refresh();
11232
+ });
11195
11233
  const $new = _panel.querySelector('.cp-new-btn');
11196
11234
 
11197
11235
  const $brand = _panel.querySelector('.cp-brand');
@@ -11606,6 +11644,13 @@ function wireEvents() {
11606
11644
  const $sessMenu = _panel.querySelector('#cp-session-menu');
11607
11645
  const $sessLabel = _panel.querySelector('.cp-session-label');
11608
11646
  let _sessClickTimer = null;
11647
+ // The whole name as the chip's tooltip, for when the header shows only part of it. The label is
11648
+ // written from many places (switch, rename, title, reset), so it follows the label itself.
11649
+ const syncSessionTooltip = () => {
11650
+ if (!$sessLabel.querySelector('.cp-rename-input')) $sessBtn.title = $sessLabel.textContent;
11651
+ };
11652
+ syncSessionTooltip();
11653
+ new MutationObserver(syncSessionTooltip).observe($sessLabel, { childList: true, characterData: true, subtree: true });
11609
11654
 
11610
11655
  $sessBtn.addEventListener('click', (e) => {
11611
11656
  // Block menu toggle while rename input is active