@flanksource/clicky-ui 0.3.46 → 0.3.47

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 (379) hide show
  1. package/NOTICE.md +11 -0
  2. package/dist/ai.cjs +13 -8
  3. package/dist/ai.cjs.map +1 -1
  4. package/dist/ai.js +7 -2
  5. package/dist/ai.js.map +1 -1
  6. package/dist/components/ErrorWrapper.cjs +2 -3
  7. package/dist/components/ErrorWrapper.cjs.map +1 -1
  8. package/dist/components/ErrorWrapper.d.ts.map +1 -1
  9. package/dist/components/ErrorWrapper.js +3 -4
  10. package/dist/components/ErrorWrapper.js.map +1 -1
  11. package/dist/data/Clicky.cjs +3 -0
  12. package/dist/data/Clicky.cjs.map +1 -1
  13. package/dist/data/Clicky.js +3 -0
  14. package/dist/data/Clicky.js.map +1 -1
  15. package/dist/data/FilterPill.cjs +15 -2
  16. package/dist/data/FilterPill.cjs.map +1 -1
  17. package/dist/data/FilterPill.d.ts +1 -1
  18. package/dist/data/FilterPill.d.ts.map +1 -1
  19. package/dist/data/FilterPill.js +15 -2
  20. package/dist/data/FilterPill.js.map +1 -1
  21. package/dist/data/LogViewer.cjs +27 -8
  22. package/dist/data/LogViewer.cjs.map +1 -1
  23. package/dist/data/LogViewer.d.ts +11 -3
  24. package/dist/data/LogViewer.d.ts.map +1 -1
  25. package/dist/data/LogViewer.js +27 -8
  26. package/dist/data/LogViewer.js.map +1 -1
  27. package/dist/data/Properties.cjs +2 -15
  28. package/dist/data/Properties.cjs.map +1 -1
  29. package/dist/data/Properties.d.ts +4 -0
  30. package/dist/data/Properties.d.ts.map +1 -1
  31. package/dist/data/Properties.js +2 -15
  32. package/dist/data/Properties.js.map +1 -1
  33. package/dist/data/PropertyValue.cjs +37 -0
  34. package/dist/data/PropertyValue.cjs.map +1 -0
  35. package/dist/data/PropertyValue.d.ts +6 -0
  36. package/dist/data/PropertyValue.d.ts.map +1 -0
  37. package/dist/data/PropertyValue.js +37 -0
  38. package/dist/data/PropertyValue.js.map +1 -0
  39. package/dist/data/Tree.cjs +4 -3
  40. package/dist/data/Tree.cjs.map +1 -1
  41. package/dist/data/Tree.d.ts +3 -1
  42. package/dist/data/Tree.d.ts.map +1 -1
  43. package/dist/data/Tree.js +4 -3
  44. package/dist/data/Tree.js.map +1 -1
  45. package/dist/data/ai/ChatFab.cjs +1 -1
  46. package/dist/data/ai/ChatFab.cjs.map +1 -1
  47. package/dist/data/ai/ChatFab.js +1 -1
  48. package/dist/data/ai/ChatFab.js.map +1 -1
  49. package/dist/data/ai/ChatWindow.cjs +106 -171
  50. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  51. package/dist/data/ai/ChatWindow.d.ts +6 -2
  52. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  53. package/dist/data/ai/ChatWindow.header.cjs +104 -0
  54. package/dist/data/ai/ChatWindow.header.cjs.map +1 -0
  55. package/dist/data/ai/ChatWindow.header.d.ts +29 -0
  56. package/dist/data/ai/ChatWindow.header.d.ts.map +1 -0
  57. package/dist/data/ai/ChatWindow.header.js +104 -0
  58. package/dist/data/ai/ChatWindow.header.js.map +1 -0
  59. package/dist/data/ai/ChatWindow.js +107 -172
  60. package/dist/data/ai/ChatWindow.js.map +1 -1
  61. package/dist/data/ai/ChatWindow.placement.cjs +95 -0
  62. package/dist/data/ai/ChatWindow.placement.cjs.map +1 -0
  63. package/dist/data/ai/ChatWindow.placement.d.ts +32 -0
  64. package/dist/data/ai/ChatWindow.placement.d.ts.map +1 -0
  65. package/dist/data/ai/ChatWindow.placement.js +95 -0
  66. package/dist/data/ai/ChatWindow.placement.js.map +1 -0
  67. package/dist/data/ai/SessionChatComposer.cjs +3 -1
  68. package/dist/data/ai/SessionChatComposer.cjs.map +1 -1
  69. package/dist/data/ai/SessionChatComposer.d.ts +4 -1
  70. package/dist/data/ai/SessionChatComposer.d.ts.map +1 -1
  71. package/dist/data/ai/SessionChatComposer.js +3 -1
  72. package/dist/data/ai/SessionChatComposer.js.map +1 -1
  73. package/dist/data/ai/SessionInspector.cjs +68 -72
  74. package/dist/data/ai/SessionInspector.cjs.map +1 -1
  75. package/dist/data/ai/SessionInspector.composer-slot.cjs +8 -0
  76. package/dist/data/ai/SessionInspector.composer-slot.cjs.map +1 -0
  77. package/dist/data/ai/SessionInspector.composer-slot.d.ts +9 -0
  78. package/dist/data/ai/SessionInspector.composer-slot.d.ts.map +1 -0
  79. package/dist/data/ai/SessionInspector.composer-slot.js +8 -0
  80. package/dist/data/ai/SessionInspector.composer-slot.js.map +1 -0
  81. package/dist/data/ai/SessionInspector.d.ts +6 -1
  82. package/dist/data/ai/SessionInspector.d.ts.map +1 -1
  83. package/dist/data/ai/SessionInspector.js +69 -73
  84. package/dist/data/ai/SessionInspector.js.map +1 -1
  85. package/dist/data/ai/SessionInspector.legacy.cjs +41 -42
  86. package/dist/data/ai/SessionInspector.legacy.cjs.map +1 -1
  87. package/dist/data/ai/SessionInspector.legacy.d.ts.map +1 -1
  88. package/dist/data/ai/SessionInspector.legacy.js +41 -42
  89. package/dist/data/ai/SessionInspector.legacy.js.map +1 -1
  90. package/dist/data/ai/SessionInspector.remote-view.cjs +14 -9
  91. package/dist/data/ai/SessionInspector.remote-view.cjs.map +1 -1
  92. package/dist/data/ai/SessionInspector.remote-view.d.ts +6 -2
  93. package/dist/data/ai/SessionInspector.remote-view.d.ts.map +1 -1
  94. package/dist/data/ai/SessionInspector.remote-view.js +14 -9
  95. package/dist/data/ai/SessionInspector.remote-view.js.map +1 -1
  96. package/dist/data/ai/SessionInspector.remote.cjs +84 -16
  97. package/dist/data/ai/SessionInspector.remote.cjs.map +1 -1
  98. package/dist/data/ai/SessionInspector.remote.d.ts +42 -7
  99. package/dist/data/ai/SessionInspector.remote.d.ts.map +1 -1
  100. package/dist/data/ai/SessionInspector.remote.js +86 -18
  101. package/dist/data/ai/SessionInspector.remote.js.map +1 -1
  102. package/dist/data/ai/SessionInspector.transcript.cjs +5 -0
  103. package/dist/data/ai/SessionInspector.transcript.cjs.map +1 -1
  104. package/dist/data/ai/SessionInspector.transcript.d.ts.map +1 -1
  105. package/dist/data/ai/SessionInspector.transcript.js +5 -0
  106. package/dist/data/ai/SessionInspector.transcript.js.map +1 -1
  107. package/dist/data/ai/SessionTail.cjs +63 -0
  108. package/dist/data/ai/SessionTail.cjs.map +1 -0
  109. package/dist/data/ai/SessionTail.d.ts +14 -0
  110. package/dist/data/ai/SessionTail.d.ts.map +1 -0
  111. package/dist/data/ai/SessionTail.js +63 -0
  112. package/dist/data/ai/SessionTail.js.map +1 -0
  113. package/dist/data/ai/SessionViewer.cjs +10 -3
  114. package/dist/data/ai/SessionViewer.cjs.map +1 -1
  115. package/dist/data/ai/SessionViewer.d.ts +7 -1
  116. package/dist/data/ai/SessionViewer.d.ts.map +1 -1
  117. package/dist/data/ai/SessionViewer.js +10 -3
  118. package/dist/data/ai/SessionViewer.js.map +1 -1
  119. package/dist/data/ai/SessionViewer.unified.d.ts +14 -0
  120. package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
  121. package/dist/data/ai/index.d.ts +4 -3
  122. package/dist/data/ai/index.d.ts.map +1 -1
  123. package/dist/data/ai/use-session-scroll.cjs +30 -6
  124. package/dist/data/ai/use-session-scroll.cjs.map +1 -1
  125. package/dist/data/ai/use-session-scroll.d.ts +7 -0
  126. package/dist/data/ai/use-session-scroll.d.ts.map +1 -1
  127. package/dist/data/ai/use-session-scroll.js +30 -6
  128. package/dist/data/ai/use-session-scroll.js.map +1 -1
  129. package/dist/data/chat/Chat.cjs +1 -1
  130. package/dist/data/chat/Chat.cjs.map +1 -1
  131. package/dist/data/chat/Chat.js +1 -1
  132. package/dist/data/chat/Chat.js.map +1 -1
  133. package/dist/data/chat/ChatRuntimeToolbar.cjs +4 -4
  134. package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
  135. package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
  136. package/dist/data/chat/ChatRuntimeToolbar.js +4 -4
  137. package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
  138. package/dist/data/chat/PromptInput.cjs +4 -2
  139. package/dist/data/chat/PromptInput.cjs.map +1 -1
  140. package/dist/data/chat/PromptInput.d.ts +5 -1
  141. package/dist/data/chat/PromptInput.d.ts.map +1 -1
  142. package/dist/data/chat/PromptInput.js +4 -2
  143. package/dist/data/chat/PromptInput.js.map +1 -1
  144. package/dist/data/diagnostics/ErrorDetails.cjs +13 -2
  145. package/dist/data/diagnostics/ErrorDetails.cjs.map +1 -1
  146. package/dist/data/diagnostics/ErrorDetails.d.ts +3 -1
  147. package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -1
  148. package/dist/data/diagnostics/ErrorDetails.js +14 -3
  149. package/dist/data/diagnostics/ErrorDetails.js.map +1 -1
  150. package/dist/data/diagnostics/FrameSourceWindow.cjs +3 -2
  151. package/dist/data/diagnostics/FrameSourceWindow.cjs.map +1 -1
  152. package/dist/data/diagnostics/FrameSourceWindow.d.ts.map +1 -1
  153. package/dist/data/diagnostics/FrameSourceWindow.js +3 -2
  154. package/dist/data/diagnostics/FrameSourceWindow.js.map +1 -1
  155. package/dist/data/diagnostics/error-diagnostics.cjs +5 -0
  156. package/dist/data/diagnostics/error-diagnostics.cjs.map +1 -1
  157. package/dist/data/diagnostics/error-diagnostics.d.ts +1 -0
  158. package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -1
  159. package/dist/data/diagnostics/error-diagnostics.js +6 -1
  160. package/dist/data/diagnostics/error-diagnostics.js.map +1 -1
  161. package/dist/data/har/HarPanel.cjs +3 -1
  162. package/dist/data/har/HarPanel.cjs.map +1 -1
  163. package/dist/data/har/HarPanel.d.ts +4 -1
  164. package/dist/data/har/HarPanel.d.ts.map +1 -1
  165. package/dist/data/har/HarPanel.js +3 -1
  166. package/dist/data/har/HarPanel.js.map +1 -1
  167. package/dist/data/test-runner/Expectation.cjs +57 -0
  168. package/dist/data/test-runner/Expectation.cjs.map +1 -0
  169. package/dist/data/test-runner/Expectation.d.ts +19 -0
  170. package/dist/data/test-runner/Expectation.d.ts.map +1 -0
  171. package/dist/data/test-runner/Expectation.js +57 -0
  172. package/dist/data/test-runner/Expectation.js.map +1 -0
  173. package/dist/data/test-runner/MarkIcons.cjs +38 -0
  174. package/dist/data/test-runner/MarkIcons.cjs.map +1 -0
  175. package/dist/data/test-runner/MarkIcons.d.ts +15 -0
  176. package/dist/data/test-runner/MarkIcons.d.ts.map +1 -0
  177. package/dist/data/test-runner/MarkIcons.js +38 -0
  178. package/dist/data/test-runner/MarkIcons.js.map +1 -0
  179. package/dist/data/test-runner/TestDetailPanel.cjs +74 -42
  180. package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -1
  181. package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -1
  182. package/dist/data/test-runner/TestDetailPanel.js +76 -44
  183. package/dist/data/test-runner/TestDetailPanel.js.map +1 -1
  184. package/dist/data/test-runner/TestFailureDetail.cjs +23 -27
  185. package/dist/data/test-runner/TestFailureDetail.cjs.map +1 -1
  186. package/dist/data/test-runner/TestFailureDetail.d.ts +2 -2
  187. package/dist/data/test-runner/TestFailureDetail.d.ts.map +1 -1
  188. package/dist/data/test-runner/TestFailureDetail.js +23 -27
  189. package/dist/data/test-runner/TestFailureDetail.js.map +1 -1
  190. package/dist/data/test-runner/TestFilterBar.cjs +87 -93
  191. package/dist/data/test-runner/TestFilterBar.cjs.map +1 -1
  192. package/dist/data/test-runner/TestFilterBar.d.ts +3 -2
  193. package/dist/data/test-runner/TestFilterBar.d.ts.map +1 -1
  194. package/dist/data/test-runner/TestFilterBar.js +89 -95
  195. package/dist/data/test-runner/TestFilterBar.js.map +1 -1
  196. package/dist/data/test-runner/TestRunSummary.cjs +35 -21
  197. package/dist/data/test-runner/TestRunSummary.cjs.map +1 -1
  198. package/dist/data/test-runner/TestRunSummary.d.ts.map +1 -1
  199. package/dist/data/test-runner/TestRunSummary.js +35 -21
  200. package/dist/data/test-runner/TestRunSummary.js.map +1 -1
  201. package/dist/data/test-runner/TestRunner.cjs +52 -30
  202. package/dist/data/test-runner/TestRunner.cjs.map +1 -1
  203. package/dist/data/test-runner/TestRunner.d.ts +3 -2
  204. package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
  205. package/dist/data/test-runner/TestRunner.js +52 -30
  206. package/dist/data/test-runner/TestRunner.js.map +1 -1
  207. package/dist/data/test-runner/TestTree.cjs +5 -2
  208. package/dist/data/test-runner/TestTree.cjs.map +1 -1
  209. package/dist/data/test-runner/TestTree.d.ts +5 -2
  210. package/dist/data/test-runner/TestTree.d.ts.map +1 -1
  211. package/dist/data/test-runner/TestTree.js +5 -2
  212. package/dist/data/test-runner/TestTree.js.map +1 -1
  213. package/dist/data/test-runner/TestTreeNode.cjs +27 -19
  214. package/dist/data/test-runner/TestTreeNode.cjs.map +1 -1
  215. package/dist/data/test-runner/TestTreeNode.d.ts.map +1 -1
  216. package/dist/data/test-runner/TestTreeNode.js +28 -20
  217. package/dist/data/test-runner/TestTreeNode.js.map +1 -1
  218. package/dist/data/test-runner/adapter.cjs +11 -0
  219. package/dist/data/test-runner/adapter.cjs.map +1 -1
  220. package/dist/data/test-runner/adapter.d.ts +18 -7
  221. package/dist/data/test-runner/adapter.d.ts.map +1 -1
  222. package/dist/data/test-runner/adapter.js +11 -0
  223. package/dist/data/test-runner/adapter.js.map +1 -1
  224. package/dist/data/test-runner/copy.cjs +114 -0
  225. package/dist/data/test-runner/copy.cjs.map +1 -0
  226. package/dist/data/test-runner/copy.d.ts +47 -0
  227. package/dist/data/test-runner/copy.d.ts.map +1 -0
  228. package/dist/data/test-runner/copy.js +114 -0
  229. package/dist/data/test-runner/copy.js.map +1 -0
  230. package/dist/data/test-runner/index.d.ts +5 -2
  231. package/dist/data/test-runner/index.d.ts.map +1 -1
  232. package/dist/data/test-runner/marks.cjs +143 -0
  233. package/dist/data/test-runner/marks.cjs.map +1 -0
  234. package/dist/data/test-runner/marks.d.ts +30 -0
  235. package/dist/data/test-runner/marks.d.ts.map +1 -0
  236. package/dist/data/test-runner/marks.js +143 -0
  237. package/dist/data/test-runner/marks.js.map +1 -0
  238. package/dist/data/test-runner/status.cjs +27 -44
  239. package/dist/data/test-runner/status.cjs.map +1 -1
  240. package/dist/data/test-runner/status.d.ts +12 -3
  241. package/dist/data/test-runner/status.d.ts.map +1 -1
  242. package/dist/data/test-runner/status.js +27 -44
  243. package/dist/data/test-runner/status.js.map +1 -1
  244. package/dist/data/verification/adapterViews.cjs +16 -41
  245. package/dist/data/verification/adapterViews.cjs.map +1 -1
  246. package/dist/data/verification/adapterViews.d.ts.map +1 -1
  247. package/dist/data/verification/adapterViews.js +16 -41
  248. package/dist/data/verification/adapterViews.js.map +1 -1
  249. package/dist/data/verification/adapters.cjs +115 -3
  250. package/dist/data/verification/adapters.cjs.map +1 -1
  251. package/dist/data/verification/adapters.d.ts.map +1 -1
  252. package/dist/data/verification/adapters.js +115 -3
  253. package/dist/data/verification/adapters.js.map +1 -1
  254. package/dist/data/verification/verifyReportTests.cjs.map +1 -1
  255. package/dist/data/verification/verifyReportTests.js.map +1 -1
  256. package/dist/data/version-info.cjs +3 -3
  257. package/dist/data/version-info.js +3 -3
  258. package/dist/data.cjs +44 -3
  259. package/dist/data.cjs.map +1 -1
  260. package/dist/data.d.ts +2 -0
  261. package/dist/data.d.ts.map +1 -1
  262. package/dist/data.js +45 -4
  263. package/dist/data.js.map +1 -1
  264. package/dist/icons/components/UiLogoEslint.cjs +10 -0
  265. package/dist/icons/components/UiLogoEslint.cjs.map +1 -0
  266. package/dist/icons/components/UiLogoEslint.d.ts +9 -0
  267. package/dist/icons/components/UiLogoEslint.d.ts.map +1 -0
  268. package/dist/icons/components/UiLogoEslint.js +10 -0
  269. package/dist/icons/components/UiLogoEslint.js.map +1 -0
  270. package/dist/icons/components/UiLogoGo.cjs +10 -0
  271. package/dist/icons/components/UiLogoGo.cjs.map +1 -0
  272. package/dist/icons/components/UiLogoGo.d.ts +9 -0
  273. package/dist/icons/components/UiLogoGo.d.ts.map +1 -0
  274. package/dist/icons/components/UiLogoGo.js +10 -0
  275. package/dist/icons/components/UiLogoGo.js.map +1 -0
  276. package/dist/icons/components/UiLogoJest.cjs +10 -0
  277. package/dist/icons/components/UiLogoJest.cjs.map +1 -0
  278. package/dist/icons/components/UiLogoJest.d.ts +9 -0
  279. package/dist/icons/components/UiLogoJest.d.ts.map +1 -0
  280. package/dist/icons/components/UiLogoJest.js +10 -0
  281. package/dist/icons/components/UiLogoJest.js.map +1 -0
  282. package/dist/icons/components/UiLogoMarkdown.cjs +10 -0
  283. package/dist/icons/components/UiLogoMarkdown.cjs.map +1 -0
  284. package/dist/icons/components/UiLogoMarkdown.d.ts +9 -0
  285. package/dist/icons/components/UiLogoMarkdown.d.ts.map +1 -0
  286. package/dist/icons/components/UiLogoMarkdown.js +10 -0
  287. package/dist/icons/components/UiLogoMarkdown.js.map +1 -0
  288. package/dist/icons/components/UiLogoOxc.cjs +10 -0
  289. package/dist/icons/components/UiLogoOxc.cjs.map +1 -0
  290. package/dist/icons/components/UiLogoOxc.d.ts +9 -0
  291. package/dist/icons/components/UiLogoOxc.d.ts.map +1 -0
  292. package/dist/icons/components/UiLogoOxc.js +10 -0
  293. package/dist/icons/components/UiLogoOxc.js.map +1 -0
  294. package/dist/icons/components/UiLogoPlaywright.cjs +10 -0
  295. package/dist/icons/components/UiLogoPlaywright.cjs.map +1 -0
  296. package/dist/icons/components/UiLogoPlaywright.d.ts +9 -0
  297. package/dist/icons/components/UiLogoPlaywright.d.ts.map +1 -0
  298. package/dist/icons/components/UiLogoPlaywright.js +10 -0
  299. package/dist/icons/components/UiLogoPlaywright.js.map +1 -0
  300. package/dist/icons/components/UiLogoPython.cjs +10 -0
  301. package/dist/icons/components/UiLogoPython.cjs.map +1 -0
  302. package/dist/icons/components/UiLogoPython.d.ts +9 -0
  303. package/dist/icons/components/UiLogoPython.d.ts.map +1 -0
  304. package/dist/icons/components/UiLogoPython.js +10 -0
  305. package/dist/icons/components/UiLogoPython.js.map +1 -0
  306. package/dist/icons/components/UiLogoReact.cjs +10 -0
  307. package/dist/icons/components/UiLogoReact.cjs.map +1 -0
  308. package/dist/icons/components/UiLogoReact.d.ts +9 -0
  309. package/dist/icons/components/UiLogoReact.d.ts.map +1 -0
  310. package/dist/icons/components/UiLogoReact.js +10 -0
  311. package/dist/icons/components/UiLogoReact.js.map +1 -0
  312. package/dist/icons/components/UiLogoRuff.cjs +10 -0
  313. package/dist/icons/components/UiLogoRuff.cjs.map +1 -0
  314. package/dist/icons/components/UiLogoRuff.d.ts +9 -0
  315. package/dist/icons/components/UiLogoRuff.d.ts.map +1 -0
  316. package/dist/icons/components/UiLogoRuff.js +10 -0
  317. package/dist/icons/components/UiLogoRuff.js.map +1 -0
  318. package/dist/icons/components/UiLogoTypescript.cjs +10 -0
  319. package/dist/icons/components/UiLogoTypescript.cjs.map +1 -0
  320. package/dist/icons/components/UiLogoTypescript.d.ts +9 -0
  321. package/dist/icons/components/UiLogoTypescript.d.ts.map +1 -0
  322. package/dist/icons/components/UiLogoTypescript.js +10 -0
  323. package/dist/icons/components/UiLogoTypescript.js.map +1 -0
  324. package/dist/icons/components/UiLogoVitest.cjs +10 -0
  325. package/dist/icons/components/UiLogoVitest.cjs.map +1 -0
  326. package/dist/icons/components/UiLogoVitest.d.ts +9 -0
  327. package/dist/icons/components/UiLogoVitest.d.ts.map +1 -0
  328. package/dist/icons/components/UiLogoVitest.js +10 -0
  329. package/dist/icons/components/UiLogoVitest.js.map +1 -0
  330. package/dist/icons/index.d.ts +11 -0
  331. package/dist/icons/index.d.ts.map +1 -1
  332. package/dist/icons/registry.cjs +22 -0
  333. package/dist/icons/registry.cjs.map +1 -1
  334. package/dist/icons/registry.d.ts.map +1 -1
  335. package/dist/icons/registry.js +22 -0
  336. package/dist/icons/registry.js.map +1 -1
  337. package/dist/icons.cjs +22 -0
  338. package/dist/icons.cjs.map +1 -1
  339. package/dist/icons.js +22 -0
  340. package/dist/icons.js.map +1 -1
  341. package/dist/index.cjs +44 -3
  342. package/dist/index.cjs.map +1 -1
  343. package/dist/index.js +45 -4
  344. package/dist/index.js.map +1 -1
  345. package/dist/overlay/DropdownMenuSubmenu.cjs +4 -4
  346. package/dist/overlay/DropdownMenuSubmenu.cjs.map +1 -1
  347. package/dist/overlay/DropdownMenuSubmenu.js +4 -4
  348. package/dist/overlay/DropdownMenuSubmenu.js.map +1 -1
  349. package/dist/rpc/InlineError.cjs +12 -43
  350. package/dist/rpc/InlineError.cjs.map +1 -1
  351. package/dist/rpc/InlineError.d.ts.map +1 -1
  352. package/dist/rpc/InlineError.js +13 -44
  353. package/dist/rpc/InlineError.js.map +1 -1
  354. package/dist/rpc/OperationScheduleDialog.cjs +63 -10
  355. package/dist/rpc/OperationScheduleDialog.cjs.map +1 -1
  356. package/dist/rpc/OperationScheduleDialog.d.ts +4 -0
  357. package/dist/rpc/OperationScheduleDialog.d.ts.map +1 -1
  358. package/dist/rpc/OperationScheduleDialog.js +63 -10
  359. package/dist/rpc/OperationScheduleDialog.js.map +1 -1
  360. package/dist/rpc/OperationSchedules.cjs +12 -2
  361. package/dist/rpc/OperationSchedules.cjs.map +1 -1
  362. package/dist/rpc/OperationSchedules.d.ts.map +1 -1
  363. package/dist/rpc/OperationSchedules.js +12 -2
  364. package/dist/rpc/OperationSchedules.js.map +1 -1
  365. package/dist/rpc/operation-schedule-model.cjs +2 -0
  366. package/dist/rpc/operation-schedule-model.cjs.map +1 -1
  367. package/dist/rpc/operation-schedule-model.d.ts.map +1 -1
  368. package/dist/rpc/operation-schedule-model.js +2 -0
  369. package/dist/rpc/operation-schedule-model.js.map +1 -1
  370. package/dist/rpc/operation-schedule-types.d.ts +7 -1
  371. package/dist/rpc/operation-schedule-types.d.ts.map +1 -1
  372. package/dist/styles.css +1 -1
  373. package/package.json +1 -1
  374. package/dist/data/test-runner/frameworkIcon.cjs +0 -27
  375. package/dist/data/test-runner/frameworkIcon.cjs.map +0 -1
  376. package/dist/data/test-runner/frameworkIcon.d.ts +0 -3
  377. package/dist/data/test-runner/frameworkIcon.d.ts.map +0 -1
  378. package/dist/data/test-runner/frameworkIcon.js +0 -27
  379. package/dist/data/test-runner/frameworkIcon.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ChatWindow.js","sources":["../../../src/data/ai/ChatWindow.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n} from \"react\";\nimport type { Props as RndProps } from \"react-rnd\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon } from \"../Icon\";\nimport { UiAdd, UiClose, UiFullscreen, UiGitBranch } from \"../../icons\";\nimport { Chat } from \"../chat/Chat\";\nimport { forkChatSession, type CaptainChatSession } from \"../chat/approval\";\nimport type {\n ChatBudgetConfig,\n ChatUsageSummary,\n ClaudePermissionMode,\n} from \"../chat/types\";\nimport { useChatWindowManager } from \"./chat-window-context\";\nimport { ThreadPicker } from \"./ThreadPicker\";\nimport { ContextBadges } from \"./ContextBadges\";\nimport { ToolPreferences, type ToolMeta } from \"./ToolPreferences\";\nimport type { ChatContextItem } from \"./context\";\nimport { chatWindowRequestBody } from \"./ChatWindowRequestBody\";\nimport {\n loadChatPreferences,\n saveChatPreferences,\n type StoredChatPreferences,\n} from \"./ChatWindow.preferences\";\nimport { useChatWindowRuntime } from \"./ChatWindow.runtime\";\nimport { useChatWindowCatalogs } from \"./ChatWindow.catalogs\";\nimport { normalizeToolCatalog } from \"./ChatWindow.tool-catalog\";\nimport {\n effectiveToolPolicies,\n withUserRule,\n} from \"./ToolPreferences.model\";\nimport type {\n PermissionPolicy,\n PermissionRule,\n} from \"../chat/tool-policy\";\nimport { useChatThreadSetup } from \"./ChatWindow.thread\";\nimport { ChatThreadSetupStatus } from \"./ChatWindow.thread-status\";\nimport type { ChatWindowProps } from \"./ChatWindow.types\";\nexport type {\n ChatContextPickerRenderProps,\n ChatWindowProps,\n} from \"./ChatWindow.types\";\n\nconst EMPTY_TOOLS: ToolMeta[] = [];\n\nconst MAXIMIZE_CSS = `\n.chat-maximized .react-draggable {\n transform: none !important;\n width: auto !important;\n height: auto !important;\n inset: 0 !important;\n position: absolute !important;\n}`;\n\n/** A draggable, resizable floating chat window. It lazy-loads `react-rnd` (an\n * optional dependency, so consumers of just the inner <Chat> never pull it)\n * and renders the existing <Chat> beneath a drag-handle header with thread\n * switching, a context-badge row and optional tool preferences. */\nexport function ChatWindow({\n panel,\n chat,\n title = \"Assistant\",\n sessionsApi = \"/api/chat/sessions\",\n threadsSource,\n contextTypeConfig,\n tools,\n defaultToolPolicy = \"ask\",\n toolsApi = \"/api/chat/tools\",\n runtimesApi = null,\n toolRenderers,\n headerExtras,\n renderContextPicker,\n}: ChatWindowProps) {\n const { updatePanel, closePanel, bringToFront, maximizePanel, openPanel } =\n useChatWindowManager();\n const threadSetup = useChatThreadSetup({\n threadId: panel.threadId,\n api: sessionsApi,\n source: threadsSource,\n onCreated: (threadId) => updatePanel(panel.id, { threadId }),\n });\n const [Rnd, setRnd] = useState<ComponentType<RndProps> | null>(null);\n const [storedPrefs] = useState<StoredChatPreferences>(() =>\n loadChatPreferences(),\n );\n const [budget, setBudget] = useState<ChatBudgetConfig>(\n chat?.budget ?? storedPrefs.budget ?? {},\n );\n const [permissionMode, setPermissionMode] = useState<ClaudePermissionMode>(\n chat?.permissionMode ?? storedPrefs.permissionMode ?? \"default\",\n );\n const [titleRefresh, setTitleRefresh] = useState(0);\n // Only the rules the user actually toggled are stored. Everything else is\n // derived, so a surface's rules still reach tools the user never touched, and\n // a group toggle keeps applying as the catalog grows.\n const [userToolRules, setUserToolRules] = useState<PermissionPolicy>(\n storedPrefs.toolRules ?? [],\n );\n const [fetchedTools, setFetchedTools] = useState<ToolMeta[] | undefined>(\n undefined,\n );\n const [toolsLoading, setToolsLoading] = useState(false);\n const [toolsError, setToolsError] = useState<string | null>(null);\n const resolvedTools = tools ?? fetchedTools ?? EMPTY_TOOLS;\n const modelsApi =\n chat?.modelsApi === undefined ? \"/api/chat/models\" : chat.modelsApi;\n const {\n models: resolvedModels,\n runtimeFamilies,\n loading: catalogLoading,\n error: catalogError,\n retry: retryCatalogs,\n } = useChatWindowCatalogs({\n models: chat?.models,\n modelsApi,\n runtimeFamilies: chat?.runtimeFamilies,\n runtimesApi,\n });\n const {\n runtime,\n reasoningEfforts,\n handleRuntimeChange,\n handleModelChange,\n handleReasoningEffortChange,\n replaceRuntimeIdentity,\n replaceRuntime,\n } = useChatWindowRuntime({\n chat,\n initialModel: panel.initialModel,\n models: resolvedModels,\n storedRuntime: storedPrefs.runtime,\n });\n const [messageCount, setMessageCount] = useState(0);\n const [runtimeBound, setRuntimeBound] = useState(false);\n const [forking, setForking] = useState(false);\n const runtimeLocked = runtimeBound || messageCount > 0;\n const preferredRuntimeRef = useRef(runtime);\n const threadIdRef = useRef(panel.threadId);\n threadIdRef.current = panel.threadId;\n\n useEffect(() => {\n if (!runtimeLocked) preferredRuntimeRef.current = runtime;\n }, [runtime, runtimeLocked]);\n\n useEffect(() => {\n setMessageCount(0);\n setRuntimeBound(false);\n replaceRuntime(preferredRuntimeRef.current);\n }, [panel.threadId, replaceRuntime]);\n\n useEffect(() => {\n if (chat?.budget !== undefined) setBudget(chat.budget);\n }, [chat?.budget]);\n\n useEffect(() => {\n if (chat?.permissionMode !== undefined)\n setPermissionMode(chat.permissionMode);\n }, [chat?.permissionMode]);\n\n useEffect(() => {\n if (tools || toolsApi === null) return;\n let active = true;\n setToolsLoading(true);\n setToolsError(null);\n fetch(toolsApi)\n .then((r) =>\n r.ok ? r.json() : Promise.reject(new Error(`tools ${r.status}`)),\n )\n .then((data) => {\n if (!active) return;\n setFetchedTools(normalizeToolCatalog(data));\n })\n .catch((err) => {\n if (!active) return;\n setToolsError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => {\n if (active) setToolsLoading(false);\n });\n return () => {\n active = false;\n };\n }, [tools, toolsApi]);\n\n useEffect(() => {\n saveChatPreferences({\n runtime: runtimeLocked ? preferredRuntimeRef.current : runtime,\n ...(budget.cost !== undefined || budget.maxTokens !== undefined\n ? { budget }\n : {}),\n permissionMode,\n toolRules: userToolRules,\n });\n }, [budget, permissionMode, runtime, runtimeLocked, userToolRules]);\n\n const toolPrefs = useMemo(\n () =>\n effectiveToolPolicies({\n tools: resolvedTools,\n surfacePolicy: panel.toolPolicy,\n userRules: userToolRules,\n fallback: defaultToolPolicy,\n }),\n [defaultToolPolicy, panel.toolPolicy, resolvedTools, userToolRules],\n );\n\n // The popover hands back the one rule the toggle means, not a whole map, so\n // which control was used survives into the request.\n const handleToolRule = useCallback((rule: PermissionRule) => {\n setUserToolRules((prev) => withUserRule(prev, rule));\n }, []);\n\n useEffect(() => {\n let active = true;\n import(\"react-rnd\").then((m) => {\n if (active) setRnd(() => m.Rnd as unknown as ComponentType<RndProps>);\n });\n return () => {\n active = false;\n };\n }, []);\n\n const removeContext = useCallback(\n (id: string) =>\n updatePanel(panel.id, {\n contextItems: panel.contextItems.filter((c) => c.id !== id),\n }),\n [updatePanel, panel.id, panel.contextItems],\n );\n\n const addContextItems = useCallback(\n (items: ChatContextItem[]) =>\n updatePanel(panel.id, {\n contextItems: [\n ...panel.contextItems,\n ...items.filter(\n (item, index) =>\n !panel.contextItems.some((existing) => existing.id === item.id) &&\n items.findIndex((candidate) => candidate.id === item.id) ===\n index,\n ),\n ],\n }),\n [panel.contextItems, panel.id, updatePanel],\n );\n const addContext = useCallback(\n (item: ChatContextItem) => addContextItems([item]),\n [addContextItems],\n );\n\n const mergedBody = chatWindowRequestBody({\n base: chat?.body,\n contextItems: panel.contextItems,\n tools: resolvedTools,\n surfacePolicy: panel.toolPolicy,\n userPolicy: userToolRules,\n });\n\n const initialPrompt = panel.initialPrompt ?? chat?.initialPrompt ?? null;\n const handleInitialPromptConsumed = useCallback(() => {\n if (panel.initialPrompt) updatePanel(panel.id, { initialPrompt: null });\n chat?.onInitialPromptConsumed?.();\n }, [chat, panel.id, panel.initialPrompt, updatePanel]);\n const proposedPrompts = panel.proposedPrompts?.length\n ? panel.proposedPrompts\n : (chat?.proposedPrompts ?? null);\n const handleProposedPromptsConsumed = useCallback(() => {\n if (panel.proposedPrompts?.length)\n updatePanel(panel.id, { proposedPrompts: [] });\n chat?.onProposedPromptsConsumed?.();\n }, [chat, panel.id, panel.proposedPrompts, updatePanel]);\n const handleUsage = useCallback(\n (snapshot: ChatUsageSummary) => {\n // A settled turn is also when the backend has named the conversation, so\n // this is what refreshes the picker's label.\n setTitleRefresh((value) => value + 1);\n chat?.onUsage?.(snapshot);\n },\n [chat],\n );\n const handlePermissionModeChange = useCallback(\n (next: ClaudePermissionMode) => {\n setPermissionMode(next);\n chat?.onPermissionModeChange?.(next);\n },\n [chat],\n );\n const handleSessionHydrated = useCallback(\n (session: CaptainChatSession) => {\n if (session.id !== panel.threadId) return;\n // A hydrated session names its runtime as (model, mode). Requiring a\n // `backend` key here left every loaded session unbound — the picker kept\n // its defaults and the next send posted a runtime the thread had not\n // agreed to.\n setRuntimeBound(Boolean(session.runtime?.model && session.runtime.mode));\n if (session.runtime?.model && session.runtime.mode) {\n replaceRuntimeIdentity(session.runtime);\n }\n chat?.onSessionHydrated?.(session);\n },\n [chat, panel.threadId, replaceRuntimeIdentity],\n );\n const handleMessageCountChange = useCallback(\n (count: number) => {\n setMessageCount(count);\n chat?.onMessageCountChange?.(count);\n },\n [chat],\n );\n const handleFork = useCallback(async () => {\n if (!sessionsApi || !panel.threadId || messageCount === 0 || forking)\n return;\n const sourceThreadId = panel.threadId;\n setForking(true);\n try {\n const fork = await forkChatSession(sessionsApi, sourceThreadId);\n if (threadIdRef.current !== sourceThreadId) return;\n openPanel({ threadId: fork.id });\n } catch (error) {\n console.warn(\"clicky-ui: failed to fork chat session\", error);\n } finally {\n setForking(false);\n }\n }, [forking, messageCount, openPanel, panel.threadId, sessionsApi]);\n\n const header = (\n <div className=\"chat-drag-handle flex cursor-move items-center gap-1 border-b border-border bg-muted/40 px-2 py-1.5\">\n {threadsSource != null || sessionsApi !== null ? (\n <ThreadPicker\n threadId={panel.threadId}\n onSelect={(tid) => updatePanel(panel.id, { threadId: tid })}\n onNew={() => updatePanel(panel.id, { threadId: null })}\n refreshToken={titleRefresh}\n {...(threadsSource\n ? { source: threadsSource }\n : sessionsApi !== null\n ? { api: sessionsApi }\n : {})}\n />\n ) : (\n <span className=\"px-1 text-sm font-medium\">{title}</span>\n )}\n <div className=\"flex-1\" />\n {headerExtras}\n <ToolPreferences\n tools={resolvedTools}\n value={toolPrefs}\n onRule={handleToolRule}\n rules={userToolRules}\n onRulesChange={setUserToolRules}\n models={resolvedModels}\n runtime={runtime}\n onRuntimeChange={handleRuntimeChange}\n runtimeFamilies={runtimeFamilies}\n reasoningEfforts={reasoningEfforts}\n permissionMode={permissionMode}\n onPermissionModeChange={handlePermissionModeChange}\n budget={budget}\n onBudgetChange={setBudget}\n runtimeLocked={runtimeLocked}\n {...(sessionsApi ? { costsApi: sessionsApi } : {})}\n {...(panel.threadId ? { threadId: panel.threadId } : {})}\n toolsLoading={toolsLoading}\n toolsError={toolsError}\n catalogLoading={catalogLoading}\n catalogError={catalogError}\n onCatalogRetry={retryCatalogs}\n />\n {sessionsApi && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n title={\n messageCount === 0\n ? \"Send a message before forking this conversation\"\n : \"Fork conversation into a new window\"\n }\n disabled={!panel.threadId || messageCount === 0 || forking}\n onClick={() => void handleFork()}\n >\n <Icon icon={UiGitBranch} className=\"size-4\" />\n </Button>\n )}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n title=\"New window\"\n onClick={() => openPanel()}\n >\n <Icon icon={UiAdd} className=\"size-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n title={panel.maximized ? \"Restore\" : \"Maximize\"}\n onClick={() => maximizePanel(panel.id)}\n >\n <Icon icon={UiFullscreen} className=\"size-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n title=\"Close\"\n onClick={() => closePanel(panel.id)}\n >\n <Icon icon={UiClose} className=\"size-4\" />\n </Button>\n </div>\n );\n\n const frame = (\n <div className=\"flex h-full flex-col overflow-hidden rounded-lg border border-border bg-background shadow-xl\">\n {header}\n {(renderContextPicker || panel.contextItems.length > 0) && (\n <div className=\"flex flex-wrap items-center gap-1.5 border-b border-border px-2 py-1.5\">\n {renderContextPicker?.({\n items: panel.contextItems,\n onAdd: addContext,\n onAddMany: addContextItems,\n })}\n <ContextBadges\n items={panel.contextItems}\n onRemove={removeContext}\n className=\"px-0 py-0\"\n {...(contextTypeConfig ? { typeConfig: contextTypeConfig } : {})}\n />\n </div>\n )}\n <div className=\"min-h-0 flex-1\">\n {threadSetup.blocked ? (\n <ChatThreadSetupStatus setup={threadSetup} />\n ) : (\n <Chat\n key={panel.threadId ?? `new-${panel.id}`}\n {...chat}\n {...(resolvedModels.length\n ? { models: resolvedModels, modelsApi: null }\n : {})}\n runtime={runtime}\n {...(runtimeFamilies ? { runtimeFamilies } : {})}\n permissionMode={permissionMode}\n onRuntimeChange={handleRuntimeChange}\n onModelChange={handleModelChange}\n onReasoningEffortChange={handleReasoningEffortChange}\n budget={budget}\n onUsage={handleUsage}\n runtimeLocked={runtimeLocked}\n onMessageCountChange={handleMessageCountChange}\n onSessionHydrated={handleSessionHydrated}\n {...(panel.threadId ? { threadId: panel.threadId } : {})}\n sessionsApi={sessionsApi}\n tools={resolvedTools}\n {...(toolRenderers ? { toolRenderers } : {})}\n body={mergedBody}\n initialPrompt={initialPrompt}\n onInitialPromptConsumed={handleInitialPromptConsumed}\n proposedPrompts={proposedPrompts}\n onProposedPromptsConsumed={handleProposedPromptsConsumed}\n />\n )}\n </div>\n </div>\n );\n\n const outerClass = cn(\n \"fixed pointer-events-none\",\n panel.maximized ? \"inset-4 chat-maximized\" : \"inset-0\",\n );\n\n // Until react-rnd loads (and as a graceful fallback if it never does) the\n // window is statically positioned — still usable, just not draggable.\n if (!Rnd) {\n return (\n <div className={outerClass} style={{ zIndex: panel.zIndex }}>\n <div\n className=\"pointer-events-auto h-full\"\n style={\n panel.maximized\n ? { position: \"relative\", width: \"100%\", height: \"100%\" }\n : {\n position: \"absolute\",\n left: panel.x,\n top: panel.y,\n width: panel.width,\n height: panel.height,\n }\n }\n >\n {frame}\n </div>\n </div>\n );\n }\n\n return (\n <div className={outerClass} style={{ zIndex: panel.zIndex }}>\n <style>{MAXIMIZE_CSS}</style>\n <Rnd\n default={{\n x: panel.x,\n y: panel.y,\n width: panel.width,\n height: panel.height,\n }}\n style={{ pointerEvents: \"auto\" }}\n minWidth={Math.min(360, Math.max(1, window.innerWidth - 32))}\n minHeight={Math.min(400, Math.max(1, window.innerHeight - 32))}\n bounds=\"parent\"\n dragHandleClassName=\"chat-drag-handle\"\n disableDragging={panel.maximized}\n enableResizing={!panel.maximized}\n onDragStart={() => bringToFront(panel.id)}\n onDragStop={(_e, d) => updatePanel(panel.id, { x: d.x, y: d.y })}\n onResizeStop={(_e, _dir, ref, _delta, pos) =>\n updatePanel(panel.id, {\n width: ref.offsetWidth,\n height: ref.offsetHeight,\n x: pos.x,\n y: pos.y,\n })\n }\n >\n {frame}\n </Rnd>\n </div>\n );\n}\n\n/** Renders every open window for the current {@link useChatWindowManager}.\n * Drop one of these near the root alongside a <ChatFab/>. */\nexport function ChatWindowLayer(props: Omit<ChatWindowProps, \"panel\">) {\n const { panels } = useChatWindowManager();\n return (\n <>\n {panels.map((panel) => (\n <ChatWindow key={panel.id} panel={panel} {...props} />\n ))}\n </>\n );\n}\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"ChatWindow.js","sources":["../../../src/data/ai/ChatWindow.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n} from \"react\";\nimport type { Props as RndProps } from \"react-rnd\";\nimport { cn } from \"../../lib/utils\";\nimport { useMediaQuery } from \"../../hooks/use-media-query\";\nimport { Chat } from \"../chat/Chat\";\nimport { forkChatSession, type CaptainChatSession } from \"../chat/approval\";\nimport type {\n ChatBudgetConfig,\n ChatUsageSummary,\n ClaudePermissionMode,\n} from \"../chat/types\";\nimport { useChatWindowManager } from \"./chat-window-context\";\nimport { ChatWindowHeader } from \"./ChatWindow.header\";\nimport { ContextBadges } from \"./ContextBadges\";\nimport type { ToolMeta } from \"./ToolPreferences\";\nimport type { ChatContextItem } from \"./context\";\nimport { chatWindowRequestBody } from \"./ChatWindowRequestBody\";\nimport {\n loadChatPreferences,\n saveChatPreferences,\n type StoredChatPreferences,\n} from \"./ChatWindow.preferences\";\nimport { useChatWindowRuntime } from \"./ChatWindow.runtime\";\nimport { useChatWindowCatalogs } from \"./ChatWindow.catalogs\";\nimport { normalizeToolCatalog } from \"./ChatWindow.tool-catalog\";\nimport {\n effectiveToolPolicies,\n withUserRule,\n} from \"./ToolPreferences.model\";\nimport type {\n PermissionPolicy,\n PermissionRule,\n} from \"../chat/tool-policy\";\nimport { useChatThreadSetup } from \"./ChatWindow.thread\";\nimport { ChatThreadSetupStatus } from \"./ChatWindow.thread-status\";\nimport type { ChatWindowProps } from \"./ChatWindow.types\";\nimport {\n CHAT_WINDOW_MOBILE_QUERY,\n ChatWindowFloating,\n ChatWindowSheet,\n} from \"./ChatWindow.placement\";\nexport { CHAT_WINDOW_MOBILE_QUERY };\nexport type {\n ChatContextPickerRenderProps,\n ChatWindowProps,\n} from \"./ChatWindow.types\";\n\nconst EMPTY_TOOLS: ToolMeta[] = [];\n\n/** A draggable, resizable floating chat window — or, below\n * {@link CHAT_WINDOW_MOBILE_QUERY}, a full-screen sheet. It lazy-loads `react-rnd` (an\n * optional dependency, so consumers of just the inner <Chat> never pull it)\n * and renders the existing <Chat> beneath a drag-handle header with thread\n * switching, a context-badge row and optional tool preferences. */\nexport function ChatWindow({\n panel,\n chat,\n title = \"Assistant\",\n sessionsApi = \"/api/chat/sessions\",\n threadsSource,\n contextTypeConfig,\n tools,\n defaultToolPolicy = \"ask\",\n toolsApi = \"/api/chat/tools\",\n runtimesApi = null,\n toolRenderers,\n headerExtras,\n renderContextPicker,\n}: ChatWindowProps) {\n const {\n panels,\n updatePanel,\n closePanel,\n bringToFront,\n maximizePanel,\n openPanel,\n } = useChatWindowManager();\n const mobile = useMediaQuery(CHAT_WINDOW_MOBILE_QUERY);\n const threadSetup = useChatThreadSetup({\n threadId: panel.threadId,\n api: sessionsApi,\n source: threadsSource,\n onCreated: (threadId) => updatePanel(panel.id, { threadId }),\n });\n const [Rnd, setRnd] = useState<ComponentType<RndProps> | null>(null);\n const [storedPrefs] = useState<StoredChatPreferences>(() =>\n loadChatPreferences(),\n );\n const [budget, setBudget] = useState<ChatBudgetConfig>(\n chat?.budget ?? storedPrefs.budget ?? {},\n );\n const [permissionMode, setPermissionMode] = useState<ClaudePermissionMode>(\n chat?.permissionMode ?? storedPrefs.permissionMode ?? \"default\",\n );\n const [titleRefresh, setTitleRefresh] = useState(0);\n // Only the rules the user actually toggled are stored. Everything else is\n // derived, so a surface's rules still reach tools the user never touched, and\n // a group toggle keeps applying as the catalog grows.\n const [userToolRules, setUserToolRules] = useState<PermissionPolicy>(\n storedPrefs.toolRules ?? [],\n );\n const [fetchedTools, setFetchedTools] = useState<ToolMeta[] | undefined>(\n undefined,\n );\n const [toolsLoading, setToolsLoading] = useState(false);\n const [toolsError, setToolsError] = useState<string | null>(null);\n const resolvedTools = tools ?? fetchedTools ?? EMPTY_TOOLS;\n const modelsApi =\n chat?.modelsApi === undefined ? \"/api/chat/models\" : chat.modelsApi;\n const {\n models: resolvedModels,\n runtimeFamilies,\n loading: catalogLoading,\n error: catalogError,\n retry: retryCatalogs,\n } = useChatWindowCatalogs({\n models: chat?.models,\n modelsApi,\n runtimeFamilies: chat?.runtimeFamilies,\n runtimesApi,\n });\n const {\n runtime,\n reasoningEfforts,\n handleRuntimeChange,\n handleModelChange,\n handleReasoningEffortChange,\n replaceRuntimeIdentity,\n replaceRuntime,\n } = useChatWindowRuntime({\n chat,\n initialModel: panel.initialModel,\n models: resolvedModels,\n storedRuntime: storedPrefs.runtime,\n });\n const [messageCount, setMessageCount] = useState(0);\n const [runtimeBound, setRuntimeBound] = useState(false);\n const [forking, setForking] = useState(false);\n const runtimeLocked = runtimeBound || messageCount > 0;\n const preferredRuntimeRef = useRef(runtime);\n const threadIdRef = useRef(panel.threadId);\n threadIdRef.current = panel.threadId;\n\n useEffect(() => {\n if (!runtimeLocked) preferredRuntimeRef.current = runtime;\n }, [runtime, runtimeLocked]);\n\n useEffect(() => {\n setMessageCount(0);\n setRuntimeBound(false);\n replaceRuntime(preferredRuntimeRef.current);\n }, [panel.threadId, replaceRuntime]);\n\n useEffect(() => {\n if (chat?.budget !== undefined) setBudget(chat.budget);\n }, [chat?.budget]);\n\n useEffect(() => {\n if (chat?.permissionMode !== undefined)\n setPermissionMode(chat.permissionMode);\n }, [chat?.permissionMode]);\n\n useEffect(() => {\n if (tools || toolsApi === null) return;\n let active = true;\n setToolsLoading(true);\n setToolsError(null);\n fetch(toolsApi)\n .then((r) =>\n r.ok ? r.json() : Promise.reject(new Error(`tools ${r.status}`)),\n )\n .then((data) => {\n if (!active) return;\n setFetchedTools(normalizeToolCatalog(data));\n })\n .catch((err) => {\n if (!active) return;\n setToolsError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => {\n if (active) setToolsLoading(false);\n });\n return () => {\n active = false;\n };\n }, [tools, toolsApi]);\n\n useEffect(() => {\n saveChatPreferences({\n runtime: runtimeLocked ? preferredRuntimeRef.current : runtime,\n ...(budget.cost !== undefined || budget.maxTokens !== undefined\n ? { budget }\n : {}),\n permissionMode,\n toolRules: userToolRules,\n });\n }, [budget, permissionMode, runtime, runtimeLocked, userToolRules]);\n\n const toolPrefs = useMemo(\n () =>\n effectiveToolPolicies({\n tools: resolvedTools,\n surfacePolicy: panel.toolPolicy,\n userRules: userToolRules,\n fallback: defaultToolPolicy,\n }),\n [defaultToolPolicy, panel.toolPolicy, resolvedTools, userToolRules],\n );\n\n // The popover hands back the one rule the toggle means, not a whole map, so\n // which control was used survives into the request.\n const handleToolRule = useCallback((rule: PermissionRule) => {\n setUserToolRules((prev) => withUserRule(prev, rule));\n }, []);\n\n useEffect(() => {\n if (mobile) return;\n let active = true;\n import(\"react-rnd\").then((m) => {\n if (active) setRnd(() => m.Rnd as unknown as ComponentType<RndProps>);\n });\n return () => {\n active = false;\n };\n }, [mobile]);\n\n const removeContext = useCallback(\n (id: string) =>\n updatePanel(panel.id, {\n contextItems: panel.contextItems.filter((c) => c.id !== id),\n }),\n [updatePanel, panel.id, panel.contextItems],\n );\n\n const addContextItems = useCallback(\n (items: ChatContextItem[]) =>\n updatePanel(panel.id, {\n contextItems: [\n ...panel.contextItems,\n ...items.filter(\n (item, index) =>\n !panel.contextItems.some((existing) => existing.id === item.id) &&\n items.findIndex((candidate) => candidate.id === item.id) ===\n index,\n ),\n ],\n }),\n [panel.contextItems, panel.id, updatePanel],\n );\n const addContext = useCallback(\n (item: ChatContextItem) => addContextItems([item]),\n [addContextItems],\n );\n\n const mergedBody = chatWindowRequestBody({\n base: chat?.body,\n contextItems: panel.contextItems,\n tools: resolvedTools,\n surfacePolicy: panel.toolPolicy,\n userPolicy: userToolRules,\n });\n\n const initialPrompt = panel.initialPrompt ?? chat?.initialPrompt ?? null;\n const handleInitialPromptConsumed = useCallback(() => {\n if (panel.initialPrompt) updatePanel(panel.id, { initialPrompt: null });\n chat?.onInitialPromptConsumed?.();\n }, [chat, panel.id, panel.initialPrompt, updatePanel]);\n const proposedPrompts = panel.proposedPrompts?.length\n ? panel.proposedPrompts\n : (chat?.proposedPrompts ?? null);\n const handleProposedPromptsConsumed = useCallback(() => {\n if (panel.proposedPrompts?.length)\n updatePanel(panel.id, { proposedPrompts: [] });\n chat?.onProposedPromptsConsumed?.();\n }, [chat, panel.id, panel.proposedPrompts, updatePanel]);\n const handleUsage = useCallback(\n (snapshot: ChatUsageSummary) => {\n // A settled turn is also when the backend has named the conversation, so\n // this is what refreshes the picker's label.\n setTitleRefresh((value) => value + 1);\n chat?.onUsage?.(snapshot);\n },\n [chat],\n );\n const handlePermissionModeChange = useCallback(\n (next: ClaudePermissionMode) => {\n setPermissionMode(next);\n chat?.onPermissionModeChange?.(next);\n },\n [chat],\n );\n const handleSessionHydrated = useCallback(\n (session: CaptainChatSession) => {\n if (session.id !== panel.threadId) return;\n // A hydrated session names its runtime as (model, mode). Requiring a\n // `backend` key here left every loaded session unbound — the picker kept\n // its defaults and the next send posted a runtime the thread had not\n // agreed to.\n setRuntimeBound(Boolean(session.runtime?.model && session.runtime.mode));\n if (session.runtime?.model && session.runtime.mode) {\n replaceRuntimeIdentity(session.runtime);\n }\n chat?.onSessionHydrated?.(session);\n },\n [chat, panel.threadId, replaceRuntimeIdentity],\n );\n const handleMessageCountChange = useCallback(\n (count: number) => {\n setMessageCount(count);\n chat?.onMessageCountChange?.(count);\n },\n [chat],\n );\n const handleFork = useCallback(async () => {\n if (!sessionsApi || !panel.threadId || messageCount === 0 || forking)\n return;\n const sourceThreadId = panel.threadId;\n setForking(true);\n try {\n const fork = await forkChatSession(sessionsApi, sourceThreadId);\n if (threadIdRef.current !== sourceThreadId) return;\n openPanel({ threadId: fork.id });\n } catch (error) {\n console.warn(\"clicky-ui: failed to fork chat session\", error);\n } finally {\n setForking(false);\n }\n }, [forking, messageCount, openPanel, panel.threadId, sessionsApi]);\n\n const header = (\n <ChatWindowHeader\n mobile={mobile}\n title={title}\n threadId={panel.threadId}\n maximized={panel.maximized}\n threadsSource={threadsSource}\n sessionsApi={sessionsApi}\n titleRefresh={titleRefresh}\n headerExtras={headerExtras}\n toolPreferences={{\n tools: resolvedTools,\n value: toolPrefs,\n onRule: handleToolRule,\n rules: userToolRules,\n onRulesChange: setUserToolRules,\n models: resolvedModels,\n runtime,\n onRuntimeChange: handleRuntimeChange,\n runtimeFamilies,\n reasoningEfforts,\n permissionMode,\n onPermissionModeChange: handlePermissionModeChange,\n budget,\n onBudgetChange: setBudget,\n runtimeLocked,\n ...(sessionsApi ? { costsApi: sessionsApi } : {}),\n ...(panel.threadId ? { threadId: panel.threadId } : {}),\n toolsLoading,\n toolsError,\n catalogLoading,\n catalogError,\n onCatalogRetry: retryCatalogs,\n }}\n hasMessages={messageCount > 0}\n forkDisabled={!panel.threadId || messageCount === 0 || forking}\n onSelectThread={(threadId) => updatePanel(panel.id, { threadId })}\n onNewThread={() => updatePanel(panel.id, { threadId: null })}\n onFork={() => void handleFork()}\n onNewWindow={() => openPanel()}\n onMaximize={() => maximizePanel(panel.id)}\n onClose={() => closePanel(panel.id)}\n />\n );\n\n const frame = (\n <div\n className={cn(\n \"flex h-full flex-col overflow-hidden bg-background\",\n !mobile && \"rounded-lg border border-border shadow-xl\",\n )}\n >\n {header}\n {(renderContextPicker || panel.contextItems.length > 0) && (\n <div className=\"flex flex-wrap items-center gap-1.5 border-b border-border px-2 py-1.5\">\n {renderContextPicker?.({\n items: panel.contextItems,\n onAdd: addContext,\n onAddMany: addContextItems,\n })}\n <ContextBadges\n items={panel.contextItems}\n onRemove={removeContext}\n className=\"px-0 py-0\"\n {...(contextTypeConfig ? { typeConfig: contextTypeConfig } : {})}\n />\n </div>\n )}\n <div className=\"min-h-0 flex-1\">\n {threadSetup.blocked ? (\n <ChatThreadSetupStatus setup={threadSetup} />\n ) : (\n <Chat\n key={panel.threadId ?? `new-${panel.id}`}\n {...chat}\n {...(resolvedModels.length\n ? { models: resolvedModels, modelsApi: null }\n : {})}\n runtime={runtime}\n {...(runtimeFamilies ? { runtimeFamilies } : {})}\n permissionMode={permissionMode}\n onRuntimeChange={handleRuntimeChange}\n onModelChange={handleModelChange}\n onReasoningEffortChange={handleReasoningEffortChange}\n budget={budget}\n onUsage={handleUsage}\n runtimeLocked={runtimeLocked}\n onMessageCountChange={handleMessageCountChange}\n onSessionHydrated={handleSessionHydrated}\n {...(panel.threadId ? { threadId: panel.threadId } : {})}\n sessionsApi={sessionsApi}\n tools={resolvedTools}\n {...(toolRenderers ? { toolRenderers } : {})}\n body={mergedBody}\n initialPrompt={initialPrompt}\n onInitialPromptConsumed={handleInitialPromptConsumed}\n proposedPrompts={proposedPrompts}\n onProposedPromptsConsumed={handleProposedPromptsConsumed}\n />\n )}\n </div>\n </div>\n );\n\n const layerStyle = { zIndex: panel.zIndex };\n\n if (mobile) {\n const front = panels.reduce((top, p) => (p.zIndex >= top.zIndex ? p : top));\n return (\n <ChatWindowSheet layerStyle={layerStyle} hidden={front.id !== panel.id}>\n {frame}\n </ChatWindowSheet>\n );\n }\n\n return (\n <ChatWindowFloating\n panel={panel}\n layerStyle={layerStyle}\n Rnd={Rnd}\n onDragStart={() => bringToFront(panel.id)}\n onGeometryChange={(partial) => updatePanel(panel.id, partial)}\n >\n {frame}\n </ChatWindowFloating>\n );\n}\n\n/** Renders every open window for the current {@link useChatWindowManager}.\n * Below {@link CHAT_WINDOW_MOBILE_QUERY} each is a full-screen sheet and only\n * the most recently focused one is visible. Drop one of these near the root alongside a <ChatFab/>. */\nexport function ChatWindowLayer(props: Omit<ChatWindowProps, \"panel\">) {\n const { panels } = useChatWindowManager();\n return (\n <>\n {panels.map((panel) => (\n <ChatWindow key={panel.id} panel={panel} {...props} />\n ))}\n </>\n );\n}\n"],"names":["_a"],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const utils = require("../../lib/utils.cjs");
5
+ const CHAT_WINDOW_MOBILE_QUERY = "(max-width: 767px)";
6
+ const MAXIMIZE_CSS = `
7
+ .chat-maximized .react-draggable {
8
+ transform: none !important;
9
+ width: auto !important;
10
+ height: auto !important;
11
+ inset: 0 !important;
12
+ position: absolute !important;
13
+ }`;
14
+ function ChatWindowSheet({
15
+ layerStyle,
16
+ hidden,
17
+ children
18
+ }) {
19
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { hidden, children: /* @__PURE__ */ jsxRuntime.jsx(
20
+ "div",
21
+ {
22
+ "data-testid": "chat-window-sheet",
23
+ className: utils.cn(
24
+ "fixed inset-x-0 top-0 flex h-dvh flex-col overflow-hidden bg-background",
25
+ "pt-[env(safe-area-inset-top)]",
26
+ "pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]"
27
+ ),
28
+ style: layerStyle,
29
+ children
30
+ }
31
+ ) });
32
+ }
33
+ function ChatWindowFloating({
34
+ panel,
35
+ layerStyle,
36
+ Rnd,
37
+ onDragStart,
38
+ onGeometryChange,
39
+ children
40
+ }) {
41
+ const outerClass = utils.cn(
42
+ "fixed pointer-events-none",
43
+ panel.maximized ? "inset-4 chat-maximized" : "inset-0"
44
+ );
45
+ if (!Rnd) {
46
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: outerClass, style: layerStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
47
+ "div",
48
+ {
49
+ className: "pointer-events-auto h-full",
50
+ style: panel.maximized ? { position: "relative", width: "100%", height: "100%" } : {
51
+ position: "absolute",
52
+ left: panel.x,
53
+ top: panel.y,
54
+ width: panel.width,
55
+ height: panel.height
56
+ },
57
+ children
58
+ }
59
+ ) });
60
+ }
61
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: outerClass, style: layerStyle, children: [
62
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: MAXIMIZE_CSS }),
63
+ /* @__PURE__ */ jsxRuntime.jsx(
64
+ Rnd,
65
+ {
66
+ default: {
67
+ x: panel.x,
68
+ y: panel.y,
69
+ width: panel.width,
70
+ height: panel.height
71
+ },
72
+ style: { pointerEvents: "auto" },
73
+ minWidth: Math.min(360, Math.max(1, window.innerWidth - 32)),
74
+ minHeight: Math.min(400, Math.max(1, window.innerHeight - 32)),
75
+ bounds: "parent",
76
+ dragHandleClassName: "chat-drag-handle",
77
+ disableDragging: panel.maximized,
78
+ enableResizing: !panel.maximized,
79
+ onDragStart,
80
+ onDragStop: (_e, d) => onGeometryChange({ x: d.x, y: d.y }),
81
+ onResizeStop: (_e, _dir, ref, _delta, pos) => onGeometryChange({
82
+ width: ref.offsetWidth,
83
+ height: ref.offsetHeight,
84
+ x: pos.x,
85
+ y: pos.y
86
+ }),
87
+ children
88
+ }
89
+ )
90
+ ] });
91
+ }
92
+ exports.CHAT_WINDOW_MOBILE_QUERY = CHAT_WINDOW_MOBILE_QUERY;
93
+ exports.ChatWindowFloating = ChatWindowFloating;
94
+ exports.ChatWindowSheet = ChatWindowSheet;
95
+ //# sourceMappingURL=ChatWindow.placement.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatWindow.placement.cjs","sources":["../../../src/data/ai/ChatWindow.placement.tsx"],"sourcesContent":["import type { ComponentType, CSSProperties, ReactNode } from \"react\";\nimport type { Props as RndProps } from \"react-rnd\";\nimport { cn } from \"../../lib/utils\";\nimport type { ChatWindowState } from \"./chat-window-context\";\n\n/** The small-screen query the chat window switches to a full-screen sheet at.\n * Matches AppShell's md breakpoint (its mobile drawer is md:hidden); export so hosts can align\n * their own chrome (e.g. hide a bottom bar) with it. */\nexport const CHAT_WINDOW_MOBILE_QUERY = \"(max-width: 767px)\";\n\nconst MAXIMIZE_CSS = `\n.chat-maximized .react-draggable {\n transform: none !important;\n width: auto !important;\n height: auto !important;\n inset: 0 !important;\n position: absolute !important;\n}`;\n\n/** The window on a phone: fixed to the dynamic viewport (`h-dvh`, so a URL-bar\n * or on-screen-keyboard resize never pushes the prompt off-screen), clipped so\n * the document cannot scroll, padded by the top and side safe areas (the\n * prompt bar pads its own bottom), never draggable or resizable. `hidden`\n * keeps a non-front window mounted (its stream and draft survive) without\n * painting it. */\nexport function ChatWindowSheet({\n layerStyle,\n hidden,\n children,\n}: {\n /** Stacking style of the window layer, built by the host (ChatWindow). */\n layerStyle: CSSProperties;\n hidden: boolean;\n children: ReactNode;\n}) {\n return (\n <div hidden={hidden}>\n <div\n data-testid=\"chat-window-sheet\"\n className={cn(\n \"fixed inset-x-0 top-0 flex h-dvh flex-col overflow-hidden bg-background\",\n \"pt-[env(safe-area-inset-top)]\",\n \"pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]\",\n )}\n style={layerStyle}\n >\n {children}\n </div>\n </div>\n );\n}\n\n/** The window on a larger screen: a draggable/resizable react-rnd box. Until\n * react-rnd loads (and as a graceful fallback if it never does) the window is\n * statically positioned — still usable, just not draggable. */\nexport function ChatWindowFloating({\n panel,\n layerStyle,\n Rnd,\n onDragStart,\n onGeometryChange,\n children,\n}: {\n panel: ChatWindowState;\n /** Stacking style of the window layer, built by the host (ChatWindow). */\n layerStyle: CSSProperties;\n Rnd: ComponentType<RndProps> | null;\n onDragStart: () => void;\n onGeometryChange: (\n partial: Pick<Partial<ChatWindowState>, \"x\" | \"y\" | \"width\" | \"height\">,\n ) => void;\n children: ReactNode;\n}) {\n const outerClass = cn(\n \"fixed pointer-events-none\",\n panel.maximized ? \"inset-4 chat-maximized\" : \"inset-0\",\n );\n\n if (!Rnd) {\n return (\n <div className={outerClass} style={layerStyle}>\n <div\n className=\"pointer-events-auto h-full\"\n style={\n panel.maximized\n ? { position: \"relative\", width: \"100%\", height: \"100%\" }\n : {\n position: \"absolute\",\n left: panel.x,\n top: panel.y,\n width: panel.width,\n height: panel.height,\n }\n }\n >\n {children}\n </div>\n </div>\n );\n }\n\n return (\n <div className={outerClass} style={layerStyle}>\n <style>{MAXIMIZE_CSS}</style>\n <Rnd\n default={{\n x: panel.x,\n y: panel.y,\n width: panel.width,\n height: panel.height,\n }}\n style={{ pointerEvents: \"auto\" }}\n minWidth={Math.min(360, Math.max(1, window.innerWidth - 32))}\n minHeight={Math.min(400, Math.max(1, window.innerHeight - 32))}\n bounds=\"parent\"\n dragHandleClassName=\"chat-drag-handle\"\n disableDragging={panel.maximized}\n enableResizing={!panel.maximized}\n onDragStart={onDragStart}\n onDragStop={(_e, d) => onGeometryChange({ x: d.x, y: d.y })}\n onResizeStop={(_e, _dir, ref, _delta, pos) =>\n onGeometryChange({\n width: ref.offsetWidth,\n height: ref.offsetHeight,\n x: pos.x,\n y: pos.y,\n })\n }\n >\n {children}\n </Rnd>\n </div>\n );\n}\n"],"names":["jsx","cn","jsxs"],"mappings":";;;;AAQO,MAAM,2BAA2B;AAExC,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAed,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACEA,2BAAAA,IAAC,SAAI,QACH,UAAAA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,eAAY;AAAA,MACZ,WAAWC,MAAAA;AAAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,OAAO;AAAA,MAEN;AAAA,IAAA;AAAA,EAAA,GAEL;AAEJ;AAKO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUG;AACD,QAAM,aAAaA,MAAAA;AAAAA,IACjB;AAAA,IACA,MAAM,YAAY,2BAA2B;AAAA,EAAA;AAG/C,MAAI,CAAC,KAAK;AACR,WACED,2BAAAA,IAAC,OAAA,EAAI,WAAW,YAAY,OAAO,YACjC,UAAAA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,OACE,MAAM,YACF,EAAE,UAAU,YAAY,OAAO,QAAQ,QAAQ,WAC/C;AAAA,UACE,UAAU;AAAA,UACV,MAAM,MAAM;AAAA,UACZ,KAAK,MAAM;AAAA,UACX,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,QAAA;AAAA,QAIrB;AAAA,MAAA;AAAA,IAAA,GAEL;AAAA,EAEJ;AAEA,SACEE,2BAAAA,KAAC,OAAA,EAAI,WAAW,YAAY,OAAO,YACjC,UAAA;AAAA,IAAAF,2BAAAA,IAAC,WAAO,UAAA,aAAA,CAAa;AAAA,IACrBA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS;AAAA,UACP,GAAG,MAAM;AAAA,UACT,GAAG,MAAM;AAAA,UACT,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,QAAA;AAAA,QAEhB,OAAO,EAAE,eAAe,OAAA;AAAA,QACxB,UAAU,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,OAAO,aAAa,EAAE,CAAC;AAAA,QAC3D,WAAW,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,OAAO,cAAc,EAAE,CAAC;AAAA,QAC7D,QAAO;AAAA,QACP,qBAAoB;AAAA,QACpB,iBAAiB,MAAM;AAAA,QACvB,gBAAgB,CAAC,MAAM;AAAA,QACvB;AAAA,QACA,YAAY,CAAC,IAAI,MAAM,iBAAiB,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,EAAA,CAAG;AAAA,QAC1D,cAAc,CAAC,IAAI,MAAM,KAAK,QAAQ,QACpC,iBAAiB;AAAA,UACf,OAAO,IAAI;AAAA,UACX,QAAQ,IAAI;AAAA,UACZ,GAAG,IAAI;AAAA,UACP,GAAG,IAAI;AAAA,QAAA,CACR;AAAA,QAGF;AAAA,MAAA;AAAA,IAAA;AAAA,EACH,GACF;AAEJ;;;;"}
@@ -0,0 +1,32 @@
1
+ import { ComponentType, CSSProperties, ReactNode } from 'react';
2
+ import { Props as RndProps } from 'react-rnd';
3
+ import { ChatWindowState } from './chat-window-context.js';
4
+ /** The small-screen query the chat window switches to a full-screen sheet at.
5
+ * Matches AppShell's md breakpoint (its mobile drawer is md:hidden); export so hosts can align
6
+ * their own chrome (e.g. hide a bottom bar) with it. */
7
+ export declare const CHAT_WINDOW_MOBILE_QUERY = "(max-width: 767px)";
8
+ /** The window on a phone: fixed to the dynamic viewport (`h-dvh`, so a URL-bar
9
+ * or on-screen-keyboard resize never pushes the prompt off-screen), clipped so
10
+ * the document cannot scroll, padded by the top and side safe areas (the
11
+ * prompt bar pads its own bottom), never draggable or resizable. `hidden`
12
+ * keeps a non-front window mounted (its stream and draft survive) without
13
+ * painting it. */
14
+ export declare function ChatWindowSheet({ layerStyle, hidden, children, }: {
15
+ /** Stacking style of the window layer, built by the host (ChatWindow). */
16
+ layerStyle: CSSProperties;
17
+ hidden: boolean;
18
+ children: ReactNode;
19
+ }): import("react").JSX.Element;
20
+ /** The window on a larger screen: a draggable/resizable react-rnd box. Until
21
+ * react-rnd loads (and as a graceful fallback if it never does) the window is
22
+ * statically positioned — still usable, just not draggable. */
23
+ export declare function ChatWindowFloating({ panel, layerStyle, Rnd, onDragStart, onGeometryChange, children, }: {
24
+ panel: ChatWindowState;
25
+ /** Stacking style of the window layer, built by the host (ChatWindow). */
26
+ layerStyle: CSSProperties;
27
+ Rnd: ComponentType<RndProps> | null;
28
+ onDragStart: () => void;
29
+ onGeometryChange: (partial: Pick<Partial<ChatWindowState>, "x" | "y" | "width" | "height">) => void;
30
+ children: ReactNode;
31
+ }): import("react").JSX.Element;
32
+ //# sourceMappingURL=ChatWindow.placement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatWindow.placement.d.ts","sourceRoot":"","sources":["../../../src/data/ai/ChatWindow.placement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACrE,OAAO,KAAK,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;yDAEyD;AACzD,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAW7D;;;;;mBAKmB;AACnB,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,MAAM,EACN,QAAQ,GACT,EAAE;IACD,0EAA0E;IAC1E,UAAU,EAAE,aAAa,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB,+BAgBA;AAED;;gEAEgE;AAChE,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,UAAU,EACV,GAAG,EACH,WAAW,EACX,gBAAgB,EAChB,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,eAAe,CAAC;IACvB,0EAA0E;IAC1E,UAAU,EAAE,aAAa,CAAC;IAC1B,GAAG,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACpC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,gBAAgB,EAAE,CAChB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,QAAQ,CAAC,KACpE,IAAI,CAAC;IACV,QAAQ,EAAE,SAAS,CAAC;CACrB,+BA6DA"}
@@ -0,0 +1,95 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils.js";
3
+ const CHAT_WINDOW_MOBILE_QUERY = "(max-width: 767px)";
4
+ const MAXIMIZE_CSS = `
5
+ .chat-maximized .react-draggable {
6
+ transform: none !important;
7
+ width: auto !important;
8
+ height: auto !important;
9
+ inset: 0 !important;
10
+ position: absolute !important;
11
+ }`;
12
+ function ChatWindowSheet({
13
+ layerStyle,
14
+ hidden,
15
+ children
16
+ }) {
17
+ return /* @__PURE__ */ jsx("div", { hidden, children: /* @__PURE__ */ jsx(
18
+ "div",
19
+ {
20
+ "data-testid": "chat-window-sheet",
21
+ className: cn(
22
+ "fixed inset-x-0 top-0 flex h-dvh flex-col overflow-hidden bg-background",
23
+ "pt-[env(safe-area-inset-top)]",
24
+ "pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]"
25
+ ),
26
+ style: layerStyle,
27
+ children
28
+ }
29
+ ) });
30
+ }
31
+ function ChatWindowFloating({
32
+ panel,
33
+ layerStyle,
34
+ Rnd,
35
+ onDragStart,
36
+ onGeometryChange,
37
+ children
38
+ }) {
39
+ const outerClass = cn(
40
+ "fixed pointer-events-none",
41
+ panel.maximized ? "inset-4 chat-maximized" : "inset-0"
42
+ );
43
+ if (!Rnd) {
44
+ return /* @__PURE__ */ jsx("div", { className: outerClass, style: layerStyle, children: /* @__PURE__ */ jsx(
45
+ "div",
46
+ {
47
+ className: "pointer-events-auto h-full",
48
+ style: panel.maximized ? { position: "relative", width: "100%", height: "100%" } : {
49
+ position: "absolute",
50
+ left: panel.x,
51
+ top: panel.y,
52
+ width: panel.width,
53
+ height: panel.height
54
+ },
55
+ children
56
+ }
57
+ ) });
58
+ }
59
+ return /* @__PURE__ */ jsxs("div", { className: outerClass, style: layerStyle, children: [
60
+ /* @__PURE__ */ jsx("style", { children: MAXIMIZE_CSS }),
61
+ /* @__PURE__ */ jsx(
62
+ Rnd,
63
+ {
64
+ default: {
65
+ x: panel.x,
66
+ y: panel.y,
67
+ width: panel.width,
68
+ height: panel.height
69
+ },
70
+ style: { pointerEvents: "auto" },
71
+ minWidth: Math.min(360, Math.max(1, window.innerWidth - 32)),
72
+ minHeight: Math.min(400, Math.max(1, window.innerHeight - 32)),
73
+ bounds: "parent",
74
+ dragHandleClassName: "chat-drag-handle",
75
+ disableDragging: panel.maximized,
76
+ enableResizing: !panel.maximized,
77
+ onDragStart,
78
+ onDragStop: (_e, d) => onGeometryChange({ x: d.x, y: d.y }),
79
+ onResizeStop: (_e, _dir, ref, _delta, pos) => onGeometryChange({
80
+ width: ref.offsetWidth,
81
+ height: ref.offsetHeight,
82
+ x: pos.x,
83
+ y: pos.y
84
+ }),
85
+ children
86
+ }
87
+ )
88
+ ] });
89
+ }
90
+ export {
91
+ CHAT_WINDOW_MOBILE_QUERY,
92
+ ChatWindowFloating,
93
+ ChatWindowSheet
94
+ };
95
+ //# sourceMappingURL=ChatWindow.placement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatWindow.placement.js","sources":["../../../src/data/ai/ChatWindow.placement.tsx"],"sourcesContent":["import type { ComponentType, CSSProperties, ReactNode } from \"react\";\nimport type { Props as RndProps } from \"react-rnd\";\nimport { cn } from \"../../lib/utils\";\nimport type { ChatWindowState } from \"./chat-window-context\";\n\n/** The small-screen query the chat window switches to a full-screen sheet at.\n * Matches AppShell's md breakpoint (its mobile drawer is md:hidden); export so hosts can align\n * their own chrome (e.g. hide a bottom bar) with it. */\nexport const CHAT_WINDOW_MOBILE_QUERY = \"(max-width: 767px)\";\n\nconst MAXIMIZE_CSS = `\n.chat-maximized .react-draggable {\n transform: none !important;\n width: auto !important;\n height: auto !important;\n inset: 0 !important;\n position: absolute !important;\n}`;\n\n/** The window on a phone: fixed to the dynamic viewport (`h-dvh`, so a URL-bar\n * or on-screen-keyboard resize never pushes the prompt off-screen), clipped so\n * the document cannot scroll, padded by the top and side safe areas (the\n * prompt bar pads its own bottom), never draggable or resizable. `hidden`\n * keeps a non-front window mounted (its stream and draft survive) without\n * painting it. */\nexport function ChatWindowSheet({\n layerStyle,\n hidden,\n children,\n}: {\n /** Stacking style of the window layer, built by the host (ChatWindow). */\n layerStyle: CSSProperties;\n hidden: boolean;\n children: ReactNode;\n}) {\n return (\n <div hidden={hidden}>\n <div\n data-testid=\"chat-window-sheet\"\n className={cn(\n \"fixed inset-x-0 top-0 flex h-dvh flex-col overflow-hidden bg-background\",\n \"pt-[env(safe-area-inset-top)]\",\n \"pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]\",\n )}\n style={layerStyle}\n >\n {children}\n </div>\n </div>\n );\n}\n\n/** The window on a larger screen: a draggable/resizable react-rnd box. Until\n * react-rnd loads (and as a graceful fallback if it never does) the window is\n * statically positioned — still usable, just not draggable. */\nexport function ChatWindowFloating({\n panel,\n layerStyle,\n Rnd,\n onDragStart,\n onGeometryChange,\n children,\n}: {\n panel: ChatWindowState;\n /** Stacking style of the window layer, built by the host (ChatWindow). */\n layerStyle: CSSProperties;\n Rnd: ComponentType<RndProps> | null;\n onDragStart: () => void;\n onGeometryChange: (\n partial: Pick<Partial<ChatWindowState>, \"x\" | \"y\" | \"width\" | \"height\">,\n ) => void;\n children: ReactNode;\n}) {\n const outerClass = cn(\n \"fixed pointer-events-none\",\n panel.maximized ? \"inset-4 chat-maximized\" : \"inset-0\",\n );\n\n if (!Rnd) {\n return (\n <div className={outerClass} style={layerStyle}>\n <div\n className=\"pointer-events-auto h-full\"\n style={\n panel.maximized\n ? { position: \"relative\", width: \"100%\", height: \"100%\" }\n : {\n position: \"absolute\",\n left: panel.x,\n top: panel.y,\n width: panel.width,\n height: panel.height,\n }\n }\n >\n {children}\n </div>\n </div>\n );\n }\n\n return (\n <div className={outerClass} style={layerStyle}>\n <style>{MAXIMIZE_CSS}</style>\n <Rnd\n default={{\n x: panel.x,\n y: panel.y,\n width: panel.width,\n height: panel.height,\n }}\n style={{ pointerEvents: \"auto\" }}\n minWidth={Math.min(360, Math.max(1, window.innerWidth - 32))}\n minHeight={Math.min(400, Math.max(1, window.innerHeight - 32))}\n bounds=\"parent\"\n dragHandleClassName=\"chat-drag-handle\"\n disableDragging={panel.maximized}\n enableResizing={!panel.maximized}\n onDragStart={onDragStart}\n onDragStop={(_e, d) => onGeometryChange({ x: d.x, y: d.y })}\n onResizeStop={(_e, _dir, ref, _delta, pos) =>\n onGeometryChange({\n width: ref.offsetWidth,\n height: ref.offsetHeight,\n x: pos.x,\n y: pos.y,\n })\n }\n >\n {children}\n </Rnd>\n </div>\n );\n}\n"],"names":[],"mappings":";;AAQO,MAAM,2BAA2B;AAExC,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAed,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE,oBAAC,SAAI,QACH,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,eAAY;AAAA,MACZ,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,OAAO;AAAA,MAEN;AAAA,IAAA;AAAA,EAAA,GAEL;AAEJ;AAKO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUG;AACD,QAAM,aAAa;AAAA,IACjB;AAAA,IACA,MAAM,YAAY,2BAA2B;AAAA,EAAA;AAG/C,MAAI,CAAC,KAAK;AACR,WACE,oBAAC,OAAA,EAAI,WAAW,YAAY,OAAO,YACjC,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,OACE,MAAM,YACF,EAAE,UAAU,YAAY,OAAO,QAAQ,QAAQ,WAC/C;AAAA,UACE,UAAU;AAAA,UACV,MAAM,MAAM;AAAA,UACZ,KAAK,MAAM;AAAA,UACX,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,QAAA;AAAA,QAIrB;AAAA,MAAA;AAAA,IAAA,GAEL;AAAA,EAEJ;AAEA,SACE,qBAAC,OAAA,EAAI,WAAW,YAAY,OAAO,YACjC,UAAA;AAAA,IAAA,oBAAC,WAAO,UAAA,aAAA,CAAa;AAAA,IACrB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS;AAAA,UACP,GAAG,MAAM;AAAA,UACT,GAAG,MAAM;AAAA,UACT,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,QAAA;AAAA,QAEhB,OAAO,EAAE,eAAe,OAAA;AAAA,QACxB,UAAU,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,OAAO,aAAa,EAAE,CAAC;AAAA,QAC3D,WAAW,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,OAAO,cAAc,EAAE,CAAC;AAAA,QAC7D,QAAO;AAAA,QACP,qBAAoB;AAAA,QACpB,iBAAiB,MAAM;AAAA,QACvB,gBAAgB,CAAC,MAAM;AAAA,QACvB;AAAA,QACA,YAAY,CAAC,IAAI,MAAM,iBAAiB,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,EAAA,CAAG;AAAA,QAC1D,cAAc,CAAC,IAAI,MAAM,KAAK,QAAQ,QACpC,iBAAiB;AAAA,UACf,OAAO,IAAI;AAAA,UACX,QAAQ,IAAI;AAAA,UACZ,GAAG,IAAI;AAAA,UACP,GAAG,IAAI;AAAA,QAAA,CACR;AAAA,QAGF;AAAA,MAAA;AAAA,IAAA;AAAA,EACH,GACF;AAEJ;"}
@@ -12,6 +12,7 @@ function SessionChatComposer({
12
12
  capabilities,
13
13
  queued = [],
14
14
  error,
15
+ disabledReason,
15
16
  onSubmit,
16
17
  onInterrupt,
17
18
  toolbar,
@@ -24,7 +25,7 @@ function SessionChatComposer({
24
25
  }) {
25
26
  const active = status === "running" || status === "interrupting";
26
27
  const canSubmitWhileActive = capabilities.steer || capabilities.followUp;
27
- const disabled = status === "starting" || status === "interrupting" || status === "stopping" || status === "running" && !canSubmitWhileActive;
28
+ const disabled = disabledReason !== void 0 || status === "starting" || status === "interrupting" || status === "stopping" || status === "running" && !canSubmitWhileActive;
28
29
  const pickerReadOnly = !onPermissionModeChange || status === "starting" || status === "interrupting" || status === "stopping";
29
30
  const picker = permissionMode && permissionModes && permissionModes.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
30
31
  PermissionModePicker,
@@ -65,6 +66,7 @@ function SessionChatComposer({
65
66
  {
66
67
  status: active ? "streaming" : "ready",
67
68
  disabled,
69
+ ...disabledReason !== void 0 ? { disabledReason } : {},
68
70
  allowSubmitWhileStreaming: canSubmitWhileActive,
69
71
  stopLabel: "Interrupt",
70
72
  placeholder: status === "idle" ? "Continue this session…" : "Add a follow-up…",
@@ -1 +1 @@
1
- {"version":3,"file":"SessionChatComposer.cjs","sources":["../../../src/data/ai/SessionChatComposer.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Select } from \"../../components\";\nimport { PromptInput } from \"../chat/PromptInput\";\nimport { CLAUDE_PERMISSION_MODE_OPTIONS } from \"../chat/types\";\nimport { Icon } from \"../Icon\";\nimport { sessionTone } from \"./session-tones\";\nimport { permissionModeVisual } from \"./SpecRuntimeEditor/permission-mode-visuals\";\nimport type { SpecPermissionMode } from \"./SpecRuntimeEditor.model\";\n\nexport type SessionChatCapabilities = {\n interrupt: boolean;\n steer: boolean;\n followUp: boolean;\n resume: boolean;\n /** True when the live run's runtime can switch permission posture mid-session. */\n setPermissionMode?: boolean;\n};\n\nexport type SessionChatQueuedMessage = {\n messageId: string;\n text: string;\n};\n\nexport type SessionChatComposerProps = {\n status: \"starting\" | \"running\" | \"interrupting\" | \"idle\" | \"stopping\";\n capabilities: SessionChatCapabilities;\n queued?: SessionChatQueuedMessage[];\n error?: string;\n onSubmit: (text: string) => void;\n onInterrupt?: () => void;\n toolbar?: ReactNode;\n inputAccessory?: ReactNode;\n className?: string;\n /** Current permission posture, when the host tracks one for this session. */\n permissionMode?: SpecPermissionMode;\n /** Modes the run's runtime honours, canonical order. */\n permissionModes?: SpecPermissionMode[];\n /** Agent family (\"claude\", \"codex\", \"gemini\") whose vocabulary labels the modes. */\n permissionFamily?: string;\n /** Omit to render the picker read-only. */\n onPermissionModeChange?: (mode: SpecPermissionMode) => void;\n};\n\nexport function SessionChatComposer({\n status,\n capabilities,\n queued = [],\n error,\n onSubmit,\n onInterrupt,\n toolbar,\n inputAccessory,\n className,\n permissionMode,\n permissionModes,\n permissionFamily,\n onPermissionModeChange,\n}: SessionChatComposerProps) {\n const active = status === \"running\" || status === \"interrupting\";\n const canSubmitWhileActive = capabilities.steer || capabilities.followUp;\n const disabled =\n status === \"starting\" ||\n status === \"interrupting\" ||\n status === \"stopping\" ||\n (status === \"running\" && !canSubmitWhileActive);\n const pickerReadOnly =\n !onPermissionModeChange ||\n status === \"starting\" ||\n status === \"interrupting\" ||\n status === \"stopping\";\n const picker =\n permissionMode && permissionModes && permissionModes.length > 0 ? (\n <PermissionModePicker\n mode={permissionMode}\n modes={permissionModes}\n family={permissionFamily}\n readOnly={pickerReadOnly}\n {...(onPermissionModeChange ? { onChange: onPermissionModeChange } : {})}\n />\n ) : null;\n const composedToolbar =\n picker || toolbar ? (\n <>\n {picker}\n {toolbar}\n </>\n ) : undefined;\n\n return (\n <div className={className}>\n {queued.length > 0 && (\n <div\n className=\"mb-density-2 flex flex-wrap gap-density-1\"\n aria-label=\"Queued messages\"\n >\n {queued.map((message) => (\n <span\n key={message.messageId}\n className=\"max-w-full truncate rounded-full border border-border bg-muted px-density-2 py-1 text-xs text-muted-foreground\"\n >\n Queued: {message.text}\n </span>\n ))}\n </div>\n )}\n {error && (\n <div className=\"mb-density-2 text-xs text-destructive\">{error}</div>\n )}\n <PromptInput\n status={active ? \"streaming\" : \"ready\"}\n disabled={disabled}\n allowSubmitWhileStreaming={canSubmitWhileActive}\n stopLabel=\"Interrupt\"\n placeholder={\n status === \"idle\" ? \"Continue this session…\" : \"Add a follow-up…\"\n }\n onSubmit={(text) => onSubmit(text)}\n {...(inputAccessory ? { inputAccessory } : {})}\n {...(composedToolbar ? { toolbar: composedToolbar } : {})}\n {...(capabilities.interrupt && status === \"running\" && onInterrupt\n ? { onStop: onInterrupt }\n : {})}\n />\n </div>\n );\n}\n\nfunction PermissionModePicker({\n mode,\n modes,\n family,\n readOnly,\n onChange,\n}: {\n mode: SpecPermissionMode;\n modes: SpecPermissionMode[];\n family: string | undefined;\n readOnly: boolean;\n onChange?: (mode: SpecPermissionMode) => void;\n}) {\n const visual = permissionModeVisual(family, mode);\n const tone = sessionTone(visual.tone);\n return (\n <div className=\"inline-flex items-center gap-1.5\">\n <Icon\n icon={visual.icon}\n title={visual.label}\n className={`size-3.5 ${tone.text}`}\n />\n <Select\n aria-label=\"Permission mode\"\n value={mode}\n disabled={readOnly}\n onChange={(event) =>\n onChange?.(event.target.value as SpecPermissionMode)\n }\n className=\"h-7 w-auto min-w-24 py-0 text-xs\"\n >\n {modes.map((candidate) => (\n <option\n key={candidate}\n value={candidate}\n title={descriptionFor(family, candidate)}\n >\n {permissionModeVisual(family, candidate).label}\n </option>\n ))}\n </Select>\n </div>\n );\n}\n\n// The option descriptions document Claude's postures, so other families get none.\nfunction descriptionFor(\n family: string | undefined,\n mode: SpecPermissionMode,\n): string | undefined {\n if (family && family !== \"claude\") return undefined;\n return CLAUDE_PERMISSION_MODE_OPTIONS.find(\n (option) => option.value === mode,\n )?.description;\n}\n"],"names":["jsx","jsxs","Fragment","PromptInput","permissionModeVisual","sessionTone","Icon","Select","CLAUDE_PERMISSION_MODE_OPTIONS"],"mappings":"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"}
1
+ {"version":3,"file":"SessionChatComposer.cjs","sources":["../../../src/data/ai/SessionChatComposer.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Select } from \"../../components\";\nimport { PromptInput } from \"../chat/PromptInput\";\nimport { CLAUDE_PERMISSION_MODE_OPTIONS } from \"../chat/types\";\nimport { Icon } from \"../Icon\";\nimport { sessionTone } from \"./session-tones\";\nimport { permissionModeVisual } from \"./SpecRuntimeEditor/permission-mode-visuals\";\nimport type { SpecPermissionMode } from \"./SpecRuntimeEditor.model\";\n\nexport type SessionChatCapabilities = {\n interrupt: boolean;\n steer: boolean;\n followUp: boolean;\n resume: boolean;\n /** True when the live run's runtime can switch permission posture mid-session. */\n setPermissionMode?: boolean;\n};\n\nexport type SessionChatQueuedMessage = {\n messageId: string;\n text: string;\n};\n\nexport type SessionChatComposerProps = {\n status: \"starting\" | \"running\" | \"interrupting\" | \"idle\" | \"stopping\";\n capabilities: SessionChatCapabilities;\n queued?: SessionChatQueuedMessage[];\n error?: string;\n /** Disables the input and shows this reason in it (e.g. while the session\n * it continues is still loading, or could not be read). */\n disabledReason?: string;\n onSubmit: (text: string) => void;\n onInterrupt?: () => void;\n toolbar?: ReactNode;\n inputAccessory?: ReactNode;\n className?: string;\n /** Current permission posture, when the host tracks one for this session. */\n permissionMode?: SpecPermissionMode;\n /** Modes the run's runtime honours, canonical order. */\n permissionModes?: SpecPermissionMode[];\n /** Agent family (\"claude\", \"codex\", \"gemini\") whose vocabulary labels the modes. */\n permissionFamily?: string;\n /** Omit to render the picker read-only. */\n onPermissionModeChange?: (mode: SpecPermissionMode) => void;\n};\n\nexport function SessionChatComposer({\n status,\n capabilities,\n queued = [],\n error,\n disabledReason,\n onSubmit,\n onInterrupt,\n toolbar,\n inputAccessory,\n className,\n permissionMode,\n permissionModes,\n permissionFamily,\n onPermissionModeChange,\n}: SessionChatComposerProps) {\n const active = status === \"running\" || status === \"interrupting\";\n const canSubmitWhileActive = capabilities.steer || capabilities.followUp;\n const disabled =\n disabledReason !== undefined ||\n status === \"starting\" ||\n status === \"interrupting\" ||\n status === \"stopping\" ||\n (status === \"running\" && !canSubmitWhileActive);\n const pickerReadOnly =\n !onPermissionModeChange ||\n status === \"starting\" ||\n status === \"interrupting\" ||\n status === \"stopping\";\n const picker =\n permissionMode && permissionModes && permissionModes.length > 0 ? (\n <PermissionModePicker\n mode={permissionMode}\n modes={permissionModes}\n family={permissionFamily}\n readOnly={pickerReadOnly}\n {...(onPermissionModeChange ? { onChange: onPermissionModeChange } : {})}\n />\n ) : null;\n const composedToolbar =\n picker || toolbar ? (\n <>\n {picker}\n {toolbar}\n </>\n ) : undefined;\n\n return (\n <div className={className}>\n {queued.length > 0 && (\n <div\n className=\"mb-density-2 flex flex-wrap gap-density-1\"\n aria-label=\"Queued messages\"\n >\n {queued.map((message) => (\n <span\n key={message.messageId}\n className=\"max-w-full truncate rounded-full border border-border bg-muted px-density-2 py-1 text-xs text-muted-foreground\"\n >\n Queued: {message.text}\n </span>\n ))}\n </div>\n )}\n {error && (\n <div className=\"mb-density-2 text-xs text-destructive\">{error}</div>\n )}\n <PromptInput\n status={active ? \"streaming\" : \"ready\"}\n disabled={disabled}\n {...(disabledReason !== undefined ? { disabledReason } : {})}\n allowSubmitWhileStreaming={canSubmitWhileActive}\n stopLabel=\"Interrupt\"\n placeholder={\n status === \"idle\" ? \"Continue this session…\" : \"Add a follow-up…\"\n }\n onSubmit={(text) => onSubmit(text)}\n {...(inputAccessory ? { inputAccessory } : {})}\n {...(composedToolbar ? { toolbar: composedToolbar } : {})}\n {...(capabilities.interrupt && status === \"running\" && onInterrupt\n ? { onStop: onInterrupt }\n : {})}\n />\n </div>\n );\n}\n\nfunction PermissionModePicker({\n mode,\n modes,\n family,\n readOnly,\n onChange,\n}: {\n mode: SpecPermissionMode;\n modes: SpecPermissionMode[];\n family: string | undefined;\n readOnly: boolean;\n onChange?: (mode: SpecPermissionMode) => void;\n}) {\n const visual = permissionModeVisual(family, mode);\n const tone = sessionTone(visual.tone);\n return (\n <div className=\"inline-flex items-center gap-1.5\">\n <Icon\n icon={visual.icon}\n title={visual.label}\n className={`size-3.5 ${tone.text}`}\n />\n <Select\n aria-label=\"Permission mode\"\n value={mode}\n disabled={readOnly}\n onChange={(event) =>\n onChange?.(event.target.value as SpecPermissionMode)\n }\n className=\"h-7 w-auto min-w-24 py-0 text-xs\"\n >\n {modes.map((candidate) => (\n <option\n key={candidate}\n value={candidate}\n title={descriptionFor(family, candidate)}\n >\n {permissionModeVisual(family, candidate).label}\n </option>\n ))}\n </Select>\n </div>\n );\n}\n\n// The option descriptions document Claude's postures, so other families get none.\nfunction descriptionFor(\n family: string | undefined,\n mode: SpecPermissionMode,\n): string | undefined {\n if (family && family !== \"claude\") return undefined;\n return CLAUDE_PERMISSION_MODE_OPTIONS.find(\n (option) => option.value === mode,\n )?.description;\n}\n"],"names":["jsx","jsxs","Fragment","PromptInput","permissionModeVisual","sessionTone","Icon","Select","CLAUDE_PERMISSION_MODE_OPTIONS"],"mappings":"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"}
@@ -17,6 +17,9 @@ export type SessionChatComposerProps = {
17
17
  capabilities: SessionChatCapabilities;
18
18
  queued?: SessionChatQueuedMessage[];
19
19
  error?: string;
20
+ /** Disables the input and shows this reason in it (e.g. while the session
21
+ * it continues is still loading, or could not be read). */
22
+ disabledReason?: string;
20
23
  onSubmit: (text: string) => void;
21
24
  onInterrupt?: () => void;
22
25
  toolbar?: ReactNode;
@@ -31,5 +34,5 @@ export type SessionChatComposerProps = {
31
34
  /** Omit to render the picker read-only. */
32
35
  onPermissionModeChange?: (mode: SpecPermissionMode) => void;
33
36
  };
34
- export declare function SessionChatComposer({ status, capabilities, queued, error, onSubmit, onInterrupt, toolbar, inputAccessory, className, permissionMode, permissionModes, permissionFamily, onPermissionModeChange, }: SessionChatComposerProps): import("react").JSX.Element;
37
+ export declare function SessionChatComposer({ status, capabilities, queued, error, disabledReason, onSubmit, onInterrupt, toolbar, inputAccessory, className, permissionMode, permissionModes, permissionFamily, onPermissionModeChange, }: SessionChatComposerProps): import("react").JSX.Element;
35
38
  //# sourceMappingURL=SessionChatComposer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionChatComposer.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionChatComposer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;IACtE,YAAY,EAAE,uBAAuB,CAAC;IACtC,MAAM,CAAC,EAAE,wBAAwB,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,wDAAwD;IACxD,eAAe,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACvC,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IAC3C,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC7D,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,YAAY,EACZ,MAAW,EACX,KAAK,EACL,QAAQ,EACR,WAAW,EACX,OAAO,EACP,cAAc,EACd,SAAS,EACT,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,sBAAsB,GACvB,EAAE,wBAAwB,+BAoE1B"}
1
+ {"version":3,"file":"SessionChatComposer.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionChatComposer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;IACtE,YAAY,EAAE,uBAAuB,CAAC;IACtC,MAAM,CAAC,EAAE,wBAAwB,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;gEAC4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,wDAAwD;IACxD,eAAe,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACvC,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IAC3C,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC7D,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,YAAY,EACZ,MAAW,EACX,KAAK,EACL,cAAc,EACd,QAAQ,EACR,WAAW,EACX,OAAO,EACP,cAAc,EACd,SAAS,EACT,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,sBAAsB,GACvB,EAAE,wBAAwB,+BAsE1B"}
@@ -10,6 +10,7 @@ function SessionChatComposer({
10
10
  capabilities,
11
11
  queued = [],
12
12
  error,
13
+ disabledReason,
13
14
  onSubmit,
14
15
  onInterrupt,
15
16
  toolbar,
@@ -22,7 +23,7 @@ function SessionChatComposer({
22
23
  }) {
23
24
  const active = status === "running" || status === "interrupting";
24
25
  const canSubmitWhileActive = capabilities.steer || capabilities.followUp;
25
- const disabled = status === "starting" || status === "interrupting" || status === "stopping" || status === "running" && !canSubmitWhileActive;
26
+ const disabled = disabledReason !== void 0 || status === "starting" || status === "interrupting" || status === "stopping" || status === "running" && !canSubmitWhileActive;
26
27
  const pickerReadOnly = !onPermissionModeChange || status === "starting" || status === "interrupting" || status === "stopping";
27
28
  const picker = permissionMode && permissionModes && permissionModes.length > 0 ? /* @__PURE__ */ jsx(
28
29
  PermissionModePicker,
@@ -63,6 +64,7 @@ function SessionChatComposer({
63
64
  {
64
65
  status: active ? "streaming" : "ready",
65
66
  disabled,
67
+ ...disabledReason !== void 0 ? { disabledReason } : {},
66
68
  allowSubmitWhileStreaming: canSubmitWhileActive,
67
69
  stopLabel: "Interrupt",
68
70
  placeholder: status === "idle" ? "Continue this session…" : "Add a follow-up…",
@@ -1 +1 @@
1
- {"version":3,"file":"SessionChatComposer.js","sources":["../../../src/data/ai/SessionChatComposer.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Select } from \"../../components\";\nimport { PromptInput } from \"../chat/PromptInput\";\nimport { CLAUDE_PERMISSION_MODE_OPTIONS } from \"../chat/types\";\nimport { Icon } from \"../Icon\";\nimport { sessionTone } from \"./session-tones\";\nimport { permissionModeVisual } from \"./SpecRuntimeEditor/permission-mode-visuals\";\nimport type { SpecPermissionMode } from \"./SpecRuntimeEditor.model\";\n\nexport type SessionChatCapabilities = {\n interrupt: boolean;\n steer: boolean;\n followUp: boolean;\n resume: boolean;\n /** True when the live run's runtime can switch permission posture mid-session. */\n setPermissionMode?: boolean;\n};\n\nexport type SessionChatQueuedMessage = {\n messageId: string;\n text: string;\n};\n\nexport type SessionChatComposerProps = {\n status: \"starting\" | \"running\" | \"interrupting\" | \"idle\" | \"stopping\";\n capabilities: SessionChatCapabilities;\n queued?: SessionChatQueuedMessage[];\n error?: string;\n onSubmit: (text: string) => void;\n onInterrupt?: () => void;\n toolbar?: ReactNode;\n inputAccessory?: ReactNode;\n className?: string;\n /** Current permission posture, when the host tracks one for this session. */\n permissionMode?: SpecPermissionMode;\n /** Modes the run's runtime honours, canonical order. */\n permissionModes?: SpecPermissionMode[];\n /** Agent family (\"claude\", \"codex\", \"gemini\") whose vocabulary labels the modes. */\n permissionFamily?: string;\n /** Omit to render the picker read-only. */\n onPermissionModeChange?: (mode: SpecPermissionMode) => void;\n};\n\nexport function SessionChatComposer({\n status,\n capabilities,\n queued = [],\n error,\n onSubmit,\n onInterrupt,\n toolbar,\n inputAccessory,\n className,\n permissionMode,\n permissionModes,\n permissionFamily,\n onPermissionModeChange,\n}: SessionChatComposerProps) {\n const active = status === \"running\" || status === \"interrupting\";\n const canSubmitWhileActive = capabilities.steer || capabilities.followUp;\n const disabled =\n status === \"starting\" ||\n status === \"interrupting\" ||\n status === \"stopping\" ||\n (status === \"running\" && !canSubmitWhileActive);\n const pickerReadOnly =\n !onPermissionModeChange ||\n status === \"starting\" ||\n status === \"interrupting\" ||\n status === \"stopping\";\n const picker =\n permissionMode && permissionModes && permissionModes.length > 0 ? (\n <PermissionModePicker\n mode={permissionMode}\n modes={permissionModes}\n family={permissionFamily}\n readOnly={pickerReadOnly}\n {...(onPermissionModeChange ? { onChange: onPermissionModeChange } : {})}\n />\n ) : null;\n const composedToolbar =\n picker || toolbar ? (\n <>\n {picker}\n {toolbar}\n </>\n ) : undefined;\n\n return (\n <div className={className}>\n {queued.length > 0 && (\n <div\n className=\"mb-density-2 flex flex-wrap gap-density-1\"\n aria-label=\"Queued messages\"\n >\n {queued.map((message) => (\n <span\n key={message.messageId}\n className=\"max-w-full truncate rounded-full border border-border bg-muted px-density-2 py-1 text-xs text-muted-foreground\"\n >\n Queued: {message.text}\n </span>\n ))}\n </div>\n )}\n {error && (\n <div className=\"mb-density-2 text-xs text-destructive\">{error}</div>\n )}\n <PromptInput\n status={active ? \"streaming\" : \"ready\"}\n disabled={disabled}\n allowSubmitWhileStreaming={canSubmitWhileActive}\n stopLabel=\"Interrupt\"\n placeholder={\n status === \"idle\" ? \"Continue this session…\" : \"Add a follow-up…\"\n }\n onSubmit={(text) => onSubmit(text)}\n {...(inputAccessory ? { inputAccessory } : {})}\n {...(composedToolbar ? { toolbar: composedToolbar } : {})}\n {...(capabilities.interrupt && status === \"running\" && onInterrupt\n ? { onStop: onInterrupt }\n : {})}\n />\n </div>\n );\n}\n\nfunction PermissionModePicker({\n mode,\n modes,\n family,\n readOnly,\n onChange,\n}: {\n mode: SpecPermissionMode;\n modes: SpecPermissionMode[];\n family: string | undefined;\n readOnly: boolean;\n onChange?: (mode: SpecPermissionMode) => void;\n}) {\n const visual = permissionModeVisual(family, mode);\n const tone = sessionTone(visual.tone);\n return (\n <div className=\"inline-flex items-center gap-1.5\">\n <Icon\n icon={visual.icon}\n title={visual.label}\n className={`size-3.5 ${tone.text}`}\n />\n <Select\n aria-label=\"Permission mode\"\n value={mode}\n disabled={readOnly}\n onChange={(event) =>\n onChange?.(event.target.value as SpecPermissionMode)\n }\n className=\"h-7 w-auto min-w-24 py-0 text-xs\"\n >\n {modes.map((candidate) => (\n <option\n key={candidate}\n value={candidate}\n title={descriptionFor(family, candidate)}\n >\n {permissionModeVisual(family, candidate).label}\n </option>\n ))}\n </Select>\n </div>\n );\n}\n\n// The option descriptions document Claude's postures, so other families get none.\nfunction descriptionFor(\n family: string | undefined,\n mode: SpecPermissionMode,\n): string | undefined {\n if (family && family !== \"claude\") return undefined;\n return CLAUDE_PERMISSION_MODE_OPTIONS.find(\n (option) => option.value === mode,\n )?.description;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionChatComposer.js","sources":["../../../src/data/ai/SessionChatComposer.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Select } from \"../../components\";\nimport { PromptInput } from \"../chat/PromptInput\";\nimport { CLAUDE_PERMISSION_MODE_OPTIONS } from \"../chat/types\";\nimport { Icon } from \"../Icon\";\nimport { sessionTone } from \"./session-tones\";\nimport { permissionModeVisual } from \"./SpecRuntimeEditor/permission-mode-visuals\";\nimport type { SpecPermissionMode } from \"./SpecRuntimeEditor.model\";\n\nexport type SessionChatCapabilities = {\n interrupt: boolean;\n steer: boolean;\n followUp: boolean;\n resume: boolean;\n /** True when the live run's runtime can switch permission posture mid-session. */\n setPermissionMode?: boolean;\n};\n\nexport type SessionChatQueuedMessage = {\n messageId: string;\n text: string;\n};\n\nexport type SessionChatComposerProps = {\n status: \"starting\" | \"running\" | \"interrupting\" | \"idle\" | \"stopping\";\n capabilities: SessionChatCapabilities;\n queued?: SessionChatQueuedMessage[];\n error?: string;\n /** Disables the input and shows this reason in it (e.g. while the session\n * it continues is still loading, or could not be read). */\n disabledReason?: string;\n onSubmit: (text: string) => void;\n onInterrupt?: () => void;\n toolbar?: ReactNode;\n inputAccessory?: ReactNode;\n className?: string;\n /** Current permission posture, when the host tracks one for this session. */\n permissionMode?: SpecPermissionMode;\n /** Modes the run's runtime honours, canonical order. */\n permissionModes?: SpecPermissionMode[];\n /** Agent family (\"claude\", \"codex\", \"gemini\") whose vocabulary labels the modes. */\n permissionFamily?: string;\n /** Omit to render the picker read-only. */\n onPermissionModeChange?: (mode: SpecPermissionMode) => void;\n};\n\nexport function SessionChatComposer({\n status,\n capabilities,\n queued = [],\n error,\n disabledReason,\n onSubmit,\n onInterrupt,\n toolbar,\n inputAccessory,\n className,\n permissionMode,\n permissionModes,\n permissionFamily,\n onPermissionModeChange,\n}: SessionChatComposerProps) {\n const active = status === \"running\" || status === \"interrupting\";\n const canSubmitWhileActive = capabilities.steer || capabilities.followUp;\n const disabled =\n disabledReason !== undefined ||\n status === \"starting\" ||\n status === \"interrupting\" ||\n status === \"stopping\" ||\n (status === \"running\" && !canSubmitWhileActive);\n const pickerReadOnly =\n !onPermissionModeChange ||\n status === \"starting\" ||\n status === \"interrupting\" ||\n status === \"stopping\";\n const picker =\n permissionMode && permissionModes && permissionModes.length > 0 ? (\n <PermissionModePicker\n mode={permissionMode}\n modes={permissionModes}\n family={permissionFamily}\n readOnly={pickerReadOnly}\n {...(onPermissionModeChange ? { onChange: onPermissionModeChange } : {})}\n />\n ) : null;\n const composedToolbar =\n picker || toolbar ? (\n <>\n {picker}\n {toolbar}\n </>\n ) : undefined;\n\n return (\n <div className={className}>\n {queued.length > 0 && (\n <div\n className=\"mb-density-2 flex flex-wrap gap-density-1\"\n aria-label=\"Queued messages\"\n >\n {queued.map((message) => (\n <span\n key={message.messageId}\n className=\"max-w-full truncate rounded-full border border-border bg-muted px-density-2 py-1 text-xs text-muted-foreground\"\n >\n Queued: {message.text}\n </span>\n ))}\n </div>\n )}\n {error && (\n <div className=\"mb-density-2 text-xs text-destructive\">{error}</div>\n )}\n <PromptInput\n status={active ? \"streaming\" : \"ready\"}\n disabled={disabled}\n {...(disabledReason !== undefined ? { disabledReason } : {})}\n allowSubmitWhileStreaming={canSubmitWhileActive}\n stopLabel=\"Interrupt\"\n placeholder={\n status === \"idle\" ? \"Continue this session…\" : \"Add a follow-up…\"\n }\n onSubmit={(text) => onSubmit(text)}\n {...(inputAccessory ? { inputAccessory } : {})}\n {...(composedToolbar ? { toolbar: composedToolbar } : {})}\n {...(capabilities.interrupt && status === \"running\" && onInterrupt\n ? { onStop: onInterrupt }\n : {})}\n />\n </div>\n );\n}\n\nfunction PermissionModePicker({\n mode,\n modes,\n family,\n readOnly,\n onChange,\n}: {\n mode: SpecPermissionMode;\n modes: SpecPermissionMode[];\n family: string | undefined;\n readOnly: boolean;\n onChange?: (mode: SpecPermissionMode) => void;\n}) {\n const visual = permissionModeVisual(family, mode);\n const tone = sessionTone(visual.tone);\n return (\n <div className=\"inline-flex items-center gap-1.5\">\n <Icon\n icon={visual.icon}\n title={visual.label}\n className={`size-3.5 ${tone.text}`}\n />\n <Select\n aria-label=\"Permission mode\"\n value={mode}\n disabled={readOnly}\n onChange={(event) =>\n onChange?.(event.target.value as SpecPermissionMode)\n }\n className=\"h-7 w-auto min-w-24 py-0 text-xs\"\n >\n {modes.map((candidate) => (\n <option\n key={candidate}\n value={candidate}\n title={descriptionFor(family, candidate)}\n >\n {permissionModeVisual(family, candidate).label}\n </option>\n ))}\n </Select>\n </div>\n );\n}\n\n// The option descriptions document Claude's postures, so other families get none.\nfunction descriptionFor(\n family: string | undefined,\n mode: SpecPermissionMode,\n): string | undefined {\n if (family && family !== \"claude\") return undefined;\n return CLAUDE_PERMISSION_MODE_OPTIONS.find(\n (option) => option.value === mode,\n )?.description;\n}\n"],"names":[],"mappings":"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"}