@deepseek-harness-tui/dsh-tui 0.12.0 → 0.14.0

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 (1542) hide show
  1. package/README.md +124 -8
  2. package/assets/claude-girl/claude-girl-happy.png +0 -0
  3. package/assets/claude-girl/claude-girl.png +0 -0
  4. package/assets/codex-girl/codex-girl-happy.png +0 -0
  5. package/assets/codex-girl/codex-girl.png +0 -0
  6. package/assets/deepy/README.md +60 -0
  7. package/assets/deepy/frames.json +1 -0
  8. package/assets/whale-girl/whale-girl-happy.png +0 -0
  9. package/assets/whaleGirl/README.md +7 -0
  10. package/assets/whaleGirl/frames.json +1 -0
  11. package/assets/whaleGirl/img/building/00.png +0 -0
  12. package/assets/whaleGirl/img/building/01.png +0 -0
  13. package/assets/whaleGirl/img/building/02.png +0 -0
  14. package/assets/whaleGirl/img/building/03.png +0 -0
  15. package/assets/whaleGirl/img/building/04.png +0 -0
  16. package/assets/whaleGirl/img/building/05.png +0 -0
  17. package/assets/whaleGirl/img/building/06.png +0 -0
  18. package/assets/whaleGirl/img/building/07.png +0 -0
  19. package/assets/whaleGirl/img/building/08.png +0 -0
  20. package/assets/whaleGirl/img/building/09.png +0 -0
  21. package/assets/whaleGirl/img/building/10.png +0 -0
  22. package/assets/whaleGirl/img/building/11.png +0 -0
  23. package/assets/whaleGirl/img/building/12.png +0 -0
  24. package/assets/whaleGirl/img/building/13.png +0 -0
  25. package/assets/whaleGirl/img/building/14.png +0 -0
  26. package/assets/whaleGirl/img/building/15.png +0 -0
  27. package/assets/whaleGirl/img/building/16.png +0 -0
  28. package/assets/whaleGirl/img/building/17.png +0 -0
  29. package/assets/whaleGirl/img/building/18.png +0 -0
  30. package/assets/whaleGirl/img/building/19.png +0 -0
  31. package/assets/whaleGirl/img/building/20.png +0 -0
  32. package/assets/whaleGirl/img/building/21.png +0 -0
  33. package/assets/whaleGirl/img/building/22.png +0 -0
  34. package/assets/whaleGirl/img/building/23.png +0 -0
  35. package/assets/whaleGirl/img/carrying/00.png +0 -0
  36. package/assets/whaleGirl/img/carrying/01.png +0 -0
  37. package/assets/whaleGirl/img/carrying/02.png +0 -0
  38. package/assets/whaleGirl/img/carrying/03.png +0 -0
  39. package/assets/whaleGirl/img/carrying/04.png +0 -0
  40. package/assets/whaleGirl/img/carrying/05.png +0 -0
  41. package/assets/whaleGirl/img/carrying/06.png +0 -0
  42. package/assets/whaleGirl/img/carrying/07.png +0 -0
  43. package/assets/whaleGirl/img/compacting/00.png +0 -0
  44. package/assets/whaleGirl/img/compacting/01.png +0 -0
  45. package/assets/whaleGirl/img/compacting/02.png +0 -0
  46. package/assets/whaleGirl/img/compacting/03.png +0 -0
  47. package/assets/whaleGirl/img/compacting/04.png +0 -0
  48. package/assets/whaleGirl/img/compacting/05.png +0 -0
  49. package/assets/whaleGirl/img/compacting/06.png +0 -0
  50. package/assets/whaleGirl/img/compacting/07.png +0 -0
  51. package/assets/whaleGirl/img/compacting/08.png +0 -0
  52. package/assets/whaleGirl/img/compacting/09.png +0 -0
  53. package/assets/whaleGirl/img/conducting/00.png +0 -0
  54. package/assets/whaleGirl/img/conducting/01.png +0 -0
  55. package/assets/whaleGirl/img/conducting/02.png +0 -0
  56. package/assets/whaleGirl/img/conducting/03.png +0 -0
  57. package/assets/whaleGirl/img/conducting/04.png +0 -0
  58. package/assets/whaleGirl/img/conducting/05.png +0 -0
  59. package/assets/whaleGirl/img/conducting/06.png +0 -0
  60. package/assets/whaleGirl/img/conducting/07.png +0 -0
  61. package/assets/whaleGirl/img/conducting/08.png +0 -0
  62. package/assets/whaleGirl/img/conducting/09.png +0 -0
  63. package/assets/whaleGirl/img/conducting/10.png +0 -0
  64. package/assets/whaleGirl/img/conducting/11.png +0 -0
  65. package/assets/whaleGirl/img/drag/00.png +0 -0
  66. package/assets/whaleGirl/img/drag/01.png +0 -0
  67. package/assets/whaleGirl/img/drag/02.png +0 -0
  68. package/assets/whaleGirl/img/drag/03.png +0 -0
  69. package/assets/whaleGirl/img/drag/04.png +0 -0
  70. package/assets/whaleGirl/img/drag/05.png +0 -0
  71. package/assets/whaleGirl/img/drag/06.png +0 -0
  72. package/assets/whaleGirl/img/drag/07.png +0 -0
  73. package/assets/whaleGirl/img/drag/08.png +0 -0
  74. package/assets/whaleGirl/img/drag/09.png +0 -0
  75. package/assets/whaleGirl/img/error/00.png +0 -0
  76. package/assets/whaleGirl/img/error/01.png +0 -0
  77. package/assets/whaleGirl/img/error/02.png +0 -0
  78. package/assets/whaleGirl/img/error/03.png +0 -0
  79. package/assets/whaleGirl/img/error/04.png +0 -0
  80. package/assets/whaleGirl/img/error/05.png +0 -0
  81. package/assets/whaleGirl/img/error/06.png +0 -0
  82. package/assets/whaleGirl/img/error/07.png +0 -0
  83. package/assets/whaleGirl/img/error/08.png +0 -0
  84. package/assets/whaleGirl/img/error/09.png +0 -0
  85. package/assets/whaleGirl/img/happy/00.png +0 -0
  86. package/assets/whaleGirl/img/happy/01.png +0 -0
  87. package/assets/whaleGirl/img/happy/02.png +0 -0
  88. package/assets/whaleGirl/img/happy/03.png +0 -0
  89. package/assets/whaleGirl/img/happy/04.png +0 -0
  90. package/assets/whaleGirl/img/happy/05.png +0 -0
  91. package/assets/whaleGirl/img/happy/06.png +0 -0
  92. package/assets/whaleGirl/img/happy/07.png +0 -0
  93. package/assets/whaleGirl/img/happy/08.png +0 -0
  94. package/assets/whaleGirl/img/happy/09.png +0 -0
  95. package/assets/whaleGirl/img/happy/10.png +0 -0
  96. package/assets/whaleGirl/img/idle/00.png +0 -0
  97. package/assets/whaleGirl/img/idle/01.png +0 -0
  98. package/assets/whaleGirl/img/idle/02.png +0 -0
  99. package/assets/whaleGirl/img/idle/03.png +0 -0
  100. package/assets/whaleGirl/img/idle/04.png +0 -0
  101. package/assets/whaleGirl/img/idle/05.png +0 -0
  102. package/assets/whaleGirl/img/idle/06.png +0 -0
  103. package/assets/whaleGirl/img/idle/07.png +0 -0
  104. package/assets/whaleGirl/img/idle/08.png +0 -0
  105. package/assets/whaleGirl/img/idle/09.png +0 -0
  106. package/assets/whaleGirl/img/idle/10.png +0 -0
  107. package/assets/whaleGirl/img/idle/11.png +0 -0
  108. package/assets/whaleGirl/img/idle/12.png +0 -0
  109. package/assets/whaleGirl/img/idle/13.png +0 -0
  110. package/assets/whaleGirl/img/idle/14.png +0 -0
  111. package/assets/whaleGirl/img/idle/15.png +0 -0
  112. package/assets/whaleGirl/img/idle/16.png +0 -0
  113. package/assets/whaleGirl/img/idle/17.png +0 -0
  114. package/assets/whaleGirl/img/idle/18.png +0 -0
  115. package/assets/whaleGirl/img/idle/19.png +0 -0
  116. package/assets/whaleGirl/img/idle/20.png +0 -0
  117. package/assets/whaleGirl/img/idle-look/00.png +0 -0
  118. package/assets/whaleGirl/img/idle-look/01.png +0 -0
  119. package/assets/whaleGirl/img/idle-look/02.png +0 -0
  120. package/assets/whaleGirl/img/idle-look/03.png +0 -0
  121. package/assets/whaleGirl/img/idle-look/04.png +0 -0
  122. package/assets/whaleGirl/img/idle-look/05.png +0 -0
  123. package/assets/whaleGirl/img/idle-look/06.png +0 -0
  124. package/assets/whaleGirl/img/idle-look/07.png +0 -0
  125. package/assets/whaleGirl/img/idle-look/08.png +0 -0
  126. package/assets/whaleGirl/img/idle-look/09.png +0 -0
  127. package/assets/whaleGirl/img/idle-look/10.png +0 -0
  128. package/assets/whaleGirl/img/idle-look/11.png +0 -0
  129. package/assets/whaleGirl/img/idle-look/12.png +0 -0
  130. package/assets/whaleGirl/img/idle-spout/00.png +0 -0
  131. package/assets/whaleGirl/img/idle-spout/01.png +0 -0
  132. package/assets/whaleGirl/img/idle-spout/02.png +0 -0
  133. package/assets/whaleGirl/img/idle-spout/03.png +0 -0
  134. package/assets/whaleGirl/img/idle-spout/04.png +0 -0
  135. package/assets/whaleGirl/img/idle-spout/05.png +0 -0
  136. package/assets/whaleGirl/img/idle-spout/06.png +0 -0
  137. package/assets/whaleGirl/img/idle-spout/07.png +0 -0
  138. package/assets/whaleGirl/img/idle-spout/08.png +0 -0
  139. package/assets/whaleGirl/img/idle-spout/09.png +0 -0
  140. package/assets/whaleGirl/img/idle-spout/10.png +0 -0
  141. package/assets/whaleGirl/img/music/00.png +0 -0
  142. package/assets/whaleGirl/img/music/01.png +0 -0
  143. package/assets/whaleGirl/img/music/02.png +0 -0
  144. package/assets/whaleGirl/img/music/03.png +0 -0
  145. package/assets/whaleGirl/img/music/04.png +0 -0
  146. package/assets/whaleGirl/img/music/05.png +0 -0
  147. package/assets/whaleGirl/img/music/06.png +0 -0
  148. package/assets/whaleGirl/img/music/07.png +0 -0
  149. package/assets/whaleGirl/img/notification/00.png +0 -0
  150. package/assets/whaleGirl/img/notification/01.png +0 -0
  151. package/assets/whaleGirl/img/notification/02.png +0 -0
  152. package/assets/whaleGirl/img/notification/03.png +0 -0
  153. package/assets/whaleGirl/img/notification/04.png +0 -0
  154. package/assets/whaleGirl/img/notification/05.png +0 -0
  155. package/assets/whaleGirl/img/notification/06.png +0 -0
  156. package/assets/whaleGirl/img/notification/07.png +0 -0
  157. package/assets/whaleGirl/img/poke-left/00.png +0 -0
  158. package/assets/whaleGirl/img/poke-left/01.png +0 -0
  159. package/assets/whaleGirl/img/poke-left/02.png +0 -0
  160. package/assets/whaleGirl/img/poke-left/03.png +0 -0
  161. package/assets/whaleGirl/img/poke-left/04.png +0 -0
  162. package/assets/whaleGirl/img/poke-left/05.png +0 -0
  163. package/assets/whaleGirl/img/poke-left/06.png +0 -0
  164. package/assets/whaleGirl/img/poke-left/07.png +0 -0
  165. package/assets/whaleGirl/img/poke-left/08.png +0 -0
  166. package/assets/whaleGirl/img/poke-left/09.png +0 -0
  167. package/assets/whaleGirl/img/poke-left/10.png +0 -0
  168. package/assets/whaleGirl/img/poke-right/00.png +0 -0
  169. package/assets/whaleGirl/img/poke-right/01.png +0 -0
  170. package/assets/whaleGirl/img/poke-right/02.png +0 -0
  171. package/assets/whaleGirl/img/poke-right/03.png +0 -0
  172. package/assets/whaleGirl/img/poke-right/04.png +0 -0
  173. package/assets/whaleGirl/img/poke-right/05.png +0 -0
  174. package/assets/whaleGirl/img/poke-right/06.png +0 -0
  175. package/assets/whaleGirl/img/poke-right/07.png +0 -0
  176. package/assets/whaleGirl/img/poke-right/08.png +0 -0
  177. package/assets/whaleGirl/img/poke-right/09.png +0 -0
  178. package/assets/whaleGirl/img/poke-right/10.png +0 -0
  179. package/assets/whaleGirl/img/sleeping/00.png +0 -0
  180. package/assets/whaleGirl/img/sleeping/01.png +0 -0
  181. package/assets/whaleGirl/img/sleeping/02.png +0 -0
  182. package/assets/whaleGirl/img/sleeping/03.png +0 -0
  183. package/assets/whaleGirl/img/sleeping/04.png +0 -0
  184. package/assets/whaleGirl/img/sleeping/05.png +0 -0
  185. package/assets/whaleGirl/img/smile-hearts/00.png +0 -0
  186. package/assets/whaleGirl/img/smile-hearts/01.png +0 -0
  187. package/assets/whaleGirl/img/smile-hearts/02.png +0 -0
  188. package/assets/whaleGirl/img/smile-hearts/03.png +0 -0
  189. package/assets/whaleGirl/img/smile-hearts/04.png +0 -0
  190. package/assets/whaleGirl/img/smile-hearts/05.png +0 -0
  191. package/assets/whaleGirl/img/smile-hearts/06.png +0 -0
  192. package/assets/whaleGirl/img/smile-hearts/07.png +0 -0
  193. package/assets/whaleGirl/img/smile-hearts/08.png +0 -0
  194. package/assets/whaleGirl/img/smile-hearts/09.png +0 -0
  195. package/assets/whaleGirl/img/smile-hearts/10.png +0 -0
  196. package/assets/whaleGirl/img/smile-hearts/11.png +0 -0
  197. package/assets/whaleGirl/img/smile-hearts/12.png +0 -0
  198. package/assets/whaleGirl/img/smile-hearts/13.png +0 -0
  199. package/assets/whaleGirl/img/smile-hearts/14.png +0 -0
  200. package/assets/whaleGirl/img/smile-hearts/15.png +0 -0
  201. package/assets/whaleGirl/img/swim/00.png +0 -0
  202. package/assets/whaleGirl/img/swim/01.png +0 -0
  203. package/assets/whaleGirl/img/swim/02.png +0 -0
  204. package/assets/whaleGirl/img/swim/03.png +0 -0
  205. package/assets/whaleGirl/img/swim/04.png +0 -0
  206. package/assets/whaleGirl/img/swim/05.png +0 -0
  207. package/assets/whaleGirl/img/swim/06.png +0 -0
  208. package/assets/whaleGirl/img/swim/07.png +0 -0
  209. package/assets/whaleGirl/img/thinking/00.png +0 -0
  210. package/assets/whaleGirl/img/thinking/01.png +0 -0
  211. package/assets/whaleGirl/img/thinking/02.png +0 -0
  212. package/assets/whaleGirl/img/thinking/03.png +0 -0
  213. package/assets/whaleGirl/img/thinking/04.png +0 -0
  214. package/assets/whaleGirl/img/thinking/05.png +0 -0
  215. package/assets/whaleGirl/img/thinking/06.png +0 -0
  216. package/assets/whaleGirl/img/thinking/07.png +0 -0
  217. package/assets/whaleGirl/img/thinking/08.png +0 -0
  218. package/assets/whaleGirl/img/thinking/09.png +0 -0
  219. package/assets/whaleGirl/img/thinking/10.png +0 -0
  220. package/assets/whaleGirl/img/thinking/11.png +0 -0
  221. package/assets/whaleGirl/img/thinking/12.png +0 -0
  222. package/assets/whaleGirl/img/thinking/13.png +0 -0
  223. package/assets/whaleGirl/img/thinking/14.png +0 -0
  224. package/assets/whaleGirl/img/thinking/15.png +0 -0
  225. package/assets/whaleGirl/img/thinking/16.png +0 -0
  226. package/assets/whaleGirl/img/thumbs-up/00.png +0 -0
  227. package/assets/whaleGirl/img/thumbs-up/01.png +0 -0
  228. package/assets/whaleGirl/img/thumbs-up/02.png +0 -0
  229. package/assets/whaleGirl/img/thumbs-up/03.png +0 -0
  230. package/assets/whaleGirl/img/thumbs-up/04.png +0 -0
  231. package/assets/whaleGirl/img/thumbs-up/05.png +0 -0
  232. package/assets/whaleGirl/img/thumbs-up/06.png +0 -0
  233. package/assets/whaleGirl/img/thumbs-up/07.png +0 -0
  234. package/assets/whaleGirl/img/thumbs-up/08.png +0 -0
  235. package/assets/whaleGirl/img/thumbs-up/09.png +0 -0
  236. package/assets/whaleGirl/img/thumbs-up/10.png +0 -0
  237. package/assets/whaleGirl/img/thumbs-up/11.png +0 -0
  238. package/assets/whaleGirl/img/thumbs-up/12.png +0 -0
  239. package/assets/whaleGirl/img/tickle/00.png +0 -0
  240. package/assets/whaleGirl/img/tickle/01.png +0 -0
  241. package/assets/whaleGirl/img/tickle/02.png +0 -0
  242. package/assets/whaleGirl/img/tickle/03.png +0 -0
  243. package/assets/whaleGirl/img/tickle/04.png +0 -0
  244. package/assets/whaleGirl/img/tickle/05.png +0 -0
  245. package/assets/whaleGirl/img/tickle/06.png +0 -0
  246. package/assets/whaleGirl/img/tickle/07.png +0 -0
  247. package/assets/whaleGirl/img/tickle/08.png +0 -0
  248. package/assets/whaleGirl/img/tickle/09.png +0 -0
  249. package/assets/whaleGirl/img/tickle/10.png +0 -0
  250. package/assets/whaleGirl/img/tickle/11.png +0 -0
  251. package/assets/whaleGirl/img/tickle/12.png +0 -0
  252. package/assets/whaleGirl/img/tickle/13.png +0 -0
  253. package/assets/whaleGirl/img/timings.json +1 -0
  254. package/assets/whaleGirl/img/typing/00.png +0 -0
  255. package/assets/whaleGirl/img/typing/01.png +0 -0
  256. package/assets/whaleGirl/img/typing/02.png +0 -0
  257. package/assets/whaleGirl/img/typing/03.png +0 -0
  258. package/assets/whaleGirl/img/typing/04.png +0 -0
  259. package/assets/whaleGirl/img/typing/05.png +0 -0
  260. package/assets/whaleGirl/img/typing/06.png +0 -0
  261. package/assets/whaleGirl/img/typing/07.png +0 -0
  262. package/assets/whaleGirl/img/typing/08.png +0 -0
  263. package/assets/whaleGirl/img/typing/09.png +0 -0
  264. package/assets/whaleGirl/img/typing/10.png +0 -0
  265. package/assets/whaleGirl/img/typing/11.png +0 -0
  266. package/assets/whaleGirl/img/typing/12.png +0 -0
  267. package/assets/whaleGirl/img/typing/13.png +0 -0
  268. package/assets/whaleGirl/img/waking/00.png +0 -0
  269. package/assets/whaleGirl/img/waking/01.png +0 -0
  270. package/assets/whaleGirl/img/waking/02.png +0 -0
  271. package/assets/whaleGirl/img/waking/03.png +0 -0
  272. package/assets/whaleGirl/img/waking/04.png +0 -0
  273. package/assets/whaleGirl/img/waking/05.png +0 -0
  274. package/assets/whaleGirl/img/waking/06.png +0 -0
  275. package/assets/whaleGirl/img/waking/07.png +0 -0
  276. package/assets/whaleGirl/img/waking/08.png +0 -0
  277. package/assets/whaleGirl/img/waking/09.png +0 -0
  278. package/assets/whaleGirl/img/waking/10.png +0 -0
  279. package/bin/dsh-tui.js +112 -21
  280. package/cordis.patch.yml +9 -1
  281. package/cordis.yml +2 -0
  282. package/guide/dsh-tui-guide/SKILL.md +4 -2
  283. package/guide/dsh-tui-guide/claude-backend.en.md +203 -0
  284. package/guide/dsh-tui-guide/claude-backend.md +161 -0
  285. package/guide/dsh-tui-guide/codex-backend.en.md +297 -0
  286. package/guide/dsh-tui-guide/codex-backend.md +257 -0
  287. package/guide/dsh-tui-guide/configuration.en.md +13 -1
  288. package/guide/dsh-tui-guide/configuration.md +13 -1
  289. package/guide/dsh-tui-guide/getting-started.en.md +6 -3
  290. package/guide/dsh-tui-guide/getting-started.md +4 -2
  291. package/guide/dsh-tui-guide/interaction.en.md +221 -15
  292. package/guide/dsh-tui-guide/interaction.md +153 -9
  293. package/guide/dsh-tui-guide/plugins.en.md +16 -6
  294. package/guide/dsh-tui-guide/plugins.md +14 -6
  295. package/guide/dsh-tui-guide/themes.en.md +31 -4
  296. package/guide/dsh-tui-guide/themes.md +26 -4
  297. package/guide/dsh-tui-guide/user-guide.en.md +145 -27
  298. package/guide/dsh-tui-guide/user-guide.md +113 -22
  299. package/guide/dsh-tui-guide/vscode.en.md +1 -0
  300. package/guide/dsh-tui-guide/vscode.md +1 -0
  301. package/lib/settings.json +348 -1
  302. package/lib/types/adapter/channel/state.d.ts.map +1 -1
  303. package/lib/types/adapter/channel/state.js +1 -0
  304. package/lib/types/adapter/channel/ui-policy.d.ts +21 -2
  305. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  306. package/lib/types/adapter/channel/ui-policy.js +43 -1
  307. package/lib/types/adapter/channel/ui.d.ts.map +1 -1
  308. package/lib/types/adapter/channel/ui.js +45 -5
  309. package/lib/types/adapter/index.d.ts +1 -1
  310. package/lib/types/adapter/index.js +1 -1
  311. package/lib/types/adapter/kernel/host-facade.d.ts +4 -1
  312. package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
  313. package/lib/types/adapter/kernel/host-facade.js +8 -1
  314. package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
  315. package/lib/types/adapter/kernel/runtime.js +13 -0
  316. package/lib/types/adapter/kernel/slices/index.d.ts +1 -0
  317. package/lib/types/adapter/kernel/slices/index.d.ts.map +1 -1
  318. package/lib/types/adapter/kernel/slices/index.js +3 -0
  319. package/lib/types/adapter/kernel/slices/panels.d.ts +3 -0
  320. package/lib/types/adapter/kernel/slices/panels.d.ts.map +1 -0
  321. package/lib/types/adapter/kernel/slices/panels.js +14 -0
  322. package/lib/types/adapter/ports/channel-capabilities.d.ts +48 -0
  323. package/lib/types/adapter/ports/channel-capabilities.d.ts.map +1 -0
  324. package/lib/types/adapter/ports/channel-capabilities.js +2 -0
  325. package/lib/types/adapter/ports/channel-catalog.d.ts +14 -0
  326. package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
  327. package/lib/types/adapter/ports/channel-display.d.ts +17 -1
  328. package/lib/types/adapter/ports/channel-display.d.ts.map +1 -1
  329. package/lib/types/adapter/ports/channel-session.d.ts +5 -0
  330. package/lib/types/adapter/ports/channel-session.d.ts.map +1 -1
  331. package/lib/types/adapter/ports/channel-settings.d.ts +20 -0
  332. package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
  333. package/lib/types/adapter/ports/channel-ui.d.ts +243 -6
  334. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  335. package/lib/types/adapter/ports/channel-view.d.ts +566 -8
  336. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  337. package/lib/types/adapter/ports/channel.d.ts +1 -1
  338. package/lib/types/adapter/ports/channel.js +1 -1
  339. package/lib/types/adapter/ports/descriptor.d.ts +1 -1
  340. package/lib/types/adapter/ports/descriptor.js +1 -1
  341. package/lib/types/adapter/ports/index.d.ts +1 -1
  342. package/lib/types/adapter/ports/index.js +1 -1
  343. package/lib/types/adapter/ports/panels.d.ts +28 -0
  344. package/lib/types/adapter/ports/panels.d.ts.map +1 -0
  345. package/lib/types/adapter/ports/panels.js +8 -0
  346. package/lib/types/adapter/ports/workspace.d.ts +1 -1
  347. package/lib/types/adapter/ports/workspace.js +1 -1
  348. package/lib/types/adapter/spec/index.d.ts +2 -2
  349. package/lib/types/adapter/spec/index.js +2 -2
  350. package/lib/types/adapter/spec/profile.d.ts +6 -6
  351. package/lib/types/adapter/spec/profile.d.ts.map +1 -1
  352. package/lib/types/adapter/spec/profile.js +6 -6
  353. package/lib/types/adapter/spec/protocol-constants.d.ts +3 -3
  354. package/lib/types/adapter/spec/protocol-constants.d.ts.map +1 -1
  355. package/lib/types/adapter/spec/protocol-constants.js +5 -5
  356. package/lib/types/adapter/spec/tui-contributions.d.ts +4 -4
  357. package/lib/types/adapter/spec/tui-contributions.d.ts.map +1 -1
  358. package/lib/types/adapter/spec/tui-contributions.js +5 -5
  359. package/lib/types/adapter/standard/descriptor.js +1 -1
  360. package/lib/types/adapter/standard/index.d.ts +3 -3
  361. package/lib/types/adapter/standard/index.js +3 -3
  362. package/lib/types/adapter/standard/registry.d.ts +3 -2
  363. package/lib/types/adapter/standard/registry.d.ts.map +1 -1
  364. package/lib/types/adapter/standard/registry.js +6 -5
  365. package/lib/types/adapter/standard/tui-extension.d.ts +1 -1
  366. package/lib/types/adapter/standard/tui-extension.js +1 -1
  367. package/lib/types/adapter/upstream/index.d.ts +1 -0
  368. package/lib/types/adapter/upstream/index.d.ts.map +1 -1
  369. package/lib/types/adapter/upstream/index.js +1 -0
  370. package/lib/types/adapter/upstream/panels-driver.d.ts +18 -0
  371. package/lib/types/adapter/upstream/panels-driver.d.ts.map +1 -0
  372. package/lib/types/adapter/upstream/panels-driver.js +159 -0
  373. package/lib/types/agent/backend.d.ts +168 -0
  374. package/lib/types/agent/backend.d.ts.map +1 -0
  375. package/lib/types/agent/backend.js +1 -0
  376. package/lib/types/agent/capabilities.d.ts +461 -0
  377. package/lib/types/agent/capabilities.d.ts.map +1 -0
  378. package/lib/types/agent/capabilities.js +1 -0
  379. package/lib/types/agent/events.d.ts +733 -0
  380. package/lib/types/agent/events.d.ts.map +1 -0
  381. package/lib/types/agent/events.js +2 -0
  382. package/lib/types/agent/index.d.ts +8 -0
  383. package/lib/types/agent/index.d.ts.map +1 -0
  384. package/lib/types/agent/index.js +7 -0
  385. package/lib/types/agent/messages.d.ts +52 -0
  386. package/lib/types/agent/messages.d.ts.map +1 -0
  387. package/lib/types/agent/messages.js +91 -0
  388. package/lib/types/agent/presentation.d.ts +29 -0
  389. package/lib/types/agent/presentation.d.ts.map +1 -0
  390. package/lib/types/agent/presentation.js +4 -0
  391. package/lib/types/agent/refs.d.ts +30 -0
  392. package/lib/types/agent/refs.d.ts.map +1 -0
  393. package/lib/types/agent/refs.js +39 -0
  394. package/lib/types/agent/session.d.ts +78 -0
  395. package/lib/types/agent/session.d.ts.map +1 -0
  396. package/lib/types/agent/session.js +1 -0
  397. package/lib/types/api.d.ts +2 -0
  398. package/lib/types/api.d.ts.map +1 -1
  399. package/lib/types/api.js +3 -1
  400. package/lib/types/backends/claude/activity.d.ts +53 -0
  401. package/lib/types/backends/claude/activity.d.ts.map +1 -0
  402. package/lib/types/backends/claude/activity.js +103 -0
  403. package/lib/types/backends/claude/auth.d.ts +245 -0
  404. package/lib/types/backends/claude/auth.d.ts.map +1 -0
  405. package/lib/types/backends/claude/auth.js +503 -0
  406. package/lib/types/backends/claude/backend.d.ts +32 -0
  407. package/lib/types/backends/claude/backend.d.ts.map +1 -0
  408. package/lib/types/backends/claude/backend.js +296 -0
  409. package/lib/types/backends/claude/catalog.d.ts +17 -0
  410. package/lib/types/backends/claude/catalog.d.ts.map +1 -0
  411. package/lib/types/backends/claude/catalog.js +94 -0
  412. package/lib/types/backends/claude/channels.d.ts +63 -0
  413. package/lib/types/backends/claude/channels.d.ts.map +1 -0
  414. package/lib/types/backends/claude/channels.js +275 -0
  415. package/lib/types/backends/claude/contract.d.ts +37 -0
  416. package/lib/types/backends/claude/contract.d.ts.map +1 -0
  417. package/lib/types/backends/claude/contract.js +46 -0
  418. package/lib/types/backends/claude/controls.d.ts +134 -0
  419. package/lib/types/backends/claude/controls.d.ts.map +1 -0
  420. package/lib/types/backends/claude/controls.js +425 -0
  421. package/lib/types/backends/claude/dialogs.d.ts +62 -0
  422. package/lib/types/backends/claude/dialogs.d.ts.map +1 -0
  423. package/lib/types/backends/claude/dialogs.js +253 -0
  424. package/lib/types/backends/claude/flag-settings.d.ts +12 -0
  425. package/lib/types/backends/claude/flag-settings.d.ts.map +1 -0
  426. package/lib/types/backends/claude/flag-settings.js +49 -0
  427. package/lib/types/backends/claude/images.d.ts +49 -0
  428. package/lib/types/backends/claude/images.d.ts.map +1 -0
  429. package/lib/types/backends/claude/images.js +94 -0
  430. package/lib/types/backends/claude/index.d.ts +5 -0
  431. package/lib/types/backends/claude/index.d.ts.map +1 -0
  432. package/lib/types/backends/claude/index.js +4 -0
  433. package/lib/types/backends/claude/install.d.ts +15 -0
  434. package/lib/types/backends/claude/install.d.ts.map +1 -0
  435. package/lib/types/backends/claude/install.js +91 -0
  436. package/lib/types/backends/claude/modelEnv.d.ts +64 -0
  437. package/lib/types/backends/claude/modelEnv.d.ts.map +1 -0
  438. package/lib/types/backends/claude/modelEnv.js +199 -0
  439. package/lib/types/backends/claude/narrow.d.ts +10 -0
  440. package/lib/types/backends/claude/narrow.d.ts.map +1 -0
  441. package/lib/types/backends/claude/narrow.js +8 -0
  442. package/lib/types/backends/claude/older-history.d.ts +16 -0
  443. package/lib/types/backends/claude/older-history.d.ts.map +1 -0
  444. package/lib/types/backends/claude/older-history.js +101 -0
  445. package/lib/types/backends/claude/options.d.ts +181 -0
  446. package/lib/types/backends/claude/options.d.ts.map +1 -0
  447. package/lib/types/backends/claude/options.js +208 -0
  448. package/lib/types/backends/claude/permissions.d.ts +83 -0
  449. package/lib/types/backends/claude/permissions.d.ts.map +1 -0
  450. package/lib/types/backends/claude/permissions.js +331 -0
  451. package/lib/types/backends/claude/prefs.d.ts +55 -0
  452. package/lib/types/backends/claude/prefs.d.ts.map +1 -0
  453. package/lib/types/backends/claude/prefs.js +150 -0
  454. package/lib/types/backends/claude/process.d.ts +19 -0
  455. package/lib/types/backends/claude/process.d.ts.map +1 -0
  456. package/lib/types/backends/claude/process.js +156 -0
  457. package/lib/types/backends/claude/replay.d.ts +129 -0
  458. package/lib/types/backends/claude/replay.d.ts.map +1 -0
  459. package/lib/types/backends/claude/replay.js +505 -0
  460. package/lib/types/backends/claude/sdk-warnings.d.ts +23 -0
  461. package/lib/types/backends/claude/sdk-warnings.d.ts.map +1 -0
  462. package/lib/types/backends/claude/sdk-warnings.js +55 -0
  463. package/lib/types/backends/claude/sdk.d.ts +12 -0
  464. package/lib/types/backends/claude/sdk.d.ts.map +1 -0
  465. package/lib/types/backends/claude/sdk.js +34 -0
  466. package/lib/types/backends/claude/send-message.d.ts +54 -0
  467. package/lib/types/backends/claude/send-message.d.ts.map +1 -0
  468. package/lib/types/backends/claude/send-message.js +65 -0
  469. package/lib/types/backends/claude/session/auth.d.ts +47 -0
  470. package/lib/types/backends/claude/session/auth.d.ts.map +1 -0
  471. package/lib/types/backends/claude/session/auth.js +226 -0
  472. package/lib/types/backends/claude/session/channels.d.ts +82 -0
  473. package/lib/types/backends/claude/session/channels.d.ts.map +1 -0
  474. package/lib/types/backends/claude/session/channels.js +45 -0
  475. package/lib/types/backends/claude/session/input.d.ts +16 -0
  476. package/lib/types/backends/claude/session/input.d.ts.map +1 -0
  477. package/lib/types/backends/claude/session/input.js +64 -0
  478. package/lib/types/backends/claude/session/lifecycle.d.ts +6 -0
  479. package/lib/types/backends/claude/session/lifecycle.d.ts.map +1 -0
  480. package/lib/types/backends/claude/session/lifecycle.js +852 -0
  481. package/lib/types/backends/claude/session/store.d.ts +17 -0
  482. package/lib/types/backends/claude/session/store.d.ts.map +1 -0
  483. package/lib/types/backends/claude/session/store.js +122 -0
  484. package/lib/types/backends/claude/session/subagents.d.ts +13 -0
  485. package/lib/types/backends/claude/session/subagents.d.ts.map +1 -0
  486. package/lib/types/backends/claude/session/subagents.js +77 -0
  487. package/lib/types/backends/claude/session/types.d.ts +89 -0
  488. package/lib/types/backends/claude/session/types.d.ts.map +1 -0
  489. package/lib/types/backends/claude/session/types.js +1 -0
  490. package/lib/types/backends/claude/session.d.ts +4 -0
  491. package/lib/types/backends/claude/session.d.ts.map +1 -0
  492. package/lib/types/backends/claude/session.js +2 -0
  493. package/lib/types/backends/claude/side-query.d.ts +34 -0
  494. package/lib/types/backends/claude/side-query.d.ts.map +1 -0
  495. package/lib/types/backends/claude/side-query.js +116 -0
  496. package/lib/types/backends/claude/task-output.d.ts +13 -0
  497. package/lib/types/backends/claude/task-output.d.ts.map +1 -0
  498. package/lib/types/backends/claude/task-output.js +101 -0
  499. package/lib/types/backends/claude/tools.d.ts +45 -0
  500. package/lib/types/backends/claude/tools.d.ts.map +1 -0
  501. package/lib/types/backends/claude/tools.js +231 -0
  502. package/lib/types/backends/claude/transcript-file.d.ts +41 -0
  503. package/lib/types/backends/claude/transcript-file.d.ts.map +1 -0
  504. package/lib/types/backends/claude/transcript-file.js +195 -0
  505. package/lib/types/backends/claude/translate/attempts.d.ts +33 -0
  506. package/lib/types/backends/claude/translate/attempts.d.ts.map +1 -0
  507. package/lib/types/backends/claude/translate/attempts.js +243 -0
  508. package/lib/types/backends/claude/translate/content.d.ts +33 -0
  509. package/lib/types/backends/claude/translate/content.d.ts.map +1 -0
  510. package/lib/types/backends/claude/translate/content.js +91 -0
  511. package/lib/types/backends/claude/translate/core.d.ts +76 -0
  512. package/lib/types/backends/claude/translate/core.d.ts.map +1 -0
  513. package/lib/types/backends/claude/translate/core.js +447 -0
  514. package/lib/types/backends/claude/translate/events.d.ts +9 -0
  515. package/lib/types/backends/claude/translate/events.d.ts.map +1 -0
  516. package/lib/types/backends/claude/translate/events.js +77 -0
  517. package/lib/types/backends/claude/translate/lanes.d.ts +31 -0
  518. package/lib/types/backends/claude/translate/lanes.d.ts.map +1 -0
  519. package/lib/types/backends/claude/translate/lanes.js +177 -0
  520. package/lib/types/backends/claude/translate/messages.d.ts +36 -0
  521. package/lib/types/backends/claude/translate/messages.d.ts.map +1 -0
  522. package/lib/types/backends/claude/translate/messages.js +202 -0
  523. package/lib/types/backends/claude/translate/system.d.ts +40 -0
  524. package/lib/types/backends/claude/translate/system.d.ts.map +1 -0
  525. package/lib/types/backends/claude/translate/system.js +399 -0
  526. package/lib/types/backends/claude/translate/tasks.d.ts +19 -0
  527. package/lib/types/backends/claude/translate/tasks.d.ts.map +1 -0
  528. package/lib/types/backends/claude/translate/tasks.js +159 -0
  529. package/lib/types/backends/claude/translate/types.d.ts +114 -0
  530. package/lib/types/backends/claude/translate/types.d.ts.map +1 -0
  531. package/lib/types/backends/claude/translate/types.js +1 -0
  532. package/lib/types/backends/claude/translate.d.ts +9 -0
  533. package/lib/types/backends/claude/translate.d.ts.map +1 -0
  534. package/lib/types/backends/claude/translate.js +6 -0
  535. package/lib/types/backends/codex/auth/external-tokens.d.ts +66 -0
  536. package/lib/types/backends/codex/auth/external-tokens.d.ts.map +1 -0
  537. package/lib/types/backends/codex/auth/external-tokens.js +325 -0
  538. package/lib/types/backends/codex/auth/route.d.ts +14 -0
  539. package/lib/types/backends/codex/auth/route.d.ts.map +1 -0
  540. package/lib/types/backends/codex/auth/route.js +52 -0
  541. package/lib/types/backends/codex/auth/status.d.ts +16 -0
  542. package/lib/types/backends/codex/auth/status.d.ts.map +1 -0
  543. package/lib/types/backends/codex/auth/status.js +115 -0
  544. package/lib/types/backends/codex/backend.d.ts +58 -0
  545. package/lib/types/backends/codex/backend.d.ts.map +1 -0
  546. package/lib/types/backends/codex/backend.js +201 -0
  547. package/lib/types/backends/codex/catalog.d.ts +17 -0
  548. package/lib/types/backends/codex/catalog.d.ts.map +1 -0
  549. package/lib/types/backends/codex/catalog.js +128 -0
  550. package/lib/types/backends/codex/channels.d.ts +59 -0
  551. package/lib/types/backends/codex/channels.d.ts.map +1 -0
  552. package/lib/types/backends/codex/channels.js +274 -0
  553. package/lib/types/backends/codex/contract.d.ts +46 -0
  554. package/lib/types/backends/codex/contract.d.ts.map +1 -0
  555. package/lib/types/backends/codex/contract.js +80 -0
  556. package/lib/types/backends/codex/detect.d.ts +14 -0
  557. package/lib/types/backends/codex/detect.d.ts.map +1 -0
  558. package/lib/types/backends/codex/detect.js +90 -0
  559. package/lib/types/backends/codex/index.d.ts +6 -0
  560. package/lib/types/backends/codex/index.d.ts.map +1 -0
  561. package/lib/types/backends/codex/index.js +5 -0
  562. package/lib/types/backends/codex/modes.d.ts +16 -0
  563. package/lib/types/backends/codex/modes.d.ts.map +1 -0
  564. package/lib/types/backends/codex/modes.js +49 -0
  565. package/lib/types/backends/codex/narrow.d.ts +20 -0
  566. package/lib/types/backends/codex/narrow.d.ts.map +1 -0
  567. package/lib/types/backends/codex/narrow.js +18 -0
  568. package/lib/types/backends/codex/prefs.d.ts +42 -0
  569. package/lib/types/backends/codex/prefs.d.ts.map +1 -0
  570. package/lib/types/backends/codex/prefs.js +124 -0
  571. package/lib/types/backends/codex/protocol/index.d.ts +149 -0
  572. package/lib/types/backends/codex/protocol/index.d.ts.map +1 -0
  573. package/lib/types/backends/codex/protocol/index.js +130 -0
  574. package/lib/types/backends/codex/rpc/binary.d.ts +35 -0
  575. package/lib/types/backends/codex/rpc/binary.d.ts.map +1 -0
  576. package/lib/types/backends/codex/rpc/binary.js +174 -0
  577. package/lib/types/backends/codex/rpc/client.d.ts +72 -0
  578. package/lib/types/backends/codex/rpc/client.d.ts.map +1 -0
  579. package/lib/types/backends/codex/rpc/client.js +214 -0
  580. package/lib/types/backends/codex/rpc/hub.d.ts +105 -0
  581. package/lib/types/backends/codex/rpc/hub.d.ts.map +1 -0
  582. package/lib/types/backends/codex/rpc/hub.js +532 -0
  583. package/lib/types/backends/codex/rpc/transport.d.ts +39 -0
  584. package/lib/types/backends/codex/rpc/transport.d.ts.map +1 -0
  585. package/lib/types/backends/codex/rpc/transport.js +212 -0
  586. package/lib/types/backends/codex/session/activity.d.ts +18 -0
  587. package/lib/types/backends/codex/session/activity.d.ts.map +1 -0
  588. package/lib/types/backends/codex/session/activity.js +108 -0
  589. package/lib/types/backends/codex/session/approvals.d.ts +39 -0
  590. package/lib/types/backends/codex/session/approvals.d.ts.map +1 -0
  591. package/lib/types/backends/codex/session/approvals.js +477 -0
  592. package/lib/types/backends/codex/session/commands.d.ts +37 -0
  593. package/lib/types/backends/codex/session/commands.d.ts.map +1 -0
  594. package/lib/types/backends/codex/session/commands.js +141 -0
  595. package/lib/types/backends/codex/session/controls.d.ts +37 -0
  596. package/lib/types/backends/codex/session/controls.d.ts.map +1 -0
  597. package/lib/types/backends/codex/session/controls.js +303 -0
  598. package/lib/types/backends/codex/session/goals.d.ts +25 -0
  599. package/lib/types/backends/codex/session/goals.d.ts.map +1 -0
  600. package/lib/types/backends/codex/session/goals.js +97 -0
  601. package/lib/types/backends/codex/session/history.d.ts +52 -0
  602. package/lib/types/backends/codex/session/history.d.ts.map +1 -0
  603. package/lib/types/backends/codex/session/history.js +196 -0
  604. package/lib/types/backends/codex/session/images.d.ts +17 -0
  605. package/lib/types/backends/codex/session/images.d.ts.map +1 -0
  606. package/lib/types/backends/codex/session/images.js +138 -0
  607. package/lib/types/backends/codex/session/input.d.ts +75 -0
  608. package/lib/types/backends/codex/session/input.d.ts.map +1 -0
  609. package/lib/types/backends/codex/session/input.js +294 -0
  610. package/lib/types/backends/codex/session/plan-review.d.ts +19 -0
  611. package/lib/types/backends/codex/session/plan-review.d.ts.map +1 -0
  612. package/lib/types/backends/codex/session/plan-review.js +48 -0
  613. package/lib/types/backends/codex/session/prompts.d.ts +7 -0
  614. package/lib/types/backends/codex/session/prompts.d.ts.map +1 -0
  615. package/lib/types/backends/codex/session/prompts.js +47 -0
  616. package/lib/types/backends/codex/session/session.d.ts +12 -0
  617. package/lib/types/backends/codex/session/session.d.ts.map +1 -0
  618. package/lib/types/backends/codex/session/session.js +871 -0
  619. package/lib/types/backends/codex/session/side-query.d.ts +25 -0
  620. package/lib/types/backends/codex/session/side-query.d.ts.map +1 -0
  621. package/lib/types/backends/codex/session/side-query.js +121 -0
  622. package/lib/types/backends/codex/session/state.d.ts +57 -0
  623. package/lib/types/backends/codex/session/state.d.ts.map +1 -0
  624. package/lib/types/backends/codex/session/state.js +1 -0
  625. package/lib/types/backends/codex/session/subagents.d.ts +28 -0
  626. package/lib/types/backends/codex/session/subagents.d.ts.map +1 -0
  627. package/lib/types/backends/codex/session/subagents.js +286 -0
  628. package/lib/types/backends/codex/session/tasks.d.ts +25 -0
  629. package/lib/types/backends/codex/session/tasks.d.ts.map +1 -0
  630. package/lib/types/backends/codex/session/tasks.js +207 -0
  631. package/lib/types/backends/codex/session/tool-output.d.ts +9 -0
  632. package/lib/types/backends/codex/session/tool-output.d.ts.map +1 -0
  633. package/lib/types/backends/codex/session/tool-output.js +29 -0
  634. package/lib/types/backends/codex/translate/commands.d.ts +30 -0
  635. package/lib/types/backends/codex/translate/commands.d.ts.map +1 -0
  636. package/lib/types/backends/codex/translate/commands.js +103 -0
  637. package/lib/types/backends/codex/translate/events.d.ts +9 -0
  638. package/lib/types/backends/codex/translate/events.d.ts.map +1 -0
  639. package/lib/types/backends/codex/translate/events.js +71 -0
  640. package/lib/types/backends/codex/translate/items.d.ts +112 -0
  641. package/lib/types/backends/codex/translate/items.d.ts.map +1 -0
  642. package/lib/types/backends/codex/translate/items.js +375 -0
  643. package/lib/types/backends/codex/translate/live.d.ts +39 -0
  644. package/lib/types/backends/codex/translate/live.d.ts.map +1 -0
  645. package/lib/types/backends/codex/translate/live.js +315 -0
  646. package/lib/types/backends/codex/translate/notices.d.ts +27 -0
  647. package/lib/types/backends/codex/translate/notices.d.ts.map +1 -0
  648. package/lib/types/backends/codex/translate/notices.js +99 -0
  649. package/lib/types/backends/codex/translate/presentation.d.ts +49 -0
  650. package/lib/types/backends/codex/translate/presentation.d.ts.map +1 -0
  651. package/lib/types/backends/codex/translate/presentation.js +237 -0
  652. package/lib/types/backends/codex/translate/replay.d.ts +18 -0
  653. package/lib/types/backends/codex/translate/replay.d.ts.map +1 -0
  654. package/lib/types/backends/codex/translate/replay.js +33 -0
  655. package/lib/types/backends/codex/translate/usage.d.ts +29 -0
  656. package/lib/types/backends/codex/translate/usage.d.ts.map +1 -0
  657. package/lib/types/backends/codex/translate/usage.js +65 -0
  658. package/lib/types/backends/shared/atomic-file.d.ts +4 -0
  659. package/lib/types/backends/shared/atomic-file.d.ts.map +1 -0
  660. package/lib/types/backends/shared/atomic-file.js +52 -0
  661. package/lib/types/backends/shared/channel-tokens.d.ts +29 -0
  662. package/lib/types/backends/shared/channel-tokens.d.ts.map +1 -0
  663. package/lib/types/backends/shared/channel-tokens.js +161 -0
  664. package/lib/types/backends/shared/display-path.d.ts +3 -0
  665. package/lib/types/backends/shared/display-path.d.ts.map +1 -0
  666. package/lib/types/backends/shared/display-path.js +12 -0
  667. package/lib/types/branding.d.ts +92 -0
  668. package/lib/types/branding.d.ts.map +1 -0
  669. package/lib/types/branding.js +117 -0
  670. package/lib/types/channel/activity.d.ts +53 -0
  671. package/lib/types/channel/activity.d.ts.map +1 -0
  672. package/lib/types/channel/activity.js +955 -0
  673. package/lib/types/channel/capabilities.d.ts +24 -0
  674. package/lib/types/channel/capabilities.d.ts.map +1 -0
  675. package/lib/types/channel/capabilities.js +57 -0
  676. package/lib/types/channel/channel-slug.d.ts +9 -0
  677. package/lib/types/channel/channel-slug.d.ts.map +1 -0
  678. package/lib/types/channel/channel-slug.js +15 -0
  679. package/lib/types/channel/channel-wizard.d.ts +30 -0
  680. package/lib/types/channel/channel-wizard.d.ts.map +1 -0
  681. package/lib/types/channel/channel-wizard.js +226 -0
  682. package/lib/types/channel/elicitation.d.ts +135 -0
  683. package/lib/types/channel/elicitation.d.ts.map +1 -0
  684. package/lib/types/channel/elicitation.js +360 -0
  685. package/lib/types/channel/goal-command.d.ts +49 -0
  686. package/lib/types/channel/goal-command.d.ts.map +1 -0
  687. package/lib/types/channel/goal-command.js +72 -0
  688. package/lib/types/channel/history-restore.d.ts +16 -0
  689. package/lib/types/channel/history-restore.d.ts.map +1 -0
  690. package/lib/types/channel/history-restore.js +214 -0
  691. package/lib/types/channel/interaction.d.ts +38 -0
  692. package/lib/types/channel/interaction.d.ts.map +1 -0
  693. package/lib/types/channel/interaction.js +110 -0
  694. package/lib/types/channel/job-format.d.ts +6 -0
  695. package/lib/types/channel/job-format.d.ts.map +1 -0
  696. package/lib/types/channel/job-format.js +12 -0
  697. package/lib/types/channel/live-output.d.ts +35 -0
  698. package/lib/types/channel/live-output.d.ts.map +1 -0
  699. package/lib/types/channel/live-output.js +74 -0
  700. package/lib/types/channel/model-capabilities.d.ts +10 -0
  701. package/lib/types/channel/model-capabilities.d.ts.map +1 -0
  702. package/lib/types/channel/model-capabilities.js +51 -0
  703. package/lib/types/channel/permissions.d.ts +155 -0
  704. package/lib/types/channel/permissions.d.ts.map +1 -0
  705. package/lib/types/channel/permissions.js +188 -0
  706. package/lib/types/channel/projection.d.ts +110 -0
  707. package/lib/types/channel/projection.d.ts.map +1 -0
  708. package/lib/types/channel/projection.js +1521 -0
  709. package/lib/types/channel/question-record.d.ts +76 -0
  710. package/lib/types/channel/question-record.d.ts.map +1 -0
  711. package/lib/types/channel/question-record.js +109 -0
  712. package/lib/types/channel/questions.d.ts +204 -0
  713. package/lib/types/channel/questions.d.ts.map +1 -0
  714. package/lib/types/channel/questions.js +286 -0
  715. package/lib/types/channel/sanitize.d.ts +49 -0
  716. package/lib/types/channel/sanitize.d.ts.map +1 -0
  717. package/lib/types/channel/sanitize.js +88 -0
  718. package/lib/types/channel/selection-record.d.ts +18 -0
  719. package/lib/types/channel/selection-record.d.ts.map +1 -0
  720. package/lib/types/channel/selection-record.js +45 -0
  721. package/lib/types/channel/side-prompts.d.ts +59 -0
  722. package/lib/types/channel/side-prompts.d.ts.map +1 -0
  723. package/lib/types/channel/side-prompts.js +127 -0
  724. package/lib/types/channel/transcript.d.ts +17 -0
  725. package/lib/types/channel/transcript.d.ts.map +1 -0
  726. package/lib/types/channel/transcript.js +19 -0
  727. package/lib/types/channel/usage.d.ts +48 -0
  728. package/lib/types/channel/usage.d.ts.map +1 -0
  729. package/lib/types/channel/usage.js +143 -0
  730. package/lib/types/commands.d.ts +147 -0
  731. package/lib/types/commands.d.ts.map +1 -1
  732. package/lib/types/commands.js +208 -6
  733. package/lib/types/components/ActivityLine.d.ts +6 -9
  734. package/lib/types/components/ActivityLine.d.ts.map +1 -1
  735. package/lib/types/components/ActivityLine.js +7 -8
  736. package/lib/types/components/AgentMessageComposer.d.ts +50 -0
  737. package/lib/types/components/AgentMessageComposer.d.ts.map +1 -0
  738. package/lib/types/components/AgentMessageComposer.js +159 -0
  739. package/lib/types/components/BtwPanel.d.ts +13 -12
  740. package/lib/types/components/BtwPanel.d.ts.map +1 -1
  741. package/lib/types/components/BtwPanel.js +35 -24
  742. package/lib/types/components/ChannelPicker.d.ts +40 -0
  743. package/lib/types/components/ChannelPicker.d.ts.map +1 -0
  744. package/lib/types/components/ChannelPicker.js +26 -0
  745. package/lib/types/components/Chat/JobCard.d.ts +29 -14
  746. package/lib/types/components/Chat/JobCard.d.ts.map +1 -1
  747. package/lib/types/components/Chat/JobCard.js +51 -64
  748. package/lib/types/components/Chat/JobGroupHeader.d.ts +27 -0
  749. package/lib/types/components/Chat/JobGroupHeader.d.ts.map +1 -0
  750. package/lib/types/components/Chat/JobGroupHeader.js +62 -0
  751. package/lib/types/components/Chat/SubagentMessage.d.ts +4 -1
  752. package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
  753. package/lib/types/components/Chat/SubagentMessage.js +10 -3
  754. package/lib/types/components/ClaudeGirl.d.ts +27 -0
  755. package/lib/types/components/ClaudeGirl.d.ts.map +1 -0
  756. package/lib/types/components/ClaudeGirl.js +30 -0
  757. package/lib/types/components/CodeBlockFrame.d.ts +19 -0
  758. package/lib/types/components/CodeBlockFrame.d.ts.map +1 -0
  759. package/lib/types/components/CodeBlockFrame.js +138 -0
  760. package/lib/types/components/CommandSuggestions.d.ts +10 -1
  761. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  762. package/lib/types/components/CommandSuggestions.js +20 -3
  763. package/lib/types/components/ContextBarView.d.ts +2 -2
  764. package/lib/types/components/ContextBarView.d.ts.map +1 -1
  765. package/lib/types/components/ContextBarView.js +18 -8
  766. package/lib/types/components/EffortChargeGlyph.d.ts +1 -1
  767. package/lib/types/components/EffortChargeGlyph.d.ts.map +1 -1
  768. package/lib/types/components/EffortChargeGlyph.js +3 -4
  769. package/lib/types/components/EffortInputBorder.d.ts +1 -2
  770. package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
  771. package/lib/types/components/EffortInputBorder.js +7 -4
  772. package/lib/types/components/EffortSlider.d.ts +5 -1
  773. package/lib/types/components/EffortSlider.d.ts.map +1 -1
  774. package/lib/types/components/EffortSlider.js +2 -2
  775. package/lib/types/components/EffortTierBadge.d.ts +1 -2
  776. package/lib/types/components/EffortTierBadge.d.ts.map +1 -1
  777. package/lib/types/components/EffortTierBadge.js +8 -5
  778. package/lib/types/components/GoalTodoPanel.d.ts +15 -2
  779. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  780. package/lib/types/components/GoalTodoPanel.js +65 -18
  781. package/lib/types/components/InlineMathParagraph.js +1 -1
  782. package/lib/types/components/JobsPanel.d.ts +41 -2
  783. package/lib/types/components/JobsPanel.d.ts.map +1 -1
  784. package/lib/types/components/JobsPanel.js +208 -16
  785. package/lib/types/components/KernelPicker.d.ts +28 -0
  786. package/lib/types/components/KernelPicker.d.ts.map +1 -0
  787. package/lib/types/components/KernelPicker.js +37 -0
  788. package/lib/types/components/LogoV2.d.ts +49 -3
  789. package/lib/types/components/LogoV2.d.ts.map +1 -1
  790. package/lib/types/components/LogoV2.js +157 -34
  791. package/lib/types/components/Markdown.d.ts +2 -1
  792. package/lib/types/components/Markdown.d.ts.map +1 -1
  793. package/lib/types/components/Markdown.js +37 -8
  794. package/lib/types/components/MathBlock.d.ts.map +1 -1
  795. package/lib/types/components/MathBlock.js +3 -1
  796. package/lib/types/components/MermaidDiagram.d.ts.map +1 -1
  797. package/lib/types/components/MermaidDiagram.js +7 -5
  798. package/lib/types/components/MessageList.d.ts +28 -4
  799. package/lib/types/components/MessageList.d.ts.map +1 -1
  800. package/lib/types/components/MessageList.js +247 -33
  801. package/lib/types/components/ModePicker.d.ts +20 -0
  802. package/lib/types/components/ModePicker.d.ts.map +1 -0
  803. package/lib/types/components/ModePicker.js +17 -0
  804. package/lib/types/components/OverlayAbove.d.ts +11 -1
  805. package/lib/types/components/OverlayAbove.d.ts.map +1 -1
  806. package/lib/types/components/OverlayAbove.js +2 -12
  807. package/lib/types/components/PageMargin.d.ts.map +1 -1
  808. package/lib/types/components/PageMargin.js +3 -1
  809. package/lib/types/components/PluginSceneBoundary.d.ts +1 -1
  810. package/lib/types/components/PluginSceneBoundary.js +1 -1
  811. package/lib/types/components/PromptInput.d.ts +22 -24
  812. package/lib/types/components/PromptInput.d.ts.map +1 -1
  813. package/lib/types/components/PromptInput.js +720 -210
  814. package/lib/types/components/SdkInstallWizard.d.ts +44 -0
  815. package/lib/types/components/SdkInstallWizard.d.ts.map +1 -0
  816. package/lib/types/components/SdkInstallWizard.js +18 -0
  817. package/lib/types/components/SearchBox.d.ts +22 -6
  818. package/lib/types/components/SearchBox.d.ts.map +1 -1
  819. package/lib/types/components/SearchBox.js +27 -14
  820. package/lib/types/components/SplitDiffView.d.ts.map +1 -1
  821. package/lib/types/components/SplitDiffView.js +113 -6
  822. package/lib/types/components/StarPrompt.d.ts.map +1 -1
  823. package/lib/types/components/StarPrompt.js +5 -3
  824. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  825. package/lib/types/components/StreamingMarkdown.js +6 -4
  826. package/lib/types/components/SubagentCard.d.ts +2 -1
  827. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  828. package/lib/types/components/SubagentCard.js +32 -10
  829. package/lib/types/components/SubagentDashboard.d.ts +22 -3
  830. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  831. package/lib/types/components/SubagentDashboard.js +69 -10
  832. package/lib/types/components/SubagentDetailScene.d.ts +22 -1
  833. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  834. package/lib/types/components/SubagentDetailScene.js +245 -45
  835. package/lib/types/components/SurfaceEdges.d.ts +21 -0
  836. package/lib/types/components/SurfaceEdges.d.ts.map +1 -0
  837. package/lib/types/components/SurfaceEdges.js +7 -0
  838. package/lib/types/components/SyntaxText.d.ts.map +1 -1
  839. package/lib/types/components/SyntaxText.js +4 -1
  840. package/lib/types/components/ThemePicker.d.ts +9 -0
  841. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  842. package/lib/types/components/ThemePicker.js +74 -10
  843. package/lib/types/components/ThemePreviewPane.d.ts +26 -0
  844. package/lib/types/components/ThemePreviewPane.d.ts.map +1 -0
  845. package/lib/types/components/ThemePreviewPane.js +99 -0
  846. package/lib/types/components/TurnInterruptedRow.d.ts +3 -1
  847. package/lib/types/components/TurnInterruptedRow.d.ts.map +1 -1
  848. package/lib/types/components/TurnInterruptedRow.js +6 -3
  849. package/lib/types/components/TurnUsageRow.d.ts +24 -0
  850. package/lib/types/components/TurnUsageRow.d.ts.map +1 -0
  851. package/lib/types/components/TurnUsageRow.js +46 -0
  852. package/lib/types/components/WorkingSpinner.d.ts +2 -1
  853. package/lib/types/components/WorkingSpinner.d.ts.map +1 -1
  854. package/lib/types/components/WorkingSpinner.js +21 -4
  855. package/lib/types/components/approvals/ApprovalPanel.d.ts +36 -13
  856. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  857. package/lib/types/components/approvals/ApprovalPanel.js +173 -25
  858. package/lib/types/components/claudeGirlSprite.d.ts +18 -0
  859. package/lib/types/components/claudeGirlSprite.d.ts.map +1 -0
  860. package/lib/types/components/claudeGirlSprite.js +48 -0
  861. package/lib/types/components/design-system/Divider.d.ts.map +1 -1
  862. package/lib/types/components/design-system/Divider.js +14 -9
  863. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  864. package/lib/types/components/design-system/ThemeProvider.js +46 -13
  865. package/lib/types/components/design-system/ThemedText.d.ts +3 -1
  866. package/lib/types/components/design-system/ThemedText.d.ts.map +1 -1
  867. package/lib/types/components/design-system/ThemedText.js +2 -2
  868. package/lib/types/components/diffPatch.d.ts +55 -0
  869. package/lib/types/components/diffPatch.d.ts.map +1 -0
  870. package/lib/types/components/diffPatch.js +142 -0
  871. package/lib/types/components/kernelCatalog.d.ts +48 -0
  872. package/lib/types/components/kernelCatalog.d.ts.map +1 -0
  873. package/lib/types/components/kernelCatalog.js +53 -0
  874. package/lib/types/components/launchpadActions.d.ts +80 -0
  875. package/lib/types/components/launchpadActions.d.ts.map +1 -0
  876. package/lib/types/components/launchpadActions.js +133 -0
  877. package/lib/types/components/launchpadLayout.d.ts +62 -0
  878. package/lib/types/components/launchpadLayout.d.ts.map +1 -0
  879. package/lib/types/components/launchpadLayout.js +176 -0
  880. package/lib/types/components/launchpadParams.d.ts +101 -0
  881. package/lib/types/components/launchpadParams.d.ts.map +1 -0
  882. package/lib/types/components/launchpadParams.js +171 -0
  883. package/lib/types/components/maidPortrait.d.ts +37 -5
  884. package/lib/types/components/maidPortrait.d.ts.map +1 -1
  885. package/lib/types/components/maidPortrait.js +73 -54
  886. package/lib/types/components/messages/AgentMessageFlow.d.ts +20 -0
  887. package/lib/types/components/messages/AgentMessageFlow.d.ts.map +1 -0
  888. package/lib/types/components/messages/AgentMessageFlow.js +37 -0
  889. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +6 -1
  890. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  891. package/lib/types/components/messages/AssistantThinkingMessage.js +29 -5
  892. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +11 -2
  893. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  894. package/lib/types/components/messages/AssistantToolUseMessage.js +289 -36
  895. package/lib/types/components/messages/TranscriptLeaves.d.ts +85 -0
  896. package/lib/types/components/messages/TranscriptLeaves.d.ts.map +1 -0
  897. package/lib/types/components/messages/TranscriptLeaves.js +74 -0
  898. package/lib/types/components/messages/agentTeam.d.ts +69 -0
  899. package/lib/types/components/messages/agentTeam.d.ts.map +1 -0
  900. package/lib/types/components/messages/agentTeam.js +53 -0
  901. package/lib/types/components/messages/liveOutputLines.d.ts +33 -0
  902. package/lib/types/components/messages/liveOutputLines.d.ts.map +1 -0
  903. package/lib/types/components/messages/liveOutputLines.js +100 -0
  904. package/lib/types/components/messages/subagentTranscript.d.ts +146 -0
  905. package/lib/types/components/messages/subagentTranscript.d.ts.map +1 -0
  906. package/lib/types/components/messages/subagentTranscript.js +304 -0
  907. package/lib/types/components/onboardingModel.d.ts +83 -0
  908. package/lib/types/components/onboardingModel.d.ts.map +1 -0
  909. package/lib/types/components/onboardingModel.js +128 -0
  910. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +16 -1
  911. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  912. package/lib/types/components/questions/AskUserQuestionPanel.js +76 -6
  913. package/lib/types/components/questions/PlanReviewPanel.d.ts +8 -3
  914. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  915. package/lib/types/components/questions/PlanReviewPanel.js +11 -6
  916. package/lib/types/components/questions/ProviderModelEditor.d.ts +12 -0
  917. package/lib/types/components/questions/ProviderModelEditor.d.ts.map +1 -0
  918. package/lib/types/components/questions/ProviderModelEditor.js +266 -0
  919. package/lib/types/components/shimmer.d.ts +26 -0
  920. package/lib/types/components/shimmer.d.ts.map +1 -1
  921. package/lib/types/components/shimmer.js +26 -0
  922. package/lib/types/components/sidePanel/InfoPanel.d.ts +17 -0
  923. package/lib/types/components/sidePanel/InfoPanel.d.ts.map +1 -0
  924. package/lib/types/components/sidePanel/InfoPanel.js +129 -0
  925. package/lib/types/components/sidePanel/PanelBar.d.ts +21 -0
  926. package/lib/types/components/sidePanel/PanelBar.d.ts.map +1 -0
  927. package/lib/types/components/sidePanel/PanelBar.js +82 -0
  928. package/lib/types/components/sidePanel/PanelErrorBoundary.d.ts +21 -0
  929. package/lib/types/components/sidePanel/PanelErrorBoundary.d.ts.map +1 -0
  930. package/lib/types/components/sidePanel/PanelErrorBoundary.js +30 -0
  931. package/lib/types/components/sidePanel/PanelHost.d.ts +36 -0
  932. package/lib/types/components/sidePanel/PanelHost.d.ts.map +1 -0
  933. package/lib/types/components/sidePanel/PanelHost.js +81 -0
  934. package/lib/types/components/sidePanel/PanelPicker.d.ts +24 -0
  935. package/lib/types/components/sidePanel/PanelPicker.d.ts.map +1 -0
  936. package/lib/types/components/sidePanel/PanelPicker.js +45 -0
  937. package/lib/types/components/sidePanel/PanelStore.d.ts +57 -0
  938. package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -0
  939. package/lib/types/components/sidePanel/PanelStore.js +113 -0
  940. package/lib/types/components/sidePanel/SidePanelColumn.d.ts +24 -0
  941. package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -0
  942. package/lib/types/components/sidePanel/SidePanelColumn.js +67 -0
  943. package/lib/types/components/sidePanel/SidePanelLayout.d.ts +54 -0
  944. package/lib/types/components/sidePanel/SidePanelLayout.d.ts.map +1 -0
  945. package/lib/types/components/sidePanel/SidePanelLayout.js +81 -0
  946. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts +43 -0
  947. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts.map +1 -0
  948. package/lib/types/components/sidePanel/SidePanelRuntimeContext.js +26 -0
  949. package/lib/types/components/sidePanel/TrajectoryPanel.d.ts +7 -0
  950. package/lib/types/components/sidePanel/TrajectoryPanel.d.ts.map +1 -0
  951. package/lib/types/components/sidePanel/TrajectoryPanel.js +327 -0
  952. package/lib/types/components/sidePanel/WorkspacePanel.d.ts +4 -0
  953. package/lib/types/components/sidePanel/WorkspacePanel.d.ts.map +1 -0
  954. package/lib/types/components/sidePanel/WorkspacePanel.js +171 -0
  955. package/lib/types/components/sidePanel/agentViewStore.d.ts +20 -0
  956. package/lib/types/components/sidePanel/agentViewStore.d.ts.map +1 -0
  957. package/lib/types/components/sidePanel/agentViewStore.js +26 -0
  958. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +50 -0
  959. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -0
  960. package/lib/types/components/sidePanel/btw/BtwComposer.js +45 -0
  961. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +13 -0
  962. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -0
  963. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +147 -0
  964. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +14 -0
  965. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -0
  966. package/lib/types/components/sidePanel/btw/BtwThreadScene.js +131 -0
  967. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +30 -0
  968. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -0
  969. package/lib/types/components/sidePanel/btw/BtwThreadView.js +87 -0
  970. package/lib/types/components/sidePanel/btw/threads.d.ts +111 -0
  971. package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -0
  972. package/lib/types/components/sidePanel/btw/threads.js +302 -0
  973. package/lib/types/components/sidePanel/builtinPanels.d.ts +3 -0
  974. package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -0
  975. package/lib/types/components/sidePanel/builtinPanels.js +269 -0
  976. package/lib/types/components/sidePanel/companion/CompanionPanel.d.ts +11 -0
  977. package/lib/types/components/sidePanel/companion/CompanionPanel.d.ts.map +1 -0
  978. package/lib/types/components/sidePanel/companion/CompanionPanel.js +492 -0
  979. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts +32 -0
  980. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts.map +1 -0
  981. package/lib/types/components/sidePanel/companion/SplashMascot.js +103 -0
  982. package/lib/types/components/sidePanel/companion/deepy.d.ts +75 -0
  983. package/lib/types/components/sidePanel/companion/deepy.d.ts.map +1 -0
  984. package/lib/types/components/sidePanel/companion/deepy.js +222 -0
  985. package/lib/types/components/sidePanel/companion/mood.d.ts +208 -0
  986. package/lib/types/components/sidePanel/companion/mood.d.ts.map +1 -0
  987. package/lib/types/components/sidePanel/companion/mood.js +256 -0
  988. package/lib/types/components/sidePanel/companion/pose.d.ts +43 -0
  989. package/lib/types/components/sidePanel/companion/pose.d.ts.map +1 -0
  990. package/lib/types/components/sidePanel/companion/pose.js +34 -0
  991. package/lib/types/components/sidePanel/companion/skins.d.ts +136 -0
  992. package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -0
  993. package/lib/types/components/sidePanel/companion/skins.js +582 -0
  994. package/lib/types/components/sidePanel/dimensions.d.ts +60 -0
  995. package/lib/types/components/sidePanel/dimensions.d.ts.map +1 -0
  996. package/lib/types/components/sidePanel/dimensions.js +75 -0
  997. package/lib/types/components/sidePanel/jobsFocusStore.d.ts +21 -0
  998. package/lib/types/components/sidePanel/jobsFocusStore.d.ts.map +1 -0
  999. package/lib/types/components/sidePanel/jobsFocusStore.js +30 -0
  1000. package/lib/types/components/sidePanel/panelBridge.d.ts +44 -0
  1001. package/lib/types/components/sidePanel/panelBridge.d.ts.map +1 -0
  1002. package/lib/types/components/sidePanel/panelBridge.js +55 -0
  1003. package/lib/types/components/sidePanel/pluginPanelAdapter.d.ts +22 -0
  1004. package/lib/types/components/sidePanel/pluginPanelAdapter.d.ts.map +1 -0
  1005. package/lib/types/components/sidePanel/pluginPanelAdapter.js +148 -0
  1006. package/lib/types/components/sidePanel/types.d.ts +110 -0
  1007. package/lib/types/components/sidePanel/types.d.ts.map +1 -0
  1008. package/lib/types/components/sidePanel/types.js +1 -0
  1009. package/lib/types/components/sidePanel/usePanelInput.d.ts +5 -0
  1010. package/lib/types/components/sidePanel/usePanelInput.d.ts.map +1 -0
  1011. package/lib/types/components/sidePanel/usePanelInput.js +44 -0
  1012. package/lib/types/components/sidePanel/useSidePanel.d.ts +47 -0
  1013. package/lib/types/components/sidePanel/useSidePanel.d.ts.map +1 -0
  1014. package/lib/types/components/sidePanel/useSidePanel.js +284 -0
  1015. package/lib/types/components/splashFonts.d.ts +17 -9
  1016. package/lib/types/components/splashFonts.d.ts.map +1 -1
  1017. package/lib/types/components/splashFonts.js +119 -15
  1018. package/lib/types/components/splashLayout.d.ts.map +1 -1
  1019. package/lib/types/components/splashLayout.js +3 -1
  1020. package/lib/types/components/subagentDetailMemory.d.ts +17 -0
  1021. package/lib/types/components/subagentDetailMemory.d.ts.map +1 -0
  1022. package/lib/types/components/subagentDetailMemory.js +28 -0
  1023. package/lib/types/components/trajectory/Inspector.d.ts.map +1 -1
  1024. package/lib/types/components/trajectory/Inspector.js +9 -0
  1025. package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
  1026. package/lib/types/components/trajectory/Ledger.js +7 -1
  1027. package/lib/types/components/trajectory/scope.d.ts +64 -0
  1028. package/lib/types/components/trajectory/scope.d.ts.map +1 -0
  1029. package/lib/types/components/trajectory/scope.js +88 -0
  1030. package/lib/types/components/trajectory/useTrajectoryScope.d.ts +42 -0
  1031. package/lib/types/components/trajectory/useTrajectoryScope.d.ts.map +1 -0
  1032. package/lib/types/components/trajectory/useTrajectoryScope.js +86 -0
  1033. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +3 -1
  1034. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -1
  1035. package/lib/types/components/workspaces/HomeWorkspaceRow.js +3 -2
  1036. package/lib/types/customTheme.d.ts +4 -6
  1037. package/lib/types/customTheme.d.ts.map +1 -1
  1038. package/lib/types/customTheme.js +6 -8
  1039. package/lib/types/deepseekPricing.d.ts +10 -9
  1040. package/lib/types/deepseekPricing.d.ts.map +1 -1
  1041. package/lib/types/deepseekPricing.js +18 -11
  1042. package/lib/types/dsh-adapter/approvals.d.ts +18 -5
  1043. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
  1044. package/lib/types/dsh-adapter/approvals.js +17 -4
  1045. package/lib/types/dsh-adapter/backend/session.d.ts +64 -0
  1046. package/lib/types/dsh-adapter/backend/session.d.ts.map +1 -0
  1047. package/lib/types/dsh-adapter/backend/session.js +291 -0
  1048. package/lib/types/dsh-adapter/backend/translate.d.ts +58 -0
  1049. package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -0
  1050. package/lib/types/dsh-adapter/backend/translate.js +467 -0
  1051. package/lib/types/dsh-adapter/backends.d.ts +49 -0
  1052. package/lib/types/dsh-adapter/backends.d.ts.map +1 -0
  1053. package/lib/types/dsh-adapter/backends.js +124 -0
  1054. package/lib/types/dsh-adapter/channel/action-readiness.d.ts +16 -0
  1055. package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
  1056. package/lib/types/dsh-adapter/channel/action-readiness.js +109 -0
  1057. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +2 -2
  1058. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
  1059. package/lib/types/dsh-adapter/channel/attached-context.d.ts +58 -0
  1060. package/lib/types/dsh-adapter/channel/attached-context.d.ts.map +1 -0
  1061. package/lib/types/dsh-adapter/channel/attached-context.js +109 -0
  1062. package/lib/types/dsh-adapter/channel/background-action.d.ts +2 -2
  1063. package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
  1064. package/lib/types/dsh-adapter/channel/background-action.js +7 -5
  1065. package/lib/types/dsh-adapter/channel/binding-events.d.ts +25 -9
  1066. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  1067. package/lib/types/dsh-adapter/channel/binding-events.js +101 -135
  1068. package/lib/types/dsh-adapter/channel/binding.d.ts +61 -14
  1069. package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
  1070. package/lib/types/dsh-adapter/channel/binding.js +102 -35
  1071. package/lib/types/dsh-adapter/channel/capabilities.d.ts +82 -0
  1072. package/lib/types/dsh-adapter/channel/capabilities.d.ts.map +1 -0
  1073. package/lib/types/dsh-adapter/channel/capabilities.js +165 -0
  1074. package/lib/types/dsh-adapter/channel/command-completions.d.ts +3 -0
  1075. package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
  1076. package/lib/types/dsh-adapter/channel/command-completions.js +41 -4
  1077. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  1078. package/lib/types/dsh-adapter/channel/compaction.js +3 -2
  1079. package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
  1080. package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
  1081. package/lib/types/dsh-adapter/channel/composer-images.js +4 -3
  1082. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +4 -12
  1083. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
  1084. package/lib/types/dsh-adapter/channel/context-bookkeeping.js +9 -4
  1085. package/lib/types/dsh-adapter/channel/core/actions.d.ts +39 -0
  1086. package/lib/types/dsh-adapter/channel/core/actions.d.ts.map +1 -0
  1087. package/lib/types/dsh-adapter/channel/core/actions.js +152 -0
  1088. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +145 -0
  1089. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -0
  1090. package/lib/types/dsh-adapter/channel/core/binding-feed.js +289 -0
  1091. package/lib/types/dsh-adapter/channel/core/compose.d.ts +217 -0
  1092. package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -0
  1093. package/lib/types/dsh-adapter/channel/core/compose.js +938 -0
  1094. package/lib/types/dsh-adapter/channel/core/files.d.ts +57 -0
  1095. package/lib/types/dsh-adapter/channel/core/files.d.ts.map +1 -0
  1096. package/lib/types/dsh-adapter/channel/core/files.js +45 -0
  1097. package/lib/types/dsh-adapter/channel/core/host.d.ts +55 -0
  1098. package/lib/types/dsh-adapter/channel/core/host.d.ts.map +1 -0
  1099. package/lib/types/dsh-adapter/channel/core/host.js +116 -0
  1100. package/lib/types/dsh-adapter/channel/core/local-actions.d.ts +46 -0
  1101. package/lib/types/dsh-adapter/channel/core/local-actions.d.ts.map +1 -0
  1102. package/lib/types/dsh-adapter/channel/core/local-actions.js +117 -0
  1103. package/lib/types/dsh-adapter/channel/core/local-images.d.ts +20 -0
  1104. package/lib/types/dsh-adapter/channel/core/local-images.d.ts.map +1 -0
  1105. package/lib/types/dsh-adapter/channel/core/local-images.js +147 -0
  1106. package/lib/types/dsh-adapter/channel/core/reports.d.ts +12 -0
  1107. package/lib/types/dsh-adapter/channel/core/reports.d.ts.map +1 -0
  1108. package/lib/types/dsh-adapter/channel/core/reports.js +77 -0
  1109. package/lib/types/dsh-adapter/channel/core/session-controls.d.ts +39 -0
  1110. package/lib/types/dsh-adapter/channel/core/session-controls.d.ts.map +1 -0
  1111. package/lib/types/dsh-adapter/channel/core/session-controls.js +219 -0
  1112. package/lib/types/dsh-adapter/channel/core/session-switch.d.ts +174 -0
  1113. package/lib/types/dsh-adapter/channel/core/session-switch.d.ts.map +1 -0
  1114. package/lib/types/dsh-adapter/channel/core/session-switch.js +390 -0
  1115. package/lib/types/dsh-adapter/channel/core/sessions.d.ts +40 -0
  1116. package/lib/types/dsh-adapter/channel/core/sessions.d.ts.map +1 -0
  1117. package/lib/types/dsh-adapter/channel/core/sessions.js +268 -0
  1118. package/lib/types/dsh-adapter/channel/decisions.d.ts +4 -3
  1119. package/lib/types/dsh-adapter/channel/decisions.d.ts.map +1 -1
  1120. package/lib/types/dsh-adapter/channel/decisions.js +4 -4
  1121. package/lib/types/dsh-adapter/channel/emitter.d.ts +15 -2
  1122. package/lib/types/dsh-adapter/channel/emitter.d.ts.map +1 -1
  1123. package/lib/types/dsh-adapter/channel/emitter.js +5 -3
  1124. package/lib/types/dsh-adapter/channel/extensions.d.ts +36 -0
  1125. package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -0
  1126. package/lib/types/dsh-adapter/channel/extensions.js +714 -0
  1127. package/lib/types/dsh-adapter/channel/ide-selection.d.ts +1 -10
  1128. package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -1
  1129. package/lib/types/dsh-adapter/channel/ide-selection.js +4 -46
  1130. package/lib/types/dsh-adapter/channel/input-actions.d.ts +27 -4
  1131. package/lib/types/dsh-adapter/channel/input-actions.d.ts.map +1 -1
  1132. package/lib/types/dsh-adapter/channel/input-actions.js +240 -21
  1133. package/lib/types/dsh-adapter/channel/input-delivery.d.ts +34 -7
  1134. package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
  1135. package/lib/types/dsh-adapter/channel/input-delivery.js +79 -24
  1136. package/lib/types/dsh-adapter/channel/local-actions.d.ts +10 -32
  1137. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  1138. package/lib/types/dsh-adapter/channel/local-actions.js +10 -78
  1139. package/lib/types/dsh-adapter/channel/local-fs.d.ts +3 -0
  1140. package/lib/types/dsh-adapter/channel/local-fs.d.ts.map +1 -0
  1141. package/lib/types/dsh-adapter/channel/local-fs.js +46 -0
  1142. package/lib/types/dsh-adapter/channel/mode-actions.d.ts +3 -6
  1143. package/lib/types/dsh-adapter/channel/mode-actions.d.ts.map +1 -1
  1144. package/lib/types/dsh-adapter/channel/mode-actions.js +7 -2
  1145. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +10 -3
  1146. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
  1147. package/lib/types/dsh-adapter/channel/mode-permission-actions.js +0 -1
  1148. package/lib/types/dsh-adapter/channel/model-actions.d.ts +3 -3
  1149. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  1150. package/lib/types/dsh-adapter/channel/model-actions.js +38 -5
  1151. package/lib/types/dsh-adapter/channel/model-switch.d.ts +2 -2
  1152. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  1153. package/lib/types/dsh-adapter/channel/model-switch.js +9 -6
  1154. package/lib/types/dsh-adapter/channel/preferences.d.ts +1 -1
  1155. package/lib/types/dsh-adapter/channel/preferences.d.ts.map +1 -1
  1156. package/lib/types/dsh-adapter/channel/preferences.js +25 -1
  1157. package/lib/types/dsh-adapter/channel/projection.d.ts +16 -13
  1158. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  1159. package/lib/types/dsh-adapter/channel/projection.js +38 -1138
  1160. package/lib/types/dsh-adapter/channel/question-record.d.ts +3 -75
  1161. package/lib/types/dsh-adapter/channel/question-record.d.ts.map +1 -1
  1162. package/lib/types/dsh-adapter/channel/question-record.js +3 -107
  1163. package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
  1164. package/lib/types/dsh-adapter/channel/reports.js +13 -4
  1165. package/lib/types/dsh-adapter/channel/session-activity.d.ts +9 -0
  1166. package/lib/types/dsh-adapter/channel/session-activity.d.ts.map +1 -0
  1167. package/lib/types/dsh-adapter/channel/session-activity.js +42 -0
  1168. package/lib/types/dsh-adapter/channel/session-adoption.d.ts +4 -4
  1169. package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
  1170. package/lib/types/dsh-adapter/channel/session-adoption.js +3 -1
  1171. package/lib/types/dsh-adapter/channel/session-fork.d.ts +1 -1
  1172. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  1173. package/lib/types/dsh-adapter/channel/session-fork.js +2 -1
  1174. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +7 -3
  1175. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
  1176. package/lib/types/dsh-adapter/channel/session-live-adoption.js +1 -1
  1177. package/lib/types/dsh-adapter/channel/session-metadata.d.ts +2 -9
  1178. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  1179. package/lib/types/dsh-adapter/channel/session-reset.d.ts +5 -1
  1180. package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
  1181. package/lib/types/dsh-adapter/channel/session-reset.js +5 -0
  1182. package/lib/types/dsh-adapter/channel/session-resume.d.ts +5 -10
  1183. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  1184. package/lib/types/dsh-adapter/channel/session-resume.js +74 -113
  1185. package/lib/types/dsh-adapter/channel/session-rewind.d.ts +4 -4
  1186. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  1187. package/lib/types/dsh-adapter/channel/session-rewind.js +7 -6
  1188. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts +4 -4
  1189. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  1190. package/lib/types/dsh-adapter/channel/session-tree-actions.js +8 -7
  1191. package/lib/types/dsh-adapter/channel/settings-host.d.ts +1 -1
  1192. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  1193. package/lib/types/dsh-adapter/channel/settings-host.js +8 -0
  1194. package/lib/types/dsh-adapter/channel/skill-catalog.d.ts +5 -1
  1195. package/lib/types/dsh-adapter/channel/skill-catalog.d.ts.map +1 -1
  1196. package/lib/types/dsh-adapter/channel/skill-catalog.js +2 -2
  1197. package/lib/types/dsh-adapter/channel/state.d.ts +89 -2
  1198. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  1199. package/lib/types/dsh-adapter/channel/state.js +9 -4
  1200. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +58 -3
  1201. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  1202. package/lib/types/dsh-adapter/channel/subagent-projection.js +153 -9
  1203. package/lib/types/dsh-adapter/channel/subagent-transcript.d.ts +114 -0
  1204. package/lib/types/dsh-adapter/channel/subagent-transcript.d.ts.map +1 -0
  1205. package/lib/types/dsh-adapter/channel/subagent-transcript.js +279 -0
  1206. package/lib/types/dsh-adapter/channel/transcript.d.ts +7 -15
  1207. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  1208. package/lib/types/dsh-adapter/channel/transcript.js +17 -21
  1209. package/lib/types/dsh-adapter/channel/types.d.ts +16 -7
  1210. package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
  1211. package/lib/types/dsh-adapter/channel/usage.d.ts +3 -6
  1212. package/lib/types/dsh-adapter/channel/usage.d.ts.map +1 -1
  1213. package/lib/types/dsh-adapter/channel/usage.js +5 -16
  1214. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
  1215. package/lib/types/dsh-adapter/channel/workspace-actions.js +2 -1
  1216. package/lib/types/dsh-adapter/channel.d.ts +17 -8
  1217. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  1218. package/lib/types/dsh-adapter/channel.js +24 -1006
  1219. package/lib/types/dsh-adapter/context-occupancy.d.ts +209 -0
  1220. package/lib/types/dsh-adapter/context-occupancy.d.ts.map +1 -0
  1221. package/lib/types/dsh-adapter/context-occupancy.js +304 -0
  1222. package/lib/types/dsh-adapter/contract.d.ts +14 -0
  1223. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  1224. package/lib/types/dsh-adapter/contract.js +24 -0
  1225. package/lib/types/dsh-adapter/decision-guard.d.ts +24 -0
  1226. package/lib/types/dsh-adapter/decision-guard.d.ts.map +1 -1
  1227. package/lib/types/dsh-adapter/decision-guard.js +44 -0
  1228. package/lib/types/dsh-adapter/extension-events.d.ts +4 -1
  1229. package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
  1230. package/lib/types/dsh-adapter/extension-events.js +22 -10
  1231. package/lib/types/dsh-adapter/index.d.ts +71 -1
  1232. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  1233. package/lib/types/dsh-adapter/index.js +47 -1
  1234. package/lib/types/dsh-adapter/jobs.d.ts +5 -3
  1235. package/lib/types/dsh-adapter/jobs.d.ts.map +1 -1
  1236. package/lib/types/dsh-adapter/jobs.js +53 -14
  1237. package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts +1 -16
  1238. package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts.map +1 -1
  1239. package/lib/types/dsh-adapter/migrate/parse/jsonl.js +3 -29
  1240. package/lib/types/dsh-adapter/migrate/sessionize.d.ts.map +1 -1
  1241. package/lib/types/dsh-adapter/migrate/sessionize.js +11 -12
  1242. package/lib/types/dsh-adapter/oauth-credential-source.d.ts +34 -0
  1243. package/lib/types/dsh-adapter/oauth-credential-source.d.ts.map +1 -0
  1244. package/lib/types/dsh-adapter/oauth-credential-source.js +66 -0
  1245. package/lib/types/dsh-adapter/panel-runtime-registry.d.ts +39 -0
  1246. package/lib/types/dsh-adapter/panel-runtime-registry.d.ts.map +1 -0
  1247. package/lib/types/dsh-adapter/panel-runtime-registry.js +84 -0
  1248. package/lib/types/dsh-adapter/panels.d.ts +251 -0
  1249. package/lib/types/dsh-adapter/panels.d.ts.map +1 -0
  1250. package/lib/types/dsh-adapter/panels.js +407 -0
  1251. package/lib/types/dsh-adapter/plugin-host.js +1 -1
  1252. package/lib/types/dsh-adapter/plugin.d.ts +55 -3
  1253. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  1254. package/lib/types/dsh-adapter/plugin.js +708 -135
  1255. package/lib/types/dsh-adapter/presets.d.ts +26 -6
  1256. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  1257. package/lib/types/dsh-adapter/presets.js +29 -7
  1258. package/lib/types/dsh-adapter/provider-model-capabilities.d.ts +10 -0
  1259. package/lib/types/dsh-adapter/provider-model-capabilities.d.ts.map +1 -0
  1260. package/lib/types/dsh-adapter/provider-model-capabilities.js +80 -0
  1261. package/lib/types/dsh-adapter/providerWizard.d.ts +8 -2
  1262. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
  1263. package/lib/types/dsh-adapter/providerWizard.js +118 -52
  1264. package/lib/types/dsh-adapter/questions.d.ts +29 -124
  1265. package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
  1266. package/lib/types/dsh-adapter/questions.js +33 -267
  1267. package/lib/types/dsh-adapter/recap.d.ts +3 -15
  1268. package/lib/types/dsh-adapter/recap.d.ts.map +1 -1
  1269. package/lib/types/dsh-adapter/recap.js +3 -46
  1270. package/lib/types/dsh-adapter/sanitize.d.ts +4 -44
  1271. package/lib/types/dsh-adapter/sanitize.d.ts.map +1 -1
  1272. package/lib/types/dsh-adapter/sanitize.js +4 -84
  1273. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +3 -1
  1274. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -1
  1275. package/lib/types/dsh-adapter/session-mount-heartbeat.js +4 -2
  1276. package/lib/types/dsh-adapter/sessions/digest.d.ts +18 -3
  1277. package/lib/types/dsh-adapter/sessions/digest.d.ts.map +1 -1
  1278. package/lib/types/dsh-adapter/sessions/digest.js +60 -27
  1279. package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
  1280. package/lib/types/dsh-adapter/sessions/list.js +6 -4
  1281. package/lib/types/dsh-adapter/sessions/recovery.d.ts +2 -2
  1282. package/lib/types/dsh-adapter/sessions/recovery.d.ts.map +1 -1
  1283. package/lib/types/dsh-adapter/sessions/recovery.js +23 -14
  1284. package/lib/types/dsh-adapter/sessions/store.d.ts +2 -0
  1285. package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
  1286. package/lib/types/dsh-adapter/sessions/store.js +1 -0
  1287. package/lib/types/dsh-adapter/sessions/types.d.ts +2 -0
  1288. package/lib/types/dsh-adapter/sessions/types.d.ts.map +1 -1
  1289. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
  1290. package/lib/types/dsh-adapter/sideQuestion.js +3 -13
  1291. package/lib/types/dsh-adapter/startup-args.d.ts +8 -0
  1292. package/lib/types/dsh-adapter/startup-args.d.ts.map +1 -0
  1293. package/lib/types/dsh-adapter/startup-args.js +34 -0
  1294. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  1295. package/lib/types/dsh-adapter/subagents.js +7 -0
  1296. package/lib/types/dsh-adapter/themes.d.ts +1 -1
  1297. package/lib/types/dsh-adapter/themes.d.ts.map +1 -1
  1298. package/lib/types/dsh-adapter/trajectory/agent-source.d.ts +84 -0
  1299. package/lib/types/dsh-adapter/trajectory/agent-source.d.ts.map +1 -0
  1300. package/lib/types/dsh-adapter/trajectory/agent-source.js +601 -0
  1301. package/lib/types/dsh-adapter/trajectory/guards.d.ts +31 -1
  1302. package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -1
  1303. package/lib/types/dsh-adapter/trajectory/guards.js +28 -0
  1304. package/lib/types/dsh-adapter/trajectory/index.d.ts +3 -1
  1305. package/lib/types/dsh-adapter/trajectory/index.d.ts.map +1 -1
  1306. package/lib/types/dsh-adapter/trajectory/index.js +1 -0
  1307. package/lib/types/dsh-adapter/trajectory/inspect.d.ts +7 -0
  1308. package/lib/types/dsh-adapter/trajectory/inspect.d.ts.map +1 -1
  1309. package/lib/types/dsh-adapter/trajectory/inspect.js +70 -2
  1310. package/lib/types/dsh-adapter/trajectory/projection.d.ts +4 -0
  1311. package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -1
  1312. package/lib/types/dsh-adapter/trajectory/projection.js +36 -0
  1313. package/lib/types/dsh-adapter/trajectory/types.d.ts +13 -0
  1314. package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -1
  1315. package/lib/types/effortPrefs.d.ts +7 -0
  1316. package/lib/types/effortPrefs.d.ts.map +1 -1
  1317. package/lib/types/effortPrefs.js +11 -2
  1318. package/lib/types/handoffAck.d.ts +57 -0
  1319. package/lib/types/handoffAck.d.ts.map +1 -0
  1320. package/lib/types/handoffAck.js +154 -0
  1321. package/lib/types/handoffEvents.d.ts +52 -0
  1322. package/lib/types/handoffEvents.d.ts.map +1 -0
  1323. package/lib/types/handoffEvents.js +128 -0
  1324. package/lib/types/history.d.ts +24 -7
  1325. package/lib/types/history.d.ts.map +1 -1
  1326. package/lib/types/history.js +77 -18
  1327. package/lib/types/i18n.d.ts +3937 -97
  1328. package/lib/types/i18n.d.ts.map +1 -1
  1329. package/lib/types/i18n.js +1154 -12
  1330. package/lib/types/ink/colorize.d.ts.map +1 -1
  1331. package/lib/types/ink/colorize.js +8 -2
  1332. package/lib/types/ink/components/AlternateScreen.d.ts +12 -1
  1333. package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
  1334. package/lib/types/ink/components/AlternateScreen.js +25 -4
  1335. package/lib/types/ink/components/App.d.ts +19 -2
  1336. package/lib/types/ink/components/App.d.ts.map +1 -1
  1337. package/lib/types/ink/components/App.js +114 -66
  1338. package/lib/types/ink/components/Image.d.ts +8 -1
  1339. package/lib/types/ink/components/Image.d.ts.map +1 -1
  1340. package/lib/types/ink/components/Image.js +2 -2
  1341. package/lib/types/ink/components/TerminalSizeContext.d.ts +7 -0
  1342. package/lib/types/ink/components/TerminalSizeContext.d.ts.map +1 -1
  1343. package/lib/types/ink/components/Text.d.ts +8 -1
  1344. package/lib/types/ink/components/Text.d.ts.map +1 -1
  1345. package/lib/types/ink/components/Text.js +11 -1
  1346. package/lib/types/ink/dom.d.ts.map +1 -1
  1347. package/lib/types/ink/dom.js +75 -3
  1348. package/lib/types/ink/hooks/use-input.d.ts +11 -0
  1349. package/lib/types/ink/hooks/use-input.d.ts.map +1 -1
  1350. package/lib/types/ink/hooks/use-input.js +17 -6
  1351. package/lib/types/ink/hooks/use-terminal-viewport.d.ts.map +1 -1
  1352. package/lib/types/ink/hooks/use-terminal-viewport.js +3 -1
  1353. package/lib/types/ink/ink.d.ts +18 -0
  1354. package/lib/types/ink/ink.d.ts.map +1 -1
  1355. package/lib/types/ink/ink.js +59 -10
  1356. package/lib/types/ink/kitty-graphics.d.ts +7 -2
  1357. package/lib/types/ink/kitty-graphics.d.ts.map +1 -1
  1358. package/lib/types/ink/kitty-graphics.js +15 -7
  1359. package/lib/types/ink/node-cache.d.ts +15 -1
  1360. package/lib/types/ink/node-cache.d.ts.map +1 -1
  1361. package/lib/types/ink/node-cache.js +4 -1
  1362. package/lib/types/ink/output.d.ts +10 -1
  1363. package/lib/types/ink/output.d.ts.map +1 -1
  1364. package/lib/types/ink/output.js +5 -3
  1365. package/lib/types/ink/parse-keypress.d.ts +49 -3
  1366. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  1367. package/lib/types/ink/parse-keypress.js +700 -127
  1368. package/lib/types/ink/reconciler.d.ts.map +1 -1
  1369. package/lib/types/ink/reconciler.js +9 -0
  1370. package/lib/types/ink/render-node-to-output.d.ts +1 -1
  1371. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  1372. package/lib/types/ink/render-node-to-output.js +237 -9
  1373. package/lib/types/ink/render-stats.d.ts +35 -0
  1374. package/lib/types/ink/render-stats.d.ts.map +1 -0
  1375. package/lib/types/ink/render-stats.js +53 -0
  1376. package/lib/types/ink/screen.d.ts +26 -1
  1377. package/lib/types/ink/screen.d.ts.map +1 -1
  1378. package/lib/types/ink/screen.js +96 -1
  1379. package/lib/types/ink/selection.d.ts +23 -1
  1380. package/lib/types/ink/selection.d.ts.map +1 -1
  1381. package/lib/types/ink/selection.js +102 -26
  1382. package/lib/types/ink/sixel-codec.d.ts +21 -0
  1383. package/lib/types/ink/sixel-codec.d.ts.map +1 -1
  1384. package/lib/types/ink/sixel-codec.js +49 -8
  1385. package/lib/types/ink/sixel-graphics.js +2 -2
  1386. package/lib/types/ink/styles.d.ts +46 -0
  1387. package/lib/types/ink/styles.d.ts.map +1 -1
  1388. package/lib/types/ink/terminal-image.d.ts +7 -0
  1389. package/lib/types/ink/terminal-image.d.ts.map +1 -1
  1390. package/lib/types/ink/terminal-querier.d.ts +1 -1
  1391. package/lib/types/ink/terminal-querier.js +4 -4
  1392. package/lib/types/ink/text-decoration.d.ts +49 -0
  1393. package/lib/types/ink/text-decoration.d.ts.map +1 -0
  1394. package/lib/types/ink/text-decoration.js +235 -0
  1395. package/lib/types/ink/update-overflow-guard.d.ts +9 -0
  1396. package/lib/types/ink/update-overflow-guard.d.ts.map +1 -1
  1397. package/lib/types/ink/update-overflow-guard.js +41 -0
  1398. package/lib/types/ink/wrap-text.d.ts.map +1 -1
  1399. package/lib/types/ink/wrap-text.js +5 -1
  1400. package/lib/types/kernelPrefs.d.ts +51 -0
  1401. package/lib/types/kernelPrefs.d.ts.map +1 -0
  1402. package/lib/types/kernelPrefs.js +126 -0
  1403. package/lib/types/math/renderer.d.ts +2 -0
  1404. package/lib/types/math/renderer.d.ts.map +1 -1
  1405. package/lib/types/math/renderer.js +4 -0
  1406. package/lib/types/modelRecents.d.ts +10 -2
  1407. package/lib/types/modelRecents.d.ts.map +1 -1
  1408. package/lib/types/modelRecents.js +20 -7
  1409. package/lib/types/onboardingPrefs.d.ts +52 -0
  1410. package/lib/types/onboardingPrefs.d.ts.map +1 -0
  1411. package/lib/types/onboardingPrefs.js +107 -0
  1412. package/lib/types/panels.d.ts +4 -0
  1413. package/lib/types/panels.d.ts.map +1 -0
  1414. package/lib/types/panels.js +4 -0
  1415. package/lib/types/screens/AgentTranscriptScene.d.ts +42 -0
  1416. package/lib/types/screens/AgentTranscriptScene.d.ts.map +1 -0
  1417. package/lib/types/screens/AgentTranscriptScene.js +269 -0
  1418. package/lib/types/screens/Chat.d.ts +66 -7
  1419. package/lib/types/screens/Chat.d.ts.map +1 -1
  1420. package/lib/types/screens/Chat.js +1720 -381
  1421. package/lib/types/screens/Launchpad.d.ts +211 -0
  1422. package/lib/types/screens/Launchpad.d.ts.map +1 -0
  1423. package/lib/types/screens/Launchpad.js +726 -0
  1424. package/lib/types/screens/Onboarding.d.ts +37 -0
  1425. package/lib/types/screens/Onboarding.d.ts.map +1 -0
  1426. package/lib/types/screens/Onboarding.js +492 -0
  1427. package/lib/types/screens/SessionSupervisor.d.ts +3 -3
  1428. package/lib/types/screens/SessionSupervisor.d.ts.map +1 -1
  1429. package/lib/types/screens/SessionSupervisor.js +87 -17
  1430. package/lib/types/screens/Settings.d.ts.map +1 -1
  1431. package/lib/types/screens/Settings.js +211 -7
  1432. package/lib/types/screens/StatusLine.d.ts +40 -1
  1433. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  1434. package/lib/types/screens/StatusLine.js +160 -30
  1435. package/lib/types/screens/StatusMetrics.d.ts +75 -17
  1436. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  1437. package/lib/types/screens/StatusMetrics.js +161 -30
  1438. package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
  1439. package/lib/types/screens/TrajectoryScene.js +74 -12
  1440. package/lib/types/screens/chat/backendCommands.d.ts +37 -0
  1441. package/lib/types/screens/chat/backendCommands.d.ts.map +1 -0
  1442. package/lib/types/screens/chat/backendCommands.js +51 -0
  1443. package/lib/types/screens/chat/useBackendChannels.d.ts +20 -0
  1444. package/lib/types/screens/chat/useBackendChannels.d.ts.map +1 -0
  1445. package/lib/types/screens/chat/useBackendChannels.js +117 -0
  1446. package/lib/types/screens/chat/useKernelPicker.d.ts +23 -0
  1447. package/lib/types/screens/chat/useKernelPicker.d.ts.map +1 -0
  1448. package/lib/types/screens/chat/useKernelPicker.js +72 -0
  1449. package/lib/types/screens/chatOverlay.d.ts +49 -2
  1450. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  1451. package/lib/types/screens/chatOverlay.js +12 -0
  1452. package/lib/types/screens/sessionSupervisor/model.d.ts +1 -2
  1453. package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -1
  1454. package/lib/types/screens/sessionSupervisor/model.js +4 -2
  1455. package/lib/types/screens/sessionSupervisor/useForeignSessions.d.ts.map +1 -1
  1456. package/lib/types/screens/sessionSupervisor/useForeignSessions.js +5 -1
  1457. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +14 -0
  1458. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -1
  1459. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +104 -25
  1460. package/lib/types/sessionHistory.d.ts +18 -1
  1461. package/lib/types/sessionHistory.d.ts.map +1 -1
  1462. package/lib/types/sessionHistory.js +46 -4
  1463. package/lib/types/sessionPins.d.ts +7 -0
  1464. package/lib/types/sessionPins.d.ts.map +1 -1
  1465. package/lib/types/sessionPins.js +9 -0
  1466. package/lib/types/sessions/resumeFailure.d.ts.map +1 -1
  1467. package/lib/types/sessions/resumeFailure.js +2 -1
  1468. package/lib/types/settings/definitions.d.ts +167 -0
  1469. package/lib/types/settings/definitions.d.ts.map +1 -1
  1470. package/lib/types/settings/definitions.js +129 -0
  1471. package/lib/types/terminal-utils/hyperlink.d.ts +2 -2
  1472. package/lib/types/terminal-utils/hyperlink.d.ts.map +1 -1
  1473. package/lib/types/terminal-utils/hyperlink.js +21 -4
  1474. package/lib/types/terminal-utils/markdown.d.ts +34 -6
  1475. package/lib/types/terminal-utils/markdown.d.ts.map +1 -1
  1476. package/lib/types/terminal-utils/markdown.js +257 -66
  1477. package/lib/types/theme.d.ts +49 -8
  1478. package/lib/types/theme.d.ts.map +1 -1
  1479. package/lib/types/theme.js +514 -18
  1480. package/lib/types/tips.js +7 -7
  1481. package/lib/types/trajectory/effortIgnition.d.ts +25 -7
  1482. package/lib/types/trajectory/effortIgnition.d.ts.map +1 -1
  1483. package/lib/types/trajectory/effortIgnition.js +106 -34
  1484. package/lib/types/trajectory/window.d.ts +26 -0
  1485. package/lib/types/trajectory/window.d.ts.map +1 -0
  1486. package/lib/types/trajectory/window.js +27 -0
  1487. package/lib/types/tuiDisplayPrefs.d.ts +79 -2
  1488. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  1489. package/lib/types/tuiDisplayPrefs.js +118 -0
  1490. package/lib/types/update.d.ts +141 -12
  1491. package/lib/types/update.d.ts.map +1 -1
  1492. package/lib/types/update.js +386 -62
  1493. package/lib/types/utils/bmp.d.ts.map +1 -1
  1494. package/lib/types/utils/bmp.js +8 -1
  1495. package/lib/types/utils/clipboard.d.ts.map +1 -1
  1496. package/lib/types/utils/clipboard.js +25 -6
  1497. package/lib/types/utils/crashDetail.d.ts +56 -0
  1498. package/lib/types/utils/crashDetail.d.ts.map +1 -0
  1499. package/lib/types/utils/crashDetail.js +175 -0
  1500. package/lib/types/utils/credentials.d.ts.map +1 -1
  1501. package/lib/types/utils/credentials.js +5 -1
  1502. package/lib/types/utils/draftWordBoundary.d.ts +23 -0
  1503. package/lib/types/utils/draftWordBoundary.d.ts.map +1 -0
  1504. package/lib/types/utils/draftWordBoundary.js +161 -0
  1505. package/lib/types/utils/fileTarget.d.ts.map +1 -1
  1506. package/lib/types/utils/fileTarget.js +7 -9
  1507. package/lib/types/utils/imageResize.d.ts +9 -23
  1508. package/lib/types/utils/imageResize.d.ts.map +1 -1
  1509. package/lib/types/utils/imageResize.js +24 -20
  1510. package/lib/types/utils/inputPaste.d.ts +63 -0
  1511. package/lib/types/utils/inputPaste.d.ts.map +1 -0
  1512. package/lib/types/utils/inputPaste.js +148 -0
  1513. package/lib/types/utils/intl.d.ts +8 -0
  1514. package/lib/types/utils/intl.d.ts.map +1 -1
  1515. package/lib/types/utils/intl.js +11 -0
  1516. package/lib/types/utils/jsonl.d.ts +24 -0
  1517. package/lib/types/utils/jsonl.d.ts.map +1 -0
  1518. package/lib/types/utils/jsonl.js +36 -0
  1519. package/lib/types/utils/keymap.d.ts +13 -3
  1520. package/lib/types/utils/keymap.d.ts.map +1 -1
  1521. package/lib/types/utils/keymap.js +27 -5
  1522. package/package.json +36 -9
  1523. package/{dsh-ecosystem-spec → tui-profile}/registry/README.md +1 -1
  1524. package/{dsh-ecosystem-spec → tui-profile}/registry/registry-0.15.json +1 -1
  1525. /package/{dsh-ecosystem-spec → tui-profile}/protocols/profile-definitions.d.ts +0 -0
  1526. /package/{dsh-ecosystem-spec → tui-profile}/protocols/profile-definitions.js +0 -0
  1527. /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-channel-http.d.ts +0 -0
  1528. /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-channel-http.js +0 -0
  1529. /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-channel.d.ts +0 -0
  1530. /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-channel.js +0 -0
  1531. /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-contributions.d.ts +0 -0
  1532. /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-contributions.js +0 -0
  1533. /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/decision-events-v1alpha1.json +0 -0
  1534. /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/scene-v1alpha1.json +0 -0
  1535. /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/settings-section-v1alpha1.json +0 -0
  1536. /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/tui-channel-v1alpha1.json +0 -0
  1537. /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/workspace-provider-v1alpha1.json +0 -0
  1538. /package/{dsh-ecosystem-spec → tui-profile}/registry/host-descriptor.tui.example.json +0 -0
  1539. /package/{dsh-ecosystem-spec → tui-profile}/registry/permissions-0.1.json +0 -0
  1540. /package/{dsh-ecosystem-spec → tui-profile}/schemas/conformance-claim.schema.json +0 -0
  1541. /package/{dsh-ecosystem-spec → tui-profile}/schemas/effect-ledger-record.schema.json +0 -0
  1542. /package/{dsh-ecosystem-spec → tui-profile}/schemas/host-descriptor.schema.json +0 -0
@@ -1,11 +1,14 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { t, getLang, setLang, isLang, writeLangPref, readLangPref, subscribeLang, LANGS } from '../i18n.js';
4
+ import { checkForTuiUpdate, installedTuiVersion } from '../update.js';
5
+ import { installedKernelVersion } from '../dsh-adapter/contract.js';
4
6
  import { readThemePref } from '../themePrefs.js';
5
7
  import { readPresetPref } from '../presetPrefs.js';
6
8
  import { readModelPref } from '../modelPrefs.js';
7
9
  import { readActivityFrames } from '../activityPrefs.js';
8
10
  import { envThemeOverride } from '../components/design-system/ThemeProvider.js';
11
+ import { resolveBrand, setActiveBrand } from '../branding.js';
9
12
  import { hasPath } from '../dsh-adapter/settingsEditor.js';
10
13
  import { planReload } from '../reload.js';
11
14
  import { AlternateScreen, Box, Image, Text, useInput, ScrollBox, useTheme, useTerminalSize } from '../ui.js';
@@ -14,11 +17,13 @@ import { POINTER } from '../terminal-utils/figures.js';
14
17
  import { isPlainReturnInput } from '../utils/modifiers.js';
15
18
  import { actionMatches, effectiveComboDisplay, primaryComboString } from '../utils/keymap.js';
16
19
  import { formatTokens } from '../terminal-utils/format.js';
20
+ import { formatClock } from '../trajectory/format.js';
17
21
  import { homeDir } from '../utils/paths.js';
18
22
  import { execFileNoThrow } from '../utils/execFileNoThrow.js';
19
23
  import { cleanRenderText, cleanScalarText } from '../dsh-adapter/sanitize.js';
20
24
  import { deriveModelGroups, modelPickerLanding, recentCatalogModels, RECENTS_GROUP_PROVIDER, } from '../modelGroups.js';
21
25
  import { readModelRecents, recordModelUse } from '../modelRecents.js';
26
+ import { WORKING_GATE_NOTICES } from '../commands.js';
22
27
  import { TuiDialogStore } from '../dsh-adapter/dialogs.js';
23
28
  import { TuiStatusStore } from '../dsh-adapter/status.js';
24
29
  import { ActivityStore, useActivity } from '../dsh-adapter/activity-store.js';
@@ -30,11 +35,16 @@ import { renderMathRaster } from '../math/renderer.js';
30
35
  const MATH_PREVIEW_SCALE = 2;
31
36
  const MATH_PREVIEW_MAX_COLUMNS = 480;
32
37
  const MATH_PREVIEW_MAX_ROWS = 64;
33
- import { runProviderWizard } from '../dsh-adapter/providerWizard.js';
34
- import { ApprovalStore } from '../dsh-adapter/approvals.js';
38
+ import { runOAuthLogin, runProviderWizard } from '../dsh-adapter/providerWizard.js';
39
+ import { useKernelPicker } from './chat/useKernelPicker.js';
40
+ import { useBackendChannels } from './chat/useBackendChannels.js';
41
+ import { backendModeStatus as modeStatus, backendPermissionCommand, parseMcpCommand } from './chat/backendCommands.js';
42
+ import { PermissionStore } from '../channel/permissions.js';
43
+ import { goalStatusLines, parseGoalCommand } from '../channel/goal-command.js';
35
44
  import { AskUserQuestionPanel } from '../components/questions/AskUserQuestionPanel.js';
36
45
  import { ApprovalPanel } from '../components/approvals/ApprovalPanel.js';
37
46
  import { ExtensionDialog } from '../components/ExtensionDialog.js';
47
+ import { consumeBoundaryRecoveryRemount } from '../ink/update-overflow-guard.js';
38
48
  import { useSearchHighlight } from '../ink/hooks/use-search-highlight.js';
39
49
  import { useTerminalTitle } from '../ink/hooks/use-terminal-title.js';
40
50
  import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
@@ -44,24 +54,35 @@ import { NoSelect } from '../ink/components/NoSelect.js';
44
54
  import { LogoHeader, MessageList } from '../components/MessageList.js';
45
55
  import { splashFontIdOf } from '../components/splashFonts.js';
46
56
  import { StarPrompt, WhaleCouponPrompt } from '../components/StarPrompt.js';
47
- import { dueStarModal, markStarAsked, STAR_MILESTONES } from '../usageStats.js';
57
+ import { dueStarModal, markStarAsked, pendingStarMilestone, readUsage, STAR_MILESTONES } from '../usageStats.js';
48
58
  import { TimelineRail } from '../components/TimelineRail.js';
49
59
  import { ScrollbarGutter } from '../components/ScrollbarGutter.js';
50
60
  import { normalizeScrollGutter } from '../tuiDisplayPrefs.js';
51
61
  import { OverlayAbove } from '../components/OverlayAbove.js';
52
62
  import { TooltipLayer } from '../components/Tooltip.js';
53
63
  import { PromptInput } from '../components/PromptInput.js';
64
+ import { turnUsageParts } from '../components/TurnUsageRow.js';
65
+ import { AgentTranscriptScene } from './AgentTranscriptScene.js';
66
+ import { agentViewStore } from '../components/sidePanel/agentViewStore.js';
67
+ import { agentComposeTargetOf } from '../components/messages/agentTeam.js';
54
68
  import { PromptEditorLayer, usePromptEditorOpen } from '../components/PromptEditor.js';
55
69
  import { GoalTodoPanel } from '../components/GoalTodoPanel.js';
70
+ import { useSidePanel } from '../components/sidePanel/useSidePanel.js';
71
+ import { jobsFocusStore } from '../components/sidePanel/jobsFocusStore.js';
72
+ import { SidePanelLayout } from '../components/sidePanel/SidePanelLayout.js';
73
+ import { SidePanelColumn } from '../components/sidePanel/SidePanelColumn.js';
74
+ import { PanelPicker, usePanelPickerRows } from '../components/sidePanel/PanelPicker.js';
56
75
  import { AutoRecapRow } from '../components/AutoRecapRow.js';
57
76
  import { CompactionStatusRow } from '../components/CompactionStatusRow.js';
58
77
  import { BalanceReportRow } from '../components/BalanceReportRow.js';
59
78
  import { estimateSessionCostSnapshotCny } from '../deepseekPricing.js';
60
79
  import { LoadedContextPanel } from '../components/LoadedContextPanel.js';
61
- import { StatusLine } from './StatusLine.js';
80
+ import { formatCostReport, StatusLine } from './StatusLine.js';
81
+ import { channelContextOccupancy } from './StatusMetrics.js';
62
82
  import { WorkingSpinner, useThinkingStatus } from '../components/WorkingSpinner.js';
63
83
  import { ActivityLine, contextPressurePct } from '../components/ActivityLine.js';
64
84
  import { ModelPicker } from '../components/ModelPicker.js';
85
+ import { HelpMenu } from '../components/HelpMenu.js';
65
86
  import { PluginSceneBoundary } from '../components/PluginSceneBoundary.js';
66
87
  import { PluginStatusViewBoundary } from '../components/PluginStatusViewBoundary.js';
67
88
  import { ImagePreviewOverlay } from '../components/ImagePreviewOverlay.js';
@@ -81,6 +102,11 @@ import { ColorPicker } from '../components/ColorPicker.js';
81
102
  import { EffortSlider } from '../components/EffortSlider.js';
82
103
  import { PresetPicker } from '../components/PresetPicker.js';
83
104
  import { PermissionsPicker } from '../components/PermissionsPicker.js';
105
+ import { ModePicker } from '../components/ModePicker.js';
106
+ import { KernelPicker } from '../components/KernelPicker.js';
107
+ import { SdkInstallWizard } from '../components/SdkInstallWizard.js';
108
+ import { ChannelPicker } from '../components/ChannelPicker.js';
109
+ import { modeDisplayName } from '../sessionModes.js';
84
110
  import { PlanPicker } from '../components/PlanPicker.js';
85
111
  import { LangPicker } from '../components/LangPicker.js';
86
112
  import { ThemePicker, getThemeOptions } from '../components/ThemePicker.js';
@@ -89,7 +115,10 @@ import { FRAME_PRESETS, PRESET_NAMES } from '../components/activityFrames.js';
89
115
  import { ThinkingToggle } from '../components/ThinkingToggle.js';
90
116
  import { HistorySearchDialog } from '../components/HistorySearchDialog.js';
91
117
  import { RewindPicker } from '../components/RewindPicker.js';
92
- import { BtwPanel } from '../components/BtwPanel.js';
118
+ import { BtwPanelFallback } from '../components/BtwPanel.js';
119
+ import { btwThreads } from '../components/sidePanel/btw/threads.js';
120
+ import { getBtwContextBudget, getBtwContextTurns } from '../tuiDisplayPrefs.js';
121
+ import { BtwThreadScene } from '../components/sidePanel/btw/BtwThreadScene.js';
93
122
  import { RecapPanel } from '../components/RecapPanel.js';
94
123
  import { isValidSessionColor, SESSION_COLOR_NAMES } from '../terminal-utils/sessionColors.js';
95
124
  import { TipsPanel } from '../components/TipsPanel.js';
@@ -108,6 +137,12 @@ import { useAnimationFrame } from '../ink/hooks/use-animation-frame.js';
108
137
  import { useExternalVersion } from '../hooks/useExternalVersion.js';
109
138
  import { TrajectoryScene } from './TrajectoryScene.js';
110
139
  import { markHomeSeen } from '../homePrefs.js';
140
+ import { markOnboardingDone } from '../onboardingPrefs.js';
141
+ import { Launchpad, launchpadVisible } from './Launchpad.js';
142
+ import { resolveLaunchpadActions } from '../components/launchpadActions.js';
143
+ import { Onboarding } from './Onboarding.js';
144
+ import { appendHistory } from '../history.js';
145
+ import { isHiddenCommandName, isLocalCommandName, parseCommandName } from '../commands.js';
111
146
  import { extendTrajectory, projectWave } from '../dsh-adapter/trajectory/index.js';
112
147
  import { miniWakeWidth } from '../components/trajectory/MiniWake.js';
113
148
  import { readTrajectorySeen, writeTrajectorySeen } from '../trajectoryPrefs.js';
@@ -140,6 +175,27 @@ const COMMAND_RESULT_CELLS = 200;
140
175
  * file, but a healthy import of thousands of conversations finishes well
141
176
  * inside this; without a cap a wedged child would hang the loop forever. */
142
177
  const MIGRATE_CHILD_TIMEOUT_MS = 30 * 60 * 1000;
178
+ /**
179
+ * 落地页参数行四段能点开的既有选择器(第五版):模型 → /model、思考深度 →
180
+ * /effort、模式 → /plan、权限预设 → /permission。盖在落地页之上时键盘归
181
+ * 选择器(见 useInput 的 launchpad 分支注释);其余 overlay 类型不在此列,
182
+ * 落地页期间照旧整块让位。
183
+ */
184
+ const LAUNCHPAD_OVERLAY_KINDS = new Set([
185
+ 'model', 'effort', 'plan', 'preset', 'permission', 'mode',
186
+ // 第七版:左下角工作目录铭牌点开的工作区菜单(及其二级选择器/流程层)
187
+ // 也是「盖在落地页之上」的姿态——同一套 pickerPanels 挂载,Esc 回落地页。
188
+ 'workspace-menu', 'workspace-picker', 'workspace-flow',
189
+ // 第八版:帮助入口也走「盖在落地页之上」的浮层姿态(overlay kind 'help',
190
+ // HelpMenu 经 pickerPanels 挂进 OverlayAbove)——不再收掉落地页进对话页。
191
+ 'help',
192
+ // 内核选择器(/kernel 与启动页「内核」入口):同一姿态盖在落地页之上,
193
+ // 点选即切换内核并重启(组合根的 onSwitchBackend)。
194
+ 'kernel',
195
+ // SDK 安装向导(内核选择器「未安装」行 Enter 进入):同一姿态,Esc 层级
196
+ // 一样——向导收回,露出落地页。
197
+ 'sdk-install',
198
+ ]);
143
199
  function cleanCommandError(error) {
144
200
  try {
145
201
  if (error instanceof Error) {
@@ -178,6 +234,27 @@ const NO_ROWS = [];
178
234
  function capitalize(text) {
179
235
  return text.length === 0 ? text : text[0].toUpperCase() + text.slice(1);
180
236
  }
237
+ /**
238
+ * The occupancy line `/tokens` and `/status` print.
239
+ *
240
+ * Occupancy has ONE source (see `dsh-adapter/context-occupancy.ts`): this is
241
+ * the same reading the footer's ctx field, the segmented bar and the
242
+ * context-low warning use — never the session's cumulative uncached input,
243
+ * which is a different quantity by orders of magnitude.
244
+ * @param channel - Live channel surface.
245
+ * @returns The localized line, or `undefined` when no window is known.
246
+ */
247
+ function contextOccupancyLine(channel) {
248
+ const occupancy = channelContextOccupancy(channel);
249
+ if (occupancy === undefined || occupancy.contextWindow === undefined || occupancy.contextWindow <= 0)
250
+ return undefined;
251
+ const percent = Math.max(0, Math.min(100, Math.round((occupancy.usedTokens / occupancy.contextWindow) * 100)));
252
+ return t('context-occupancy', {
253
+ percent,
254
+ used: formatTokens(occupancy.usedTokens),
255
+ window: formatTokens(occupancy.contextWindow),
256
+ });
257
+ }
181
258
  /** Terminal-title spinner frames. */
182
259
  const TITLE_SPINNER_FRAMES = ['⠂', '⠐'];
183
260
  /** Searchable transcript text for one row (`/` incsearch):
@@ -230,7 +307,7 @@ const noCouponSnapshot = () => null;
230
307
  function peekKey(image, title) {
231
308
  return `${title ?? ''} ${image.id}`;
232
309
  }
233
- export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, starPrompt, }) {
310
+ export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, onSwitchBackend, onRestartFreshSession, onProbeKernels, onResolveSdkInstallTarget, onStartSdkInstall, onCheckPnpm, sdkInstallPinned, kernelPinned, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, launchpadOnBoot, onboardingOnBoot, starPrompt, }) {
234
311
  const writeRaw = React.useContext(TerminalWriteContext);
235
312
  // Re-render whenever the channel mutates; rows/status are read fresh below.
236
313
  // DEFAULT lane on purpose (useExternalVersion): the channel version bumps
@@ -251,7 +328,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
251
328
  // parks here until the panel decides; shown with priority over a pending
252
329
  // questionnaire since it gates a tool about to run. Hosts that pass no
253
330
  // approvalStore share one inert instance that never holds an ask.
254
- const approvals = approvalStore ?? (fallbackApprovalStore ??= new ApprovalStore());
331
+ const approvals = approvalStore ?? (fallbackApprovalStore ??= new PermissionStore());
255
332
  const approvalSnapshot = React.useSyncExternalStore(listener => approvals.subscribe(listener), () => approvals.getSnapshot());
256
333
  // The pending managed plugin dialog (tuiDialogs seam): a plugin's
257
334
  // select/confirm/input request parks here until the panel settles it.
@@ -350,7 +427,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
350
427
  /** Provider display identities for the /model group level; refreshed alongside `models`. */
351
428
  const [providerInfos, setProviderInfos] = React.useState([]);
352
429
  /** /model 最近使用分组:成功切换即记录(去重置顶,上限 10),重启保留。 */
353
- const [modelRecents, setModelRecents] = React.useState(() => readModelRecents());
430
+ // Recents are per backend: a Claude session's picks never evict the DSH list.
431
+ const recentsBackend = channel.backendCapabilities?.backendId;
432
+ const [modelRecents, setModelRecents] = React.useState(() => readModelRecents(undefined, recentsBackend));
354
433
  /** Two-level /model: the drilled-in provider route; undefined = group level.
355
434
  * Reset on open; stale ids resolve back to the group level via `activeModelGroup`. */
356
435
  const [modelGroup, setModelGroup] = React.useState(undefined);
@@ -384,7 +463,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
384
463
  return ok;
385
464
  if (name !== undefined)
386
465
  channel.notify(t('model-switched', { name }));
387
- setModelRecents(recordModelUse({ provider, id }));
466
+ setModelRecents(recordModelUse({ provider, id }, undefined, recentsBackend));
388
467
  return ok;
389
468
  });
390
469
  };
@@ -408,7 +487,202 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
408
487
  * on" has not been answered yet. Every later launch starts on the chat
409
488
  * screen, and the screen stays reachable.
410
489
  */
411
- const [supervisorOpen, setSupervisorOpen] = React.useState(openHomeOnBoot === true);
490
+ // 根错误边界恢复后的重挂不是一次启动:启动页、首启引导与会话管理屏都
491
+ // 不再打开,直接回到对话页(一次性标记由错误边界的恢复路径写入,见
492
+ // update-overflow-guard)。首次渲染即消费;若这次渲染被丢弃,最坏只是
493
+ // 多显示一次启动入口。
494
+ const recoveryRemountOnBoot = consumeBoundaryRecoveryRemount();
495
+ // 第七版:启动页在开时**不再**预开会话浏览器。旧姿态是「先收落地页再开
496
+ // 整屏」,浏览器必须提前藏在下面;现在整屏(会话/设置/任务面板)盖在
497
+ // 落地页**之上**、Esc 退回落地页,按需打开即可——boot 时同时为真反而会
498
+ // 让浏览器盖住落地页(渲染顺序见各 early-return)。恢复重挂同样不开它。
499
+ const [supervisorOpen, setSupervisorOpen] = React.useState(openHomeOnBoot === true && launchpadOnBoot !== true && !recoveryRemountOnBoot);
500
+ /**
501
+ * The launchpad: the landing page every ordinary launch starts on.
502
+ *
503
+ * Seeded from `launchpadOnBoot`, and the screen that closes it is the one
504
+ * that decides what comes next — a submitted line hands over to the chat
505
+ * screen, an action hands over to whatever surface that action opens.
506
+ */
507
+ const [launchpadOpen, setLaunchpadOpen] = React.useState(launchpadOnBoot === true && !recoveryRemountOnBoot);
508
+ /**
509
+ * The launchpad's draft. It lives HERE, not inside the screen, because the
510
+ * screen unmounts the moment the user submits: a draft owned by an
511
+ * unmounting component would be lost in exactly the transition it exists
512
+ * to carry.
513
+ */
514
+ const [launchpadDraft, setLaunchpadDraft] = React.useState('');
515
+ const [launchpadCaret, setLaunchpadCaret] = React.useState(0);
516
+ const [launchpadFocus, setLaunchpadFocus] = React.useState(-1);
517
+ /**
518
+ * 「整屏盖启动页」的显式授权(第七版防御位,用户实测回归:启动页一闪而过
519
+ * 被顶掉)。整屏分支排在落地页**之前**,任何一处状态在开机后被异步置真
520
+ * (杂散输入/宿主事件/未来新代码)都会把落地页挤掉。授权位只有**从落地页
521
+ * 出发的交互**(入口行/空输入 Esc/目录铭牌/命令面板里的整屏命令、Continue
522
+ * 的兜底浏览器)才置真;覆盖屏全部收起时自动落 false。开机后即便某个整屏
523
+ * 状态被误置真,落地页仍在最上层——「浮层可以盖、整屏必须经授权」。
524
+ */
525
+ const launchpadCoverRef = React.useRef(false);
526
+ /**
527
+ * 这一帧到底出不出落地页:状态开着还不够,minimal 模式(`dsh-tui.minimal`)
528
+ * 下它整块不存在——`minimalMode.ts` 的标志由 channel 在设置落地后写入,
529
+ * 建 state 时读不到,所以判定必须放在**渲染期**读(与其它 minimal 门同一口径)。
530
+ * 键盘守卫、渲染分支与"有没有整屏界面"的判定都认这一个值,三者不会分叉。
531
+ */
532
+ /**
533
+ * 右下角铭牌的版本号:`installedTuiVersion()` 每次都要读一遍 package.json,
534
+ * 而它在一个进程里不会变——mount 时读一次就够。
535
+ */
536
+ const tuiVersion = React.useMemo(() => installedTuiVersion(), []);
537
+ /**
538
+ * 内核(dsh)版本(第七版:落地页右下角双版本铭牌)。真实来源见
539
+ * `contract.installedKernelVersion`(宿主 CLI 的 manifest,回落内核线包);
540
+ * 两级都读不到 = undefined → 铭牌只画 TUI 段,绝不编造。
541
+ */
542
+ const kernelVersion = React.useMemo(() => installedKernelVersion(), []);
543
+ const launchpadShown = launchpadOpen && launchpadVisible();
544
+ /**
545
+ * 落地页之上是否盖着一个参数选择器(第五版:参数行四段各自可点,点开的
546
+ * 是聊天页同一套 /model · /effort · /plan · /permission overlay)。这时
547
+ * 键盘归选择器(Esc 关它回到落地页),渲染也要把 pickerPanels 带进
548
+ * 落地页分支——不然整屏 early-return 把 overlay 吞了,"点了没反应"。
549
+ */
550
+ const launchpadOverlayUp = launchpadShown && LAUNCHPAD_OVERLAY_KINDS.has(overlay.kind);
551
+ /**
552
+ * 渲染在**覆盖层**(而不是整屏 early-return)的那几个命令。
553
+ *
554
+ * 落地页的快捷入口与向导招式卡的「试一下」都走 `runCommand`,而 supervisor /
555
+ * settings / help 的 early-return 排在两个界面**之后**:不收掉当前界面就是
556
+ * "点了没反应",状态还滞留着、等界面关掉才突然弹出来。默认收,白名单只留给覆盖层。
557
+ */
558
+ const overlayCommandNames = React.useMemo(() => new Set(['model', 'effort', 'plan', 'preset', 'permission', 'kernel']), []);
559
+ /**
560
+ * 打开**整屏界面**的命令(第七版):从落地页触发这些命令时**不收掉落地页**
561
+ * ——整屏盖在落地页之上渲染(它们的 early-return 排在落地页分支之前),
562
+ * Esc 退出整屏回到落地页(草稿/参数/焦点原样保留)。这是「从启动页进入
563
+ * 对话页的唯一路径 = Enter 提交一条非命令消息」的落地:任何返回键都不再
564
+ * 把人甩到对话页。其余命令(star / update / help / 转录输出类)的反馈在
565
+ * 对话页,仍按旧约收掉落地页再执行。
566
+ */
567
+ const launchpadScreenCommands = React.useMemo(() => new Set(['home', 'resume', 'agentview', 'settings', 'jobs', 'tree', 'agents', 'setup', 'bg', 'background']), []);
568
+ /**
569
+ * 落地页条件位②(有新版本):`checkForTuiUpdate()`(与 /update 同一条
570
+ * 判定,src/update.ts)在启动页第一次挂起时后台探一次——registry 延迟
571
+ * 不许拖慢第一帧;失败/离线静默为 false(绝不放假按钮)。
572
+ */
573
+ const [launchpadUpdateAvailable, setLaunchpadUpdateAvailable] = React.useState(false);
574
+ const launchpadUpdateProbedRef = React.useRef(false);
575
+ React.useEffect(() => {
576
+ if (!launchpadShown || launchpadUpdateProbedRef.current)
577
+ return;
578
+ launchpadUpdateProbedRef.current = true;
579
+ void checkForTuiUpdate().then(update => {
580
+ setLaunchpadUpdateAvailable(update !== undefined);
581
+ }).catch(() => undefined);
582
+ }, [launchpadShown]);
583
+ const canInstallSdk = onResolveSdkInstallTarget !== undefined && onStartSdkInstall !== undefined
584
+ && onCheckPnpm !== undefined && sdkInstallPinned !== undefined;
585
+ const { currentId: kernelCurrentId, options: kernelOptions, open: openKernelPicker, pick: pickKernel, reprobe: reprobeKernels } = useKernelPicker({
586
+ channel, kernelVersion, launchpadShown, onProbeKernels, onSwitchBackend, canInstallSdk, dispatchOverlay,
587
+ });
588
+ /**
589
+ * SDK 安装向导的步骤态(异步进程状态,按 chatOverlay 的分工留在 Chat,
590
+ * 不进 overlay union)。生命周期约定:向导打开时从 idle 初始化,安装
591
+ * (checking/running)期间面板保持打开——所有异步落地都发生在面板还在
592
+ * 的窗口内;关闭路径(Esc/Enter 离开)一律重置回 idle,下一次打开重新
593
+ * 解析安装目标。
594
+ */
595
+ const [sdkPhase, setSdkPhase] = React.useState({ kind: 'idle' });
596
+ const sdkInstallerRef = React.useRef(undefined);
597
+ // 打开即解析安装目标(同步、只读 argv + 文件系统):profile → 确认面板;
598
+ // standalone / 无 profile → 直接给手动指引面板。
599
+ React.useEffect(() => {
600
+ if (overlay.kind !== 'sdk-install' || sdkPhase.kind !== 'idle' || onResolveSdkInstallTarget === undefined)
601
+ return;
602
+ const target = onResolveSdkInstallTarget();
603
+ if (target.kind === 'profile' && sdkInstallPinned !== undefined) {
604
+ setSdkPhase({ kind: 'confirm', dir: target.dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
605
+ }
606
+ else {
607
+ setSdkPhase({ kind: 'no-target', reason: target.kind === 'standalone' ? 'standalone' : 'no-profile' });
608
+ }
609
+ }, [overlay.kind, sdkPhase.kind, onResolveSdkInstallTarget, sdkInstallPinned]);
610
+ const closeSdkInstallToKernelPicker = () => {
611
+ setSdkPhase({ kind: 'idle' });
612
+ dispatchOverlay({ type: 'close' });
613
+ openKernelPicker();
614
+ };
615
+ const closeSdkInstall = () => {
616
+ setSdkPhase({ kind: 'idle' });
617
+ dispatchOverlay({ type: 'close' });
618
+ };
619
+ const runSdkInstall = (dir) => {
620
+ if (onStartSdkInstall === undefined || sdkInstallPinned === undefined)
621
+ return;
622
+ const installer = onStartSdkInstall(dir);
623
+ sdkInstallerRef.current = installer;
624
+ setSdkPhase({ kind: 'running' });
625
+ void installer.result.then(result => {
626
+ if (result.kind === 'ok') {
627
+ // 装好了:重探内核(灰行变亮,无需重启进程),停在完成面板。
628
+ reprobeKernels();
629
+ setSdkPhase({ kind: 'done' });
630
+ }
631
+ else if (result.kind === 'failed') {
632
+ setSdkPhase({ kind: 'failed', exitCode: result.exitCode, tail: result.tail, dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
633
+ }
634
+ else if (result.kind === 'pnpm-missing') {
635
+ setSdkPhase({ kind: 'pnpm-missing', dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
636
+ }
637
+ else {
638
+ setSdkPhase({ kind: 'cancelled' });
639
+ }
640
+ });
641
+ };
642
+ const confirmSdkInstall = (dir) => {
643
+ if (onCheckPnpm === undefined)
644
+ return;
645
+ setSdkPhase({ kind: 'checking' });
646
+ void onCheckPnpm().then(ok => {
647
+ if (!ok && sdkInstallPinned !== undefined) {
648
+ setSdkPhase({ kind: 'pnpm-missing', dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
649
+ return;
650
+ }
651
+ runSdkInstall(dir);
652
+ });
653
+ };
654
+ const host = channel.backendChannels?.();
655
+ const { rows: channelRows, open: openChannelPicker, pick: pickChannel, setMode: runBackendModeCommand, login: runBackendLogin } = useBackendChannels({
656
+ channel, host, questionStore, dispatchOverlay, onRestartFreshSession, runOAuthLogin,
657
+ });
658
+ /**
659
+ * 落地页条件位③(投喂一颗 Star):与开屏求 star 弹窗**同一口径**——
660
+ * `usageStats`(~/.dsh-tui/usage.json)里有未报过的已达档里程碑
661
+ * (`pendingStarMilestone`,首档 24h)且本进程尚未 star 成功。star 成功
662
+ * 后(`starred` 翻真)按钮立即消失;记账过的档不再纠缠。
663
+ */
664
+ /**
665
+ * The first-run guide. Renders above the launchpad (see the prop docs): a
666
+ * launch that needs setup has not answered the launchpad's question yet.
667
+ */
668
+ const [onboardingOpen, setOnboardingOpen] = React.useState(onboardingOnBoot === true && !recoveryRemountOnBoot);
669
+ /**
670
+ * 落地页那条"第一次用?跑一遍引导"的横幅认的是**还欠一次引导**,而不是启动快照:
671
+ * 完成(写进 onboarding.json)之后立刻收掉;跳过刻意保留——没记账,下次启动还会问,
672
+ * 横幅说的正是这件事。
673
+ */
674
+ const [onboardingPending, setOnboardingPending] = React.useState(onboardingOnBoot === true && !recoveryRemountOnBoot);
675
+ /**
676
+ * 品牌档(`branding.ts`):设置项 `dsh-tui.brand`(`auto` = 跟后端)与当前
677
+ * 后端 id(`backendCapabilities.backendId`,boot 时即定)的合成。开屏词、
678
+ * 立绘、大字配色读 prop;主题默认档经 `setActiveBrand` 镜像给
679
+ * ThemeProvider(它挂在 Chat 外层,拿不到 channel)——plugin 已在首帧前
680
+ * 铺过初值,这里负责 `/settings` 切品牌时的实时跟动。
681
+ */
682
+ const brand = resolveBrand(channel.brand, channel.backendCapabilities?.backendId);
683
+ React.useEffect(() => {
684
+ setActiveBrand(brand);
685
+ }, [brand]);
412
686
  /** `/tree` opens the session family tree (pi's Session Tree): every rewind
413
687
  * fork stitched back onto the message it diverged from, hover previews,
414
688
  * and per-node rewind/fork/adopt actions. Like the supervisor, a screen. */
@@ -425,11 +699,19 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
425
699
  const EMPTY_AGENT_VIEW_ROWS = [];
426
700
  const agentViewRows = React.useSyncExternalStore(listener => channel.subscribeAgentView?.(listener) ?? (() => { }), () => channel.agentViewRows?.() ?? EMPTY_AGENT_VIEW_ROWS);
427
701
  const backgroundAgentsNeedingInput = agentViewRows.filter(row => row.status === 'needs-input' && !row.current).length;
428
- /** Background the attached session and open the supervisor
429
- * (`/bg`, `/background`, and ← on an empty prompt all land here). The
430
- * backgrounded session becomes the screen's return target (final Esc
431
- * attaches back to it). */
702
+ /** Open the supervisor from `/bg`, `/background`, or an empty-prompt ←.
703
+ * DSH backgrounds the attached session first and uses it as the Esc
704
+ * return target; other backends keep the current session attached. */
432
705
  const backgroundToAgentView = React.useCallback(() => {
706
+ // The non-DSH backends have a session catalog, but no live background
707
+ // handoff. Open the shared session manager without pretending to park the
708
+ // current turn. DSH keeps its existing handoff and Esc return target.
709
+ const backendId = channel.backendCapabilities?.backendId;
710
+ if (backendId !== undefined && backendId !== 'dsh') {
711
+ agentViewOpenSessionRef.current = channel.agentId;
712
+ setSupervisorOpen(true);
713
+ return;
714
+ }
433
715
  void channel.backgroundCurrent().then((result) => {
434
716
  if (result.ok) {
435
717
  setAgentViewReturnId(result.backgroundedSessionId);
@@ -448,6 +730,16 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
448
730
  * `null` 显式关闭,传 actions 覆写两个按钮(不跑真 gh、不开真浏览器)。 */
449
731
  /** 本次会话是否已经 star 成功(开屏彩蛋标题切「捡到小星星啦」)。 */
450
732
  const [starred, setStarred] = React.useState(false);
733
+ /**
734
+ * 落地页条件位③(投喂一颗 Star):与开屏求 star 弹窗**同一口径**——
735
+ * `usageStats`(~/.dsh-tui/usage.json)里有未报过的已达档里程碑
736
+ * (`pendingStarMilestone`,首档 24h)且本进程尚未 star 成功。star 成功
737
+ * 后(`starred` 翻真)按钮立即消失;记账过的档不再纠缠。readUsage 是
738
+ * 文件读,只在 starred 翻真或测试缝变化时重算,不逐帧读盘。
739
+ */
740
+ const launchpadStarDue = React.useMemo(() => !starred && pendingStarMilestone(readUsage(starPrompt?.dir)) !== null,
741
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- dir 经测试缝注入
742
+ [starred, starPrompt]);
451
743
  const [starModal, setStarModal] = React.useState(null);
452
744
  // 单发闩:只在第一个"安静的开屏视口"上武装定时器。700ms 窗口内整屏
453
745
  // 界面打开 → cleanup 掐掉定时器且**不再重臂**(记账只发生在回调里,
@@ -462,7 +754,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
462
754
  return;
463
755
  if (starPrompt === null)
464
756
  return;
465
- if (supervisorOpen || treeOpen || settingsOpen || channel.working)
757
+ if (supervisorOpen || treeOpen || settingsOpen || launchpadShown || onboardingOpen || channel.working)
466
758
  return;
467
759
  starModalArmedRef.current = true;
468
760
  // 让开屏先画半秒:弹窗压在介绍动画之上,而不是同抢第一帧。
@@ -484,7 +776,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
484
776
  }, 700);
485
777
  return () => { clearTimeout(timer); };
486
778
  // eslint-disable-next-line react-hooks/exhaustive-deps -- 只在整屏界面开合时重判;闩保证只武装一次
487
- }, [supervisorOpen, treeOpen, settingsOpen]);
779
+ }, [supervisorOpen, treeOpen, settingsOpen, launchpadShown, onboardingOpen]);
488
780
  /** `/star` 命令、开屏标语的点击/`Alt+S` 共用的一键动作:异步跑 gh,界面
489
781
  * 全程不阻塞,结果回来按四类各报一句(成功 / 没装 gh / 没登录 / 失败)。
490
782
  * `starPrompt.onStar` 存在时走同一条测试缝(夹具因此不会真的去 star)。 */
@@ -593,10 +885,35 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
593
885
  const workspaceFlowAbortRef = React.useRef(null);
594
886
  /** `/preset` agent-preset roster (issue #8): loads async, persists. */
595
887
  const [presetOptions, setPresetOptions] = React.useState([]);
888
+ /**
889
+ * 落地页参数行的模式段(第六版设计 1)显示 preset 的**显示名**
890
+ * (Standard/PTC/极简…),名册是异步的——落地页出来时顺手预热一次
891
+ * (空名册不写;失败静默,段缺省不画)。/preset 自己的加载路径不动。
892
+ */
893
+ React.useEffect(() => {
894
+ if (!launchpadShown || presetOptions.length > 0)
895
+ return;
896
+ let cancelled = false;
897
+ channel.listPresets()
898
+ .then(list => { if (!cancelled && list.length > 0)
899
+ setPresetOptions(list); })
900
+ .catch(() => { });
901
+ return () => { cancelled = true; };
902
+ }, [launchpadShown, presetOptions.length, channel]);
596
903
  /** `/effort` adapter levels: load async before the slider opens. */
597
904
  const [effortOptions, setEffortOptions] = React.useState([]);
905
+ /** True when those levels are the CLI-standard compatibility ladder (the
906
+ * model row declares no tiers of its own) — the slider says so. */
907
+ const [effortLevelsFallback, setEffortLevelsFallback] = React.useState(false);
598
908
  const [themeName, setTheme] = useTheme();
599
909
  const { rows: terminalRows } = useTerminalSize();
910
+ /**
911
+ * 帮助盖屏(第八版,overlay kind 'help')的滚动视口:HelpMenu 自带
912
+ * ScrollBox,键盘(↑/↓/PgUp/PgDn/Home/End)由 Chat 的 overlay 分支驱动。
913
+ * 视口预算与 PromptInput 的 helpViewportHeight 同式(PR #446 的口径)。
914
+ */
915
+ const helpCoverScrollRef = React.useRef(null);
916
+ const helpCoverViewportHeight = Math.max(3, Math.min(terminalRows - 7, 15));
600
917
  const [showAllMessages, setShowAllMessages] = React.useState(false);
601
918
  /** Scope the fold to this question: an aborted ask can promote its queued
602
919
  * successor without ever publishing an idle (null) snapshot. */
@@ -612,15 +929,31 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
612
929
  * plugin answering after the user moved on must not open a confirm for
613
930
  * a row they are no longer looking at). */
614
931
  const rewindRequestRef = React.useRef(0);
615
- /** /btw side-question overlay: pure UI state — the answer never
616
- * enters the transcript or the session log. */
617
- const [btw, setBtw] = React.useState(null);
618
- const btwAbortRef = React.useRef(null);
619
- const closeBtw = () => {
620
- btwAbortRef.current?.abort();
621
- btwAbortRef.current = null;
622
- setBtw(null);
932
+ /** /btw side-question thread: pure UI state in btwThreads — the answers
933
+ * never enter the transcript or the session log. The floating overlay is
934
+ * only the FALLBACK surface (btw panel not enabled); with the panel
935
+ * enabled the same thread routes to the sidebar instead — one answer,
936
+ * exactly one surface. */
937
+ const [btwOverlayOpen, setBtwOverlayOpen] = React.useState(false);
938
+ /** ⤢ fullscreen thread scene (openPanelFullscreen 'btw' route). */
939
+ const [btwSceneOpen, setBtwSceneOpen] = React.useState(false);
940
+ // Only the fallback overlay reads the thread here. With the overlay closed
941
+ // the snapshot stays undefined, so an answer streaming into the sidebar
942
+ // panel does not re-render the whole Chat on every delta.
943
+ const btwOverlayThread = React.useSyncExternalStore(btwThreads.subscribe, () => (btwOverlayOpen ? btwThreads.get(String(channel.agentId)) : undefined));
944
+ const closeBtwOverlay = () => {
945
+ // Fallback parity with the pre-thread overlay: closing cancels the
946
+ // in-flight ask (completed turns stay in the thread).
947
+ btwThreads.abortActive(String(channel.agentId));
948
+ setBtwOverlayOpen(false);
623
949
  };
950
+ /** 有模态或整屏界面时,/btw 的回答不抢着打开面板,只标未读。 */
951
+ const btwSurfaceFree = () => approvalSnapshot === null && dialogSnapshot === null && questionSnapshot === null
952
+ && overlay.kind === 'none' && !helpOpen && !starModal && !couponVisible
953
+ && !supervisorOpen && !treeOpen && !settingsOpen && !jobsPanelOpen
954
+ && !sceneOpen && channel.pluginScene === undefined
955
+ && !subagentDashboardOpen && subagentDetailId === null
956
+ && !onboardingOpen && !launchpadShown && !btwSceneOpen && !promptEditorOpen;
624
957
  /** /recap overlay (pi-recap semantics): pure UI state like /btw — the
625
958
  * summary never enters the transcript or session log; applying the
626
959
  * proposed title goes through the normal /rename path. `auto` marks the
@@ -657,14 +990,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
657
990
  balanceSeqRef.current += 1;
658
991
  setBalance(null);
659
992
  }, [balanceSessionId]);
660
- // A side question belongs to its captured session just like a recap. Chat
661
- // remains mounted across /resume, so explicitly retire its request/UI when
662
- // the binding changes instead of allowing a former conversation to finish.
663
- React.useEffect(() => {
664
- btwAbortRef.current?.abort();
665
- btwAbortRef.current = null;
666
- setBtw(null);
667
- }, [channel.agentId]);
993
+ // A side question belongs to its captured session just like a recap. The
994
+ // THREAD stays in memory under its own session id (an archived thread may
995
+ // keep streaming); only the FALLBACK overlay is retired on a binding change
996
+ // (see the btwSessionIdRef effect above) so an old conversation never leaks
997
+ // onto the new one's screen.
668
998
  // Auto-recap (`dsh-tui.recapOnOpen`): every time the session switches
669
999
  // (mount = open/resume, rewind/fork included), summarize its tail into
670
1000
  // the dim AutoRecapRow. Failures stay silent in auto mode — `/recap`
@@ -755,7 +1085,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
755
1085
  setSearchCursor(0);
756
1086
  setSearchCount(0);
757
1087
  setSearchCurrent(0);
758
- closeBtw();
1088
+ setBtwOverlayOpen(false);
759
1089
  repaintTranscript();
760
1090
  }, [channel.agentId]); // eslint-disable-line react-hooks/exhaustive-deps
761
1091
  /** The session attached when the agent view opened; a close on a
@@ -772,17 +1102,102 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
772
1102
  /** Subagent dashboard (Ctrl+A): displays active/completed subagents. */
773
1103
  const [subagentDashboardOpen, setSubagentDashboardOpen] = React.useState(false);
774
1104
  const [jobsPanelOpen, setJobsPanelOpen] = React.useState(false);
1105
+ /** Job id the panel should focus on open: set by a transcript card click
1106
+ * (open the panel AT that job), cleared on close so the keyboard/command
1107
+ * path reopens at the top. */
1108
+ const [jobsPanelFocusId, setJobsPanelFocusId] = React.useState(null);
1109
+ // Side-panel routing needs the controller, which is created further down;
1110
+ // a ref keeps this identity-stable callback fresh anyway.
1111
+ const sidePanelRef = React.useRef(null);
775
1112
  // MessageList forwards these open handlers to every memoized row. Their
776
1113
  // identities must survive token/metrics updates, including for tool rows.
777
- const openJobsPanel = React.useCallback(() => setJobsPanelOpen(true), []);
1114
+ const openJobsPanel = React.useCallback((focusId) => {
1115
+ const sidePanel = sidePanelRef.current;
1116
+ // Split mode: open the jobs side panel at the requested job (the focus
1117
+ // lane carries the id; a fresh nonce refocuses even for the same id).
1118
+ if (sidePanel !== null && sidePanel.split && sidePanel.enabledPanelIds.includes('jobs')) {
1119
+ if (typeof focusId === 'string' && focusId !== '')
1120
+ jobsFocusStore.request(focusId);
1121
+ sidePanel.openPanel('jobs', { focus: true });
1122
+ return;
1123
+ }
1124
+ // Narrow / inline fallback: the full-screen overlay (unchanged).
1125
+ if (typeof focusId === 'string' && focusId !== '')
1126
+ setJobsPanelFocusId(focusId);
1127
+ setJobsPanelOpen(true);
1128
+ }, []);
1129
+ // A job card / the panel keeps its output tail fresh while on screen, when
1130
+ // the backend reads output on demand. The control is re-projected on every
1131
+ // read; this handler keeps one identity per channel capability so the
1132
+ // memoized rows are not re-rendered by it.
1133
+ const jobControlRef = React.useRef(channel.jobControl);
1134
+ jobControlRef.current = channel.jobControl;
1135
+ const jobOutputWatchable = typeof channel.jobControl?.watchOutput === 'function';
1136
+ const watchJobOutput = React.useMemo(() => jobOutputWatchable ? (id) => jobControlRef.current?.watchOutput?.(id) ?? (() => undefined) : undefined, [jobOutputWatchable]);
1137
+ /** Ctrl+A / detail 回退:侧栏分栏且 agents 已启用时打开右栏 Panel(内部
1138
+ * dashboard ↔ detail 二级路由自己管);窄屏 / inline 保留整屏形态。 */
1139
+ const openSubagentDashboard = React.useCallback(() => {
1140
+ const sidePanel = sidePanelRef.current;
1141
+ if (sidePanel !== null && sidePanel.split && sidePanel.enabledPanelIds.includes('agents')) {
1142
+ sidePanel.openPanel('agents', { focus: true });
1143
+ return;
1144
+ }
1145
+ setSubagentDashboardOpen(true);
1146
+ }, []);
778
1147
  /** Detail view for a specific subagent (opened from dashboard). */
779
1148
  const [subagentDetailId, setSubagentDetailId] = React.useState(null);
1149
+ /**
1150
+ * 主屏只读 Agent View:Chat 自己的场景层。父 Chat、Channel 与 PromptInput
1151
+ * 保持挂载(草稿经 draftCache 往返),场景只借用屏幕与键盘;Esc 回到打开它
1152
+ * 的地方(对话 / 代理面板 / 详情 / 转录卡)。不建第二个 Channel。
1153
+ */
1154
+ const [agentView, setAgentView] = React.useState(null);
1155
+ const openAgentView = React.useCallback((agentId, source) => {
1156
+ setAgentView({ agentId, source });
1157
+ }, []);
1158
+ /** 工作台里切到同级或父代理:原地换被查看的代理,Esc 仍回最初的入口。 */
1159
+ const switchViewedAgent = React.useCallback((agentId) => {
1160
+ setAgentView(prev => prev === null ? prev : { ...prev, agentId });
1161
+ }, []);
1162
+ /** 转录卡入口的稳定句柄:MessageList 的 memo 行按 props 身份比较,内联
1163
+ * 箭头会让每个流式 tick 重渲染全部落定行(verify-tool-history-window)。 */
1164
+ const openSubagentViewFromCard = React.useCallback((agentId, rowId) => {
1165
+ openAgentView(agentId, { kind: 'transcript-card', rowId });
1166
+ }, [openAgentView]);
1167
+ // 侧栏 agents 面板 / 其 Detail 的主屏查看请求(面板没有 Chat 的场景 state)。
1168
+ React.useEffect(() => agentViewStore.subscribe(() => {
1169
+ const request = agentViewStore.get();
1170
+ if (request === null)
1171
+ return;
1172
+ const source = request.source === 'agents-dashboard'
1173
+ ? { kind: 'agents-dashboard', ...(request.panel ? { panel: true } : {}) }
1174
+ : { kind: 'agent-detail', agentId: request.agentId, ...(request.panel ? { panel: true } : {}) };
1175
+ setAgentView({ agentId: request.agentId, source });
1176
+ }), []);
1177
+ /** Esc 的返回路由:面板来源回面板(路由经模块记忆保真),整屏来源回整屏。 */
1178
+ const exitAgentView = React.useCallback((source) => {
1179
+ setAgentView(null);
1180
+ const sidePanel = sidePanelRef.current;
1181
+ const panelReturn = (sidePanel !== null && sidePanel.split && sidePanel.enabledPanelIds.includes('agents'));
1182
+ if (source.kind === 'agents-dashboard') {
1183
+ if (source.panel === true && panelReturn)
1184
+ sidePanel.openPanel('agents', { focus: true });
1185
+ else
1186
+ setSubagentDashboardOpen(true);
1187
+ return;
1188
+ }
1189
+ if (source.kind === 'agent-detail') {
1190
+ if (source.panel === true && panelReturn)
1191
+ sidePanel.openPanel('agents', { focus: true });
1192
+ else
1193
+ setSubagentDetailId(source.agentId);
1194
+ }
1195
+ }, []);
780
1196
  /**
781
1197
  * Hidden `/deepseek` easter egg: each invocation bumps this key so the
782
1198
  * logo header remounts and replays the whale spout + text shimmer.
783
1199
  */
784
1200
  const [logoNonce, setLogoNonce] = React.useState(0);
785
- React.useEffect(() => () => btwAbortRef.current?.abort(), []);
786
1201
  React.useEffect(() => () => recapAbortRef.current?.abort(), []);
787
1202
  /**
788
1203
  * The trajectory scene (issue #80 evolution). Unlike every other overlay
@@ -802,16 +1217,64 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
802
1217
  const closeScene = React.useCallback(() => {
803
1218
  setSceneOpen(false);
804
1219
  }, []);
805
- /** Open the scene, mark failures seen, and retire the key hint for good. */
806
- const openScene = React.useCallback(() => {
1220
+ /**
1221
+ * 整屏分支的「盖启动页」闸门(第七版防御位,用户实测回归:启动页一闪
1222
+ * 而过被顶掉)。落地页在屏上时,只有**经 `launchpadCoverRef` 授权**
1223
+ * (= 从落地页出发的交互打开)的整屏才盖它;否则该整屏状态被无视
1224
+ * (渲染落到落地页),启动页永远不被开机期的杂散状态挤掉。落地页不在
1225
+ * 屏上时闸门恒开(普通姿态与从前逐字节一致)。
1226
+ *
1227
+ * ⚠ 这一段必须排在组件**所有** early-return 之前(hooks 规则):曾放在
1228
+ * onboarding/interrupt 分支之后,向导一开就少跑这个 effect,React 直接
1229
+ * 报 hooks 乱序(verify-launchpad-onboarding-chat A2/E5/H2 全红)。
1230
+ */
1231
+ const launchpadGate = () => !launchpadShown || launchpadCoverRef.current;
1232
+ // 覆盖屏全部收起时收回授权:下一次打开必须再经过落地页自己的交互。
1233
+ const launchpadCoverScreenUp = supervisorOpen || treeOpen || settingsOpen
1234
+ || jobsPanelOpen || subagentDashboardOpen || subagentDetailId !== null || sceneOpen
1235
+ || agentView !== null
1236
+ || btwSceneOpen;
1237
+ React.useEffect(() => {
1238
+ if (!launchpadCoverScreenUp)
1239
+ launchpadCoverRef.current = false;
1240
+ }, [launchpadCoverScreenUp]);
1241
+ /**
1242
+ * 从落地页出发的交互要开整屏前先授权(配合 `launchpadGate`):调用点只在
1243
+ * 落地页自己的回调里(onAction / onCommandPick / onEscape 的会话浏览路)。
1244
+ * 异步误置真的整屏状态没有这道授权 → 闸门挡下,落地页留在最上层。
1245
+ */
1246
+ const authorizeLaunchpadCover = () => { launchpadCoverRef.current = true; };
1247
+ /**
1248
+ * Open the trajectory, mark failures seen, and retire the key hint for good.
1249
+ *
1250
+ * Ctrl+T and `/trace` share this one entry point, and it is SPLIT-AWARE the
1251
+ * same way `/jobs` and `/agents` already are: while the sidebar is
1252
+ * rendering, the trajectory opens as the `trajectory` panel inside it
1253
+ * instead of taking the whole screen. `options.fullscreen` is the escape
1254
+ * hatch the panel's own ⤢ button uses — without it that button would route
1255
+ * straight back into the panel it is trying to leave.
1256
+ */
1257
+ const openScene = React.useCallback((options) => {
1258
+ // /trace, Ctrl+T, the sidebar tab and ⤢ all open the trajectory. A
1259
+ // kernel without a trajectory source reports 'unsupported' and the
1260
+ // scene/panel say so; no entry point refuses on its own, so they can
1261
+ // never disagree about the capability.
807
1262
  seenFailuresRef.current = trajectoryRef.current?.counts.errors ?? 0;
808
1263
  setTrajectorySeen(previous => {
809
1264
  if (!previous)
810
1265
  writeTrajectorySeen();
811
1266
  return true;
812
1267
  });
1268
+ const controller = sidePanelRef.current;
1269
+ if (options?.fullscreen !== true
1270
+ && controller !== null
1271
+ && controller.split
1272
+ && controller.enabledPanelIds.includes('trajectory')) {
1273
+ controller.openPanel('trajectory', { focus: true });
1274
+ return;
1275
+ }
813
1276
  setSceneOpen(true);
814
- }, []);
1277
+ }, [channel]);
815
1278
  /**
816
1279
  * Leave the session supervisor for the conversation.
817
1280
  *
@@ -840,6 +1303,32 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
840
1303
  }).catch(() => undefined);
841
1304
  }
842
1305
  }, [agentViewReturnId, channel, repaintTranscript]);
1306
+ /**
1307
+ * Leave the first-run guide.
1308
+ *
1309
+ * `done` writes the one-shot marker; `skipped` deliberately does NOT — the
1310
+ * user has not answered, and a later launch is exactly when they might.
1311
+ * Both cases land on the launchpad rather than the transcript: the wizard
1312
+ * interrupted a launch, so the launch resumes where it left off.
1313
+ *
1314
+ * The write is best-effort by design (`markOnboardingDone` returns false
1315
+ * when the data directory is unwritable); a read-only install gets one more
1316
+ * offer next launch, which is the recoverable end of the trade.
1317
+ */
1318
+ const closeOnboarding = React.useCallback((outcome) => {
1319
+ setOnboardingOpen(false);
1320
+ if (outcome === 'done') {
1321
+ const written = markOnboardingDone();
1322
+ setOnboardingPending(false);
1323
+ channel.notify(t(written ? 'onboarding-finished' : 'onboarding-write-failed'), {
1324
+ color: written ? 'success' : 'warning',
1325
+ timeoutMs: written ? 3000 : 6000,
1326
+ });
1327
+ }
1328
+ else {
1329
+ channel.notify(t('onboarding-skipped'), { timeoutMs: 4000 });
1330
+ }
1331
+ }, [channel]);
843
1332
  /** The startup summary gives way to transcript rows after the first local command or message. */
844
1333
  const loadedContextVisible = channel.rows.length === 0 && channel.loadedContext !== undefined;
845
1334
  /** Startup context panel: collapsed by default, toggled with Ctrl+P. */
@@ -1634,6 +2123,69 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1634
2123
  : t('migrate-failed', { n: failures }), failures === 0 ? { timeoutMs: 6000 } : { color: 'error', timeoutMs: 10000 });
1635
2124
  })();
1636
2125
  };
2126
+ /**
2127
+ * Close the launchpad and hand the draft to the chat screen.
2128
+ *
2129
+ * THREE cases, and they are genuinely different:
2130
+ *
2131
+ * - a slash command → `runCommand`, the same dispatch a typed command
2132
+ * takes in the composer. The line is NOT submitted to the model.
2133
+ * Recognition is the composer's OWN rule (第六版 BUG 1 修复): the merged
2134
+ * command list (locals + plugin/registry commands via channel.commandList)
2135
+ * decides whether the line is a command — isLocalCommandName alone missed
2136
+ * registry-only names (e.g. /plan, /goal), which then fell through to
2137
+ * channel.submit and went to the model as a user message.
2138
+ * - ordinary text → SENT DIRECTLY (fifth revision, user-reported bug:
2139
+ * "按了回车就直接进入流式输出"). The line rides the composer's own
2140
+ * submit path (`channel.submit`, which queues through the DSH inbox
2141
+ * while a turn is running) — no draft is parked anywhere, the composer
2142
+ * mounts EMPTY because the content is already gone as the first turn.
2143
+ * - empty → nothing to send; just show the conversation.
2144
+ *
2145
+ * History is appended for the two non-empty cases (matching what PromptInput
2146
+ * does on submit) so the launchpad's first line is reachable with ↑ later.
2147
+ */
2148
+ const closeLaunchpad = React.useCallback((submit) => {
2149
+ const text = submit.trim();
2150
+ setLaunchpadOpen(false);
2151
+ // 首启时 openHomeOnBoot 与落地页同时为真:会话浏览器已经开着、只是被落地页盖住。
2152
+ // 提交首句后必须把它收掉,否则用户落到浏览器而不是"草稿就在眼前的对话",
2153
+ // 与本函数 doc 承诺的落点直接矛盾。
2154
+ setSupervisorOpen(false);
2155
+ setLaunchpadFocus(-1);
2156
+ setLaunchpadDraft('');
2157
+ setLaunchpadCaret(0);
2158
+ if (text === '')
2159
+ return;
2160
+ void appendHistory(text);
2161
+ const parsed = text.startsWith('/') ? parseCommandName(text) : undefined;
2162
+ // 第八版:/help 在落地页上也是盖屏浮层(补全面板被 Esc 收掉后直接
2163
+ // Enter 的那条路)——不收落地页、不进对话页。聊天页里 /help 的行为
2164
+ // 不变(那边不走这个回调)。
2165
+ if (parsed !== undefined && parsed.name === 'help' && launchpadOpen) {
2166
+ dispatchOverlay({ type: 'open', overlay: { kind: 'help' } });
2167
+ return;
2168
+ }
2169
+ // 与 composer 的 tryRunCommand 同一条判定:合并命令表(LOCAL_COMMANDS +
2170
+ // channel.commandList 的插件/registry 命令)里有名字才是命令;hidden
2171
+ // 命令照旧认。判定之外的 / 开头行才走 submit(与聊天页 Enter 行为一致)。
2172
+ if (parsed !== undefined && (isLocalCommandName(parsed.name)
2173
+ || isHiddenCommandName(parsed.name)
2174
+ || channel.commandList.some(entry => entry.name === parsed.name))) {
2175
+ void runCommand(parsed.name, parsed.rawInput);
2176
+ return;
2177
+ }
2178
+ // 直接发送:与 composer 回车同一条提交路径。发出去之后输入框是空的
2179
+ // (内容已作为首轮发出,绝不"既发了又留在框里"),也没有交接提示——
2180
+ // 没有草稿要交,一句"已放进输入框"的 toast 反而是假的。
2181
+ channel.submit(text);
2182
+ }, [channel, launchpadOpen]);
2183
+ /**
2184
+ * The screen's command dispatcher. Every entry point reaches this one
2185
+ * closure — PromptInput's `onRunCommand`, the completion menu, this screen's
2186
+ * own `/` cases, and the launchpad handoff above. There is deliberately no
2187
+ * second dispatcher for the landing page.
2188
+ */
1637
2189
  const runCommand = (name, rawInput = '', images = []) => {
1638
2190
  switch (name) {
1639
2191
  case 'activity': {
@@ -1746,11 +2298,12 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1746
2298
  return true;
1747
2299
  }
1748
2300
  setHelpOpen(false);
1749
- void channel.listEfforts().then(({ efforts, defaultEffort }) => {
2301
+ void channel.listEfforts().then(({ efforts, defaultEffort, levelsFallback }) => {
1750
2302
  // 0/1-tier routes were already notified by listEfforts.
1751
2303
  if (efforts.length <= 1)
1752
2304
  return;
1753
2305
  setEffortOptions(efforts);
2306
+ setEffortLevelsFallback(levelsFallback === true);
1754
2307
  const current = channel.reasoningEffort ?? defaultEffort;
1755
2308
  const index = efforts.findIndex(effort => effort.id === current);
1756
2309
  // open-if: a picker the user opened during the round trip wins
@@ -1916,9 +2469,24 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1916
2469
  setSelectedId(null);
1917
2470
  setSelectionActive(false);
1918
2471
  return true;
1919
- case 'compact':
1920
- channel.compact();
2472
+ case 'compact': {
2473
+ // The TUI's own transaction is the primary path: it owns the
2474
+ // `tui/compact` decision event, the progress row with live token
2475
+ // count, Esc cancellation, and the settle before a session switch
2476
+ // (issue #1092) — the official `dsh-command-compact` command has none
2477
+ // of that. A composition that mounts no compaction service falls back
2478
+ // to the registry command; one with neither says WHY up front instead
2479
+ // of looking usable and failing on use (channel/capabilities.ts).
2480
+ const compact = channel.capabilities().compact;
2481
+ if (compact.route === 'local') {
2482
+ channel.compact();
2483
+ return true;
2484
+ }
2485
+ if (compact.route === 'registry')
2486
+ return runExternalCommand('compact', rawInput, images);
2487
+ channel.notify(t('capability-unavailable', { name: 'compact', reason: t(compact.reasonKey) }), { color: 'warning', timeoutMs: 8000 });
1921
2488
  return true;
2489
+ }
1922
2490
  case 'trace':
1923
2491
  // `/trace` is kept as the discoverable spelling of Ctrl+T: the
1924
2492
  // command menu is where a user finds out the trajectory exists.
@@ -1946,7 +2514,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1946
2514
  setHelpOpen(false);
1947
2515
  const spec = parts[0];
1948
2516
  const slash = spec.indexOf('/');
1949
- const provider = slash >= 0 ? spec.slice(0, slash) : undefined;
2517
+ // Backend model routes accept an unqualified model id.
2518
+ const singleProvider = channel.backendCapabilities?.modelRoutes === 'backend';
2519
+ const provider = slash >= 0 ? spec.slice(0, slash) : singleProvider ? channel.provider : undefined;
1950
2520
  const id = slash >= 0 ? spec.slice(slash + 1) : spec;
1951
2521
  if (provider === undefined || id.length === 0 || provider.length === 0) {
1952
2522
  channel.notify(t('model-usage'), { color: 'warning' });
@@ -1973,7 +2543,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1973
2543
  let recentsNow = modelRecents;
1974
2544
  if (channel.provider !== '' && channel.model !== ''
1975
2545
  && !recentsNow.some(ref => ref.provider === channel.provider && ref.id === channel.model)) {
1976
- recentsNow = recordModelUse({ provider: channel.provider, id: channel.model });
2546
+ recentsNow = recordModelUse({ provider: channel.provider, id: channel.model }, undefined, recentsBackend);
1977
2547
  setModelRecents(recentsNow);
1978
2548
  }
1979
2549
  // Two-level landing: recents (when catalogued) focus their pinned
@@ -2078,14 +2648,39 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2078
2648
  });
2079
2649
  return true;
2080
2650
  case 'tokens': {
2081
- const usage = t('tokens-usage', { in: formatTokens(channel.tokens.input), out: formatTokens(channel.tokens.output) });
2082
- if (channel.contextWindow === undefined) {
2083
- channel.notify(usage);
2084
- }
2085
- else {
2086
- const percent = Math.max(0, Math.min(100, Math.round((channel.tokens.input / channel.contextWindow) * 100)));
2087
- channel.notify(t('tokens-usage-context', { usage, percent }));
2651
+ // Four separately-labelled facts, never two measures side by side:
2652
+ // what THIS request uploaded (the provider's mutually-exclusive prompt
2653
+ // buckets, with when it was sampled), what the last turn used (its
2654
+ // own ledger, never added into the session counters), what the
2655
+ // session has accumulated, and how full the window is (the channel's
2656
+ // single occupancy reading — the same number the footer and the
2657
+ // context-low warning show).
2658
+ const usage = channel.lastUsage;
2659
+ const lines = [];
2660
+ if (usage !== undefined) {
2661
+ const upload = usage.input + usage.cacheRead + usage.cacheWrite;
2662
+ const rate = upload > 0 ? ((usage.cacheRead / upload) * 100).toFixed(1) : '0.0';
2663
+ lines.push(`${t('tokens-request-upload', {
2664
+ upload: formatTokens(upload),
2665
+ input: formatTokens(usage.input),
2666
+ read: formatTokens(usage.cacheRead),
2667
+ write: formatTokens(usage.cacheWrite),
2668
+ rate,
2669
+ })} · ${t('usage-sampled-at', { time: formatClock(usage.at) })}`);
2088
2670
  }
2671
+ const turn = channel.turnUsage;
2672
+ if (turn !== undefined)
2673
+ lines.push(`${t('usage-turn-summary')} ${turnUsageParts(turn).join(' · ')}`);
2674
+ lines.push(t('tokens-session-breakdown', {
2675
+ input: formatTokens(channel.tokens.input),
2676
+ output: formatTokens(channel.tokens.output),
2677
+ read: formatTokens(channel.tokens.cacheRead),
2678
+ write: formatTokens(channel.tokens.cacheWrite),
2679
+ }));
2680
+ const occupancyLine = contextOccupancyLine(channel);
2681
+ if (occupancyLine !== undefined)
2682
+ lines.push(occupancyLine);
2683
+ channel.notify(lines.join('\n'));
2089
2684
  return true;
2090
2685
  }
2091
2686
  case 'resume':
@@ -2098,7 +2693,26 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2098
2693
  * commands is about muscle memory, not about three surfaces — every one
2099
2694
  * of them lands here, on the same runtime.
2100
2695
  */
2101
- case 'home':
2696
+ case 'home': {
2697
+ setHelpOpen(false);
2698
+ // Split-aware, like /trace and /jobs: while the sidebar is rendering
2699
+ // and the workspace panel is enabled, the workspace view opens THERE.
2700
+ // The panel's own ⤢ goes back to the full-screen home. The panel reads
2701
+ // the DSH workspace ledger, though: a backend without that capability
2702
+ // (capability snapshots absent on test stubs = DSH) would have its
2703
+ // /resume swallowed by an unsupported panel and no history anywhere —
2704
+ // those keep the full-screen session supervisor.
2705
+ const capabilities = channel.backendCapabilities;
2706
+ const controller = sidePanelRef.current;
2707
+ if ((capabilities === undefined || capabilities.commands.includes('workspace'))
2708
+ && controller !== null && controller.split && controller.enabledPanelIds.includes('workspace')) {
2709
+ controller.openPanel('workspace', { focus: true });
2710
+ return true;
2711
+ }
2712
+ agentViewOpenSessionRef.current = channel.agentId;
2713
+ setSupervisorOpen(true);
2714
+ return true;
2715
+ }
2102
2716
  case 'agentview': {
2103
2717
  setHelpOpen(false);
2104
2718
  // The screen opens immediately and loads its own list. Waiting for the
@@ -2110,9 +2724,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2110
2724
  }
2111
2725
  case 'bg':
2112
2726
  case 'background': {
2113
- // `/background`: the attached session moves to the background
2114
- // (it keeps running in this process), the terminal lands on a fresh
2115
- // session, and the supervisor opens on top.
2727
+ // DSH parks the attached session before opening the supervisor;
2728
+ // other backends open it over their still-attached session.
2116
2729
  setHelpOpen(false);
2117
2730
  backgroundToAgentView();
2118
2731
  return true;
@@ -2199,23 +2812,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2199
2812
  return true;
2200
2813
  case 'status': {
2201
2814
  const usage = channel.lastUsage;
2202
- const pct = channel.contextWindow === undefined
2203
- ? undefined
2204
- : Math.max(0, Math.min(100, Math.round((channel.tokens.input / channel.contextWindow) * 100)));
2205
2815
  const lines = [
2206
2816
  `${t('status-model', { model: channel.model })}${channel.reasoningEffort ? ` · ${capitalize(channel.reasoningEffort)} effort` : ''}`,
2207
2817
  `${t('status-state', { state: channel.working ? t('status-working') : t('status-idle') })}`,
2208
2818
  `${t('status-session', { id: channel.agentId })}`,
2209
2819
  `${t('status-dir', { cwd: channel.displayCwd })}${channel.gitBranch ? ` · ${channel.gitBranch}` : ''}`,
2210
- `Tokens ${formatTokens(channel.tokens.input)} in → ${formatTokens(channel.tokens.output)} out`,
2820
+ t('tokens-session-total', {
2821
+ input: formatTokens(channel.tokens.input),
2822
+ output: formatTokens(channel.tokens.output),
2823
+ }),
2211
2824
  ];
2212
2825
  if (usage !== undefined) {
2213
2826
  const total = usage.input + usage.cacheRead + usage.cacheWrite;
2214
2827
  const rate = total > 0 ? ((usage.cacheRead / total) * 100).toFixed(1) : '0.0';
2215
- lines.push(t('cost-cache-rate', { rate, read: formatTokens(usage.cacheRead), write: formatTokens(usage.cacheWrite) }));
2828
+ lines.push(`${t('cost-cache-rate', { rate, read: formatTokens(usage.cacheRead), write: formatTokens(usage.cacheWrite) })} · ${t('usage-sampled-at', { time: formatClock(usage.at) })}`);
2216
2829
  }
2217
- if (pct !== undefined)
2218
- lines.push(t('cost-context', { pct }));
2830
+ // The last turn gets its own labelled line so it never reads as part
2831
+ // of the session totals.
2832
+ const turn = channel.turnUsage;
2833
+ if (turn !== undefined)
2834
+ lines.push(`${t('usage-turn-summary')} ${turnUsageParts(turn).join(' · ')}`);
2835
+ const occupancyLine = contextOccupancyLine(channel);
2836
+ if (occupancyLine !== undefined)
2837
+ lines.push(occupancyLine);
2219
2838
  if (channel.sessionTitle)
2220
2839
  lines.push(t('status-title', { title: channel.sessionTitle }));
2221
2840
  setHelpOpen(false);
@@ -2225,13 +2844,26 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2225
2844
  case 'cost': {
2226
2845
  const usage = channel.lastUsage;
2227
2846
  const lines = [
2228
- `Tokens ${formatTokens(channel.tokens.input)} in → ${formatTokens(channel.tokens.output)} out`,
2847
+ t('tokens-session-total', {
2848
+ input: formatTokens(channel.tokens.input),
2849
+ output: formatTokens(channel.tokens.output),
2850
+ }),
2229
2851
  ];
2230
2852
  if (usage !== undefined) {
2231
2853
  const total = usage.input + usage.cacheRead + usage.cacheWrite;
2232
2854
  const rate = total > 0 ? ((usage.cacheRead / total) * 100).toFixed(1) : '0.0';
2233
2855
  lines.push(t('cost-cache-hit-rate', { rate, read: formatTokens(usage.cacheRead), write: formatTokens(usage.cacheWrite) }));
2234
2856
  }
2857
+ // A backend that reports its own session cost (Claude) states the
2858
+ // bill itself; the DeepSeek estimate below would only be noise.
2859
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- partial embedder channels omit the report
2860
+ const report = channel.costReport;
2861
+ if (report !== undefined) {
2862
+ lines.push(`${formatCostReport(report)} · ${t(report.source === 'backend' ? 'cost-source-backend' : 'status-cost-note')}`);
2863
+ setHelpOpen(false);
2864
+ channel.pushLocal('/cost', lines);
2865
+ return true;
2866
+ }
2235
2867
  // 金额与拆解:主会话按模型分桶 + 子代理按各自 (provider, model) 分桶;
2236
2868
  // 全部未计价时只报 token 并标注未计价,不显示 ¥0.00 金额行(DESIGN D4/D6)。
2237
2869
  const estimate = estimateSessionCostSnapshotCny({
@@ -2274,6 +2906,54 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2274
2906
  setSettingsOpen(true);
2275
2907
  return true;
2276
2908
  }
2909
+ case 'continue': {
2910
+ // 落地页第四版的 Continue(最高频动作):继续**最近一条可继续会话**。
2911
+ // 数据是真的——`agentViewRows`(含持久化名册,listing 落地后含全部历史)
2912
+ // 里挑 updatedAt 最新的非当前行;没有可继续的就去会话名册挑,失败也不
2913
+ // 静默(notify + 打开 supervisor 让用户自己挑),绝不点了个没反应。
2914
+ setHelpOpen(false);
2915
+ const candidates = agentViewRows.filter(row => !row.current && row.id !== channel.agentId && row.title.trim() !== '');
2916
+ const latest = candidates.reduce((acc, row) => (acc === undefined || row.updatedAt > acc.updatedAt ? row : acc), undefined);
2917
+ if (latest === undefined) {
2918
+ channel.notify(t('launchpad-continue-none'), { color: 'error', timeoutMs: 6000 });
2919
+ agentViewOpenSessionRef.current = channel.agentId;
2920
+ // 第七版:无可继续会话时浏览器盖在落地页之上(不收落地页)——Esc
2921
+ // 回启动页,与合并入口「会话与工作区」同一条姿态。
2922
+ setSupervisorOpen(true);
2923
+ return true;
2924
+ }
2925
+ setLaunchpadOpen(false);
2926
+ void channel.resumeTo(latest.id)
2927
+ .then((result) => {
2928
+ if (!result.ok) {
2929
+ channel.notify(t('launchpad-continue-failed'), { color: 'error', timeoutMs: 8000 });
2930
+ agentViewOpenSessionRef.current = channel.agentId;
2931
+ setSupervisorOpen(true);
2932
+ return;
2933
+ }
2934
+ channel.notify(t('resume-resumed'));
2935
+ suppressLogoIntroRef.current = true;
2936
+ setAgentViewReturnId(undefined);
2937
+ repaintTranscript();
2938
+ })
2939
+ .catch(() => {
2940
+ channel.notify(t('launchpad-continue-failed'), { color: 'error', timeoutMs: 8000 });
2941
+ });
2942
+ return true;
2943
+ }
2944
+ case 'setup': {
2945
+ // `/setup` re-runs the first-run guide. Unlike the boot path this is
2946
+ // an EXPLICIT request, so it opens unconditionally — a user who typed
2947
+ // it has already decided the wizard is what they want. It reuses the
2948
+ // same screen and the same `onClose`, so completing it here also
2949
+ // (re)writes the one-shot marker.
2950
+ // 第七版:向导的 early-return 在落地页**之前**,天然盖在落地页之上;
2951
+ // 不再收掉落地页——Esc/跳过/完成都回到启动页(旧姿态收掉落地页后,
2952
+ // 向导关掉就落到对话页,正是用户报的 bug 形态之一)。
2953
+ setHelpOpen(false);
2954
+ setOnboardingOpen(true);
2955
+ return true;
2956
+ }
2277
2957
  case 'star': {
2278
2958
  // 一键 star:**只有用户主动敲 /star 才会跑**(绝不自动)。动作用
2279
2959
  // runStarAction(与开屏弹窗共用),异步执行、结果用 notify 报。
@@ -2367,6 +3047,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2367
3047
  return true;
2368
3048
  }
2369
3049
  case 'init': {
3050
+ const backend = channel.backendInit?.();
3051
+ if (backend !== undefined) {
3052
+ void backend.run();
3053
+ return true;
3054
+ }
2370
3055
  const result = channel.initWorkspace();
2371
3056
  if (result === null)
2372
3057
  channel.notify(t('agentsmd-create-failed'), { color: 'error' });
@@ -2376,10 +3061,52 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2376
3061
  channel.notify(t('agentsmd-created', { result }));
2377
3062
  return true;
2378
3063
  }
2379
- case 'jobs':
3064
+ case 'jobs': {
2380
3065
  setHelpOpen(false);
2381
- setJobsPanelOpen(true);
3066
+ // Split mode routes to the side panel; narrow terminals keep the
3067
+ // full-screen overlay.
3068
+ if (sidePanel.split && sidePanel.enabledPanelIds.includes('jobs')) {
3069
+ sidePanel.openPanel('jobs', { focus: true });
3070
+ }
3071
+ else {
3072
+ setJobsPanelFocusId(null);
3073
+ setJobsPanelOpen(true);
3074
+ }
2382
3075
  return true;
3076
+ }
3077
+ case 'panel': {
3078
+ setHelpOpen(false);
3079
+ // 无参 → 面板选择器(overlay 互斥结构内);有参 → 侧栏命令分发。
3080
+ if (rawInput.trim() === '' && sidePanel.splitAvailable && panelPickerRows.length > 0) {
3081
+ const current = panelPickerRows.findIndex(row => row.id === sidePanel.activePanelId);
3082
+ dispatchOverlay({ type: 'open', overlay: { kind: 'panel', index: Math.max(0, current) } });
3083
+ return true;
3084
+ }
3085
+ if (sidePanel.command(rawInput))
3086
+ return true;
3087
+ // 分栏不可用(窄屏 / inline / 编辑器展开 / splitEnabled=false)
3088
+ // 或参数未知时的整屏回退与兜底:已知面板走整屏形态,其余消费
3089
+ // 掉并提示——绝不原样返回 false,否则 PromptInput 会把
3090
+ // "/panel …" 当普通消息发给模型。
3091
+ const arg = rawInput.trim().toLowerCase();
3092
+ const target = arg === '' || arg === 'focus' || arg === 'toggle' || arg === 'zoom'
3093
+ ? sidePanel.activePanelId
3094
+ : arg;
3095
+ if (target === 'jobs') {
3096
+ setJobsPanelFocusId(null);
3097
+ setJobsPanelOpen(true);
3098
+ return true;
3099
+ }
3100
+ if (target === 'agents') {
3101
+ setSubagentDashboardOpen(true);
3102
+ return true;
3103
+ }
3104
+ if (arg === 'toggle' || arg === 'focus' || arg === 'zoom' || arg === '' || target !== undefined) {
3105
+ channel.notify(t('panel-unavailable-hint'));
3106
+ return true;
3107
+ }
3108
+ return false;
3109
+ }
2383
3110
  case 'agents':
2384
3111
  setHelpOpen(false);
2385
3112
  void channel.listSubagents().then((lines) => {
@@ -2388,6 +3115,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2388
3115
  return true;
2389
3116
  case 'login': {
2390
3117
  setHelpOpen(false);
3118
+ if (runBackendLogin())
3119
+ return true;
2391
3120
  void channel.describeCredential('DEEPSEEK_API_KEY')
2392
3121
  .catch(() => undefined)
2393
3122
  .then(async (status) => {
@@ -2431,9 +3160,14 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2431
3160
  });
2432
3161
  return true;
2433
3162
  }
2434
- case 'logout':
2435
- channel.notify(t('login-logout-hint'));
3163
+ case 'logout': {
3164
+ const auth = channel.backendAuth();
3165
+ if (auth?.logout === undefined)
3166
+ channel.notify(t('login-logout-hint'));
3167
+ else
3168
+ void auth.logout();
2436
3169
  return true;
3170
+ }
2437
3171
  case 'permission': {
2438
3172
  // The command itself is registered by the permission-presets row
2439
3173
  // (dsh-base): bare `/permission` opens the preset picker and Enter
@@ -2498,15 +3232,32 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2498
3232
  setHelpOpen(false);
2499
3233
  return runPermissionCommand(rawInput, images);
2500
3234
  }
2501
- return false;
3235
+ const native = backendPermissionCommand(channel.backendModes?.()?.snapshot(), rawInput, modeDisplayName(channel.mode));
3236
+ if (native === undefined)
3237
+ return false;
3238
+ if (native.kind === 'unknown') {
3239
+ channel.notify(t('permission-mode-unknown', { id: native.id }), { color: 'error' });
3240
+ return true;
3241
+ }
3242
+ setHelpOpen(false);
3243
+ if (native.kind === 'status')
3244
+ channel.pushLocal('/permission', native.lines);
3245
+ else if (native.kind === 'picker')
3246
+ dispatchOverlay({ type: 'open', overlay: native.overlay });
3247
+ else
3248
+ void runBackendModeCommand(native.mode.id, native.mode.name);
3249
+ return true;
2502
3250
  }
2503
3251
  case 'plan': {
2504
3252
  // Registered by dsh-plan-mode: bare `/plan` opens an on/off picker
2505
3253
  // marked with the current state instead of toggling blindly; Enter
2506
3254
  // dispatches `/plan` or `/plan off`. Arguments pass through verbatim
2507
- // (`/plan off`), and an unmounted row falls back to the default
2508
- // external path.
2509
- const mounted = channel.commandList.some(command => command.external && command.name === 'plan');
3255
+ // (`/plan off`). Availability comes from the shared capability facts
3256
+ // (the same read Shift+Tab uses), not from a second command-list
3257
+ // scan; with no registry command the line falls through to the model,
3258
+ // exactly as before.
3259
+ const plan = channel.capabilities().plan;
3260
+ const mounted = plan.route !== 'none';
2510
3261
  const parts = rawInput.trim().split(/\s+/).filter(Boolean);
2511
3262
  if (mounted && parts.length === 0) {
2512
3263
  setHelpOpen(false);
@@ -2536,17 +3287,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2536
3287
  t('hooks-mount-hint'),
2537
3288
  ]);
2538
3289
  return true;
2539
- case 'mcp':
3290
+ case 'mcp': {
2540
3291
  setHelpOpen(false);
3292
+ const control = channel.backendMcp?.();
3293
+ const request = parseMcpCommand(rawInput);
3294
+ if (control !== undefined && request.kind !== 'status') {
3295
+ if (request.kind === 'usage')
3296
+ channel.notify(t('mcp-control-usage'), { color: 'warning' });
3297
+ else if (request.kind === 'reconnect')
3298
+ void control.reconnect(request.name);
3299
+ else
3300
+ void control.toggle(request.name, request.enabled);
3301
+ return true;
3302
+ }
2541
3303
  channel.pushLocal('/mcp', channel.mcpStatus());
2542
3304
  return true;
3305
+ }
2543
3306
  case 'update':
2544
3307
  setHelpOpen(false);
2545
3308
  if (onUpdate === undefined) {
2546
3309
  channel.notify(t('update-unavailable'), { color: 'warning' });
2547
3310
  }
2548
3311
  else if (channel.working) {
2549
- channel.notify(t('update-working'), { color: 'warning' });
3312
+ channel.notify(t(WORKING_GATE_NOTICES.update), { color: 'warning' });
2550
3313
  }
2551
3314
  else {
2552
3315
  channel.notify(t('update-starting'));
@@ -2630,6 +3393,64 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2630
3393
  channel.pushLocal('/reload', lines);
2631
3394
  return true;
2632
3395
  }
3396
+ case 'goal': {
3397
+ // DSH: the `dsh-command-goal` registry row owns /goal, exactly as the
3398
+ // default branch below would dispatch it.
3399
+ if (channel.commandList.some(command => command.external && command.name === 'goal')) {
3400
+ setHelpOpen(false);
3401
+ return runExternalCommand(name, rawInput, images);
3402
+ }
3403
+ // Another backend: the channel core's host over its typed `goals`
3404
+ // capability. None (DSH without the row, or a backend's own `goal`
3405
+ // command) keeps the previous route: the line goes on as text. A
3406
+ // backend with neither never gets here — PromptInput refuses /goal
3407
+ // as unavailable (isUnavailableLocalCommand).
3408
+ const goals = channel.backendGoals?.();
3409
+ if (goals === undefined)
3410
+ return false;
3411
+ setHelpOpen(false);
3412
+ // The capability calls settle like registry commands: the draft is
3413
+ // consumed only once the backend took the change (a failure is
3414
+ // reported by the host and leaves the line editable). An invalid
3415
+ // line is never sent anywhere: it stays in the composer.
3416
+ const command = parseGoalCommand(rawInput);
3417
+ switch (command.kind) {
3418
+ case 'status':
3419
+ channel.pushLocal('/goal', goalStatusLines(channel.goal));
3420
+ return true;
3421
+ case 'invalid':
3422
+ channel.notify(command.reason, { color: 'error' });
3423
+ return Promise.resolve(false);
3424
+ case 'set':
3425
+ return goals.set(command.objective, command.tokenBudget === undefined ? undefined : { tokenBudget: command.tokenBudget });
3426
+ case 'pause':
3427
+ return goals.pause();
3428
+ case 'resume':
3429
+ return goals.resume();
3430
+ case 'clear':
3431
+ return goals.clear();
3432
+ }
3433
+ }
3434
+ case 'channel': {
3435
+ // 渠道选择器。/channel 只在声明了 channels 能力的内核下进命令表,
3436
+ // 能走到这里就说明可用。与 /kernel 一样,再执行一次就收起。
3437
+ setHelpOpen(false);
3438
+ if (overlay.kind === 'channel')
3439
+ dispatchOverlay({ type: 'close' });
3440
+ else
3441
+ openChannelPicker();
3442
+ return true;
3443
+ }
3444
+ case 'kernel':
3445
+ // 内核选择器,每个内核下都可用(在对话页里切回 DSH 只有这一条路)。
3446
+ // 确认后由组合根的 onSwitchBackend 记住选择并以新内核重启。与 /help、
3447
+ // 参数行一致:选择器已开着就收起,没开才打开。
3448
+ setHelpOpen(false);
3449
+ if (overlay.kind === 'kernel')
3450
+ dispatchOverlay({ type: 'close' });
3451
+ else
3452
+ openKernelPicker();
3453
+ return true;
2633
3454
  case 'restart':
2634
3455
  // pi-style reload tail: /reload cannot re-read boot-time-only state
2635
3456
  // (cordis.yml root config, frozen fullscreen layout, newly built
@@ -2640,7 +3461,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2640
3461
  channel.notify(t('restart-unavailable'), { color: 'warning' });
2641
3462
  }
2642
3463
  else if (channel.working) {
2643
- channel.notify(t('update-working'), { color: 'warning' });
3464
+ channel.notify(t(WORKING_GATE_NOTICES.restart), { color: 'warning' });
2644
3465
  }
2645
3466
  else {
2646
3467
  channel.notify(t('restart-starting'));
@@ -2695,30 +3516,28 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2695
3516
  return true;
2696
3517
  }
2697
3518
  case 'btw': {
2698
- // `/btw`:单轮无工具侧问,overlay 态纯 UI,不打断主回合、不写
2699
- // 会话历史。空参数只提示用法。
3519
+ // `/btw`:单轮无工具侧问,线程只在内存里(btwThreads,按会话
3520
+ // 隔离),不打断主回合、不写会话历史。空参数只提示用法。启用了
3521
+ // btw 面板就进面板线程(有模态界面时不抢开,只标未读);没启用
3522
+ // 就用浮层。同一个问答只出现在一处。
2700
3523
  setHelpOpen(false);
2701
3524
  const question = rawInput.trim();
2702
3525
  if (!question) {
2703
3526
  channel.notify(t('btw-usage'), { timeoutMs: 3000 });
2704
3527
  return true;
2705
3528
  }
2706
- btwAbortRef.current?.abort();
2707
- const controller = new AbortController();
2708
- btwAbortRef.current = controller;
2709
- setBtw({ question, answer: '', done: false });
2710
- void channel.sideQuestion(question, {
2711
- signal: controller.signal,
2712
- onText: delta => setBtw(prev => (prev ? { ...prev, answer: prev.answer + delta } : prev)),
2713
- }).then(result => {
2714
- if (controller.signal.aborted)
2715
- return;
2716
- setBtw(prev => (prev ? { ...prev, answer: result.answer ?? prev.answer, error: result.error, done: true } : prev));
2717
- }).catch(error => {
2718
- if (controller.signal.aborted)
2719
- return;
2720
- setBtw(prev => prev ? { ...prev, error: error instanceof Error ? error.message : String(error), done: true } : prev);
2721
- });
3529
+ const btwResult = btwThreads.submit(String(channel.agentId), question, (q, options) => channel.sideQuestion(q, options), { recentTurnsLimit: getBtwContextTurns(), contextBudget: getBtwContextBudget() });
3530
+ if (!btwResult.ok) {
3531
+ channel.notify(t('btw-thread-busy'), { color: 'warning', timeoutMs: 3000 });
3532
+ return true;
3533
+ }
3534
+ if (sidePanel.enabledPanelIds.includes('btw')) {
3535
+ if (btwSurfaceFree())
3536
+ sidePanel.openPanel('btw');
3537
+ }
3538
+ else {
3539
+ setBtwOverlayOpen(true);
3540
+ }
2722
3541
  return true;
2723
3542
  }
2724
3543
  case 'deepseek': {
@@ -2785,6 +3604,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2785
3604
  : NO_ROWS;
2786
3605
  /** Open the rewind picker (from PromptInput's double-Esc on an empty input). */
2787
3606
  const openRewind = () => {
3607
+ if (channel.backendCapabilities?.rewind === false) {
3608
+ channel.notify(t('capability-unavailable-backend', { name: 'rewind' }), { color: 'warning', timeoutMs: 4000 });
3609
+ return;
3610
+ }
2788
3611
  // The overlay is not 'rewind' yet this render, so rewindRows is empty —
2789
3612
  // scan directly instead of reading the gated list.
2790
3613
  const candidates = channel.rows
@@ -2854,7 +3677,63 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2854
3677
  */
2855
3678
  const { columns: terminalColumns } = useTerminalSize();
2856
3679
  const pageInsetX = usePageInset().x;
2857
- const wakeWidth = miniWakeWidth(terminalColumns);
3680
+ // 侧栏控制器:几何(chatColumns/panelColumns)、焦点与键盘分发都在
3681
+ // 这个 hook 里(设计文档 §16.5——Chat 只多一次调用、一处键盘让位、
3682
+ // 一条 runCommand case)。编辑器展开时几何强制 collapsed。
3683
+ const sidePanel = useSidePanel({
3684
+ columns: terminalColumns,
3685
+ fullscreen,
3686
+ editorOpen: promptEditorOpen,
3687
+ });
3688
+ /**
3689
+ * 「全屏」出口(PanelBar 的 ⤢):把侧栏里那个面板的内容切到它原本的整屏
3690
+ * 形态。只映射**真的有整屏对应物**的面板 id(能力位 capabilities.fullscreen
3691
+ * 决定按钮画不画,这里决定点了去哪);没映射到的 id 静默无操作——按钮与
3692
+ * 落地页、键盘入口共用同一个状态位,所以从整屏返回时侧栏还在原处。
3693
+ */
3694
+ const openPanelFullscreen = React.useCallback((panelId) => {
3695
+ if (panelId === 'jobs') {
3696
+ sidePanelRef.current?.focusChat();
3697
+ setJobsPanelOpen(true);
3698
+ return;
3699
+ }
3700
+ if (panelId === 'agents') {
3701
+ sidePanelRef.current?.focusChat();
3702
+ setSubagentDashboardOpen(true);
3703
+ return;
3704
+ }
3705
+ if (panelId === 'trajectory') {
3706
+ sidePanelRef.current?.focusChat();
3707
+ // 强制整屏:默认的 openScene 在分屏下会路由回面板(见它的注释)。
3708
+ openScene({ fullscreen: true });
3709
+ return;
3710
+ }
3711
+ if (panelId === 'workspace') {
3712
+ sidePanelRef.current?.focusChat();
3713
+ setSupervisorOpen(true);
3714
+ return;
3715
+ }
3716
+ if (panelId === 'btw') {
3717
+ // ⤢ 进整屏线程场景:Esc 返回侧栏,不清 thread/draft(面板
3718
+ // mountPolicy=enabled 保挂载,路由/焦点/滚动原样恢复)。
3719
+ sidePanelRef.current?.focusChat();
3720
+ setBtwSceneOpen(true);
3721
+ }
3722
+ }, [openScene]);
3723
+ // openJobsPanel(在上方、identity 稳定)经 ref 读取最新控制器。
3724
+ sidePanelRef.current = sidePanel;
3725
+ /**
3726
+ * 宠物「代言」判定:分屏开着且 companion 是活动面板时,新通知由宠物头顶
3727
+ * 气泡说出,输入框上方的 toast 不再重复同一条。error 色恒不压制(可能
3728
+ * 要行动)。渲染期读控制器状态——与气泡同一提交,无先闪后消的竞态。
3729
+ */
3730
+ const petSaysNotices = React.useCallback((item) => item.color !== 'error' && sidePanel.split && sidePanel.activePanelId === 'companion', [sidePanel.split, sidePanel.activePanelId]);
3731
+ // 聊天列宽:收起时 = 内容区全宽(与现状逐字节一致),分栏时 = 左栏宽。
3732
+ // 所有显式下传的宽度(gutter / 图片预览区 / wake 条)都改用它;转录
3733
+ // 子树则经 SidePanelLayout 的 TerminalSizeContext 覆盖自动拿到。
3734
+ const chatColumns = sidePanel.chatColumns;
3735
+ const wakeWidth = miniWakeWidth(chatColumns);
3736
+ const panelPickerRows = usePanelPickerRows(sidePanel);
2858
3737
  const wakeBand = React.useMemo(() => wakeWidth === 0
2859
3738
  ? undefined
2860
3739
  // `sequence`, not the scene's `compressed`: at sixteen columns an idle
@@ -3021,9 +3900,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3021
3900
  const lastModalEnterAtRef = React.useRef(0);
3022
3901
  const couponVisible = coupon !== null && starModal === null
3023
3902
  && approvalSnapshot === null && dialogSnapshot === null && questionSnapshot === null
3024
- && overlay.kind === 'none' && btw === null && recap === null
3903
+ && overlay.kind === 'none' && !btwOverlayOpen && recap === null
3025
3904
  && !supervisorOpen && !treeOpen && !settingsOpen && !jobsPanelOpen
3026
- && !sceneOpen && !subagentDashboardOpen && subagentDetailId === null;
3905
+ && !sceneOpen && !subagentDashboardOpen && subagentDetailId === null
3906
+ && !btwSceneOpen;
3027
3907
  const markCouponShown = React.useCallback((orderId) => {
3028
3908
  bonusNotices?.shown(orderId);
3029
3909
  }, [bonusNotices]);
@@ -3042,10 +3922,27 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3042
3922
  // still lets the panel receive them. PromptInput now stays mounted but
3043
3923
  // suspended to preserve async command drafts, making this guard also
3044
3924
  // essential for Ctrl+C: it must never clear the hidden composer.
3045
- if (btw !== null
3925
+ if (btwOverlayOpen
3046
3926
  || overlay.kind === 'tips'
3047
3927
  || (recap !== null && (!recap.auto || recap.expanded)))
3048
3928
  return;
3929
+ // The first-run guide owns the whole terminal while it is up: it is a
3930
+ // wizard with its own step navigation, its own focus ring inside the
3931
+ // pickers it borrows, and no free-text input at all. Registered ABOVE the
3932
+ // launchpad because it renders above it.
3933
+ if (onboardingOpen)
3934
+ return;
3935
+ // The launchpad owns the whole terminal while it is up — including the
3936
+ // plain letters that would otherwise reach the composer, which is exactly
3937
+ // the point: it IS the composer on this screen, and its draft is submitted
3938
+ // directly (see closeLaunchpad). ONE exception (fifth revision): a picker
3939
+ // opened from the param row renders ABOVE the launchpad and therefore owns
3940
+ // the keyboard — fall through to the overlay branches below (Esc closes the
3941
+ // picker back onto the launchpad). The launchpad's own useInput is paused
3942
+ // via inputPaused for exactly this window, so keys the picker does not
3943
+ // consume cannot leak into the draft.
3944
+ if (launchpadShown && !launchpadOverlayUp)
3945
+ return;
3049
3946
  // The session tree owns the whole terminal while it is up: plain letters
3050
3947
  // drive its search, clicks and Enter drive its action menu.
3051
3948
  if (treeOpen)
@@ -3063,12 +3960,20 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3063
3960
  // Subagent dashboard or detail scene: it owns the keyboard while open.
3064
3961
  if (subagentDashboardOpen || subagentDetailId !== null)
3065
3962
  return;
3963
+ // The main-screen Agent View owns the whole terminal while open (its
3964
+ // composer, scrolling and Esc layering live in the scene).
3965
+ if (agentView !== null)
3966
+ return;
3066
3967
  // The `/jobs` panel replaces the conversation too, so it owns Esc (close)
3067
3968
  // and k (kill) while open. Unguarded, Esc meant to CLOSE the panel also
3068
3969
  // reached the chat:cancel branch below whenever a turn was in flight —
3069
3970
  // dismissing the panel and killing the turn with one key.
3070
3971
  if (jobsPanelOpen)
3071
3972
  return;
3973
+ // The ⤢ btw thread scene owns the keyboard the same way: Esc there
3974
+ // returns to the sidebar (never the chat:cancel branch below).
3975
+ if (btwSceneOpen)
3976
+ return;
3072
3977
  // A plugin scene (dsh-tui-scenes) or the trajectory scene owns the whole
3073
3978
  // screen while open: every key belongs to it. Unguarded, an Esc meant to
3074
3979
  // CLOSE the scene also reached the chat:cancel branch below whenever a
@@ -3093,7 +3998,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3093
3998
  // Events only arrive with mouse tracking on; inline mode never sees
3094
3999
  // them, so this is a no-op there.
3095
4000
  if (key.wheelUp || key.wheelDown) {
3096
- if (helpOpen)
4001
+ // 焦点在右栏时滚轮不回落到转录:落在面板矩形上的滚轮已由命中
4002
+ // 测试路由给面板自己的 ScrollBox,到达这里的兜底事件不应在
4003
+ // 用户操作右栏时误滚左栏。
4004
+ if (helpOpen || sidePanel.focus === 'panel')
3097
4005
  return;
3098
4006
  // Any open transient dialog is modal to the wheel; the one exception
3099
4007
  // mirrors the render gate — a workspace picker whose target list has
@@ -3130,7 +4038,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3130
4038
  // pending. The panels bind ↑/↓/Space/Tab/Enter/Esc and never these keys,
3131
4039
  // so paging cannot steal anything from them.
3132
4040
  if ((key.pageUp || key.pageDown) && fullscreen) {
3133
- if (helpOpen)
4041
+ // 焦点在右栏时 PgUp/PgDn 属于活动面板(经侧栏键盘分发)。
4042
+ if (helpOpen || sidePanel.focus === 'panel')
3134
4043
  return;
3135
4044
  const overlayModal = overlay.kind !== 'none' &&
3136
4045
  (overlay.kind !== 'workspace-picker' || workspaceTargets.length > 0);
@@ -3169,6 +4078,12 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3169
4078
  }
3170
4079
  return;
3171
4080
  }
4081
+ // 侧栏键盘分发(v2.1 优先级):上面的审批 / 问卷 / 对话框守卫仍然
4082
+ // 最先,其次是侧栏全局快捷键(Ctrl+B / Alt+Z,两种焦点都生效),
4083
+ // 然后焦点在右栏时一切按键归侧栏——活动面板的业务键优先,宿主
4084
+ // 回退键(←/→ 切面板、z、+/-、Esc 回聊天)兜底。
4085
+ if (sidePanel.handleKey(input, key, event))
4086
+ return;
3172
4087
  const returnCandidate = isPlainReturnInput(input, key);
3173
4088
  const returnNow = Date.now();
3174
4089
  const plainReturn = returnCandidate && returnNow - lastModalEnterAtRef.current >= 80;
@@ -3263,6 +4178,32 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3263
4178
  event.stopImmediatePropagation();
3264
4179
  return;
3265
4180
  }
4181
+ if (overlay.kind === 'help') {
4182
+ // 帮助盖屏(第八版):Esc/Ctrl+C/Enter 收起回落地页;纵向导航归这个
4183
+ // 视口(与 PromptInput 的 helpOpen 分支同一套键位),其余按键模态吞掉
4184
+ // ——绝不漏进落地页草稿。
4185
+ const page = Math.max(1, helpCoverViewportHeight - 2);
4186
+ if (key.upArrow || key.wheelUp) {
4187
+ helpCoverScrollRef.current?.scrollBy(key.wheelUp ? -3 : -1);
4188
+ }
4189
+ else if (key.downArrow || key.wheelDown) {
4190
+ helpCoverScrollRef.current?.scrollBy(key.wheelDown ? 3 : 1);
4191
+ }
4192
+ else if (key.pageUp || key.pageDown) {
4193
+ helpCoverScrollRef.current?.scrollBy(key.pageUp ? -page : page);
4194
+ }
4195
+ else if (key.home) {
4196
+ helpCoverScrollRef.current?.scrollTo(0);
4197
+ }
4198
+ else if (key.end) {
4199
+ helpCoverScrollRef.current?.scrollTo(Number.MAX_SAFE_INTEGER);
4200
+ }
4201
+ else if (key.escape || (key.ctrl && (input === 'c' || input === 'd')) || plainReturn) {
4202
+ dispatchOverlay({ type: 'close' });
4203
+ }
4204
+ event.stopImmediatePropagation();
4205
+ return;
4206
+ }
3266
4207
  if (overlay.kind === 'thinking') {
3267
4208
  if (key.upArrow || key.downArrow) {
3268
4209
  dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: 2 });
@@ -3632,6 +4573,84 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3632
4573
  }
3633
4574
  return;
3634
4575
  }
4576
+ if (overlay.kind === 'mode') {
4577
+ if (key.upArrow || key.downArrow) {
4578
+ dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: overlay.modes.length });
4579
+ }
4580
+ else if (plainReturn) {
4581
+ const option = overlay.modes[overlay.index];
4582
+ dispatchOverlay({ type: 'close' });
4583
+ if (option !== undefined)
4584
+ void runBackendModeCommand(option.id, option.name);
4585
+ }
4586
+ else if (key.escape) {
4587
+ dispatchOverlay({ type: 'close' });
4588
+ }
4589
+ return;
4590
+ }
4591
+ if (overlay.kind === 'kernel') {
4592
+ // 名册不冻在 overlay 里(kernelOptions 是渲染期派生值):探测落地后
4593
+ // 选择器自己就刷新成完整目录,不需要重开。
4594
+ if (key.upArrow || key.downArrow) {
4595
+ dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: kernelOptions.length });
4596
+ }
4597
+ else if (plainReturn) {
4598
+ pickKernel(overlay.index);
4599
+ }
4600
+ else if (key.escape) {
4601
+ dispatchOverlay({ type: 'close' });
4602
+ }
4603
+ return;
4604
+ }
4605
+ if (overlay.kind === 'sdk-install') {
4606
+ // 向导按键按步骤态分派;checking/running 期间除 Esc(取消安装)外
4607
+ // 全部吞掉——异步落地只发生在面板还在的窗口内(见 sdkPhase 注释)。
4608
+ if (sdkPhase.kind === 'confirm') {
4609
+ if (plainReturn)
4610
+ confirmSdkInstall(sdkPhase.dir);
4611
+ else if (key.escape)
4612
+ closeSdkInstallToKernelPicker();
4613
+ }
4614
+ else if (sdkPhase.kind === 'checking') {
4615
+ // 亚秒级预检,无键可按。
4616
+ }
4617
+ else if (sdkPhase.kind === 'running') {
4618
+ if (key.escape)
4619
+ sdkInstallerRef.current?.cancel();
4620
+ }
4621
+ else if (sdkPhase.kind === 'done') {
4622
+ if (plainReturn)
4623
+ closeSdkInstallToKernelPicker();
4624
+ else if (key.escape)
4625
+ closeSdkInstall();
4626
+ }
4627
+ else if (sdkPhase.kind === 'failed') {
4628
+ if (input === 'r' && !key.ctrl && !key.meta)
4629
+ confirmSdkInstall(sdkPhase.dir);
4630
+ else if (key.escape)
4631
+ closeSdkInstallToKernelPicker();
4632
+ }
4633
+ else {
4634
+ // pnpm-missing / cancelled / no-target:Esc 回内核选择器。
4635
+ if (key.escape)
4636
+ closeSdkInstallToKernelPicker();
4637
+ }
4638
+ return;
4639
+ }
4640
+ if (overlay.kind === 'channel') {
4641
+ // 名册不冻在 overlay 里(channelRows 是渲染期派生值):切换/导入后
4642
+ // 选择器自己就刷新成新状态,不需要重开。
4643
+ if (key.upArrow || key.downArrow) {
4644
+ dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: channelRows.length });
4645
+ }
4646
+ else if (plainReturn) {
4647
+ pickChannel(overlay.index);
4648
+ }
4649
+ else if (key.escape) {
4650
+ dispatchOverlay({ type: 'close' });
4651
+ }
4652
+ return;
4653
+ }
3635
4654
  if (overlay.kind === 'plan') {
3636
4655
  if (key.upArrow || key.downArrow) {
3637
4656
  dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: 2 });
@@ -3661,6 +4680,21 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3661
4680
  }
3662
4681
  return;
3663
4682
  }
4683
+ if (overlay.kind === 'panel') {
4684
+ if (key.upArrow || key.downArrow) {
4685
+ dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: panelPickerRows.length });
4686
+ }
4687
+ else if (plainReturn) {
4688
+ const row = panelPickerRows[overlay.index];
4689
+ dispatchOverlay({ type: 'close' });
4690
+ if (row !== undefined)
4691
+ sidePanel.openPanel(row.id, { focus: true });
4692
+ }
4693
+ else if (key.escape) {
4694
+ dispatchOverlay({ type: 'close' });
4695
+ }
4696
+ return;
4697
+ }
3664
4698
  if (overlay.kind === 'theme') {
3665
4699
  const options = getThemeOptions(themeHost);
3666
4700
  if (key.upArrow || key.downArrow) {
@@ -3832,11 +4866,12 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3832
4866
  return;
3833
4867
  }
3834
4868
  if (actionMatches('dashboard', input, key)) {
3835
- // The subagent dashboard key (default Ctrl+A) opens the dashboard.
3836
- // Consume the key: without the stop the prompt editor's readline
3837
- // binding ALSO fires (Ctrl+A moves the caret to line start), so one
3838
- // press both opens the overlay and jumps the cursor.
3839
- setSubagentDashboardOpen(true);
4869
+ // The subagent dashboard key (default Ctrl+A) opens the dashboard —
4870
+ // split mode routes it to the agents side panel instead. Consume the
4871
+ // key: without the stop the prompt editor's readline binding ALSO
4872
+ // fires (Ctrl+A moves the caret to line start), so one press both
4873
+ // opens the view and jumps the cursor.
4874
+ openSubagentDashboard();
3840
4875
  event.stopImmediatePropagation();
3841
4876
  return;
3842
4877
  }
@@ -3848,7 +4883,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3848
4883
  return;
3849
4884
  }
3850
4885
  if (actionMatches('history', input, key) && !helpOpen) {
3851
- setHistoryEntries(loadHistory());
4886
+ setHistoryEntries(loadHistory(channel.cwd));
3852
4887
  dispatchOverlay({
3853
4888
  type: 'open',
3854
4889
  overlay: { kind: 'history', query: '', cursor: 0, focus: 0 },
@@ -3873,22 +4908,25 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3873
4908
  setSelectedId(null);
3874
4909
  }
3875
4910
  }
4911
+ else if (key.escape && promptControllerRef.current?.consumeEscape()) {
4912
+ // Selection/editor Esc stays with the composer even though Chat's
4913
+ // global listener runs first. Consume it before interrupting the turn.
4914
+ event.stopImmediatePropagation();
4915
+ }
3876
4916
  else if (key.escape && channel.working && !helpOpen && !promptControllerRef.current?.vimActive()) {
3877
4917
  // Esc interrupts a running turn (the prompt input
3878
4918
  // only sees esc when idle, where it has the double-tap-clear meaning).
3879
- // With messages queued for delivery, interrupt-and-deliver them right
3880
- // away (Codex behavior); otherwise a plain interrupt parks the queue.
4919
+ // With messages queued, the queue DOCKS (Claude Code parity): the
4920
+ // abort drops the backend copies, the previews park channel-side and
4921
+ // the composer's dock hint offers ↑ to edit one / ⏎ to send them all
4922
+ // — nothing auto-sends. Already-docked rows dock nothing new; the
4923
+ // turn still needs its plain abort.
3881
4924
  // vim mode (either submode) yields: there Esc is a MODE key (INSERT→
3882
4925
  // NORMAL, NORMAL = no-op/cancel pending d) and the prompt owns it;
3883
4926
  // interrupting still works via Ctrl+C / Ctrl+Enter.
3884
4927
  if (channel.pending.length > 0) {
3885
- const count = channel.interruptAndDeliver(channel.pending.map(item => ({
3886
- text: item.text,
3887
- images: item.images ?? [],
3888
- })));
3889
- if (count > 0) {
3890
- channel.notify(t('interrupt-delivered', { n: count }), { timeoutMs: 2500 });
3891
- }
4928
+ if (channel.interruptAndDock() === 0)
4929
+ channel.cancel();
3892
4930
  }
3893
4931
  else {
3894
4932
  channel.cancel();
@@ -4040,10 +5078,17 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4040
5078
  // (wired to the toast below).
4041
5079
  event.stopImmediatePropagation();
4042
5080
  }
5081
+ }, {
5082
+ // Chat's global layer must see every key before the composer and the
5083
+ // panels it hosts (the handler's yield guards and readline shadowing
5084
+ // both assume it), whether or not they mounted in the same
5085
+ // commit — child effects run first, so append order would put a
5086
+ // first-mount PromptInput ahead of Chat (#1155).
5087
+ prepend: true,
4043
5088
  });
4044
5089
  // Working-activity line (spinner slot): context-pressure prefix shares the
4045
- // StatusLine thresholds (amber ≥ 80, red ≥ 95).
4046
- const activityWarnPct = contextPressurePct(channel.lastUsage, channel.contextWindow);
5090
+ // StatusLine thresholds (amber ≥ 80, red ≥ 95) and its occupancy source.
5091
+ const activityWarnPct = contextPressurePct(channelContextOccupancy(channel));
4047
5092
  // Who owns the spinner slot: with the working-activity line on, that slot
4048
5093
  // draws the user's `/activity` preset, so the compaction row borrows the same
4049
5094
  // indicator instead of answering with the classic dot.
@@ -4064,7 +5109,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4064
5109
  // covered screen is unmounted, exactly like the chat-state prompt slot.
4065
5110
  // The panel elements are shared with the prompt-slot chain below so the
4066
5111
  // two mount sites cannot drift.
4067
- const approvalPanelNode = approvalSnapshot !== null ? (_jsx(ApprovalPanel, { approval: approvalSnapshot, background: approvalSnapshot.agentId !== channel.agentId, onDecide: outcome => approvals.decide(outcome) }, approvalSnapshot.key)) : null;
5112
+ const approvalPanelNode = approvalSnapshot !== null ? (_jsx(ApprovalPanel, { approval: approvalSnapshot, background: approvalSnapshot.agentId !== channel.agentId, onDecide: (outcome, decision) => approvals.decide(outcome, decision) }, approvalSnapshot.key)) : null;
4068
5113
  const questionPanelNode = questionSnapshot !== null ? (_jsx(AskUserQuestionPanel, { question: questionSnapshot.question, position: questionSnapshot.position, total: questionSnapshot.total, answered: questionSnapshot.answered, initialDraft: questionSnapshot.draft, onAnswer: selection => {
4069
5114
  if (!questionStore.stillCurrent(questionSnapshot.key))
4070
5115
  return;
@@ -4099,8 +5144,201 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4099
5144
  }
4100
5145
  : undefined, collapsed: questionMinimized, onExpand: () => setMinimizedQuestionKey(null), onToggleFold: () => setMinimizedQuestionKey(previous => previous === questionSnapshot.key ? null : questionSnapshot.key), fullscreen: fullscreen }, questionSnapshot.key)) : null;
4101
5146
  const interruptPanel = approvalPanelNode ?? questionPanelNode;
5147
+ /**
5148
+ * Transient picker panels (pickers/dialogs) - this JSX feeds TWO mount
5149
+ * points since the fifth launchpad revision: the chat page OverlayAbove
5150
+ * (above the input cluster) and the launchpad itself (above its input
5151
+ * card, see the launchpad branch). Defined once so the two never drift.
5152
+ */
5153
+ const backendModeStatus = modeStatus(channel.backendModes?.()?.snapshot(), () => { void runCommand('permission', ''); });
5154
+ /**
5155
+ * 底栏模型段/思考档位段的点击(与模式段同一契约):后端声明了模型目录或
5156
+ * effort 能力(backendCapabilities 位)才挂,点击 = 既有 /model · /effort
5157
+ * 命令(同一批选择器);无能力不挂点击,hover 也不承诺(StatusLine 的
5158
+ * effort hover id 与点击同乘,model hover 只是不追加操作行)。
5159
+ */
5160
+ const backendCaps = channel.backendCapabilities;
5161
+ const modelPickerStatus = backendCaps?.models === false
5162
+ ? undefined
5163
+ : { onOpen: () => { void runCommand('model', ''); } };
5164
+ const effortPickerStatus = backendCaps?.effort === false
5165
+ ? undefined
5166
+ : { onOpen: () => { void runCommand('effort', ''); } };
5167
+ const pickerPanels = (_jsxs(_Fragment, { children: [overlay.kind === 'help' && (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: _jsx(HelpMenu, { commands: channel.commandList, viewportHeight: helpCoverViewportHeight, viewportWidth: chatColumns, scrollRef: helpCoverScrollRef, onCommandPick: (name) => {
5168
+ // 点击命令行 = 把 /name 填进落地页草稿(聊天页 Tab 补全的
5169
+ // 鼠标等价),浮层收起、人还在启动页(第八版:不许进对话页)。
5170
+ dispatchOverlay({ type: 'close' });
5171
+ const filled = '/' + name + ' ';
5172
+ setLaunchpadDraft(filled);
5173
+ setLaunchpadCaret(filled.length);
5174
+ setLaunchpadFocus(-1);
5175
+ } }) })), overlay.kind === 'thinking' && (_jsx(ThinkingToggle, { currentValue: thinkingVisible, focusIndex: overlay.focus, onPick: (index) => {
5176
+ // 点击行 = 设焦点 + 应用(与 Enter 同一条路径)
5177
+ const visible = index === 0;
5178
+ setThinkingVisible(visible);
5179
+ dispatchOverlay({ type: 'close' });
5180
+ channel.notify(t('thinking-toggled', { state: visible ? t('thinking-on') : t('thinking-off') }));
5181
+ } })), overlay.kind === 'workspace-picker' && workspaceTargets.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspacePicker, { targets: workspaceTargets, focusIndex: overlay.index, currentCwd: channel.cwd, onPick: (index) => {
5182
+ // 点击行 = 切换该行目标(与 Enter 同一条路径)
5183
+ const target = workspaceTargets[index];
5184
+ dispatchOverlay({ type: 'close' });
5185
+ if (target !== undefined)
5186
+ void channel.switchWorkspace(target);
5187
+ } }) })), overlay.kind === 'workspace-menu' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspaceMenuPicker, { options: workspaceMenuOptions, focusIndex: overlay.index, onPick: (index) => {
5188
+ // 点击行 = 执行该行(与 Enter 同一条路径)
5189
+ runWorkspaceMenuOption(workspaceMenuOptions[index]);
5190
+ } }) })), overlay.kind === 'workspace-flow' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspaceFlowPicker, { title: overlay.flow.title, choices: overlay.flow.choices, focusIndex: overlay.index, busy: overlay.busy, input: overlay.input, onPick: (index) => {
5191
+ // 点击行 = 设焦点 + 执行分支(与 Enter 同一条路径);
5192
+ // busy/输入态在组件侧禁点
5193
+ const choice = overlay.flow.choices[index];
5194
+ if (choice === undefined)
5195
+ return;
5196
+ dispatchOverlay({ type: 'set-index', kind: 'workspace-flow', index });
5197
+ runWorkspaceFlowAction(signal => choice.choose(signal));
5198
+ } }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: models.length === 0 ? (_jsx(ModelPickerLoading, {})) : activeModelGroup === undefined ? (_jsx(ModelPicker, { groups: modelGroups, focusIndex: overlay.index, currentProvider: channel.provider, onPick: (index) => {
5199
+ // 点击分组行 = 进入该组(与 Enter 同一条路径)
5200
+ const group = modelGroups[index];
5201
+ if (!group)
5202
+ return;
5203
+ setModelGroup(group.provider);
5204
+ if (group.provider === RECENTS_GROUP_PROVIDER) {
5205
+ dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
5206
+ return;
5207
+ }
5208
+ const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
5209
+ dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
5210
+ } })) : (_jsx(ModelPicker, { models: groupModels, groupLabel: activeModelGroup === RECENTS_GROUP_PROVIDER
5211
+ ? t('picker-group-recent')
5212
+ : modelGroups.find(group => group.provider === activeModelGroup)?.label, showBack: modelGroups.length > 1 && !modelPickerDirect, showProviderPrefix: activeModelGroup === RECENTS_GROUP_PROVIDER, focusIndex: overlay.index, currentModel: `${channel.provider}/${channel.model}`, onPick: (index) => {
5213
+ // 点击行 = 应用该行模型(与 Enter 同一条路径)
5214
+ const model = groupModels[index];
5215
+ if (!model)
5216
+ return;
5217
+ dispatchOverlay({ type: 'close' });
5218
+ void switchModelRecorded(model.provider, model.id, model.name);
5219
+ } })) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
5220
+ const row = (migrateRows ?? [])[index];
5221
+ if (!row)
5222
+ return;
5223
+ setMigrateChecked(current => {
5224
+ const next = new Set(current);
5225
+ if (next.has(row.agentId))
5226
+ next.delete(row.agentId);
5227
+ else
5228
+ next.add(row.agentId);
5229
+ return next;
5230
+ });
5231
+ } }) })), overlay.kind === 'migrate-confirm' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigrateConfirm, { rows: migratePending }) })), overlay.kind === 'skills' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: skillsList === null ? (_jsx(SkillsPickerLoading, {})) : (_jsx(SkillsPicker, { skills: skillsList, focusIndex: overlay.index, onPick: (index) => {
5232
+ const skill = skillsList[index];
5233
+ if (!skill)
5234
+ return;
5235
+ dispatchOverlay({ type: 'close' });
5236
+ if (skill.userInvocable)
5237
+ setHistoryFill(`/${skill.name} `);
5238
+ } })) })), overlay.kind === 'activity' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ActivityPicker, { focusIndex: overlay.index, currentPreset: channel.activityFrames, onPick: (index) => {
5239
+ dispatchOverlay({ type: 'close' });
5240
+ const name = PRESET_NAMES[index];
5241
+ if (name)
5242
+ channel.setActivityFrames(name);
5243
+ } }) })), overlay.kind === 'color' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ColorPicker, { focusIndex: overlay.index, currentColor: channel.sessionColor, onPick: (index) => {
5244
+ dispatchOverlay({ type: 'close' });
5245
+ const name = SESSION_COLOR_NAMES[index];
5246
+ if (name) {
5247
+ channel.setSessionColor(name);
5248
+ channel.notify(t('color-set', { name }), { color: 'success' });
5249
+ }
5250
+ } }) })), overlay.kind === 'panel' && panelPickerRows.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PanelPicker, { rows: panelPickerRows, focusIndex: overlay.index, activeId: sidePanel.activePanelId, onPick: (index) => {
5251
+ const row = panelPickerRows[index];
5252
+ dispatchOverlay({ type: 'close' });
5253
+ if (row !== undefined)
5254
+ sidePanel.openPanel(row.id, { focus: true });
5255
+ } }) })), overlay.kind === 'effort' && effortOptions.length > 1 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(EffortSlider, { options: effortOptions, focusIndex: overlay.index, currentId: channel.reasoningEffort, levelsFallback: effortLevelsFallback,
5256
+ // 点击档位 = 移到该档并即时应用(与 ←/→ 同语义)
5257
+ onPick: (index) => {
5258
+ dispatchOverlay({ type: 'set-index', kind: 'effort', index });
5259
+ const option = effortOptions[index];
5260
+ if (option)
5261
+ void channel.setEffort(option.id);
5262
+ } }) })), overlay.kind === 'preset' && presetOptions.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PresetPicker, { presets: presetOptions, focusIndex: overlay.index, currentPreset: channel.agentPreset, onPick: (index) => {
5263
+ dispatchOverlay({ type: 'close' });
5264
+ const option = presetOptions[index];
5265
+ if (option)
5266
+ void channel.switchPreset(option.id);
5267
+ } }) })), overlay.kind === 'permission' && overlay.snapshot.options.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PermissionsPicker, { options: overlay.snapshot.options, focusIndex: overlay.index, currentValue: overlay.snapshot.current?.value, cwd: channel.cwd, onPick: (index) => {
5268
+ if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5269
+ return;
5270
+ const option = overlay.snapshot.options[index];
5271
+ dispatchOverlay({ type: 'close' });
5272
+ if (option !== undefined)
5273
+ void runPermissionCommand(` ${option.value}`);
5274
+ } }) })), overlay.kind === 'mode' && overlay.modes.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ModePicker, { modes: overlay.modes, focusIndex: overlay.index, currentId: overlay.currentId, onPick: (index) => {
5275
+ if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5276
+ return;
5277
+ const option = overlay.modes[index];
5278
+ dispatchOverlay({ type: 'close' });
5279
+ if (option !== undefined)
5280
+ void runBackendModeCommand(option.id, option.name);
5281
+ } }) })), overlay.kind === 'kernel' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(KernelPicker, { options: kernelOptions, focusIndex: overlay.index, pinned: kernelPinned === true, onPick: (index) => {
5282
+ if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5283
+ return;
5284
+ pickKernel(index);
5285
+ } }) })), overlay.kind === 'sdk-install' && sdkPhase.kind !== 'idle' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(SdkInstallWizard, { phase: sdkPhase }) })), overlay.kind === 'channel' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ChannelPicker, { rows: channelRows, focusIndex: overlay.index, onPick: (index) => {
5286
+ if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5287
+ return;
5288
+ pickChannel(index);
5289
+ } }) })), overlay.kind === 'plan' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PlanPicker, { focusIndex: overlay.index, currentOn: channel.mode.plan === true, onPick: (index) => {
5290
+ dispatchOverlay({ type: 'close' });
5291
+ const on = index === 0;
5292
+ void runExternalCommand('plan', on ? '' : ' off');
5293
+ } }) })), overlay.kind === 'lang' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(LangPicker, { focusIndex: overlay.index, currentLang: getLang(), onPick: (index) => {
5294
+ const lang = LANGS[index];
5295
+ if (lang === undefined)
5296
+ return;
5297
+ dispatchOverlay({ type: 'close' });
5298
+ applyLang(lang);
5299
+ } }) })), overlay.kind === 'theme' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ThemePicker, { focusIndex: overlay.index, currentTheme: themeName, themeHost: themeHost, onPick: (index) => {
5300
+ dispatchOverlay({ type: 'close' });
5301
+ const name = getThemeOptions(themeHost)[index]?.value;
5302
+ if (name !== undefined) {
5303
+ const ok = setTheme(name);
5304
+ channel.notify(ok ? t('theme-switched-saved', { name }) : t('theme-switch-failed', { name }), { color: ok ? 'success' : 'error' });
5305
+ }
5306
+ } }) })), overlay.kind === 'history' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(HistorySearchDialog, { query: overlay.query, cursorOffset: overlay.cursor, matches: historyMatches, focusIndex: overlay.focus, onPick: (index) => {
5307
+ // 点击行 = 填入该历史命令(与 Enter 同路径)
5308
+ const entry = historyMatches[index];
5309
+ if (entry) {
5310
+ setHistoryFill(entry.text);
5311
+ dispatchOverlay({ type: 'close' });
5312
+ }
5313
+ } }) })), overlay.kind === 'rewind' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(RewindPicker, { rows: rewindRows, focusIndex: overlay.index, confirmRow: overlay.confirm, modes: overlay.modes, modeIndex: overlay.modeIndex, busy: overlay.busy, onPickRow: (index) => {
5314
+ // 列表页点击只选中:进入确认态保留键盘 Enter 显式触发
5315
+ dispatchOverlay({ type: 'set-index', kind: 'rewind', index });
5316
+ }, onConfirm: () => {
5317
+ // 确认页即显式确认层,点击直接执行(与 Enter 同路径)
5318
+ const row = overlay.confirm;
5319
+ if (row === null)
5320
+ return;
5321
+ dispatchOverlay({ type: 'close' });
5322
+ void performRewind(row);
5323
+ }, onPickMode: (index) => {
5324
+ // 模式列表点击直接执行该模式(与 Enter 同路径)
5325
+ const row = overlay.confirm;
5326
+ if (row === null)
5327
+ return;
5328
+ // 模式页仅当 modes 非空才渲染,这里空安全取值
5329
+ const mode = index === 0 ? null : (overlay.modes?.[index - 1]?.id ?? null);
5330
+ dispatchOverlay({ type: 'close' });
5331
+ void performRewind(row, mode);
5332
+ } }) })), overlay.kind === 'file-actions' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(FileActionsPanel, { path: overlay.path, isDir: overlay.isDir, focusIndex: overlay.index, onPick: (index) => {
5333
+ // 点击行直接执行该动作(与 Enter 同路径)
5334
+ const path = overlay.path;
5335
+ dispatchOverlay({ type: 'close' });
5336
+ runFileAction(index, path);
5337
+ } }) })), overlay.kind === 'search' && _jsx(TranscriptSearch, { query: searchQuery, cursorOffset: searchCursor, count: searchCount, current: searchCurrent })] }));
4102
5338
  const screenOpen = channel.pluginScene !== undefined || supervisorOpen || settingsOpen
4103
- || subagentDetailId !== null || subagentDashboardOpen || sceneOpen;
5339
+ || subagentDetailId !== null || subagentDashboardOpen || sceneOpen
5340
+ || agentView !== null
5341
+ || launchpadShown || onboardingOpen;
4104
5342
  if (interruptPanel !== null && screenOpen) {
4105
5343
  const node = (_jsx(Box, { flexDirection: "column", width: "100%", paddingX: 1, children: interruptPanel }));
4106
5344
  return fullscreen ? node : _jsx(AlternateScreen, { children: node });
@@ -4126,6 +5364,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4126
5364
  }, children: renderScene ? renderScene(pluginScene.id, channel) : _jsxs(Text, { children: ["Scene unavailable: ", pluginScene.id] }) }));
4127
5365
  return fullscreen ? node : _jsx(AlternateScreen, { children: node });
4128
5366
  }
5367
+ /**
5368
+ * The first-run guide — the FIRST frame of a fresh installation.
5369
+ *
5370
+ * It sits above every other screen because it answers a question that comes
5371
+ * before all of them: "is this thing wired up at all". A launch that needs
5372
+ * setup has nothing useful to show behind a browser or a landing page.
5373
+ *
5374
+ * `activeModel` is deliberately undefined here: the wizard's model step
5375
+ * switches models through `channel.switchModel`, which is the same path the
5376
+ * chat screen uses, so a switch made inside the wizard is already live when
5377
+ * the user lands on the launcher.
5378
+ */
5379
+ if (onboardingOpen) {
5380
+ const node = (_jsx(Onboarding, { channel: channel, themeHost: themeHost, onClose: closeOnboarding, onApplyLang: applyLang, onRunCommand: (name) => {
5381
+ // 与落地页的 onAction 同一条规则:打开整屏界面的命令要先把向导收掉。
5382
+ // 走 `closeOnboarding('skipped')` 而不是直接置 false——用户是去试命令、
5383
+ // 没答完引导,按 skipped 的口径不记账(下次启动还会问)。
5384
+ if (!overlayCommandNames.has(name))
5385
+ closeOnboarding('skipped');
5386
+ void runCommand(name, '');
5387
+ } }));
5388
+ return fullscreen ? node : _jsx(AlternateScreen, { children: node });
5389
+ }
4129
5390
  /**
4130
5391
  * The session supervisor: a screen in the same sense as the tree — an early
4131
5392
  * return after every hook above has run, so there is no transcript
@@ -4142,7 +5403,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4142
5403
  * while they read the list, which is why closing the screen only repaints
4143
5404
  * the transcript when the attached session actually changed.
4144
5405
  */
4145
- if (supervisorOpen) {
5406
+ if (supervisorOpen && launchpadGate()) {
4146
5407
  /**
4147
5408
  * Live state per session, from the channel's own agent-view projection.
4148
5409
  * Reading the projection rather than a parallel source is what keeps this
@@ -4150,7 +5411,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4150
5411
  * about which session is waiting for input.
4151
5412
  */
4152
5413
  const agentRowOf = (sessionId) => agentViewRows.find(row => row.id === sessionId);
4153
- const supervisorNode = (_jsx(SessionSupervisor, { channel: channel, home: homeDir(), onClose: closeHome, approval: approvalSnapshot, onApprove: outcome => approvals.decide(outcome), onOpenSession: async (sessionId) => {
5414
+ const supervisorNode = (_jsx(SessionSupervisor, { channel: channel, home: homeDir(), onClose: closeHome, approval: approvalSnapshot, onApprove: (outcome, decision) => approvals.decide(outcome, decision), onOpenSession: async (sessionId) => {
4154
5415
  // A refusal is reported by the screen itself (see `openSession`):
4155
5416
  // the composer that draws channel notifications is not mounted here.
4156
5417
  const result = await channel.resumeTo(sessionId);
@@ -4160,6 +5421,15 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4160
5421
  suppressLogoIntroRef.current = true;
4161
5422
  setAgentViewReturnId(undefined);
4162
5423
  setSupervisorOpen(false);
5424
+ // 第七版:明确选中一个会话 = 有意导航(与 Esc「退出」相对)——浏览页
5425
+ // 与盖在它底下的落地页**一起收**,人落在那个会话的聊天页。只收浏览页
5426
+ // 会露出启动页,正是用户实测的「选完会话还是回到启动页」。落地页的
5427
+ // 草稿/焦点也按 closeLaunchpad 同一口径清掉(进入的是别的会话,旧草稿
5428
+ // 不该跟过去)。
5429
+ setLaunchpadOpen(false);
5430
+ setLaunchpadFocus(-1);
5431
+ setLaunchpadDraft('');
5432
+ setLaunchpadCaret(0);
4163
5433
  repaintTranscript();
4164
5434
  return result;
4165
5435
  }, onNewSession: async (target) => {
@@ -4168,14 +5438,24 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4168
5438
  suppressLogoIntroRef.current = true;
4169
5439
  setAgentViewReturnId(undefined);
4170
5440
  setSupervisorOpen(false);
5441
+ // 同 onOpenSession:新建/切工作区会话也是有意导航,落地页一并收。
5442
+ setLaunchpadOpen(false);
5443
+ setLaunchpadFocus(-1);
5444
+ setLaunchpadDraft('');
5445
+ setLaunchpadCaret(0);
4171
5446
  repaintTranscript();
4172
5447
  }
4173
5448
  return ok;
4174
5449
  }, onStopSession: async (sessionId) => channel.stopBackgroundAgent?.(sessionId) ?? false, liveStateOf: (sessionId) => {
4175
5450
  const row = agentRowOf(sessionId);
4176
- return row === undefined
4177
- ? undefined
4178
- : { status: row.status, live: row.live, current: row.current, summary: row.summary };
5451
+ if (row !== undefined)
5452
+ return { status: row.status, live: row.live, current: row.current, summary: row.summary };
5453
+ // Without agent view, only this terminal's current session has live state.
5454
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- runtime guard: headless hosts render Chat with a partial channel
5455
+ const hasAgentView = channel.backendCapabilities?.commands.includes('agentview') ?? true;
5456
+ if (hasAgentView || sessionId !== channel.agentId)
5457
+ return undefined;
5458
+ return { status: channel.working ? 'working' : 'idle', live: true, current: true, summary: '' };
4179
5459
  } }));
4180
5460
  // Inline hosts enter the alternate screen for the duration; full-screen
4181
5461
  // hosts are already in it and must not nest a second one.
@@ -4185,7 +5465,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4185
5465
  // conversation (an early return after every hook above has run), so there
4186
5466
  // is no transcript underneath to be repainted or bled through. The dropped
4187
5467
  // turn's prompt returns through the same fill path a rewind picker uses.
4188
- if (treeOpen) {
5468
+ if (treeOpen && launchpadGate()) {
4189
5469
  const tree = (_jsx(SessionTree, { channel: channel, currentSessionId: channel.agentId, onClose: () => setTreeOpen(false), onRestoreText: (text) => {
4190
5470
  // The tree rewound to a node and is handing that turn's prompt back,
4191
5471
  // exactly like the picker does. It belongs to the binding the tree
@@ -4198,21 +5478,47 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4198
5478
  // The settings screen follows the browser's rule exactly: it REPLACES the
4199
5479
  // conversation (an early return after every hook above has run), so there
4200
5480
  // is no transcript underneath to be repainted or bled through.
4201
- if (settingsOpen) {
5481
+ if (settingsOpen && launchpadGate()) {
4202
5482
  const screen = _jsx(Settings, { channel: channel, onClose: () => setSettingsOpen(false) });
4203
5483
  return fullscreen ? screen : _jsx(AlternateScreen, { children: screen });
4204
5484
  }
5485
+ // Main-screen read-only Agent View: a scene over the mounted Chat, with no
5486
+ // second Channel and no change of the bound session. It borrows the screen
5487
+ // the way the trajectory scene does; Chat stays mounted, so the parent's
5488
+ // rows, draft, pending queue and usage are untouched by the round trip.
5489
+ // Esc returns to wherever the view was opened from.
5490
+ if (agentView !== null && launchpadGate()) {
5491
+ const viewSubagent = channel.subagents.find(s => s.agentId === agentView.agentId);
5492
+ if (!viewSubagent) {
5493
+ // The roster lost this child (session switch): pop the view, don't crash.
5494
+ setAgentView(null);
5495
+ return null;
5496
+ }
5497
+ // Headless stubs mount Chat without a subagentControl at all.
5498
+ const messageControl = channel.subagentControl?.message;
5499
+ const loadTranscript = channel.subagentControl?.history;
5500
+ const viewMessages = messageControl === undefined ? [] : messageControl.messages().filter(m => m.from === agentView.agentId || m.to === agentView.agentId);
5501
+ const viewTarget = agentComposeTargetOf(agentView.agentId, new Map(channel.subagents.map(s => [s.agentId, s.description])));
5502
+ const viewScene = (_jsx(AgentTranscriptScene, { subagent: viewSubagent, source: agentView.source, onExit: () => exitAgentView(agentView.source), ...(loadTranscript === undefined ? {} : { loadTranscript }), messages: viewMessages, ...(messageControl === undefined ? {} : { compose: { control: messageControl, target: viewTarget } }), roster: channel.subagents,
5503
+ // Switching to a sibling or the parent swaps the viewed agent in
5504
+ // place; Esc still returns to the original entry point.
5505
+ onSwitchAgent: switchViewedAgent }));
5506
+ return fullscreen ? viewScene : _jsx(AlternateScreen, { children: viewScene });
5507
+ }
4205
5508
  // Subagent detail scene: displays detailed view of a specific subagent.
4206
5509
  // Like the browser and settings, it replaces the conversation entirely.
4207
- if (subagentDetailId !== null) {
5510
+ if (subagentDetailId !== null && launchpadGate()) {
4208
5511
  const subagent = channel.subagents.find(s => s.agentId === subagentDetailId);
4209
5512
  if (!subagent) {
4210
- // Agent not found, go back to dashboard
5513
+ // Agent not found, go back to the dashboard (side panel when split).
4211
5514
  setSubagentDetailId(null);
4212
- setSubagentDashboardOpen(true);
5515
+ openSubagentDashboard();
4213
5516
  return null;
4214
5517
  }
4215
- const scene = (_jsx(SubagentDetailScene, { subagent: subagent, onInterrupt: (id) => channel.subagentControl.interrupt(id), onBack: () => {
5518
+ const detailControl = channel.subagentControl?.message;
5519
+ const detailMessages = detailControl === undefined ? [] : detailControl.messages().filter(m => m.from === subagent.agentId || m.to === subagent.agentId);
5520
+ const detailTarget = agentComposeTargetOf(subagent.agentId, new Map(channel.subagents.map(s => [s.agentId, s.description])));
5521
+ const scene = (_jsx(SubagentDetailScene, { subagent: subagent, onInterrupt: (id) => channel.subagentControl?.interrupt(id), ...(channel.subagentControl?.history === undefined ? {} : { loadTranscript: channel.subagentControl.history }), onOpenView: () => openAgentView(subagent.agentId, { kind: 'agent-detail', agentId: subagent.agentId }), messages: detailMessages, ...(detailControl === undefined ? {} : { compose: { control: detailControl, target: detailTarget } }), onBack: () => {
4216
5522
  setSubagentDetailId(null);
4217
5523
  setSubagentDashboardOpen(true);
4218
5524
  } }));
@@ -4220,8 +5526,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4220
5526
  }
4221
5527
  // Jobs panel: background jobs (running/killed) with kill/inspect actions.
4222
5528
  // Like the browser and settings, it replaces the conversation entirely.
4223
- if (jobsPanelOpen) {
4224
- const panel = (_jsx(JobsPanel, { jobs: channel.backgroundJobs ?? [], onClose: () => setJobsPanelOpen(false), onKill: (id) => {
5529
+ if (jobsPanelOpen && launchpadGate()) {
5530
+ const panel = (_jsx(JobsPanel, { jobs: channel.backgroundJobs ?? [], initialFocusId: jobsPanelFocusId ?? undefined, onClose: () => { setJobsPanelOpen(false); setJobsPanelFocusId(null); }, onWatchOutput: watchJobOutput, onKill: (id) => {
4225
5531
  // Stub channels (verify harnesses) have no jobControl — surface
4226
5532
  // the same failure toast as a refused kill instead of throwing.
4227
5533
  if (channel.jobControl?.kill(id) !== true) {
@@ -4230,19 +5536,28 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4230
5536
  } }));
4231
5537
  return fullscreen ? panel : _jsx(AlternateScreen, { children: panel });
4232
5538
  }
5539
+ // ⤢ btw thread scene (openPanelFullscreen 'btw'): the whole-terminal form
5540
+ // of the sidebar panel. Esc returns to the sidebar exactly as it was — the
5541
+ // thread and the composer draft live in btwThreads, nothing is cleared.
5542
+ if (btwSceneOpen && launchpadGate()) {
5543
+ const scene = (_jsx(BtwThreadScene, { channel: channel, onClose: () => setBtwSceneOpen(false) }));
5544
+ return fullscreen ? scene : _jsx(AlternateScreen, { children: scene });
5545
+ }
4233
5546
  // Subagent dashboard: displays all active and completed subagents.
4234
5547
  // Like the browser and settings, it replaces the conversation entirely.
4235
- if (subagentDashboardOpen) {
5548
+ if (subagentDashboardOpen && launchpadGate()) {
5549
+ // No kernel serves agents from other sessions yet, so the dashboard gets
5550
+ // no `peers`; once one does, pass them here.
4236
5551
  const dashboard = (_jsx(SubagentDashboard, { subagents: [...channel.subagents], onSelect: (id) => {
4237
5552
  setSubagentDashboardOpen(false);
4238
5553
  setSubagentDetailId(id);
4239
- }, onClose: () => setSubagentDashboardOpen(false) }));
5554
+ }, onOpenView: (id) => openAgentView(id, { kind: 'agents-dashboard' }), messages: channel.subagentControl?.message?.messages(), onClose: () => setSubagentDashboardOpen(false) }));
4240
5555
  return fullscreen ? dashboard : _jsx(AlternateScreen, { children: dashboard });
4241
5556
  }
4242
5557
  /** Prompt input is inert while a modal dialog owns the keyboard. The
4243
5558
  * overlay union covers every picker/dialog and /tips in one check;
4244
5559
  * message-selection mode and the /btw panel live outside it. */
4245
- const promptSelectionActive = selectionActive || overlay.kind !== 'none' || btw !== null;
5560
+ const promptSelectionActive = selectionActive || overlay.kind !== 'none' || btwOverlayOpen;
4246
5561
  // These panels replace the visible composer, but PromptInput remains
4247
5562
  // mounted (suspended) so an async registry command cannot lose its exact
4248
5563
  // text/image draft while it waits for a user decision.
@@ -4250,7 +5565,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4250
5565
  || dialogSnapshot !== null
4251
5566
  || overlay.kind === 'tips'
4252
5567
  || (recap !== null && (!recap.auto || recap.expanded))
4253
- || btw !== null
5568
+ || btwOverlayOpen
4254
5569
  || questionPanelNode !== null
4255
5570
  || starModal !== null
4256
5571
  || couponVisible;
@@ -4262,10 +5577,158 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4262
5577
  // `<AlternateScreen>` is skipped when the app is already fullscreen —
4263
5578
  // nesting it would emit a second DEC 1049, and its unmount would drop the
4264
5579
  // whole app back to the main screen.
4265
- if (sceneOpen) {
5580
+ if (sceneOpen && launchpadGate()) {
4266
5581
  const scene = _jsx(TrajectoryScene, { channel: channel, build: trajectory, onClose: closeScene });
4267
5582
  return fullscreen ? scene : _jsx(AlternateScreen, { children: scene });
4268
5583
  }
5584
+ /**
5585
+ * The launchpad — the landing page an ordinary launch starts on.
5586
+ *
5587
+ * 第七版渲染姿态:early-return 排在**所有整屏界面(会话浏览器 / 设置 /
5588
+ * 任务面板 / 家谱 / 子代理 / 轨迹场景)之后**——从落地页打开的整屏盖在
5589
+ * 落地页之上,Esc 退出整屏回到这里(草稿/参数/焦点原样保留)。硬约束:
5590
+ * 从启动页进入对话页的唯一路径是**提交一条非命令消息**(Enter 发送);
5591
+ * 任何 Esc/返回都回到启动页。参数行点开的选择器经 `pickerPanels` +
5592
+ * `inputPaused` 渲染在本屏之上,Esc 关掉它也回到这里。
5593
+ */
5594
+ if (launchpadShown) {
5595
+ // 参数行的「模式/权限」两段(第三版):模式看 channel.mode.plan;权限看
5596
+ // permissionPresets() 的当前身份——只认 runtime 名册,legacy/unavailable 与
5597
+ // 抛错都按「拿不到」处理(缺省不画那一段,两段都可选)。
5598
+ let launchpadPermission;
5599
+ try {
5600
+ const snapshot = channel.permissionPresets();
5601
+ launchpadPermission = snapshot.availability === 'runtime' ? snapshot.current?.name : undefined;
5602
+ }
5603
+ catch {
5604
+ launchpadPermission = undefined;
5605
+ }
5606
+ // 第七版动作表:状态快照全部来自既有数据源(详见 launchpadActions.ts)——
5607
+ // - lastSessionTitle = agentViewRows(含持久化名册)里最近一条非当前会话
5608
+ // 的标题——listing 是异步的,落地前没有 Continue、落地后自动长出来;
5609
+ // - jobsRunning / updateAvailable / starDue = 条件位三连(后台任务面 /
5610
+ // checkForTuiUpdate / usageStats 里程碑口径)。
5611
+ const resumableRows = agentViewRows
5612
+ .filter(row => !row.current && row.id !== channel.agentId && row.title.trim() !== '');
5613
+ const latestRow = resumableRows.reduce((best, row) => (best === undefined || row.updatedAt > best.updatedAt ? row : best), undefined);
5614
+ const launchpadActions = resolveLaunchpadActions({
5615
+ lastSessionTitle: latestRow?.title,
5616
+ // 条件位①:后台任务面是真数据(JobsPanel 同一个 channel.backgroundJobs),
5617
+ // running/stopping 都算「在跑」。
5618
+ jobsRunning: (channel.backgroundJobs ?? []).some(job => job.status === 'running' || job.status === 'stopping'),
5619
+ updateAvailable: launchpadUpdateAvailable,
5620
+ starDue: launchpadStarDue,
5621
+ // 内核入口带名(「内核 · Claude」):backendId 是内核身份的唯一来源。
5622
+ backendId: kernelCurrentId,
5623
+ });
5624
+ const launchpad = (_jsx(Launchpad, { query: launchpadDraft, cursorOffset: launchpadCaret, focusIndex: launchpadFocus, isTerminalFocused: terminalFocused, whale: channel.whale, whaleIdle: channel.whaleIdle, whaleGirl: channel.whaleGirl, fontId: splashFontIdOf(channel.splashFont), brand: brand, starred: starred, onStarClick: runStarAction, firstRun: onboardingPending, actions: launchpadActions,
5625
+ // 参数行四段点开的既有选择器(第五版):pickerPanels 与聊天页共用
5626
+ // 同一份 JSX,盖在落地页之上;选择器开着时落地页键盘让位(inputPaused)。
5627
+ overlayPanel: launchpadOverlayUp ? pickerPanels : undefined, inputPaused: launchpadOverlayUp, onParamPick: (segment) => {
5628
+ // 四段 → 既有命令:model→/model、effort→/effort、preset→/preset、
5629
+ // permission→/permission。全部在 overlayCommandNames 白名单里,
5630
+ // 落地页不收,选择器盖上来。
5631
+ // 第八版切换式(用户原话「点一下是展开 再点一下收起来」):**同一段**
5632
+ // 再点/再按 Enter = 收起(展开 ↔ 收起,键盘与鼠标同一条 onParamPick)。
5633
+ // 点另一段仍直接切换,点空白/Esc 仍收起(上一版契约不回退)。
5634
+ if (overlay.kind === segment) {
5635
+ dispatchOverlay({ type: 'close' });
5636
+ return;
5637
+ }
5638
+ // BUG 3(点另一段直接切换):/effort 的选择器是异步 open-if(when:
5639
+ // ['none']),盖着别的选择器时会被丢弃——这就是"点了没反应"的根因。
5640
+ // 先把屏上的参数选择器收掉再开新的,一个在屏、且就是点的那段。
5641
+ if (overlay.kind !== 'none') {
5642
+ dispatchOverlay({ type: 'close' });
5643
+ }
5644
+ void runCommand(segment, '');
5645
+ }, onQueryChange: (text, cursor) => {
5646
+ setLaunchpadDraft(text);
5647
+ setLaunchpadCaret(cursor);
5648
+ }, onSubmit: closeLaunchpad, onFocusChange: setLaunchpadFocus, onAction: (action) => {
5649
+ // 第八版(用户实测:「刚点帮助,不知道为什么直接进入聊天页面了」):
5650
+ // 帮助**不属于**离开启动页的两条路(Enter 发非命令消息 / 会话浏览
5651
+ // 里选中会话)——它盖在落地页之上(overlay kind 'help'),再点同一
5652
+ // 入口 = 收起(与参数段同一条切换语义)。
5653
+ if (action.command === 'help') {
5654
+ dispatchOverlay(overlay.kind === 'help'
5655
+ ? { type: 'close' }
5656
+ : { type: 'open', overlay: { kind: 'help' } });
5657
+ return;
5658
+ }
5659
+ // 第七版姿态:覆盖层命令(overlayCommandNames)盖在落地页之上;
5660
+ // **整屏命令**(launchpadScreenCommands:会话与工作区 / 设置 / 后台
5661
+ // 任务 / 家谱 / 子代理 / 引导)也盖在落地页之上——落地页不收,
5662
+ // Esc 退出整屏回到落地页(草稿/参数/焦点都在)。整屏要先过
5663
+ // launchpadGate 的授权位(防御:异步误置的整屏状态盖不走启动页)。
5664
+ // 其余命令(star / update——反馈在对话页的转录/通知)仍收掉落地页
5665
+ // 再执行,这是用户主动执行命令,不是「返回」。
5666
+ if (launchpadScreenCommands.has(action.command)) {
5667
+ authorizeLaunchpadCover();
5668
+ }
5669
+ else if (!overlayCommandNames.has(action.command)) {
5670
+ setLaunchpadOpen(false);
5671
+ }
5672
+ void runCommand(action.command, '');
5673
+ }, onEscape: (intent) => {
5674
+ if (intent === 'exit') {
5675
+ requestExit();
5676
+ return;
5677
+ }
5678
+ // 空输入按 Esc:这一屏的"下一步"通常是去挑工作区/会话。第七版:
5679
+ // 会话浏览器**盖在落地页之上**(落地页不收)——Esc 退出浏览器回到
5680
+ // 落地页,绝不落到对话页。这是从落地页出发的交互:过闸门授权。
5681
+ agentViewOpenSessionRef.current = channel.agentId;
5682
+ authorizeLaunchpadCover();
5683
+ setSupervisorOpen(true);
5684
+ }, onBlankClick: () => {
5685
+ // BUG 3(点别处关掉选择器):沿用"点空白收回焦点"的兜底路径——
5686
+ // 有参数选择器盖在落地页之上时,空白点击先把选择器收掉(焦点照旧
5687
+ // 收回输入框)。选择器内部的点击已被 Launchpad 的浮层包装拦住
5688
+ // 冒泡,不会走到这里。
5689
+ if (overlay.kind !== 'none')
5690
+ dispatchOverlay({ type: 'close' });
5691
+ setLaunchpadFocus(-1);
5692
+ }, model: channel.modelDisplay ?? channel.model, effort: channel.reasoningEffort, preset: channel.agentPreset === undefined
5693
+ ? undefined
5694
+ : presetOptions.find(option => option.id === channel.agentPreset)?.name ?? channel.agentPreset, permission: launchpadPermission, commands: launchpadOverlayUp || !launchpadDraft.startsWith('/')
5695
+ ? undefined
5696
+ : channel.commandCompletions(launchpadDraft), onCommandPick: (commandLine) => {
5697
+ // 补全面板选中(Enter/Tab/点击):走 runCommand,与快捷入口同一条
5698
+ // 白名单口径——覆盖层与整屏命令(第七版 launchpadScreenCommands)
5699
+ // 不收落地页(盖在它之上),其余收掉再执行。/help 与快捷入口同一条
5700
+ // 拦截:盖屏浮层,不进对话页(第八版)。
5701
+ const parsed = parseCommandName(commandLine);
5702
+ if (parsed === undefined)
5703
+ return;
5704
+ if (parsed.name === 'help') {
5705
+ dispatchOverlay({ type: 'open', overlay: { kind: 'help' } });
5706
+ return;
5707
+ }
5708
+ if (launchpadScreenCommands.has(parsed.name)) {
5709
+ authorizeLaunchpadCover();
5710
+ }
5711
+ else if (!overlayCommandNames.has(parsed.name)) {
5712
+ setLaunchpadOpen(false);
5713
+ }
5714
+ void runCommand(parsed.name, parsed.rawInput);
5715
+ }, cwd: channel.displayCwd, branch: channel.gitBranch, tuiVersion: tuiVersion,
5716
+ // 右下角的内核行:与选择器同一份目录,标出当前内核,点它打开选择器。
5717
+ kernels: kernelOptions, onKernelPick: () => openKernelPicker(),
5718
+ // 左下角工作目录铭牌(第七版):点开/回车开既有 /workspace 菜单——
5719
+ // workspace-menu 在 LAUNCHPAD_OVERLAY_KINDS 里,选择器盖在落地页之上,
5720
+ // Esc 回落地页(与参数行选择器同一姿态),不新造面板。
5721
+ onOpenWorkspace: () => { void runCommand('workspace', ''); } }));
5722
+ // 落地页这一屏的完整树(AC-4):Tooltip 单例层挂在**最外层最后**——与下面
5723
+ // 聊天主树末尾那处(SidePanelLayout 里)是同一个组件、同一条"单例层挂树尾"
5724
+ // 姿态;参数行被截断的段(ParamChip 写的锚点)hover 600ms 后由它画完整名。
5725
+ // 本屏没有滚动、也没有面板几何过渡 ⇒ 不需要 subscribeInvalidation;但**必须**给
5726
+ // invalidationKey:选择器是**盖在落地页之上**的浮层,落地页不卸载、指针也不一定
5727
+ // 离开被悬停的那一段,没有这个键时旧卡片会继续画在选择器上方(复核场景回归见
5728
+ // `verify-launchpad-onboarding-chat` 的 R4)。
5729
+ const node = (_jsxs(_Fragment, { children: [launchpad, _jsx(TooltipLayer, { invalidationKey: overlay.kind })] }));
5730
+ return fullscreen ? node : _jsx(AlternateScreen, { children: node });
5731
+ }
4269
5732
  // 浮层整体挂载条件:与内部各面板的可见条件同值(数据门在
4270
5733
  // dialogOverlayVisible 里逐面板镜像)。关闭时把整个 absolute 浮层从树里
4271
5734
  // 移除——渲染器的"移除 absolute 节点"检测只看被移除子树自身的
@@ -4276,6 +5739,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4276
5739
  workspaceTargetCount: workspaceTargets.length,
4277
5740
  effortOptionCount: effortOptions.length,
4278
5741
  presetOptionCount: presetOptions.length,
5742
+ panelCount: panelPickerRows.length,
4279
5743
  }) && !(overlay.kind === 'permission'
4280
5744
  && (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null));
4281
5745
  // The sticky header pins the turn owning the viewport top row once its
@@ -4298,8 +5762,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4298
5762
  // the transcript viewport height from the ScrollBox handle and the content
4299
5763
  // column width. The full-screen (editor-open) placement uses the terminal.
4300
5764
  const imagePreviewRegion = promptEditorOpen
4301
- ? { columns: terminalColumns, rows: terminalRows }
4302
- : { columns: terminalColumns, rows: handle?.getViewportHeight() ?? terminalRows };
5765
+ ? { columns: chatColumns, rows: terminalRows }
5766
+ : { columns: chatColumns, rows: handle?.getViewportHeight() ?? terminalRows };
4303
5767
  const imagePreviewNode = activePreview !== null && (activePreview.peek || imagePreviewOwned)
4304
5768
  ? (_jsx(ImagePreviewOverlay, { image: activePreview.image, title: activePreview.title, navigation: previewGallery.length > 1 && previewIndex >= 0 ? {
4305
5769
  index: previewIndex, total: previewGallery.length,
@@ -4308,253 +5772,128 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4308
5772
  ? () => setPeekSuppressed(peekKey(activePreview.image, activePreview.title))
4309
5773
  : () => dispatchOverlay({ type: 'close-if', kind: 'image-preview' }), region: imagePreviewRegion }))
4310
5774
  : null;
4311
- return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [!isSticky && timeline.activeId !== null && (_jsx(PinnedTurnHeader, { text: anchorUserText || null, onClick: () => {
4312
- // Click snaps the pinned prompt to the viewport top. Jump by the
4313
- // SAME content coordinate the
4314
- // rail's tick uses (timeline turn top = the prompt TEXT top):
4315
- // the element-based seek lands the row wrapper's margin at the
4316
- // top instead — one row shy of the text top the anchor rule
4317
- // compares against — and the header would flip to the previous
4318
- // turn immediately after the click.
4319
- const turn = timeline.turns.find(t => t.id === anchorUserRowId);
4320
- if (turn)
4321
- handle?.scrollTo(turn.top);
4322
- else if (anchorUserRowId !== null)
4323
- seekRow(anchorUserRowId);
4324
- else
4325
- handle?.scrollToBottom();
4326
- } })), _jsxs(Box, { flexDirection: "row", flexGrow: 1, flexShrink: 1, marginRight: -pageInsetX, children: [_jsxs(ScrollBox, { ref: setHandle, flexDirection: "column", flexGrow: 1, flexShrink: 1, stickyScroll: true, children: [_jsx(LogoHeader, { model: channel.model, effort: channel.reasoningEffort, cwd: channel.displayCwd,
4327
- // 大字字面(设置项 `dsh-tui.splashFont`):`daily` 交回按天轮换
4328
- // (`undefined`),其余 pin 住一款。
4329
- fontId: splashFontIdOf(channel.splashFont), whale: channel.whale, whaleIdle: channel.whaleIdle && whaleArtVisible, whaleGirl: channel.whaleGirl, starred: starred, onStarClick: runStarAction, working: channel.working,
4330
- // Resuming a long session skips the ~3.4s opening animation: it
4331
- // keeps firing low-frequency React commits that compete with the
4332
- // transcript mount batches (and the first wheel events) for the
4333
- // frame budget right when the user wants to read history. Fresh
4334
- // sessions keep the full intro; restored ones settle instantly.
4335
- // A remount after a whole screen closed also settles instantly
4336
- // (see suppressLogoIntroRef).
4337
- skipIntro: suppressLogoIntroRef.current || channel.rows.length > 30 }, logoNonce), loadedContextVisible && (_jsx(LoadedContextPanel, { context: channel.loadedContext, open: loadedContextOpen, onToggle: toggleLoadedContext })), _jsx(MessageList, { rows: channel.rows, failureHintRowId: failureHintRowId, failureHint: t('traj-hint-failure', { key: primaryComboString('trajectory') }), expanded: expanded, expandedRows: expandedRows, selectedId: selectionActive ? selectedId : null, onToggleRow: toggleRowExpanded, streamViewToggledRows: streamViewToggledRows, onToggleStreamView: toggleStreamView, model: channel.model, diffLayout: channel.diffLayout, thinkingFold: channel.thinkingFold, toolBackground: channel.toolBackground, foldTerminalCommand: channel.foldTerminalCommand, smoothStreaming: channel.smoothStreaming, activityFrames: channel.activityFrames, showAll: showAllMessages, thinkingVisible: thinkingVisible, historyPaintEnabled: !fullscreen, onToggleAll: () => { setShowAllMessages(previous => !previous); }, onLoadOlder: () => channel.loadOlder(), registerRowRef: registerRowRef, scrollHandle: handle, forceMountRowId: forceMountRowId, newSinceRowId: isSticky ? null : lastSeenRowIdRef.current, onUnseenCount: setUnseenCount, onTimeline: setTimeline, onOpenSubagent: setSubagentDetailId, onOpenJobs: openJobsPanel, onOpenFile: openFileActions, sessionCwd: channel.cwd, onPreviewImage: openImagePreview, suppressImageGraphics: activePreview !== null })] }), (() => {
4338
- // Gutter mode (settings `dsh-tui.scrollGutter`): the timeline
4339
- // rail (default), the proportional scrollbar, or nothing. The
4340
- // slot keeps its 2 columns in both rendered modes (Qwen's
4341
- // permanent-gutter rule — an appearing/disappearing gutter
4342
- // changes the transcript width and rewraps everything).
4343
- const gutter = normalizeScrollGutter(channel.scrollGutter);
4344
- if (gutter === 'hidden')
4345
- return null;
4346
- if (gutter === 'scrollbar') {
4347
- return _jsx(ScrollbarGutter, { handle: handle, terminalWidth: terminalColumns });
4348
- }
4349
- return (_jsx(TimelineRail, { handle: handle, turns: timeline.turns, activeId: timeline.activeId, upId: timeline.upId, downId: timeline.downId, terminalWidth: terminalColumns, hoverEnabled: !promptSelectionActive, onRevealTurn: revealAndSeekRow }));
4350
- })(), !promptEditorOpen && imagePreviewNode] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [showPill && (_jsx(NewMessagesPill, { count: unseenCount, onClick: () => handle?.scrollToBottom() })), channel.working &&
4351
- (activitySlot &&
4352
- workingActivity !== undefined &&
4353
- workingActivity.line !== '' &&
4354
- workingActivity.phase !== 'idle' ? (_jsx(Box, { marginTop: 1, children: _jsx(ActivityLine, { activity: workingActivity, activityFrames: channel.activityFrames, warnPct: activityWarnPct, warnDanger: activityWarnPct !== undefined && activityWarnPct >= 95,
4355
- // Upload = real tokens of the last request; download =
4356
- // the animated chars/4 estimate, matching the classic
4357
- // spinner's counter (the suffix used raw chars before,
4358
- // inflating the reading next to a real upload number). An
4359
- // automatic compaction mid-turn badges THIS line too — it is
4360
- // the spinner slot whenever real activity data exists.
4361
- suffix: `${lastUploadTokens > 0 ? ` · ↑ ${formatTokens(lastUploadTokens)}` : ''} · ↓ ${formatTokens(Math.round(channel.responseChars / 4))} tokens${compactionBadge === undefined ? '' : ` · ${compactionBadge}`}` }) })) : (_jsx(WorkingSpinner, { mode: channel.spinnerMode, hasActiveTools: channel.activeToolCount > 0, responseLengthRef: responseLengthRef, uploadTokensRef: uploadTokensRef, loadingStartTimeRef: loadingStartTimeRef, totalPausedMsRef: totalPausedMsRef, pauseStartTimeRef: pauseStartTimeRef, thinkingStatus: thinkingStatus, suffix: compactionBadge }))), !channel.working && channel.compaction !== undefined && (_jsx(CompactionStatusRow, { compaction: channel.compaction, activityPreset: activitySlot ? channel.activityFrames : undefined })), _jsx(GoalTodoPanel, { channel: channel, collapsed: todoCollapsed, onToggle: () => setTodoCollapsed(previous => !previous) }), recap !== null && recap.auto && !recap.expanded && (_jsx(AutoRecapRow, { summary: recap.summary, streaming: !recap.done, onExpand: () => setRecap(prev => (prev ? { ...prev, expanded: true } : prev)), onDismiss: () => closeRecap() })), balance !== null && (_jsx(BalanceReportRow, { result: balance.result, refreshing: balance.refreshing, tokens: channel.tokens, model: channel.model, provider: channel.provider, mainCost: channel.mainCost, subagentCost: channel.subagentCost, onRefresh: runBalance, onDismiss: () => setBalance(null) })), statusEntries.length > 0 && (_jsx(Text, { dimColor: true, wrap: "truncate", children: statusEntries.map(entry => entry.text).join(' · ') })), activePreview === null && statusViews.map(view => (_jsx(PluginStatusViewBoundary, { viewKey: view.key, onError: (key, error) => statusContributions.reportViewError(key, error), children: _jsx(Box, { flexDirection: "column", flexShrink: 0, maxHeight: view.maxRows, overflow: "hidden", children: _jsx(Box, { flexDirection: "column", flexShrink: 0, children: React.createElement(view.component, {
4362
- React,
4363
- ui: STATUS_VIEW_UI,
4364
- }) }) }) }, `${view.key}:${view.registrationId}`))), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [approvalPanelNode !== null ? (approvalPanelNode) : dialogSnapshot !== null ? (_jsx(ExtensionDialog, { dialog: dialogSnapshot, onDecide: value => dialogs.decide(dialogSnapshot.key, value), onCancel: () => dialogs.cancel(dialogSnapshot.key) }, dialogSnapshot.key)) : overlay.kind === 'tips' ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(TipsPanel, { onClose: () => dispatchOverlay({ type: 'close-if', kind: 'tips' }) }) })) : recap !== null && (!recap.auto || recap.expanded) ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(RecapPanel, { summary: recap.summary, title: recap.title, error: recap.error, streaming: !recap.done, titleApplied: recap.titleApplied, onClose: () => {
4365
- // An expanded auto recap collapses back to its dim row;
4366
- // a manual /recap closes outright.
4367
- if (recap.auto) {
4368
- setRecap(prev => (prev ? { ...prev, expanded: false } : prev));
4369
- }
4370
- else {
4371
- closeRecap();
4372
- }
4373
- }, onCopy: () => {
4374
- void setClipboard(recap.summary ?? '').then(raw => { if (raw)
4375
- writeRaw?.(raw); });
4376
- channel.notify(t('copied-chars', { n: (recap.summary ?? '').length }), { timeoutMs: 1500 });
4377
- }, onApplyTitle: () => {
4378
- if (recap.title === undefined || recap.titleApplied)
4379
- return;
4380
- channel.renameSession(recap.title);
4381
- setRecap(prev => (prev ? { ...prev, titleApplied: true } : prev));
4382
- channel.notify(t('recap-title-applied-notify', { title: recap.title }), { color: 'success' });
4383
- } }) })) : btw !== null ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(BtwPanel, { question: btw.question, answer: btw.answer, error: btw.error, streaming: !btw.done, onClose: closeBtw, onCopy: () => {
4384
- void setClipboard(btw.answer ?? '').then(raw => { if (raw)
4385
- writeRaw?.(raw); });
4386
- channel.notify(t('copied-chars', { n: (btw.answer ?? '').length }), { timeoutMs: 1500 });
4387
- } }) })) : questionPanelNode !== null ? (questionPanelNode) : null, _jsx(PromptInput, { channel: channel, suspended: promptReplacementOpen, draftCache: promptDraftRef.current, helpOpen: helpOpen, onToggleHelp: () => { setHelpOpen(previous => !previous); }, onRunCommand: runCommand, selectionActive: promptSelectionActive, fillText: historyFill, onFillConsumed: () => setHistoryFill(null), onRewindRequest: openRewind, onBackgroundRequest: backgroundToAgentView,
4388
- // The 🏠 at the head of the input row opens the same session screen
4389
- // `/resume` and `/agentview` open — one surface, three doors. It is
4390
- // gated on this prop rather than a setting, so hosts that mount the
4391
- // prompt without a session screen (and the layout regressions that
4392
- // pin the row's column budget) keep the row they had.
4393
- onOpenSessions: () => {
4394
- agentViewOpenSessionRef.current = channel.agentId;
4395
- setSupervisorOpen(true);
4396
- }, backgroundAgentsNeedingInput:
4397
- // Only the real channel supplies the seam; pre-agent-view test
4398
- // stubs must not grow the footer row (layout-dependent
4399
- // regressions pin the visible row count). The footer only
4400
- // renders while some session actually waits (N > 0): a
4401
- // permanent idle row would steal a transcript row on every
4402
- // real channel — one row is enough to scroll the startup
4403
- // header fully off a short terminal, pausing its viewport
4404
- // clock and shifting every row-count layout invariant.
4405
- channel.agentViewRows !== undefined && backgroundAgentsNeedingInput > 0
4406
- ? backgroundAgentsNeedingInput
4407
- : undefined, controllerRef: promptControllerRef, onCaretImage: handleCaretImage, caretPreviewOpen: peekPreview !== null, onDismissCaretPreview: dismissPeek }, "prompt-input"), _jsx(StatusLine, { channel: channel, activity: workingActivity, selectionActive: selectionActive, helpOpen: helpOpen, wake: wakeBand === undefined
4408
- ? undefined
4409
- : {
4410
- band: wakeBand,
4411
- hint: trajectorySeen ? undefined : primaryComboString('trajectory'),
4412
- tick: Math.floor(wakeTime / 120),
4413
- onOpen: openScene,
4414
- hoverHint: primaryComboString('trajectory'),
4415
- } }), dialogOverlayOpen && (_jsxs(OverlayAbove, { maxHeight: Math.max(terminalRows - 8, 1), children: [overlay.kind === 'thinking' && (_jsx(ThinkingToggle, { currentValue: thinkingVisible, focusIndex: overlay.focus, onPick: (index) => {
4416
- // 点击行 = 设焦点 + 应用(与 Enter 同一条路径)
4417
- const visible = index === 0;
4418
- setThinkingVisible(visible);
4419
- dispatchOverlay({ type: 'close' });
4420
- channel.notify(t('thinking-toggled', { state: visible ? t('thinking-on') : t('thinking-off') }));
4421
- } })), overlay.kind === 'workspace-picker' && workspaceTargets.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspacePicker, { targets: workspaceTargets, focusIndex: overlay.index, currentCwd: channel.cwd, onPick: (index) => {
4422
- // 点击行 = 切换该行目标(与 Enter 同一条路径)
4423
- const target = workspaceTargets[index];
4424
- dispatchOverlay({ type: 'close' });
4425
- if (target !== undefined)
4426
- void channel.switchWorkspace(target);
4427
- } }) })), overlay.kind === 'workspace-menu' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspaceMenuPicker, { options: workspaceMenuOptions, focusIndex: overlay.index, onPick: (index) => {
4428
- // 点击行 = 执行该行(与 Enter 同一条路径)
4429
- runWorkspaceMenuOption(workspaceMenuOptions[index]);
4430
- } }) })), overlay.kind === 'workspace-flow' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspaceFlowPicker, { title: overlay.flow.title, choices: overlay.flow.choices, focusIndex: overlay.index, busy: overlay.busy, input: overlay.input, onPick: (index) => {
4431
- // 点击行 = 设焦点 + 执行分支(与 Enter 同一条路径);
4432
- // busy/输入态在组件侧禁点
4433
- const choice = overlay.flow.choices[index];
4434
- if (choice === undefined)
4435
- return;
4436
- dispatchOverlay({ type: 'set-index', kind: 'workspace-flow', index });
4437
- runWorkspaceFlowAction(signal => choice.choose(signal));
4438
- } }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: models.length === 0 ? (_jsx(ModelPickerLoading, {})) : activeModelGroup === undefined ? (_jsx(ModelPicker, { groups: modelGroups, focusIndex: overlay.index, currentProvider: channel.provider, onPick: (index) => {
4439
- // 点击分组行 = 进入该组(与 Enter 同一条路径)
4440
- const group = modelGroups[index];
4441
- if (!group)
4442
- return;
4443
- setModelGroup(group.provider);
4444
- if (group.provider === RECENTS_GROUP_PROVIDER) {
4445
- dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
4446
- return;
4447
- }
4448
- const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
4449
- dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
4450
- } })) : (_jsx(ModelPicker, { models: groupModels, groupLabel: activeModelGroup === RECENTS_GROUP_PROVIDER
4451
- ? t('picker-group-recent')
4452
- : modelGroups.find(group => group.provider === activeModelGroup)?.label, showBack: modelGroups.length > 1 && !modelPickerDirect, showProviderPrefix: activeModelGroup === RECENTS_GROUP_PROVIDER, focusIndex: overlay.index, currentModel: `${channel.provider}/${channel.model}`, onPick: (index) => {
4453
- // 点击行 = 应用该行模型(与 Enter 同一条路径)
4454
- const model = groupModels[index];
4455
- if (!model)
4456
- return;
4457
- dispatchOverlay({ type: 'close' });
4458
- void switchModelRecorded(model.provider, model.id, model.name);
4459
- } })) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
4460
- const row = (migrateRows ?? [])[index];
4461
- if (!row)
4462
- return;
4463
- setMigrateChecked(current => {
4464
- const next = new Set(current);
4465
- if (next.has(row.agentId))
4466
- next.delete(row.agentId);
4467
- else
4468
- next.add(row.agentId);
4469
- return next;
4470
- });
4471
- } }) })), overlay.kind === 'migrate-confirm' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigrateConfirm, { rows: migratePending }) })), overlay.kind === 'skills' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: skillsList === null ? (_jsx(SkillsPickerLoading, {})) : (_jsx(SkillsPicker, { skills: skillsList, focusIndex: overlay.index, onPick: (index) => {
4472
- const skill = skillsList[index];
4473
- if (!skill)
4474
- return;
4475
- dispatchOverlay({ type: 'close' });
4476
- if (skill.userInvocable)
4477
- setHistoryFill(`/${skill.name} `);
4478
- } })) })), overlay.kind === 'activity' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ActivityPicker, { focusIndex: overlay.index, currentPreset: channel.activityFrames, onPick: (index) => {
4479
- dispatchOverlay({ type: 'close' });
4480
- const name = PRESET_NAMES[index];
4481
- if (name)
4482
- channel.setActivityFrames(name);
4483
- } }) })), overlay.kind === 'color' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ColorPicker, { focusIndex: overlay.index, currentColor: channel.sessionColor, onPick: (index) => {
4484
- dispatchOverlay({ type: 'close' });
4485
- const name = SESSION_COLOR_NAMES[index];
4486
- if (name) {
4487
- channel.setSessionColor(name);
4488
- channel.notify(t('color-set', { name }), { color: 'success' });
4489
- }
4490
- } }) })), overlay.kind === 'effort' && effortOptions.length > 1 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(EffortSlider, { options: effortOptions, focusIndex: overlay.index, currentId: channel.reasoningEffort,
4491
- // 点击档位 = 移到该档并即时应用(与 ←/→ 同语义)
4492
- onPick: (index) => {
4493
- dispatchOverlay({ type: 'set-index', kind: 'effort', index });
4494
- const option = effortOptions[index];
4495
- if (option)
4496
- void channel.setEffort(option.id);
4497
- } }) })), overlay.kind === 'preset' && presetOptions.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PresetPicker, { presets: presetOptions, focusIndex: overlay.index, currentPreset: channel.agentPreset, onPick: (index) => {
4498
- dispatchOverlay({ type: 'close' });
4499
- const option = presetOptions[index];
4500
- if (option)
4501
- void channel.switchPreset(option.id);
4502
- } }) })), overlay.kind === 'permission' && overlay.snapshot.options.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PermissionsPicker, { options: overlay.snapshot.options, focusIndex: overlay.index, currentValue: overlay.snapshot.current?.value, cwd: channel.cwd, onPick: (index) => {
4503
- if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
4504
- return;
4505
- const option = overlay.snapshot.options[index];
4506
- dispatchOverlay({ type: 'close' });
4507
- if (option !== undefined)
4508
- void runPermissionCommand(` ${option.value}`);
4509
- } }) })), overlay.kind === 'plan' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PlanPicker, { focusIndex: overlay.index, currentOn: channel.mode.plan === true, onPick: (index) => {
4510
- dispatchOverlay({ type: 'close' });
4511
- const on = index === 0;
4512
- void runExternalCommand('plan', on ? '' : ' off');
4513
- } }) })), overlay.kind === 'lang' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(LangPicker, { focusIndex: overlay.index, currentLang: getLang(), onPick: (index) => {
4514
- const lang = LANGS[index];
4515
- if (lang === undefined)
4516
- return;
4517
- dispatchOverlay({ type: 'close' });
4518
- applyLang(lang);
4519
- } }) })), overlay.kind === 'theme' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ThemePicker, { focusIndex: overlay.index, currentTheme: themeName, themeHost: themeHost, onPick: (index) => {
4520
- dispatchOverlay({ type: 'close' });
4521
- const name = getThemeOptions(themeHost)[index]?.value;
4522
- if (name !== undefined) {
4523
- const ok = setTheme(name);
4524
- channel.notify(ok ? t('theme-switched-saved', { name }) : t('theme-switch-failed', { name }), { color: ok ? 'success' : 'error' });
5775
+ return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [_jsxs(SidePanelLayout, { geometry: sidePanel.geometry, focus: sidePanel.focus, onActivateChat: sidePanel.focusChat, onActivatePanel: sidePanel.focusPanel, side: _jsx(SidePanelColumn, { width: sidePanel.panelColumns, controller: sidePanel, channel: channel, activity: workingActivity, attention: {
5776
+ approvals: approvalSnapshot !== null ? 1 : 0,
5777
+ questions: questionSnapshot !== null ? 1 : 0,
5778
+ }, trajectory: trajectory, onExpand: openPanelFullscreen }), children: [!isSticky && timeline.activeId !== null && (_jsx(PinnedTurnHeader, { text: anchorUserText || null, onClick: () => {
5779
+ // Click snaps the pinned prompt to the viewport top. Jump by the
5780
+ // SAME content coordinate the
5781
+ // rail's tick uses (timeline turn top = the prompt TEXT top):
5782
+ // the element-based seek lands the row wrapper's margin at the
5783
+ // top instead — one row shy of the text top the anchor rule
5784
+ // compares against — and the header would flip to the previous
5785
+ // turn immediately after the click.
5786
+ const turn = timeline.turns.find(t => t.id === anchorUserRowId);
5787
+ if (turn)
5788
+ handle?.scrollTo(turn.top);
5789
+ else if (anchorUserRowId !== null)
5790
+ seekRow(anchorUserRowId);
5791
+ else
5792
+ handle?.scrollToBottom();
5793
+ } })), _jsxs(Box, { flexDirection: "row", flexGrow: 1, flexShrink: 1, marginRight: sidePanel.split ? 0 : -pageInsetX, children: [_jsxs(ScrollBox, { ref: setHandle, flexDirection: "column", flexGrow: 1, flexShrink: 1, stickyScroll: true, children: [_jsx(LogoHeader, { model: channel.modelDisplay ?? channel.model, effort: channel.reasoningEffort, cwd: channel.displayCwd,
5794
+ // 大字字面(设置项 `dsh-tui.splashFont`):`daily` 交回按天轮换
5795
+ // (`undefined`),其余 pin 住一款。
5796
+ fontId: splashFontIdOf(channel.splashFont), whale: channel.whale, whaleIdle: channel.whaleIdle && whaleArtVisible, whaleGirl: channel.whaleGirl, brand: brand, starred: starred, onStarClick: runStarAction, working: channel.working,
5797
+ // Resuming a long session skips the ~3.4s opening animation: it
5798
+ // keeps firing low-frequency React commits that compete with the
5799
+ // transcript mount batches (and the first wheel events) for the
5800
+ // frame budget right when the user wants to read history. Fresh
5801
+ // sessions keep the full intro; restored ones settle instantly.
5802
+ // A remount after a whole screen closed also settles instantly
5803
+ // (see suppressLogoIntroRef).
5804
+ skipIntro: suppressLogoIntroRef.current || channel.rows.length > 30 }, logoNonce), loadedContextVisible && (_jsx(LoadedContextPanel, { context: channel.loadedContext, open: loadedContextOpen, onToggle: toggleLoadedContext })), _jsx(MessageList, { rows: channel.rows, failureHintRowId: failureHintRowId, failureHint: t('traj-hint-failure', { key: primaryComboString('trajectory') }), expanded: expanded, expandedRows: expandedRows, selectedId: selectionActive ? selectedId : null, onToggleRow: toggleRowExpanded, streamViewToggledRows: streamViewToggledRows, onToggleStreamView: toggleStreamView, model: channel.modelDisplay ?? channel.model, diffLayout: channel.diffLayout, thinkingFold: channel.thinkingFold, jobGroupFold: channel.jobGroupFold, toolBackground: channel.toolBackground, foldTerminalCommand: channel.foldTerminalCommand, turnUsageRow: channel.turnUsageRow, smoothStreaming: channel.smoothStreaming, activityFrames: channel.activityFrames, showAll: showAllMessages, thinkingVisible: thinkingVisible, historyPaintEnabled: !fullscreen, fullscreen: fullscreen, onToggleAll: () => { setShowAllMessages(previous => !previous); }, onLoadOlder: () => channel.loadOlder(), registerRowRef: registerRowRef, scrollHandle: handle, forceMountRowId: forceMountRowId, newSinceRowId: isSticky ? null : lastSeenRowIdRef.current, onUnseenCount: setUnseenCount, onTimeline: setTimeline, onOpenSubagent: setSubagentDetailId, onOpenSubagentView: openSubagentViewFromCard, onOpenJobs: openJobsPanel, onOpenFile: openFileActions, sessionCwd: channel.cwd, onPreviewImage: openImagePreview, suppressImageGraphics: activePreview !== null, olderHistory: channel.olderHistory, onWatchJobOutput: watchJobOutput })] }), (() => {
5805
+ // Gutter mode (settings `dsh-tui.scrollGutter`): the timeline
5806
+ // rail (default), the proportional scrollbar, or nothing. The
5807
+ // slot keeps its 2 columns in both rendered modes (Qwen's
5808
+ // permanent-gutter rule — an appearing/disappearing gutter
5809
+ // changes the transcript width and rewraps everything).
5810
+ const gutter = normalizeScrollGutter(channel.scrollGutter);
5811
+ if (gutter === 'hidden')
5812
+ return null;
5813
+ if (gutter === 'scrollbar') {
5814
+ return _jsx(ScrollbarGutter, { handle: handle, terminalWidth: chatColumns });
5815
+ }
5816
+ return (_jsx(TimelineRail, { handle: handle, turns: timeline.turns, activeId: timeline.activeId, upId: timeline.upId, downId: timeline.downId, terminalWidth: chatColumns, hoverEnabled: !promptSelectionActive, onRevealTurn: revealAndSeekRow }));
5817
+ })(), !promptEditorOpen && imagePreviewNode] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [showPill && (_jsx(NewMessagesPill, { count: unseenCount, onClick: () => handle?.scrollToBottom() })), channel.working &&
5818
+ (activitySlot &&
5819
+ workingActivity !== undefined &&
5820
+ workingActivity.line !== '' &&
5821
+ workingActivity.phase !== 'idle' ? (_jsx(Box, { marginTop: 1, children: _jsx(ActivityLine, { activity: workingActivity, activityFrames: channel.activityFrames, warnPct: activityWarnPct, warnDanger: activityWarnPct !== undefined && activityWarnPct >= 95,
5822
+ // Upload = real tokens of the last request; download =
5823
+ // the animated chars/4 estimate, matching the classic
5824
+ // spinner's counter (the suffix used raw chars before,
5825
+ // inflating the reading next to a real upload number). An
5826
+ // automatic compaction mid-turn badges THIS line too — it is
5827
+ // the spinner slot whenever real activity data exists.
5828
+ suffix: `${lastUploadTokens > 0 ? ` · ↑ ${formatTokens(lastUploadTokens)}` : ''} · ↓ ${formatTokens(Math.round(channel.responseChars / 4))} tokens${compactionBadge === undefined ? '' : ` · ${compactionBadge}`}` }) })) : (_jsx(WorkingSpinner, { mode: channel.spinnerMode, hasActiveTools: channel.activeToolCount > 0, responseLengthRef: responseLengthRef, uploadTokensRef: uploadTokensRef, loadingStartTimeRef: loadingStartTimeRef, totalPausedMsRef: totalPausedMsRef, pauseStartTimeRef: pauseStartTimeRef, thinkingStatus: thinkingStatus, suffix: compactionBadge }))), !channel.working && channel.compaction !== undefined && (_jsx(CompactionStatusRow, { compaction: channel.compaction, activityPreset: activitySlot ? channel.activityFrames : undefined })), !(sidePanel.split && sidePanel.enabledPanelIds.includes('todo')) && (_jsx(GoalTodoPanel, { channel: channel, collapsed: todoCollapsed, onToggle: () => setTodoCollapsed(previous => !previous) })), recap !== null && recap.auto && !recap.expanded && (_jsx(AutoRecapRow, { summary: recap.summary, streaming: !recap.done, onExpand: () => setRecap(prev => (prev ? { ...prev, expanded: true } : prev)), onDismiss: () => closeRecap() })), balance !== null && (_jsx(BalanceReportRow, { result: balance.result, refreshing: balance.refreshing, tokens: channel.tokens, model: channel.modelDisplay ?? channel.model, provider: channel.provider, mainCost: channel.mainCost, subagentCost: channel.subagentCost, onRefresh: runBalance, onDismiss: () => setBalance(null) })), statusEntries.length > 0 && (_jsx(Text, { dimColor: true, wrap: "truncate", children: statusEntries.map(entry => entry.text).join(' · ') })), activePreview === null && statusViews.map(view => (_jsx(PluginStatusViewBoundary, { viewKey: view.key, onError: (key, error) => statusContributions.reportViewError(key, error), children: _jsx(Box, { flexDirection: "column", flexShrink: 0, maxHeight: view.maxRows, overflow: "hidden", children: _jsx(Box, { flexDirection: "column", flexShrink: 0, children: React.createElement(view.component, {
5829
+ React,
5830
+ ui: STATUS_VIEW_UI,
5831
+ }) }) }) }, `${view.key}:${view.registrationId}`))), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [approvalPanelNode !== null ? (approvalPanelNode) : dialogSnapshot !== null ? (_jsx(ExtensionDialog, { dialog: dialogSnapshot, onDecide: value => dialogs.decide(dialogSnapshot.key, value), onCancel: () => dialogs.cancel(dialogSnapshot.key) }, dialogSnapshot.key)) : overlay.kind === 'tips' ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(TipsPanel, { onClose: () => dispatchOverlay({ type: 'close-if', kind: 'tips' }) }) })) : recap !== null && (!recap.auto || recap.expanded) ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(RecapPanel, { summary: recap.summary, title: recap.title, error: recap.error, streaming: !recap.done, titleApplied: recap.titleApplied, onClose: () => {
5832
+ // An expanded auto recap collapses back to its dim row;
5833
+ // a manual /recap closes outright.
5834
+ if (recap.auto) {
5835
+ setRecap(prev => (prev ? { ...prev, expanded: false } : prev));
4525
5836
  }
4526
- } }) })), overlay.kind === 'history' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(HistorySearchDialog, { query: overlay.query, cursorOffset: overlay.cursor, matches: historyMatches, focusIndex: overlay.focus, onPick: (index) => {
4527
- // 点击行 = 填入该历史命令(与 Enter 同路径)
4528
- const entry = historyMatches[index];
4529
- if (entry) {
4530
- setHistoryFill(entry.text);
4531
- dispatchOverlay({ type: 'close' });
5837
+ else {
5838
+ closeRecap();
4532
5839
  }
4533
- } }) })), overlay.kind === 'rewind' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(RewindPicker, { rows: rewindRows, focusIndex: overlay.index, confirmRow: overlay.confirm, modes: overlay.modes, modeIndex: overlay.modeIndex, busy: overlay.busy, onPickRow: (index) => {
4534
- // 列表页点击只选中:进入确认态保留键盘 Enter 显式触发
4535
- dispatchOverlay({ type: 'set-index', kind: 'rewind', index });
4536
- }, onConfirm: () => {
4537
- // 确认页即显式确认层,点击直接执行(与 Enter 同路径)
4538
- const row = overlay.confirm;
4539
- if (row === null)
4540
- return;
4541
- dispatchOverlay({ type: 'close' });
4542
- void performRewind(row);
4543
- }, onPickMode: (index) => {
4544
- // 模式列表点击直接执行该模式(与 Enter 同路径)
4545
- const row = overlay.confirm;
4546
- if (row === null)
5840
+ }, onCopy: () => {
5841
+ void setClipboard(recap.summary ?? '').then(raw => { if (raw)
5842
+ writeRaw?.(raw); });
5843
+ channel.notify(t('copied-chars', { n: (recap.summary ?? '').length }), { timeoutMs: 1500 });
5844
+ }, onApplyTitle: () => {
5845
+ if (recap.title === undefined || recap.titleApplied)
4547
5846
  return;
4548
- // 模式页仅当 modes 非空才渲染,这里空安全取值
4549
- const mode = index === 0 ? null : (overlay.modes?.[index - 1]?.id ?? null);
4550
- dispatchOverlay({ type: 'close' });
4551
- void performRewind(row, mode);
4552
- } }) })), overlay.kind === 'file-actions' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(FileActionsPanel, { path: overlay.path, isDir: overlay.isDir, focusIndex: overlay.index, onPick: (index) => {
4553
- // 点击行直接执行该动作(与 Enter 同路径)
4554
- const path = overlay.path;
4555
- dispatchOverlay({ type: 'close' });
4556
- runFileAction(index, path);
4557
- } }) })), overlay.kind === 'search' && _jsx(TranscriptSearch, { query: searchQuery, cursorOffset: searchCursor, count: searchCount, current: searchCurrent })] }))] })] }), _jsx(TooltipLayer, { invalidationKey: `${overlay.kind}:${dialogOverlayOpen}:${btw !== null}`, subscribeInvalidation: subscribeTooltipInvalidation }), _jsx(PromptEditorLayer, {}), promptEditorOpen && imagePreviewNode, starModal !== null && STAR_MILESTONES[starModal.index] !== undefined && (_jsx(StarPrompt, { milestone: STAR_MILESTONES[starModal.index], actions: starModalActions, onClose: closeStarModal, initialPhase: starModal.phase })), couponVisible && coupon !== null && (_jsx(WhaleCouponPrompt, { notice: coupon, onShown: markCouponShown, onClose: closeCoupon }))] }));
5847
+ channel.renameSession(recap.title);
5848
+ setRecap(prev => (prev ? { ...prev, titleApplied: true } : prev));
5849
+ channel.notify(t('recap-title-applied-notify', { title: recap.title }), { color: 'success' });
5850
+ } }) })) : btwOverlayOpen && !sidePanel.enabledPanelIds.includes('btw') ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(BtwPanelFallback, { thread: btwOverlayThread, onClose: closeBtwOverlay, onCopy: answer => {
5851
+ void setClipboard(answer).then(raw => { if (raw)
5852
+ writeRaw?.(raw); });
5853
+ channel.notify(t('copied-chars', { n: answer.length }), { timeoutMs: 1500 });
5854
+ } }) })) : questionPanelNode !== null ? (questionPanelNode) : null, _jsx(PromptInput, { channel: channel, suspended: promptReplacementOpen,
5855
+ // 宠物面板是活动面板时,通知由它的头顶气泡「说出来」,输入框上方
5856
+ // 不再重复弹同一条(error 色除外——可能要行动的信号永远走 toast)。
5857
+ // 渲染期判定(split + activePanelId),与气泡同一次提交切换,不会
5858
+ // 先闪一帧 toast 再消失。
5859
+ toastSuppressed: petSaysNotices, draftCache: promptDraftRef.current, helpOpen: helpOpen, onToggleHelp: () => { setHelpOpen(previous => !previous); }, onRunCommand: runCommand, selectionActive: promptSelectionActive, fillText: historyFill, onFillConsumed: () => setHistoryFill(null), onRewindRequest: openRewind, onBackgroundRequest: backgroundToAgentView,
5860
+ // The 🏠 at the head of the input row opens the same session screen
5861
+ // `/resume` and `/agentview` open — one surface, three doors. It is
5862
+ // gated on this prop rather than a setting, so hosts that mount the
5863
+ // prompt without a session screen (and the layout regressions that
5864
+ // pin the row's column budget) keep the row they had.
5865
+ onOpenSessions: () => {
5866
+ agentViewOpenSessionRef.current = channel.agentId;
5867
+ setSupervisorOpen(true);
5868
+ }, backgroundAgentsNeedingInput:
5869
+ // Only the real channel supplies the seam; pre-agent-view test
5870
+ // stubs must not grow the footer row (layout-dependent
5871
+ // regressions pin the visible row count). The footer only
5872
+ // renders while some session actually waits (N > 0): a
5873
+ // permanent idle row would steal a transcript row on every
5874
+ // real channel — one row is enough to scroll the startup
5875
+ // header fully off a short terminal, pausing its viewport
5876
+ // clock and shifting every row-count layout invariant.
5877
+ channel.agentViewRows !== undefined && backgroundAgentsNeedingInput > 0
5878
+ ? backgroundAgentsNeedingInput
5879
+ : undefined, controllerRef: promptControllerRef, onCaretImage: handleCaretImage, caretPreviewOpen: peekPreview !== null, onDismissCaretPreview: dismissPeek }, "prompt-input"), _jsx(StatusLine, { channel: channel, activity: workingActivity, selectionActive: selectionActive, helpOpen: helpOpen,
5880
+ // Backend-native permission modes: the footer mode segment always
5881
+ // shows (the base mode included) and clicks into the same
5882
+ // /permission picker the command opens (the launchpad param row's
5883
+ // route). DSH answers an empty list here — no prop, byte-identical
5884
+ // rendering.
5885
+ backendMode: backendModeStatus,
5886
+ // 模型段/思考档位段:能力位在才可点,点击走既有 /model · /effort
5887
+ // 命令(与模式段打开 /permission 完全同构)。
5888
+ modelPicker: modelPickerStatus, effortPicker: effortPickerStatus, wake: wakeBand === undefined
5889
+ ? undefined
5890
+ : {
5891
+ band: wakeBand,
5892
+ hint: trajectorySeen ? undefined : primaryComboString('trajectory'),
5893
+ tick: Math.floor(wakeTime / 120),
5894
+ onOpen: openScene,
5895
+ hoverHint: primaryComboString('trajectory'),
5896
+ } }), dialogOverlayOpen && (_jsx(OverlayAbove, { maxHeight: Math.max(terminalRows - 8, 1), children: pickerPanels }))] })] }), _jsx(TooltipLayer, { invalidationKey: `${overlay.kind}:${dialogOverlayOpen}:${btwOverlayOpen}`, subscribeInvalidation: subscribeTooltipInvalidation })] }), _jsx(PromptEditorLayer, {}), promptEditorOpen && imagePreviewNode, starModal !== null && STAR_MILESTONES[starModal.index] !== undefined && (_jsx(StarPrompt, { milestone: STAR_MILESTONES[starModal.index], actions: starModalActions, onClose: closeStarModal, initialPhase: starModal.phase })), couponVisible && coupon !== null && (_jsx(WhaleCouponPrompt, { notice: coupon, onShown: markCouponShown, onClose: closeCoupon }))] }));
4558
5897
  }
4559
5898
  /**
4560
5899
  * The pinned prompt header shown above the ScrollBox while the user has