@flanksource/clicky-ui 0.3.17 → 0.3.18

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 (822) hide show
  1. package/dist/ai.cjs +12 -6
  2. package/dist/ai.cjs.map +1 -1
  3. package/dist/ai.js +10 -4
  4. package/dist/ai.js.map +1 -1
  5. package/dist/chat.cjs +36 -0
  6. package/dist/chat.cjs.map +1 -1
  7. package/dist/chat.js +37 -1
  8. package/dist/chat.js.map +1 -1
  9. package/dist/components/Combobox.cjs +122 -153
  10. package/dist/components/Combobox.cjs.map +1 -1
  11. package/dist/components/Combobox.d.ts.map +1 -1
  12. package/dist/components/Combobox.js +124 -155
  13. package/dist/components/Combobox.js.map +1 -1
  14. package/dist/components/ComboboxControl.cjs +145 -0
  15. package/dist/components/ComboboxControl.cjs.map +1 -0
  16. package/dist/components/ComboboxControl.d.ts +37 -0
  17. package/dist/components/ComboboxControl.d.ts.map +1 -0
  18. package/dist/components/ComboboxControl.js +145 -0
  19. package/dist/components/ComboboxControl.js.map +1 -0
  20. package/dist/components/ComboboxMenu.cjs +31 -14
  21. package/dist/components/ComboboxMenu.cjs.map +1 -1
  22. package/dist/components/ComboboxMenu.d.ts.map +1 -1
  23. package/dist/components/ComboboxMenu.js +31 -14
  24. package/dist/components/ComboboxMenu.js.map +1 -1
  25. package/dist/components/ComboboxTags.cjs +40 -0
  26. package/dist/components/ComboboxTags.cjs.map +1 -0
  27. package/dist/components/ComboboxTags.d.ts +8 -0
  28. package/dist/components/ComboboxTags.d.ts.map +1 -0
  29. package/dist/components/ComboboxTags.js +40 -0
  30. package/dist/components/ComboboxTags.js.map +1 -0
  31. package/dist/components/ErrorWrapper.cjs +168 -0
  32. package/dist/components/ErrorWrapper.cjs.map +1 -0
  33. package/dist/components/ErrorWrapper.d.ts +19 -0
  34. package/dist/components/ErrorWrapper.d.ts.map +1 -0
  35. package/dist/components/ErrorWrapper.js +168 -0
  36. package/dist/components/ErrorWrapper.js.map +1 -0
  37. package/dist/components/FilterBar.cjs +64 -2
  38. package/dist/components/FilterBar.cjs.map +1 -1
  39. package/dist/components/FilterBar.d.ts +18 -1
  40. package/dist/components/FilterBar.d.ts.map +1 -1
  41. package/dist/components/FilterBar.js +64 -2
  42. package/dist/components/FilterBar.js.map +1 -1
  43. package/dist/components/JSONPathField.cjs +91 -0
  44. package/dist/components/JSONPathField.cjs.map +1 -0
  45. package/dist/components/JSONPathField.d.ts +19 -0
  46. package/dist/components/JSONPathField.d.ts.map +1 -0
  47. package/dist/components/JSONPathField.js +91 -0
  48. package/dist/components/JSONPathField.js.map +1 -0
  49. package/dist/components/JsonSchemaForm.cjs +8 -4
  50. package/dist/components/JsonSchemaForm.cjs.map +1 -1
  51. package/dist/components/JsonSchemaForm.d.ts.map +1 -1
  52. package/dist/components/JsonSchemaForm.js +8 -4
  53. package/dist/components/JsonSchemaForm.js.map +1 -1
  54. package/dist/components/TreePickerField.cjs +22 -4
  55. package/dist/components/TreePickerField.cjs.map +1 -1
  56. package/dist/components/TreePickerField.d.ts +22 -2
  57. package/dist/components/TreePickerField.d.ts.map +1 -1
  58. package/dist/components/TreePickerField.js +22 -4
  59. package/dist/components/TreePickerField.js.map +1 -1
  60. package/dist/components/TriStateToggle.cjs +53 -0
  61. package/dist/components/TriStateToggle.cjs.map +1 -0
  62. package/dist/components/TriStateToggle.d.ts +27 -0
  63. package/dist/components/TriStateToggle.d.ts.map +1 -0
  64. package/dist/components/TriStateToggle.js +53 -0
  65. package/dist/components/TriStateToggle.js.map +1 -0
  66. package/dist/components/combobox-types.d.ts +16 -1
  67. package/dist/components/combobox-types.d.ts.map +1 -1
  68. package/dist/components/combobox-utils.cjs +26 -0
  69. package/dist/components/combobox-utils.cjs.map +1 -1
  70. package/dist/components/combobox-utils.d.ts +10 -0
  71. package/dist/components/combobox-utils.d.ts.map +1 -1
  72. package/dist/components/combobox-utils.js +26 -0
  73. package/dist/components/combobox-utils.js.map +1 -1
  74. package/dist/components/filter-bar-utils.cjs +5 -0
  75. package/dist/components/filter-bar-utils.cjs.map +1 -1
  76. package/dist/components/filter-bar-utils.d.ts.map +1 -1
  77. package/dist/components/filter-bar-utils.js +5 -0
  78. package/dist/components/filter-bar-utils.js.map +1 -1
  79. package/dist/components/json-schema-form-accordion-array.cjs +290 -0
  80. package/dist/components/json-schema-form-accordion-array.cjs.map +1 -0
  81. package/dist/components/json-schema-form-accordion-array.d.ts +7 -0
  82. package/dist/components/json-schema-form-accordion-array.d.ts.map +1 -0
  83. package/dist/components/json-schema-form-accordion-array.js +290 -0
  84. package/dist/components/json-schema-form-accordion-array.js.map +1 -0
  85. package/dist/components/json-schema-form-array.cjs +99 -110
  86. package/dist/components/json-schema-form-array.cjs.map +1 -1
  87. package/dist/components/json-schema-form-array.d.ts +1 -1
  88. package/dist/components/json-schema-form-array.d.ts.map +1 -1
  89. package/dist/components/json-schema-form-array.js +98 -109
  90. package/dist/components/json-schema-form-array.js.map +1 -1
  91. package/dist/components/json-schema-form-error-display.cjs +4 -2
  92. package/dist/components/json-schema-form-error-display.cjs.map +1 -1
  93. package/dist/components/json-schema-form-error-display.d.ts +4 -2
  94. package/dist/components/json-schema-form-error-display.d.ts.map +1 -1
  95. package/dist/components/json-schema-form-error-display.js +4 -2
  96. package/dist/components/json-schema-form-error-display.js.map +1 -1
  97. package/dist/components/json-schema-form-extensions.cjs +10 -0
  98. package/dist/components/json-schema-form-extensions.cjs.map +1 -0
  99. package/dist/components/json-schema-form-extensions.d.ts +8 -0
  100. package/dist/components/json-schema-form-extensions.d.ts.map +1 -0
  101. package/dist/components/json-schema-form-extensions.js +10 -0
  102. package/dist/components/json-schema-form-extensions.js.map +1 -0
  103. package/dist/components/json-schema-form-fields.cjs +25 -101
  104. package/dist/components/json-schema-form-fields.cjs.map +1 -1
  105. package/dist/components/json-schema-form-fields.d.ts +1 -32
  106. package/dist/components/json-schema-form-fields.d.ts.map +1 -1
  107. package/dist/components/json-schema-form-fields.js +28 -104
  108. package/dist/components/json-schema-form-fields.js.map +1 -1
  109. package/dist/components/json-schema-form-item-summary.cjs +131 -0
  110. package/dist/components/json-schema-form-item-summary.cjs.map +1 -0
  111. package/dist/components/json-schema-form-item-summary.d.ts +13 -0
  112. package/dist/components/json-schema-form-item-summary.d.ts.map +1 -0
  113. package/dist/components/json-schema-form-item-summary.js +131 -0
  114. package/dist/components/json-schema-form-item-summary.js.map +1 -0
  115. package/dist/components/json-schema-form-layout.cjs +156 -0
  116. package/dist/components/json-schema-form-layout.cjs.map +1 -0
  117. package/dist/components/json-schema-form-layout.d.ts +43 -0
  118. package/dist/components/json-schema-form-layout.d.ts.map +1 -0
  119. package/dist/components/json-schema-form-layout.js +156 -0
  120. package/dist/components/json-schema-form-layout.js.map +1 -0
  121. package/dist/components/json-schema-form-lookup-tree.cjs +149 -0
  122. package/dist/components/json-schema-form-lookup-tree.cjs.map +1 -0
  123. package/dist/components/json-schema-form-lookup-tree.d.ts +22 -0
  124. package/dist/components/json-schema-form-lookup-tree.d.ts.map +1 -0
  125. package/dist/components/json-schema-form-lookup-tree.js +149 -0
  126. package/dist/components/json-schema-form-lookup-tree.js.map +1 -0
  127. package/dist/components/json-schema-form-object.cjs +11 -4
  128. package/dist/components/json-schema-form-object.cjs.map +1 -1
  129. package/dist/components/json-schema-form-object.d.ts.map +1 -1
  130. package/dist/components/json-schema-form-object.js +11 -4
  131. package/dist/components/json-schema-form-object.js.map +1 -1
  132. package/dist/components/json-schema-form-render.cjs +51 -28
  133. package/dist/components/json-schema-form-render.cjs.map +1 -1
  134. package/dist/components/json-schema-form-render.d.ts.map +1 -1
  135. package/dist/components/json-schema-form-render.js +51 -28
  136. package/dist/components/json-schema-form-render.js.map +1 -1
  137. package/dist/components/json-schema-form-resolve.cjs +62 -13
  138. package/dist/components/json-schema-form-resolve.cjs.map +1 -1
  139. package/dist/components/json-schema-form-resolve.d.ts +1 -0
  140. package/dist/components/json-schema-form-resolve.d.ts.map +1 -1
  141. package/dist/components/json-schema-form-resolve.js +62 -13
  142. package/dist/components/json-schema-form-resolve.js.map +1 -1
  143. package/dist/components/json-schema-form-table-array.cjs +123 -0
  144. package/dist/components/json-schema-form-table-array.cjs.map +1 -0
  145. package/dist/components/json-schema-form-table-array.d.ts +7 -0
  146. package/dist/components/json-schema-form-table-array.d.ts.map +1 -0
  147. package/dist/components/json-schema-form-table-array.js +123 -0
  148. package/dist/components/json-schema-form-table-array.js.map +1 -0
  149. package/dist/components/json-schema-form-tone.cjs +34 -0
  150. package/dist/components/json-schema-form-tone.cjs.map +1 -0
  151. package/dist/components/json-schema-form-tone.d.ts +8 -0
  152. package/dist/components/json-schema-form-tone.d.ts.map +1 -0
  153. package/dist/components/json-schema-form-tone.js +34 -0
  154. package/dist/components/json-schema-form-tone.js.map +1 -0
  155. package/dist/components/json-schema-form-types.d.ts +79 -10
  156. package/dist/components/json-schema-form-types.d.ts.map +1 -1
  157. package/dist/components/json-schema-form-utils.cjs +47 -4
  158. package/dist/components/json-schema-form-utils.cjs.map +1 -1
  159. package/dist/components/json-schema-form-utils.d.ts +19 -4
  160. package/dist/components/json-schema-form-utils.d.ts.map +1 -1
  161. package/dist/components/json-schema-form-utils.js +47 -4
  162. package/dist/components/json-schema-form-utils.js.map +1 -1
  163. package/dist/components/tri-state.cjs +8 -0
  164. package/dist/components/tri-state.cjs.map +1 -0
  165. package/dist/components/tri-state.d.ts +5 -0
  166. package/dist/components/tri-state.d.ts.map +1 -0
  167. package/dist/components/tri-state.js +8 -0
  168. package/dist/components/tri-state.js.map +1 -0
  169. package/dist/components/useComboboxLayout.cjs +59 -0
  170. package/dist/components/useComboboxLayout.cjs.map +1 -0
  171. package/dist/components/useComboboxLayout.d.ts +5 -0
  172. package/dist/components/useComboboxLayout.d.ts.map +1 -0
  173. package/dist/components/useComboboxLayout.js +59 -0
  174. package/dist/components/useComboboxLayout.js.map +1 -0
  175. package/dist/components.cjs +21 -0
  176. package/dist/components.cjs.map +1 -1
  177. package/dist/components.d.ts +14 -4
  178. package/dist/components.d.ts.map +1 -1
  179. package/dist/components.js +22 -1
  180. package/dist/components.js.map +1 -1
  181. package/dist/data/Clicky.cjs +51 -2
  182. package/dist/data/Clicky.cjs.map +1 -1
  183. package/dist/data/Clicky.d.ts +10 -1
  184. package/dist/data/Clicky.d.ts.map +1 -1
  185. package/dist/data/Clicky.js +51 -2
  186. package/dist/data/Clicky.js.map +1 -1
  187. package/dist/data/DataTable.cjs +185 -53
  188. package/dist/data/DataTable.cjs.map +1 -1
  189. package/dist/data/DataTable.d.ts +63 -3
  190. package/dist/data/DataTable.d.ts.map +1 -1
  191. package/dist/data/DataTable.js +185 -53
  192. package/dist/data/DataTable.js.map +1 -1
  193. package/dist/data/LogsTable.cjs +10 -1
  194. package/dist/data/LogsTable.cjs.map +1 -1
  195. package/dist/data/LogsTable.d.ts +3 -1
  196. package/dist/data/LogsTable.d.ts.map +1 -1
  197. package/dist/data/LogsTable.js +10 -1
  198. package/dist/data/LogsTable.js.map +1 -1
  199. package/dist/data/TaskManager.cjs +99 -14
  200. package/dist/data/TaskManager.cjs.map +1 -1
  201. package/dist/data/TaskManager.d.ts.map +1 -1
  202. package/dist/data/TaskManager.js +100 -15
  203. package/dist/data/TaskManager.js.map +1 -1
  204. package/dist/data/TaskProgress.cjs +50 -11
  205. package/dist/data/TaskProgress.cjs.map +1 -1
  206. package/dist/data/TaskProgress.d.ts +2 -1
  207. package/dist/data/TaskProgress.d.ts.map +1 -1
  208. package/dist/data/TaskProgress.js +50 -11
  209. package/dist/data/TaskProgress.js.map +1 -1
  210. package/dist/data/ai/AdvancedChatConfig.cjs +289 -0
  211. package/dist/data/ai/AdvancedChatConfig.cjs.map +1 -0
  212. package/dist/data/ai/AdvancedChatConfig.d.ts +21 -0
  213. package/dist/data/ai/AdvancedChatConfig.d.ts.map +1 -0
  214. package/dist/data/ai/AdvancedChatConfig.js +289 -0
  215. package/dist/data/ai/AdvancedChatConfig.js.map +1 -0
  216. package/dist/data/ai/AdvancedCostsPanel.cjs +120 -0
  217. package/dist/data/ai/AdvancedCostsPanel.cjs.map +1 -0
  218. package/dist/data/ai/AdvancedCostsPanel.d.ts +16 -0
  219. package/dist/data/ai/AdvancedCostsPanel.d.ts.map +1 -0
  220. package/dist/data/ai/AdvancedCostsPanel.js +120 -0
  221. package/dist/data/ai/AdvancedCostsPanel.js.map +1 -0
  222. package/dist/data/ai/ChatWindow.catalogs.cjs +74 -0
  223. package/dist/data/ai/ChatWindow.catalogs.cjs.map +1 -0
  224. package/dist/data/ai/ChatWindow.catalogs.d.ts +16 -0
  225. package/dist/data/ai/ChatWindow.catalogs.d.ts.map +1 -0
  226. package/dist/data/ai/ChatWindow.catalogs.js +74 -0
  227. package/dist/data/ai/ChatWindow.catalogs.js.map +1 -0
  228. package/dist/data/ai/ChatWindow.cjs +78 -100
  229. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  230. package/dist/data/ai/ChatWindow.d.ts +1 -1
  231. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  232. package/dist/data/ai/ChatWindow.js +80 -102
  233. package/dist/data/ai/ChatWindow.js.map +1 -1
  234. package/dist/data/ai/ChatWindow.preferences.cjs.map +1 -1
  235. package/dist/data/ai/ChatWindow.preferences.d.ts +2 -4
  236. package/dist/data/ai/ChatWindow.preferences.d.ts.map +1 -1
  237. package/dist/data/ai/ChatWindow.preferences.js.map +1 -1
  238. package/dist/data/ai/ChatWindow.runtime.cjs +120 -0
  239. package/dist/data/ai/ChatWindow.runtime.cjs.map +1 -0
  240. package/dist/data/ai/ChatWindow.runtime.d.ts +20 -0
  241. package/dist/data/ai/ChatWindow.runtime.d.ts.map +1 -0
  242. package/dist/data/ai/ChatWindow.runtime.js +120 -0
  243. package/dist/data/ai/ChatWindow.runtime.js.map +1 -0
  244. package/dist/data/ai/ChatWindow.thread.cjs +1 -1
  245. package/dist/data/ai/ChatWindow.thread.cjs.map +1 -1
  246. package/dist/data/ai/ChatWindow.thread.js +1 -1
  247. package/dist/data/ai/ChatWindow.thread.js.map +1 -1
  248. package/dist/data/ai/ChatWindow.tool-catalog.cjs +20 -0
  249. package/dist/data/ai/ChatWindow.tool-catalog.cjs.map +1 -1
  250. package/dist/data/ai/ChatWindow.tool-catalog.d.ts +17 -1
  251. package/dist/data/ai/ChatWindow.tool-catalog.d.ts.map +1 -1
  252. package/dist/data/ai/ChatWindow.tool-catalog.js +20 -0
  253. package/dist/data/ai/ChatWindow.tool-catalog.js.map +1 -1
  254. package/dist/data/ai/ChatWindow.types.d.ts +13 -5
  255. package/dist/data/ai/ChatWindow.types.d.ts.map +1 -1
  256. package/dist/data/ai/ChatWindowManager.cjs +3 -1
  257. package/dist/data/ai/ChatWindowManager.cjs.map +1 -1
  258. package/dist/data/ai/ChatWindowManager.d.ts.map +1 -1
  259. package/dist/data/ai/ChatWindowManager.js +3 -1
  260. package/dist/data/ai/ChatWindowManager.js.map +1 -1
  261. package/dist/data/ai/PromptPicker/PromptPicker.cjs +1 -1
  262. package/dist/data/ai/PromptPicker/PromptPicker.cjs.map +1 -1
  263. package/dist/data/ai/PromptPicker/PromptPicker.d.ts +1 -1
  264. package/dist/data/ai/PromptPicker/PromptPicker.d.ts.map +1 -1
  265. package/dist/data/ai/PromptPicker/PromptPicker.js +1 -1
  266. package/dist/data/ai/PromptPicker/PromptPicker.js.map +1 -1
  267. package/dist/data/ai/PromptRunEditor/index.cjs +2 -2
  268. package/dist/data/ai/PromptRunEditor/index.cjs.map +1 -1
  269. package/dist/data/ai/PromptRunEditor/index.d.ts +1 -1
  270. package/dist/data/ai/PromptRunEditor/index.d.ts.map +1 -1
  271. package/dist/data/ai/PromptRunEditor/index.js +2 -2
  272. package/dist/data/ai/PromptRunEditor/index.js.map +1 -1
  273. package/dist/data/ai/RuntimeModePicker.cjs +1 -1
  274. package/dist/data/ai/RuntimeModePicker.cjs.map +1 -1
  275. package/dist/data/ai/RuntimeModePicker.d.ts +1 -1
  276. package/dist/data/ai/RuntimeModePicker.d.ts.map +1 -1
  277. package/dist/data/ai/RuntimeModePicker.js +1 -1
  278. package/dist/data/ai/RuntimeModePicker.js.map +1 -1
  279. package/dist/data/ai/SessionInspector.files.cjs +26 -43
  280. package/dist/data/ai/SessionInspector.files.cjs.map +1 -1
  281. package/dist/data/ai/SessionInspector.files.d.ts.map +1 -1
  282. package/dist/data/ai/SessionInspector.files.js +26 -43
  283. package/dist/data/ai/SessionInspector.files.js.map +1 -1
  284. package/dist/data/ai/SessionInspector.hierarchy.cjs +1 -1
  285. package/dist/data/ai/SessionInspector.hierarchy.cjs.map +1 -1
  286. package/dist/data/ai/SessionInspector.hierarchy.js +1 -1
  287. package/dist/data/ai/SessionInspector.hierarchy.js.map +1 -1
  288. package/dist/data/ai/SessionInspector.model.cjs +1 -1
  289. package/dist/data/ai/SessionInspector.model.cjs.map +1 -1
  290. package/dist/data/ai/SessionInspector.model.js +1 -1
  291. package/dist/data/ai/SessionInspector.model.js.map +1 -1
  292. package/dist/data/ai/SessionViewer.rows.cjs +4 -16
  293. package/dist/data/ai/SessionViewer.rows.cjs.map +1 -1
  294. package/dist/data/ai/SessionViewer.rows.d.ts.map +1 -1
  295. package/dist/data/ai/SessionViewer.rows.js +4 -16
  296. package/dist/data/ai/SessionViewer.rows.js.map +1 -1
  297. package/dist/data/ai/SpecRuntimeEditor/ModelSection.cjs +12 -3
  298. package/dist/data/ai/SpecRuntimeEditor/ModelSection.cjs.map +1 -1
  299. package/dist/data/ai/SpecRuntimeEditor/ModelSection.d.ts +1 -1
  300. package/dist/data/ai/SpecRuntimeEditor/ModelSection.d.ts.map +1 -1
  301. package/dist/data/ai/SpecRuntimeEditor/ModelSection.js +12 -3
  302. package/dist/data/ai/SpecRuntimeEditor/ModelSection.js.map +1 -1
  303. package/dist/data/ai/SpecRuntimeEditor/VerifySection.cjs.map +1 -1
  304. package/dist/data/ai/SpecRuntimeEditor/VerifySection.d.ts +1 -1
  305. package/dist/data/ai/SpecRuntimeEditor/VerifySection.d.ts.map +1 -1
  306. package/dist/data/ai/SpecRuntimeEditor/VerifySection.js.map +1 -1
  307. package/dist/data/ai/SpecRuntimeEditor/fields.js +1 -1
  308. package/dist/data/ai/SpecRuntimeEditor/index.cjs.map +1 -1
  309. package/dist/data/ai/SpecRuntimeEditor/index.d.ts +2 -2
  310. package/dist/data/ai/SpecRuntimeEditor/index.d.ts.map +1 -1
  311. package/dist/data/ai/SpecRuntimeEditor/index.js.map +1 -1
  312. package/dist/data/ai/ThreadPicker.cjs +65 -3
  313. package/dist/data/ai/ThreadPicker.cjs.map +1 -1
  314. package/dist/data/ai/ThreadPicker.d.ts +11 -5
  315. package/dist/data/ai/ThreadPicker.d.ts.map +1 -1
  316. package/dist/data/ai/ThreadPicker.js +65 -3
  317. package/dist/data/ai/ThreadPicker.js.map +1 -1
  318. package/dist/data/ai/ToolPreferences.cjs +65 -685
  319. package/dist/data/ai/ToolPreferences.cjs.map +1 -1
  320. package/dist/data/ai/ToolPreferences.d.ts +15 -17
  321. package/dist/data/ai/ToolPreferences.d.ts.map +1 -1
  322. package/dist/data/ai/ToolPreferences.js +64 -683
  323. package/dist/data/ai/ToolPreferences.js.map +1 -1
  324. package/dist/data/ai/ToolPreferences.model.cjs +148 -0
  325. package/dist/data/ai/ToolPreferences.model.cjs.map +1 -0
  326. package/dist/data/ai/ToolPreferences.model.d.ts +31 -0
  327. package/dist/data/ai/ToolPreferences.model.d.ts.map +1 -0
  328. package/dist/data/ai/ToolPreferences.model.js +148 -0
  329. package/dist/data/ai/ToolPreferences.model.js.map +1 -0
  330. package/dist/data/ai/ToolPreferencesList.cjs +270 -0
  331. package/dist/data/ai/ToolPreferencesList.cjs.map +1 -0
  332. package/dist/data/ai/ToolPreferencesList.d.ts +18 -0
  333. package/dist/data/ai/ToolPreferencesList.d.ts.map +1 -0
  334. package/dist/data/ai/ToolPreferencesList.js +270 -0
  335. package/dist/data/ai/ToolPreferencesList.js.map +1 -0
  336. package/dist/data/ai/agent-action-icons.cjs.map +1 -1
  337. package/dist/data/ai/agent-action-icons.js.map +1 -1
  338. package/dist/data/ai/chat-window-context.cjs +4 -1
  339. package/dist/data/ai/chat-window-context.cjs.map +1 -1
  340. package/dist/data/ai/chat-window-context.d.ts +7 -0
  341. package/dist/data/ai/chat-window-context.d.ts.map +1 -1
  342. package/dist/data/ai/chat-window-context.js +4 -1
  343. package/dist/data/ai/chat-window-context.js.map +1 -1
  344. package/dist/data/ai/index.d.ts +6 -3
  345. package/dist/data/ai/index.d.ts.map +1 -1
  346. package/dist/data/ai/session-tones.cjs +67 -0
  347. package/dist/data/ai/session-tones.cjs.map +1 -0
  348. package/dist/data/ai/session-tones.d.ts +34 -0
  349. package/dist/data/ai/session-tones.d.ts.map +1 -0
  350. package/dist/data/ai/session-tones.js +67 -0
  351. package/dist/data/ai/session-tones.js.map +1 -0
  352. package/dist/data/ai/thread-costs.cjs +39 -0
  353. package/dist/data/ai/thread-costs.cjs.map +1 -0
  354. package/dist/data/ai/thread-costs.d.ts +62 -0
  355. package/dist/data/ai/thread-costs.d.ts.map +1 -0
  356. package/dist/data/ai/thread-costs.js +39 -0
  357. package/dist/data/ai/thread-costs.js.map +1 -0
  358. package/dist/data/cells/CellFilterActions.cjs +68 -0
  359. package/dist/data/cells/CellFilterActions.cjs.map +1 -0
  360. package/dist/data/cells/CellFilterActions.d.ts +15 -0
  361. package/dist/data/cells/CellFilterActions.d.ts.map +1 -0
  362. package/dist/data/cells/CellFilterActions.js +68 -0
  363. package/dist/data/cells/CellFilterActions.js.map +1 -0
  364. package/dist/data/chat/Chat.cjs +156 -113
  365. package/dist/data/chat/Chat.cjs.map +1 -1
  366. package/dist/data/chat/Chat.d.ts +24 -7
  367. package/dist/data/chat/Chat.d.ts.map +1 -1
  368. package/dist/data/chat/Chat.fixtures.cjs +48 -3
  369. package/dist/data/chat/Chat.fixtures.cjs.map +1 -1
  370. package/dist/data/chat/Chat.fixtures.d.ts +1 -1
  371. package/dist/data/chat/Chat.fixtures.d.ts.map +1 -1
  372. package/dist/data/chat/Chat.fixtures.js +48 -3
  373. package/dist/data/chat/Chat.fixtures.js.map +1 -1
  374. package/dist/data/chat/Chat.js +160 -117
  375. package/dist/data/chat/Chat.js.map +1 -1
  376. package/dist/data/chat/Chat.runtime.cjs +63 -0
  377. package/dist/data/chat/Chat.runtime.cjs.map +1 -0
  378. package/dist/data/chat/Chat.runtime.d.ts +16 -0
  379. package/dist/data/chat/Chat.runtime.d.ts.map +1 -0
  380. package/dist/data/chat/Chat.runtime.js +63 -0
  381. package/dist/data/chat/Chat.runtime.js.map +1 -0
  382. package/dist/data/chat/ChatRuntimeToolbar.cjs +62 -0
  383. package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -0
  384. package/dist/data/chat/ChatRuntimeToolbar.d.ts +14 -0
  385. package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -0
  386. package/dist/data/chat/ChatRuntimeToolbar.js +62 -0
  387. package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -0
  388. package/dist/data/chat/ToolCall.cjs +86 -24
  389. package/dist/data/chat/ToolCall.cjs.map +1 -1
  390. package/dist/data/chat/ToolCall.d.ts +12 -5
  391. package/dist/data/chat/ToolCall.d.ts.map +1 -1
  392. package/dist/data/chat/ToolCall.js +86 -24
  393. package/dist/data/chat/ToolCall.js.map +1 -1
  394. package/dist/data/chat/approval.cjs +49 -6
  395. package/dist/data/chat/approval.cjs.map +1 -1
  396. package/dist/data/chat/approval.d.ts +11 -4
  397. package/dist/data/chat/approval.d.ts.map +1 -1
  398. package/dist/data/chat/approval.js +49 -6
  399. package/dist/data/chat/approval.js.map +1 -1
  400. package/dist/data/chat/index.d.ts +5 -3
  401. package/dist/data/chat/index.d.ts.map +1 -1
  402. package/dist/data/chat/tool-render/ToolArgs.cjs +50 -0
  403. package/dist/data/chat/tool-render/ToolArgs.cjs.map +1 -0
  404. package/dist/data/chat/tool-render/ToolArgs.d.ts +7 -0
  405. package/dist/data/chat/tool-render/ToolArgs.d.ts.map +1 -0
  406. package/dist/data/chat/tool-render/ToolArgs.js +50 -0
  407. package/dist/data/chat/tool-render/ToolArgs.js.map +1 -0
  408. package/dist/data/chat/tool-render/ToolParams.cjs +155 -0
  409. package/dist/data/chat/tool-render/ToolParams.cjs.map +1 -0
  410. package/dist/data/chat/tool-render/ToolParams.d.ts +20 -0
  411. package/dist/data/chat/tool-render/ToolParams.d.ts.map +1 -0
  412. package/dist/data/chat/tool-render/ToolParams.js +155 -0
  413. package/dist/data/chat/tool-render/ToolParams.js.map +1 -0
  414. package/dist/data/chat/tool-render/ToolValue.cjs +140 -0
  415. package/dist/data/chat/tool-render/ToolValue.cjs.map +1 -0
  416. package/dist/data/chat/tool-render/ToolValue.d.ts +16 -0
  417. package/dist/data/chat/tool-render/ToolValue.d.ts.map +1 -0
  418. package/dist/data/chat/tool-render/ToolValue.js +140 -0
  419. package/dist/data/chat/tool-render/ToolValue.js.map +1 -0
  420. package/dist/data/chat/tool-render/adapter.cjs +48 -0
  421. package/dist/data/chat/tool-render/adapter.cjs.map +1 -0
  422. package/dist/data/chat/tool-render/adapter.d.ts +57 -0
  423. package/dist/data/chat/tool-render/adapter.d.ts.map +1 -0
  424. package/dist/data/chat/tool-render/adapter.js +48 -0
  425. package/dist/data/chat/tool-render/adapter.js.map +1 -0
  426. package/dist/data/chat/tool-render/context.cjs +16 -0
  427. package/dist/data/chat/tool-render/context.cjs.map +1 -0
  428. package/dist/data/chat/tool-render/context.d.ts +6 -0
  429. package/dist/data/chat/tool-render/context.d.ts.map +1 -0
  430. package/dist/data/chat/tool-render/context.js +16 -0
  431. package/dist/data/chat/tool-render/context.js.map +1 -0
  432. package/dist/data/chat/tool-render/defaults.cjs +45 -0
  433. package/dist/data/chat/tool-render/defaults.cjs.map +1 -0
  434. package/dist/data/chat/tool-render/defaults.d.ts +11 -0
  435. package/dist/data/chat/tool-render/defaults.d.ts.map +1 -0
  436. package/dist/data/chat/tool-render/defaults.js +45 -0
  437. package/dist/data/chat/tool-render/defaults.js.map +1 -0
  438. package/dist/data/chat/tool-render/index.d.ts +13 -0
  439. package/dist/data/chat/tool-render/index.d.ts.map +1 -0
  440. package/dist/data/chat/tool-render/known-tool-views.cjs +208 -0
  441. package/dist/data/chat/tool-render/known-tool-views.cjs.map +1 -0
  442. package/dist/data/chat/tool-render/known-tool-views.d.ts +10 -0
  443. package/dist/data/chat/tool-render/known-tool-views.d.ts.map +1 -0
  444. package/dist/data/chat/tool-render/known-tool-views.js +208 -0
  445. package/dist/data/chat/tool-render/known-tool-views.js.map +1 -0
  446. package/dist/data/chat/tool-render/known-tools.cjs +58 -0
  447. package/dist/data/chat/tool-render/known-tools.cjs.map +1 -0
  448. package/dist/data/chat/tool-render/known-tools.d.ts +4 -0
  449. package/dist/data/chat/tool-render/known-tools.d.ts.map +1 -0
  450. package/dist/data/chat/tool-render/known-tools.js +58 -0
  451. package/dist/data/chat/tool-render/known-tools.js.map +1 -0
  452. package/dist/data/chat/tool-render/normalize.cjs +42 -0
  453. package/dist/data/chat/tool-render/normalize.cjs.map +1 -0
  454. package/dist/data/chat/tool-render/normalize.d.ts +13 -0
  455. package/dist/data/chat/tool-render/normalize.d.ts.map +1 -0
  456. package/dist/data/chat/tool-render/normalize.js +42 -0
  457. package/dist/data/chat/tool-render/normalize.js.map +1 -0
  458. package/dist/data/chat/tool-render/registry.cjs +14 -0
  459. package/dist/data/chat/tool-render/registry.cjs.map +1 -0
  460. package/dist/data/chat/tool-render/registry.d.ts +7 -0
  461. package/dist/data/chat/tool-render/registry.d.ts.map +1 -0
  462. package/dist/data/chat/tool-render/registry.js +14 -0
  463. package/dist/data/chat/tool-render/registry.js.map +1 -0
  464. package/dist/data/chat/tool-render/schema.cjs +57 -0
  465. package/dist/data/chat/tool-render/schema.cjs.map +1 -0
  466. package/dist/data/chat/tool-render/schema.d.ts +28 -0
  467. package/dist/data/chat/tool-render/schema.d.ts.map +1 -0
  468. package/dist/data/chat/tool-render/schema.js +57 -0
  469. package/dist/data/chat/tool-render/schema.js.map +1 -0
  470. package/dist/data/chat/tool-render/shape.cjs +94 -0
  471. package/dist/data/chat/tool-render/shape.cjs.map +1 -0
  472. package/dist/data/chat/tool-render/shape.d.ts +39 -0
  473. package/dist/data/chat/tool-render/shape.d.ts.map +1 -0
  474. package/dist/data/chat/tool-render/shape.js +94 -0
  475. package/dist/data/chat/tool-render/shape.js.map +1 -0
  476. package/dist/data/chat/tool-render/summary.cjs +34 -0
  477. package/dist/data/chat/tool-render/summary.cjs.map +1 -0
  478. package/dist/data/chat/tool-render/summary.d.ts +8 -0
  479. package/dist/data/chat/tool-render/summary.d.ts.map +1 -0
  480. package/dist/data/chat/tool-render/summary.js +34 -0
  481. package/dist/data/chat/tool-render/summary.js.map +1 -0
  482. package/dist/data/chat/types.cjs.map +1 -1
  483. package/dist/data/chat/types.d.ts +7 -0
  484. package/dist/data/chat/types.d.ts.map +1 -1
  485. package/dist/data/chat/types.js.map +1 -1
  486. package/dist/data/chat/usage-snapshot.cjs +17 -0
  487. package/dist/data/chat/usage-snapshot.cjs.map +1 -0
  488. package/dist/data/chat/usage-snapshot.d.ts +21 -0
  489. package/dist/data/chat/usage-snapshot.d.ts.map +1 -0
  490. package/dist/data/chat/usage-snapshot.js +17 -0
  491. package/dist/data/chat/usage-snapshot.js.map +1 -0
  492. package/dist/data/data-table-filter-values.cjs +83 -0
  493. package/dist/data/data-table-filter-values.cjs.map +1 -0
  494. package/dist/data/data-table-filter-values.d.ts +18 -0
  495. package/dist/data/data-table-filter-values.d.ts.map +1 -0
  496. package/dist/data/data-table-filter-values.js +83 -0
  497. package/dist/data/data-table-filter-values.js.map +1 -0
  498. package/dist/data/data-table-server-filters.cjs +171 -0
  499. package/dist/data/data-table-server-filters.cjs.map +1 -0
  500. package/dist/data/data-table-server-filters.d.ts +128 -0
  501. package/dist/data/data-table-server-filters.d.ts.map +1 -0
  502. package/dist/data/data-table-server-filters.js +171 -0
  503. package/dist/data/data-table-server-filters.js.map +1 -0
  504. package/dist/data/query-browser/QueryBrowser.cjs +96 -19
  505. package/dist/data/query-browser/QueryBrowser.cjs.map +1 -1
  506. package/dist/data/query-browser/QueryBrowser.d.ts +37 -6
  507. package/dist/data/query-browser/QueryBrowser.d.ts.map +1 -1
  508. package/dist/data/query-browser/QueryBrowser.js +96 -19
  509. package/dist/data/query-browser/QueryBrowser.js.map +1 -1
  510. package/dist/data/query-browser/index.d.ts +1 -1
  511. package/dist/data/query-browser/index.d.ts.map +1 -1
  512. package/dist/data/runtime/ProviderStatusPanel.cjs +187 -0
  513. package/dist/data/runtime/ProviderStatusPanel.cjs.map +1 -0
  514. package/dist/data/runtime/ProviderStatusPanel.d.ts +10 -0
  515. package/dist/data/runtime/ProviderStatusPanel.d.ts.map +1 -0
  516. package/dist/data/runtime/ProviderStatusPanel.js +187 -0
  517. package/dist/data/runtime/ProviderStatusPanel.js.map +1 -0
  518. package/dist/data/runtime/RuntimeBar.cjs +147 -0
  519. package/dist/data/runtime/RuntimeBar.cjs.map +1 -0
  520. package/dist/data/{ai → runtime}/RuntimeBar.d.ts +8 -6
  521. package/dist/data/runtime/RuntimeBar.d.ts.map +1 -0
  522. package/dist/data/runtime/RuntimeBar.js +147 -0
  523. package/dist/data/runtime/RuntimeBar.js.map +1 -0
  524. package/dist/data/runtime/RuntimeBar.model.cjs.map +1 -0
  525. package/dist/data/{ai → runtime}/RuntimeBar.model.d.ts +2 -2
  526. package/dist/data/runtime/RuntimeBar.model.d.ts.map +1 -0
  527. package/dist/data/runtime/RuntimeBar.model.js.map +1 -0
  528. package/dist/data/{ai → runtime}/RuntimeBarCombo.cjs +25 -30
  529. package/dist/data/runtime/RuntimeBarCombo.cjs.map +1 -0
  530. package/dist/data/{ai → runtime}/RuntimeBarCombo.d.ts +4 -3
  531. package/dist/data/runtime/RuntimeBarCombo.d.ts.map +1 -0
  532. package/dist/data/{ai → runtime}/RuntimeBarCombo.js +25 -30
  533. package/dist/data/runtime/RuntimeBarCombo.js.map +1 -0
  534. package/dist/data/{ai/RuntimeBar.cjs → runtime/RuntimeBarSegments.cjs} +54 -120
  535. package/dist/data/runtime/RuntimeBarSegments.cjs.map +1 -0
  536. package/dist/data/runtime/RuntimeBarSegments.d.ts +25 -0
  537. package/dist/data/runtime/RuntimeBarSegments.d.ts.map +1 -0
  538. package/dist/data/{ai/RuntimeBar.js → runtime/RuntimeBarSegments.js} +58 -124
  539. package/dist/data/runtime/RuntimeBarSegments.js.map +1 -0
  540. package/dist/data/runtime/availability.cjs +11 -0
  541. package/dist/data/runtime/availability.cjs.map +1 -0
  542. package/dist/data/runtime/availability.d.ts +6 -0
  543. package/dist/data/runtime/availability.d.ts.map +1 -0
  544. package/dist/data/runtime/availability.js +11 -0
  545. package/dist/data/runtime/availability.js.map +1 -0
  546. package/dist/data/runtime/model-capabilities.cjs.map +1 -0
  547. package/dist/data/runtime/model-capabilities.d.ts.map +1 -0
  548. package/dist/data/runtime/model-capabilities.js.map +1 -0
  549. package/dist/data/runtime/provider-status.cjs +106 -0
  550. package/dist/data/runtime/provider-status.cjs.map +1 -0
  551. package/dist/data/runtime/provider-status.d.ts +24 -0
  552. package/dist/data/runtime/provider-status.d.ts.map +1 -0
  553. package/dist/data/runtime/provider-status.js +106 -0
  554. package/dist/data/runtime/provider-status.js.map +1 -0
  555. package/dist/data/{ai → runtime}/runtime-mode.cjs +119 -27
  556. package/dist/data/runtime/runtime-mode.cjs.map +1 -0
  557. package/dist/data/{ai → runtime}/runtime-mode.d.ts +7 -1
  558. package/dist/data/runtime/runtime-mode.d.ts.map +1 -0
  559. package/dist/data/{ai → runtime}/runtime-mode.js +120 -28
  560. package/dist/data/runtime/runtime-mode.js.map +1 -0
  561. package/dist/data/task-query-keys.cjs +26 -0
  562. package/dist/data/task-query-keys.cjs.map +1 -0
  563. package/dist/data/task-query-keys.d.ts +27 -0
  564. package/dist/data/task-query-keys.d.ts.map +1 -0
  565. package/dist/data/task-query-keys.js +26 -0
  566. package/dist/data/task-query-keys.js.map +1 -0
  567. package/dist/data/version-info.cjs +3 -3
  568. package/dist/data/version-info.js +3 -3
  569. package/dist/data.cjs +16 -0
  570. package/dist/data.cjs.map +1 -1
  571. package/dist/data.d.ts +6 -2
  572. package/dist/data.d.ts.map +1 -1
  573. package/dist/data.js +16 -0
  574. package/dist/data.js.map +1 -1
  575. package/dist/hooks/use-hotkey.cjs +6 -1
  576. package/dist/hooks/use-hotkey.cjs.map +1 -1
  577. package/dist/hooks/use-hotkey.d.ts.map +1 -1
  578. package/dist/hooks/use-hotkey.js +6 -1
  579. package/dist/hooks/use-hotkey.js.map +1 -1
  580. package/dist/hooks/use-task-run.cjs +7 -4
  581. package/dist/hooks/use-task-run.cjs.map +1 -1
  582. package/dist/hooks/use-task-run.d.ts +12 -0
  583. package/dist/hooks/use-task-run.d.ts.map +1 -1
  584. package/dist/hooks/use-task-run.js +7 -4
  585. package/dist/hooks/use-task-run.js.map +1 -1
  586. package/dist/icons/index.d.ts +1 -0
  587. package/dist/icons/index.d.ts.map +1 -1
  588. package/dist/icons/registry.cjs +692 -0
  589. package/dist/icons/registry.cjs.map +1 -0
  590. package/dist/icons/registry.d.ts +21 -0
  591. package/dist/icons/registry.d.ts.map +1 -0
  592. package/dist/icons/registry.js +692 -0
  593. package/dist/icons/registry.js.map +1 -0
  594. package/dist/icons.cjs +3 -0
  595. package/dist/icons.cjs.map +1 -1
  596. package/dist/icons.js +4 -1
  597. package/dist/icons.js.map +1 -1
  598. package/dist/index.cjs +47 -0
  599. package/dist/index.cjs.map +1 -1
  600. package/dist/index.js +49 -2
  601. package/dist/index.js.map +1 -1
  602. package/dist/layout/AppShell.cjs +92 -56
  603. package/dist/layout/AppShell.cjs.map +1 -1
  604. package/dist/layout/AppShell.d.ts +49 -1
  605. package/dist/layout/AppShell.d.ts.map +1 -1
  606. package/dist/layout/AppShell.js +92 -56
  607. package/dist/layout/AppShell.js.map +1 -1
  608. package/dist/layout/AppShell.nav.cjs +144 -19
  609. package/dist/layout/AppShell.nav.cjs.map +1 -1
  610. package/dist/layout/AppShell.nav.d.ts +6 -1
  611. package/dist/layout/AppShell.nav.d.ts.map +1 -1
  612. package/dist/layout/AppShell.nav.js +144 -19
  613. package/dist/layout/AppShell.nav.js.map +1 -1
  614. package/dist/layout/SplitPane.cjs +23 -7
  615. package/dist/layout/SplitPane.cjs.map +1 -1
  616. package/dist/layout/SplitPane.d.ts +3 -1
  617. package/dist/layout/SplitPane.d.ts.map +1 -1
  618. package/dist/layout/SplitPane.js +23 -7
  619. package/dist/layout/SplitPane.js.map +1 -1
  620. package/dist/lib/format.cjs +86 -4
  621. package/dist/lib/format.cjs.map +1 -1
  622. package/dist/lib/format.d.ts +69 -0
  623. package/dist/lib/format.d.ts.map +1 -1
  624. package/dist/lib/format.js +86 -4
  625. package/dist/lib/format.js.map +1 -1
  626. package/dist/lib/path-tree.cjs +69 -0
  627. package/dist/lib/path-tree.cjs.map +1 -0
  628. package/dist/lib/path-tree.d.ts +54 -0
  629. package/dist/lib/path-tree.d.ts.map +1 -0
  630. package/dist/lib/path-tree.js +69 -0
  631. package/dist/lib/path-tree.js.map +1 -0
  632. package/dist/monaco.d.ts +1 -0
  633. package/dist/monaco.d.ts.map +1 -1
  634. package/dist/overlay/DropdownMenuSubmenu.cjs +13 -7
  635. package/dist/overlay/DropdownMenuSubmenu.cjs.map +1 -1
  636. package/dist/overlay/DropdownMenuSubmenu.d.ts.map +1 -1
  637. package/dist/overlay/DropdownMenuSubmenu.js +13 -7
  638. package/dist/overlay/DropdownMenuSubmenu.js.map +1 -1
  639. package/dist/overlay/Tour.cjs +173 -0
  640. package/dist/overlay/Tour.cjs.map +1 -0
  641. package/dist/overlay/Tour.d.ts +61 -0
  642. package/dist/overlay/Tour.d.ts.map +1 -0
  643. package/dist/overlay/Tour.js +173 -0
  644. package/dist/overlay/Tour.js.map +1 -0
  645. package/dist/overlay/TourCard.cjs +108 -0
  646. package/dist/overlay/TourCard.cjs.map +1 -0
  647. package/dist/overlay/TourCard.d.ts +23 -0
  648. package/dist/overlay/TourCard.d.ts.map +1 -0
  649. package/dist/overlay/TourCard.js +108 -0
  650. package/dist/overlay/TourCard.js.map +1 -0
  651. package/dist/overlay/TourProvider.cjs +160 -0
  652. package/dist/overlay/TourProvider.cjs.map +1 -0
  653. package/dist/overlay/TourProvider.d.ts +31 -0
  654. package/dist/overlay/TourProvider.d.ts.map +1 -0
  655. package/dist/overlay/TourProvider.js +160 -0
  656. package/dist/overlay/TourProvider.js.map +1 -0
  657. package/dist/overlay/TourSpotlight.cjs +47 -0
  658. package/dist/overlay/TourSpotlight.cjs.map +1 -0
  659. package/dist/overlay/TourSpotlight.d.ts +12 -0
  660. package/dist/overlay/TourSpotlight.d.ts.map +1 -0
  661. package/dist/overlay/TourSpotlight.js +47 -0
  662. package/dist/overlay/TourSpotlight.js.map +1 -0
  663. package/dist/overlay/modalStack.cjs +18 -4
  664. package/dist/overlay/modalStack.cjs.map +1 -1
  665. package/dist/overlay/modalStack.d.ts +10 -2
  666. package/dist/overlay/modalStack.d.ts.map +1 -1
  667. package/dist/overlay/modalStack.js +19 -5
  668. package/dist/overlay/modalStack.js.map +1 -1
  669. package/dist/overlay/tour-anchor.cjs +114 -0
  670. package/dist/overlay/tour-anchor.cjs.map +1 -0
  671. package/dist/overlay/tour-anchor.d.ts +30 -0
  672. package/dist/overlay/tour-anchor.d.ts.map +1 -0
  673. package/dist/overlay/tour-anchor.js +114 -0
  674. package/dist/overlay/tour-anchor.js.map +1 -0
  675. package/dist/overlay/tour-context.cjs +12 -0
  676. package/dist/overlay/tour-context.cjs.map +1 -0
  677. package/dist/overlay/tour-context.d.ts +40 -0
  678. package/dist/overlay/tour-context.d.ts.map +1 -0
  679. package/dist/overlay/tour-context.js +12 -0
  680. package/dist/overlay/tour-context.js.map +1 -0
  681. package/dist/overlay/tour-geometry.cjs +65 -0
  682. package/dist/overlay/tour-geometry.cjs.map +1 -0
  683. package/dist/overlay/tour-geometry.d.ts +47 -0
  684. package/dist/overlay/tour-geometry.d.ts.map +1 -0
  685. package/dist/overlay/tour-geometry.js +65 -0
  686. package/dist/overlay/tour-geometry.js.map +1 -0
  687. package/dist/overlay/tour-model.cjs +79 -0
  688. package/dist/overlay/tour-model.cjs.map +1 -0
  689. package/dist/overlay/tour-model.d.ts +29 -0
  690. package/dist/overlay/tour-model.d.ts.map +1 -0
  691. package/dist/overlay/tour-model.js +79 -0
  692. package/dist/overlay/tour-model.js.map +1 -0
  693. package/dist/overlay/tour-progress.cjs +54 -0
  694. package/dist/overlay/tour-progress.cjs.map +1 -0
  695. package/dist/overlay/tour-progress.d.ts +40 -0
  696. package/dist/overlay/tour-progress.d.ts.map +1 -0
  697. package/dist/overlay/tour-progress.js +54 -0
  698. package/dist/overlay/tour-progress.js.map +1 -0
  699. package/dist/overlay/tour-types.d.ts +144 -0
  700. package/dist/overlay/tour-types.d.ts.map +1 -0
  701. package/dist/overlay/use-tour-anchor.cjs +43 -0
  702. package/dist/overlay/use-tour-anchor.cjs.map +1 -0
  703. package/dist/overlay/use-tour-anchor.d.ts +23 -0
  704. package/dist/overlay/use-tour-anchor.d.ts.map +1 -0
  705. package/dist/overlay/use-tour-anchor.js +43 -0
  706. package/dist/overlay/use-tour-anchor.js.map +1 -0
  707. package/dist/overlay/use-tour-rect.cjs +33 -0
  708. package/dist/overlay/use-tour-rect.cjs.map +1 -0
  709. package/dist/overlay/use-tour-rect.d.ts +12 -0
  710. package/dist/overlay/use-tour-rect.d.ts.map +1 -0
  711. package/dist/overlay/use-tour-rect.js +33 -0
  712. package/dist/overlay/use-tour-rect.js.map +1 -0
  713. package/dist/overlay/use-tour-step.cjs +66 -0
  714. package/dist/overlay/use-tour-step.cjs.map +1 -0
  715. package/dist/overlay/use-tour-step.d.ts +45 -0
  716. package/dist/overlay/use-tour-step.d.ts.map +1 -0
  717. package/dist/overlay/use-tour-step.js +66 -0
  718. package/dist/overlay/use-tour-step.js.map +1 -0
  719. package/dist/overlay/zIndex.cjs +8 -0
  720. package/dist/overlay/zIndex.cjs.map +1 -1
  721. package/dist/overlay/zIndex.d.ts +8 -0
  722. package/dist/overlay/zIndex.d.ts.map +1 -1
  723. package/dist/overlay/zIndex.js +8 -0
  724. package/dist/overlay/zIndex.js.map +1 -1
  725. package/dist/rpc/CommandOutput.cjs +8 -0
  726. package/dist/rpc/CommandOutput.cjs.map +1 -1
  727. package/dist/rpc/CommandOutput.d.ts +4 -1
  728. package/dist/rpc/CommandOutput.d.ts.map +1 -1
  729. package/dist/rpc/CommandOutput.js +8 -0
  730. package/dist/rpc/CommandOutput.js.map +1 -1
  731. package/dist/rpc/EntityExplorerApp.cjs +10 -16
  732. package/dist/rpc/EntityExplorerApp.cjs.map +1 -1
  733. package/dist/rpc/EntityExplorerApp.d.ts.map +1 -1
  734. package/dist/rpc/EntityExplorerApp.js +10 -16
  735. package/dist/rpc/EntityExplorerApp.js.map +1 -1
  736. package/dist/rpc/OperationActionBar.cjs +1 -1
  737. package/dist/rpc/OperationActionBar.cjs.map +1 -1
  738. package/dist/rpc/OperationActionBar.js +1 -1
  739. package/dist/rpc/OperationActionBar.js.map +1 -1
  740. package/dist/rpc/OperationCatalog.cjs +83 -7
  741. package/dist/rpc/OperationCatalog.cjs.map +1 -1
  742. package/dist/rpc/OperationCatalog.d.ts.map +1 -1
  743. package/dist/rpc/OperationCatalog.js +84 -8
  744. package/dist/rpc/OperationCatalog.js.map +1 -1
  745. package/dist/rpc/OperationResultView.cjs +2 -0
  746. package/dist/rpc/OperationResultView.cjs.map +1 -1
  747. package/dist/rpc/OperationResultView.d.ts +6 -0
  748. package/dist/rpc/OperationResultView.d.ts.map +1 -1
  749. package/dist/rpc/OperationResultView.js +2 -0
  750. package/dist/rpc/OperationResultView.js.map +1 -1
  751. package/dist/rpc/SchemaActionForm.cjs +2 -21
  752. package/dist/rpc/SchemaActionForm.cjs.map +1 -1
  753. package/dist/rpc/SchemaActionForm.d.ts.map +1 -1
  754. package/dist/rpc/SchemaActionForm.js +3 -22
  755. package/dist/rpc/SchemaActionForm.js.map +1 -1
  756. package/dist/rpc/apiClient.cjs +16 -2
  757. package/dist/rpc/apiClient.cjs.map +1 -1
  758. package/dist/rpc/apiClient.d.ts.map +1 -1
  759. package/dist/rpc/apiClient.js +16 -2
  760. package/dist/rpc/apiClient.js.map +1 -1
  761. package/dist/rpc/formMetadata.cjs +89 -49
  762. package/dist/rpc/formMetadata.cjs.map +1 -1
  763. package/dist/rpc/formMetadata.d.ts +14 -6
  764. package/dist/rpc/formMetadata.d.ts.map +1 -1
  765. package/dist/rpc/formMetadata.js +87 -47
  766. package/dist/rpc/formMetadata.js.map +1 -1
  767. package/dist/rpc/operationFilterSearch.cjs +23 -0
  768. package/dist/rpc/operationFilterSearch.cjs.map +1 -0
  769. package/dist/rpc/operationFilterSearch.d.ts +22 -0
  770. package/dist/rpc/operationFilterSearch.d.ts.map +1 -0
  771. package/dist/rpc/operationFilterSearch.js +23 -0
  772. package/dist/rpc/operationFilterSearch.js.map +1 -0
  773. package/dist/rpc/operationLookupFetcher.cjs +28 -0
  774. package/dist/rpc/operationLookupFetcher.cjs.map +1 -0
  775. package/dist/rpc/operationLookupFetcher.d.ts +17 -0
  776. package/dist/rpc/operationLookupFetcher.d.ts.map +1 -0
  777. package/dist/rpc/operationLookupFetcher.js +28 -0
  778. package/dist/rpc/operationLookupFetcher.js.map +1 -0
  779. package/dist/rpc/surfaceNav.cjs +77 -0
  780. package/dist/rpc/surfaceNav.cjs.map +1 -0
  781. package/dist/rpc/surfaceNav.d.ts +19 -0
  782. package/dist/rpc/surfaceNav.d.ts.map +1 -0
  783. package/dist/rpc/surfaceNav.js +77 -0
  784. package/dist/rpc/surfaceNav.js.map +1 -0
  785. package/dist/rpc/types.cjs.map +1 -1
  786. package/dist/rpc/types.d.ts +12 -1
  787. package/dist/rpc/types.d.ts.map +1 -1
  788. package/dist/rpc/types.js.map +1 -1
  789. package/dist/rpc.cjs +2 -0
  790. package/dist/rpc.cjs.map +1 -1
  791. package/dist/rpc.d.ts +1 -0
  792. package/dist/rpc.d.ts.map +1 -1
  793. package/dist/rpc.js +2 -0
  794. package/dist/rpc.js.map +1 -1
  795. package/dist/styles.css +1 -1
  796. package/dist/utils.cjs +8 -0
  797. package/dist/utils.cjs.map +1 -1
  798. package/dist/utils.d.ts +2 -1
  799. package/dist/utils.d.ts.map +1 -1
  800. package/dist/utils.js +10 -2
  801. package/dist/utils.js.map +1 -1
  802. package/package.json +1 -1
  803. package/dist/data/ai/RuntimeBar.cjs.map +0 -1
  804. package/dist/data/ai/RuntimeBar.d.ts.map +0 -1
  805. package/dist/data/ai/RuntimeBar.js.map +0 -1
  806. package/dist/data/ai/RuntimeBar.model.cjs.map +0 -1
  807. package/dist/data/ai/RuntimeBar.model.d.ts.map +0 -1
  808. package/dist/data/ai/RuntimeBar.model.js.map +0 -1
  809. package/dist/data/ai/RuntimeBarCombo.cjs.map +0 -1
  810. package/dist/data/ai/RuntimeBarCombo.d.ts.map +0 -1
  811. package/dist/data/ai/RuntimeBarCombo.js.map +0 -1
  812. package/dist/data/ai/model-capabilities.cjs.map +0 -1
  813. package/dist/data/ai/model-capabilities.d.ts.map +0 -1
  814. package/dist/data/ai/model-capabilities.js.map +0 -1
  815. package/dist/data/ai/runtime-mode.cjs.map +0 -1
  816. package/dist/data/ai/runtime-mode.d.ts.map +0 -1
  817. package/dist/data/ai/runtime-mode.js.map +0 -1
  818. /package/dist/data/{ai → runtime}/RuntimeBar.model.cjs +0 -0
  819. /package/dist/data/{ai → runtime}/RuntimeBar.model.js +0 -0
  820. /package/dist/data/{ai → runtime}/model-capabilities.cjs +0 -0
  821. /package/dist/data/{ai → runtime}/model-capabilities.d.ts +0 -0
  822. /package/dist/data/{ai → runtime}/model-capabilities.js +0 -0
package/dist/data.js CHANGED
@@ -7,6 +7,8 @@ import { CodeBlock } from "./data/CodeBlock.js";
7
7
  import { CodeDiff } from "./data/CodeDiff.js";
8
8
  import { computeLineDiff, parseUnifiedDiff } from "./data/code-diff.js";
9
9
  import { inferColumns } from "./data/data-table-utils.js";
10
+ import { parseMultiFilterValue, serializeMultiFilterValue, splitCommaValues, updateFilterSelection } from "./data/data-table-filter-values.js";
11
+ import { DATA_TABLE_FILTER_LOOKUP_LIMIT, serverColumnsToDataTableColumns, serverFiltersToFilterBar } from "./data/data-table-server-filters.js";
10
12
  import { DataTable } from "./data/DataTable.js";
11
13
  import { groupRecords, isGroupCollapsedByDefault } from "./data/DataTable.grouping.js";
12
14
  import { StatStrip } from "./data/StatStrip.js";
@@ -14,6 +16,7 @@ import { EntityCell } from "./data/cells/EntityCell.js";
14
16
  import { Timestamp } from "./data/cells/Timestamp.js";
15
17
  import { chooseTimestampFormat, formatDateTimeRelative, formatRelativeTime, formatTimestamp, modeToFormat, parseTimestamp } from "./data/cells/timestamp-format.js";
16
18
  import { TagActionsProvider, TagList } from "./data/cells/TagList.js";
19
+ import { CellFilterActions } from "./data/cells/CellFilterActions.js";
17
20
  import { normalizeTags, splitTagToken, tagActionsFromRecord, tagFilterTokens, useTagActions, useTagActionsValue } from "./data/cells/tag-utils.js";
18
21
  import { StatusDot } from "./data/cells/StatusDot.js";
19
22
  import { STATUS_TOKEN_GROUPS, normalizeStatus } from "./data/cells/status-mapping.js";
@@ -69,6 +72,7 @@ import { allGroupsTerminal, isTerminalStatus } from "./data/TaskSnapshot.js";
69
72
  import { bucketTasks, logLevelColor, taskSegments, taskStatusBg, taskStatusColor, taskStatusIcon } from "./data/task-status.js";
70
73
  import { TaskProgress } from "./data/TaskProgress.js";
71
74
  import { TaskManager } from "./data/TaskManager.js";
75
+ import { taskQueryKeys } from "./data/task-query-keys.js";
72
76
  import { TaskManagerButton } from "./data/TaskManagerButton.js";
73
77
  import { PromptDialog } from "./data/PromptDialog.js";
74
78
  import { PromptBanner } from "./data/PromptBanner.js";
@@ -425,6 +429,7 @@ import { annotateRoutePaths, findNodeByRoutePath, slugify } from "./data/test-ru
425
429
  import { applyFixtureFrontmatterRaw, applyFixtureFrontmatterState, fixtureFrontmatterState, parseFixtureFrontmatter } from "./data/FixtureEditor/fixture-frontmatter.js";
426
430
  import { cacheQueryKeys, createCacheClient } from "./data/cache-browser/api.js";
427
431
  import { changeIconAliases, getChangeIcon } from "./icons/changeIconAliases.js";
432
+ import { clickyIconProvider, iconsByConsumerName } from "./icons/registry.js";
428
433
  import { createChecklistMarkdown, createFenceMarkdown, fixtureFenceKind, fixtureFenceSchemaAliases, fixtureFenceSnippetInfo, parseFixtureYaml, resolveFixtureFenceSchema, schemaKeys, stringifyFixtureYaml } from "./data/FixtureEditor/fixture-blocks.js";
429
434
  import { cycleFilterState, decodeFilterState, emptyTestFilters, encodeFilterState, filterStateToRecord, matchesFilterState, recordToFilterState } from "./data/test-runner/filterState.js";
430
435
  import { formatGitCommitDateHeader } from "./data/git/git-dates.js";
@@ -442,9 +447,11 @@ export {
442
447
  CacheStatsOverview,
443
448
  CacheTree,
444
449
  CacheValue,
450
+ CellFilterActions,
445
451
  CodeBlock,
446
452
  CodeDiff,
447
453
  CopyBadge,
454
+ DATA_TABLE_FILTER_LOOKUP_LIMIT,
448
455
  DataTable,
449
456
  DiagnosticsDetailPanel,
450
457
  DiagnosticsTree,
@@ -1132,6 +1139,7 @@ export {
1132
1139
  changeIconAliases,
1133
1140
  chooseTimestampFormat,
1134
1141
  clickyFormatForMarkdownPreview,
1142
+ clickyIconProvider,
1135
1143
  collapseSingleChildChains,
1136
1144
  collectFrameworks,
1137
1145
  compactStackPath,
@@ -1177,6 +1185,7 @@ export {
1177
1185
  hasHoverMeta,
1178
1186
  hasPending,
1179
1187
  humanizeName,
1188
+ iconsByConsumerName,
1180
1189
  inferColumns,
1181
1190
  isApplicationStackFrame,
1182
1191
  isGroupCollapsedByDefault,
@@ -1200,6 +1209,7 @@ export {
1200
1209
  parseInlineJsonContextValue,
1201
1210
  parseJavaStackTrace,
1202
1211
  parseJvmThreadDump,
1212
+ parseMultiFilterValue,
1203
1213
  parseServerTiming,
1204
1214
  parseStackDump,
1205
1215
  parseTimestamp,
@@ -1214,11 +1224,15 @@ export {
1214
1224
  resolveSeries,
1215
1225
  schemaKeys,
1216
1226
  segment,
1227
+ serializeMultiFilterValue,
1217
1228
  seriesStats,
1229
+ serverColumnsToDataTableColumns,
1230
+ serverFiltersToFilterBar,
1218
1231
  serverTimingCounterSummary,
1219
1232
  serverTimingMetricLabel,
1220
1233
  setFallbackIconProvider,
1221
1234
  slugify,
1235
+ splitCommaValues,
1222
1236
  splitTagToken,
1223
1237
  statusIconFor,
1224
1238
  statusToneFor,
@@ -1227,12 +1241,14 @@ export {
1227
1241
  sumNonTaskTests,
1228
1242
  tagActionsFromRecord,
1229
1243
  tagFilterTokens,
1244
+ taskQueryKeys,
1230
1245
  taskSegments,
1231
1246
  taskStatusBg,
1232
1247
  taskStatusColor,
1233
1248
  taskStatusIcon,
1234
1249
  testStatus,
1235
1250
  totalDuration,
1251
+ updateFilterSelection,
1236
1252
  usePrompts,
1237
1253
  useTagActions,
1238
1254
  useTagActionsValue,
package/dist/data.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"data.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -48,12 +48,17 @@ function isFormElement(target) {
48
48
  if (target.isContentEditable) return true;
49
49
  return ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName);
50
50
  }
51
+ function eventOrigin(event) {
52
+ var _a;
53
+ return ((_a = event.composedPath) == null ? void 0 : _a.call(event)[0]) ?? event.target;
54
+ }
51
55
  function onKeyDown(event) {
52
56
  if (event.defaultPrevented || event.isComposing) return;
57
+ const origin = eventOrigin(event);
53
58
  let winner;
54
59
  for (const registration of registrations) {
55
60
  if (!matches(event, registration.combo)) continue;
56
- if (!registration.enableOnFormElements && isFormElement(event.target)) continue;
61
+ if (!registration.enableOnFormElements && isFormElement(origin)) continue;
57
62
  if (!winner || registration.priority >= winner.priority) winner = registration;
58
63
  }
59
64
  if (!winner) return;
@@ -1 +1 @@
1
- {"version":3,"file":"use-hotkey.cjs","sources":["../../src/hooks/use-hotkey.ts"],"sourcesContent":["import { useEffect, useId, useRef } from \"react\";\n\n// A process-wide registry of global keyboard shortcuts, modeled on the escape\n// layer in ../overlay/modalStack. Bindings mount independently (no shared\n// provider), so the registry lives at module scope. Exactly ONE binding wins a\n// given key combo — the highest `priority`, breaking ties toward the most\n// recently mounted. Without that discipline every mounted component that binds\n// the same combo fires on one keypress, which is how two ⌘K search fields end\n// up racing to focus themselves.\n//\n// The listener is attached to `document`, matching modalStack, so hotkeys and\n// escape layers agree on event target and ordering.\n\ntype Registration = {\n id: string;\n combo: ParsedHotkey;\n priority: number;\n enableOnFormElements: boolean;\n run: (event: KeyboardEvent) => void;\n};\n\nconst registrations: Registration[] = [];\nlet boundDocument: Document | null = null;\n\nexport type ParsedHotkey = {\n /** Bare key, lower-cased (e.g. \"k\"). */\n key: string;\n /** Requires cmd on macOS / ctrl elsewhere. */\n mod: boolean;\n shift: boolean;\n alt: boolean;\n};\n\nfunction isMacPlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);\n}\n\n/**\n * Parses a combo string such as `\"mod+k\"` or `\"mod+shift+p\"`. `mod` means ⌘ on\n * macOS and Ctrl elsewhere. The last segment is the key; order is irrelevant.\n */\nexport function parseHotkey(combo: string): ParsedHotkey {\n const parts = combo\n .split(\"+\")\n .map((part) => part.trim().toLowerCase())\n .filter(Boolean);\n const key = parts[parts.length - 1];\n if (!key) throw new Error(`useHotkey: empty combo \"${combo}\"`);\n return {\n key,\n mod: parts.includes(\"mod\") || parts.includes(\"cmd\") || parts.includes(\"ctrl\"),\n shift: parts.includes(\"shift\"),\n alt: parts.includes(\"alt\") || parts.includes(\"option\"),\n };\n}\n\n/**\n * Renders a combo for display — `\"mod+k\"` becomes `\"⌘K\"` on macOS and `\"Ctrl+K\"`\n * elsewhere. Deriving the label from the combo (rather than hand-authoring the\n * label and reverse-engineering the key from it) keeps the two in sync.\n */\nexport function formatHotkey(combo: string, platform?: \"mac\" | \"other\"): string {\n const parsed = parseHotkey(combo);\n const mac = platform ? platform === \"mac\" : isMacPlatform();\n const key = parsed.key.length === 1 ? parsed.key.toUpperCase() : titleCase(parsed.key);\n if (mac) {\n return `${parsed.mod ? \"⌘\" : \"\"}${parsed.alt ? \"⌥\" : \"\"}${parsed.shift ? \"⇧\" : \"\"}${key}`;\n }\n const segments = [\n ...(parsed.mod ? [\"Ctrl\"] : []),\n ...(parsed.alt ? [\"Alt\"] : []),\n ...(parsed.shift ? [\"Shift\"] : []),\n key,\n ];\n return segments.join(\"+\");\n}\n\nfunction titleCase(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction matches(event: KeyboardEvent, combo: ParsedHotkey): boolean {\n if (event.key.toLowerCase() !== combo.key) return false;\n if (combo.mod !== (event.metaKey || event.ctrlKey)) return false;\n if (combo.shift !== event.shiftKey) return false;\n if (combo.alt !== event.altKey) return false;\n return true;\n}\n\nfunction isFormElement(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n if (target.isContentEditable) return true;\n return [\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(target.tagName);\n}\n\nfunction onKeyDown(event: KeyboardEvent) {\n if (event.defaultPrevented || event.isComposing) return;\n\n // Highest priority wins; ties go to the most recently registered, so a\n // transient surface layered over the page takes precedence over the chrome.\n let winner: Registration | undefined;\n for (const registration of registrations) {\n if (!matches(event, registration.combo)) continue;\n if (!registration.enableOnFormElements && isFormElement(event.target)) continue;\n if (!winner || registration.priority >= winner.priority) winner = registration;\n }\n if (!winner) return;\n\n event.preventDefault();\n winner.run(event);\n}\n\nfunction ensureListener() {\n if (boundDocument || typeof document === \"undefined\") return;\n boundDocument = document;\n boundDocument.addEventListener(\"keydown\", onKeyDown);\n}\n\nfunction unregister(id: string) {\n const index = registrations.findIndex((entry) => entry.id === id);\n if (index !== -1) registrations.splice(index, 1);\n\n if (registrations.length === 0 && boundDocument) {\n boundDocument.removeEventListener(\"keydown\", onKeyDown);\n boundDocument = null;\n }\n}\n\nexport type UseHotkeyOptions = {\n /** Register the binding. Defaults to `true`. */\n enabled?: boolean | undefined;\n /**\n * Ordering among bindings for the same combo. Higher wins; ties break toward\n * the most recently mounted. Defaults to `0`.\n */\n priority?: number | undefined;\n /**\n * Fire while focus sits in an input, textarea, select, or contenteditable.\n * Defaults to `true` for combos carrying a modifier (⌘K should work while\n * typing) and `false` for bare keys (which would swallow ordinary typing).\n */\n enableOnFormElements?: boolean | undefined;\n};\n\n/**\n * Binds a global keyboard shortcut for as long as the component is mounted and\n * `enabled`. Pass `null`/`undefined` as the combo to bind nothing. Only the\n * winning registration for a combo runs, so overlapping bindings cannot both\n * fire on a single keypress.\n */\nexport function useHotkey(\n combo: string | null | undefined,\n handler: (event: KeyboardEvent) => void,\n options: UseHotkeyOptions = {},\n): void {\n const id = useId();\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n const { enabled = true, priority = 0, enableOnFormElements } = options;\n\n useEffect(() => {\n if (!combo || !enabled) return;\n const parsed = parseHotkey(combo);\n\n ensureListener();\n registrations.push({\n id,\n combo: parsed,\n priority,\n enableOnFormElements: enableOnFormElements ?? parsed.mod,\n run: (event) => handlerRef.current(event),\n });\n\n return () => unregister(id);\n }, [combo, enabled, priority, enableOnFormElements, id]);\n}\n"],"names":["useId","useRef","useEffect"],"mappings":"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"}
1
+ {"version":3,"file":"use-hotkey.cjs","sources":["../../src/hooks/use-hotkey.ts"],"sourcesContent":["import { useEffect, useId, useRef } from \"react\";\n\n// A process-wide registry of global keyboard shortcuts, modeled on the escape\n// layer in ../overlay/modalStack. Bindings mount independently (no shared\n// provider), so the registry lives at module scope. Exactly ONE binding wins a\n// given key combo — the highest `priority`, breaking ties toward the most\n// recently mounted. Without that discipline every mounted component that binds\n// the same combo fires on one keypress, which is how two ⌘K search fields end\n// up racing to focus themselves.\n//\n// The listener is attached to `document`, matching modalStack, so hotkeys and\n// escape layers agree on event target and ordering.\n\ntype Registration = {\n id: string;\n combo: ParsedHotkey;\n priority: number;\n enableOnFormElements: boolean;\n run: (event: KeyboardEvent) => void;\n};\n\nconst registrations: Registration[] = [];\nlet boundDocument: Document | null = null;\n\nexport type ParsedHotkey = {\n /** Bare key, lower-cased (e.g. \"k\"). */\n key: string;\n /** Requires cmd on macOS / ctrl elsewhere. */\n mod: boolean;\n shift: boolean;\n alt: boolean;\n};\n\nfunction isMacPlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);\n}\n\n/**\n * Parses a combo string such as `\"mod+k\"` or `\"mod+shift+p\"`. `mod` means ⌘ on\n * macOS and Ctrl elsewhere. The last segment is the key; order is irrelevant.\n */\nexport function parseHotkey(combo: string): ParsedHotkey {\n const parts = combo\n .split(\"+\")\n .map((part) => part.trim().toLowerCase())\n .filter(Boolean);\n const key = parts[parts.length - 1];\n if (!key) throw new Error(`useHotkey: empty combo \"${combo}\"`);\n return {\n key,\n mod: parts.includes(\"mod\") || parts.includes(\"cmd\") || parts.includes(\"ctrl\"),\n shift: parts.includes(\"shift\"),\n alt: parts.includes(\"alt\") || parts.includes(\"option\"),\n };\n}\n\n/**\n * Renders a combo for display — `\"mod+k\"` becomes `\"⌘K\"` on macOS and `\"Ctrl+K\"`\n * elsewhere. Deriving the label from the combo (rather than hand-authoring the\n * label and reverse-engineering the key from it) keeps the two in sync.\n */\nexport function formatHotkey(combo: string, platform?: \"mac\" | \"other\"): string {\n const parsed = parseHotkey(combo);\n const mac = platform ? platform === \"mac\" : isMacPlatform();\n const key = parsed.key.length === 1 ? parsed.key.toUpperCase() : titleCase(parsed.key);\n if (mac) {\n return `${parsed.mod ? \"⌘\" : \"\"}${parsed.alt ? \"⌥\" : \"\"}${parsed.shift ? \"⇧\" : \"\"}${key}`;\n }\n const segments = [\n ...(parsed.mod ? [\"Ctrl\"] : []),\n ...(parsed.alt ? [\"Alt\"] : []),\n ...(parsed.shift ? [\"Shift\"] : []),\n key,\n ];\n return segments.join(\"+\");\n}\n\nfunction titleCase(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction matches(event: KeyboardEvent, combo: ParsedHotkey): boolean {\n if (event.key.toLowerCase() !== combo.key) return false;\n if (combo.mod !== (event.metaKey || event.ctrlKey)) return false;\n if (combo.shift !== event.shiftKey) return false;\n if (combo.alt !== event.altKey) return false;\n return true;\n}\n\nfunction isFormElement(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n if (target.isContentEditable) return true;\n return [\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(target.tagName);\n}\n\n// Across a shadow boundary `event.target` is retargeted to the shadow HOST, so a\n// key typed into an input inside a shadow root looks like a bare keypress on a\n// <div> and would fire hotkeys that must not fire while typing. The composed\n// path's first entry is the true origin.\nfunction eventOrigin(event: KeyboardEvent): EventTarget | null {\n return event.composedPath?.()[0] ?? event.target;\n}\n\nfunction onKeyDown(event: KeyboardEvent) {\n if (event.defaultPrevented || event.isComposing) return;\n\n // Highest priority wins; ties go to the most recently registered, so a\n // transient surface layered over the page takes precedence over the chrome.\n const origin = eventOrigin(event);\n let winner: Registration | undefined;\n for (const registration of registrations) {\n if (!matches(event, registration.combo)) continue;\n if (!registration.enableOnFormElements && isFormElement(origin)) continue;\n if (!winner || registration.priority >= winner.priority) winner = registration;\n }\n if (!winner) return;\n\n event.preventDefault();\n winner.run(event);\n}\n\nfunction ensureListener() {\n if (boundDocument || typeof document === \"undefined\") return;\n boundDocument = document;\n boundDocument.addEventListener(\"keydown\", onKeyDown);\n}\n\nfunction unregister(id: string) {\n const index = registrations.findIndex((entry) => entry.id === id);\n if (index !== -1) registrations.splice(index, 1);\n\n if (registrations.length === 0 && boundDocument) {\n boundDocument.removeEventListener(\"keydown\", onKeyDown);\n boundDocument = null;\n }\n}\n\nexport type UseHotkeyOptions = {\n /** Register the binding. Defaults to `true`. */\n enabled?: boolean | undefined;\n /**\n * Ordering among bindings for the same combo. Higher wins; ties break toward\n * the most recently mounted. Defaults to `0`.\n */\n priority?: number | undefined;\n /**\n * Fire while focus sits in an input, textarea, select, or contenteditable.\n * Defaults to `true` for combos carrying a modifier (⌘K should work while\n * typing) and `false` for bare keys (which would swallow ordinary typing).\n */\n enableOnFormElements?: boolean | undefined;\n};\n\n/**\n * Binds a global keyboard shortcut for as long as the component is mounted and\n * `enabled`. Pass `null`/`undefined` as the combo to bind nothing. Only the\n * winning registration for a combo runs, so overlapping bindings cannot both\n * fire on a single keypress.\n */\nexport function useHotkey(\n combo: string | null | undefined,\n handler: (event: KeyboardEvent) => void,\n options: UseHotkeyOptions = {},\n): void {\n const id = useId();\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n const { enabled = true, priority = 0, enableOnFormElements } = options;\n\n useEffect(() => {\n if (!combo || !enabled) return;\n const parsed = parseHotkey(combo);\n\n ensureListener();\n registrations.push({\n id,\n combo: parsed,\n priority,\n enableOnFormElements: enableOnFormElements ?? parsed.mod,\n run: (event) => handlerRef.current(event),\n });\n\n return () => unregister(id);\n }, [combo, enabled, priority, enableOnFormElements, id]);\n}\n"],"names":["useId","useRef","useEffect"],"mappings":";;;AAqBA,MAAM,gBAAgC,CAAA;AACtC,IAAI,gBAAiC;AAWrC,SAAS,gBAAyB;AAChC,MAAI,OAAO,cAAc,YAAa,QAAO;AAC7C,SAAO,wBAAwB,KAAK,UAAU,YAAY,UAAU,SAAS;AAC/E;AAMO,SAAS,YAAY,OAA6B;AACvD,QAAM,QAAQ,MACX,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,OAAO,YAAA,CAAa,EACvC,OAAO,OAAO;AACjB,QAAM,MAAM,MAAM,MAAM,SAAS,CAAC;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,2BAA2B,KAAK,GAAG;AAC7D,SAAO;AAAA,IACL;AAAA,IACA,KAAK,MAAM,SAAS,KAAK,KAAK,MAAM,SAAS,KAAK,KAAK,MAAM,SAAS,MAAM;AAAA,IAC5E,OAAO,MAAM,SAAS,OAAO;AAAA,IAC7B,KAAK,MAAM,SAAS,KAAK,KAAK,MAAM,SAAS,QAAQ;AAAA,EAAA;AAEzD;AAOO,SAAS,aAAa,OAAe,UAAoC;AAC9E,QAAM,SAAS,YAAY,KAAK;AAChC,QAAM,MAAM,WAAW,aAAa,QAAQ,cAAA;AAC5C,QAAM,MAAM,OAAO,IAAI,WAAW,IAAI,OAAO,IAAI,YAAA,IAAgB,UAAU,OAAO,GAAG;AACrF,MAAI,KAAK;AACP,WAAO,GAAG,OAAO,MAAM,MAAM,EAAE,GAAG,OAAO,MAAM,MAAM,EAAE,GAAG,OAAO,QAAQ,MAAM,EAAE,GAAG,GAAG;AAAA,EACzF;AACA,QAAM,WAAW;AAAA,IACf,GAAI,OAAO,MAAM,CAAC,MAAM,IAAI,CAAA;AAAA,IAC5B,GAAI,OAAO,MAAM,CAAC,KAAK,IAAI,CAAA;AAAA,IAC3B,GAAI,OAAO,QAAQ,CAAC,OAAO,IAAI,CAAA;AAAA,IAC/B;AAAA,EAAA;AAEF,SAAO,SAAS,KAAK,GAAG;AAC1B;AAEA,SAAS,UAAU,OAAuB;AACxC,SAAO,MAAM,OAAO,CAAC,EAAE,gBAAgB,MAAM,MAAM,CAAC;AACtD;AAEA,SAAS,QAAQ,OAAsB,OAA8B;AACnE,MAAI,MAAM,IAAI,YAAA,MAAkB,MAAM,IAAK,QAAO;AAClD,MAAI,MAAM,SAAS,MAAM,WAAW,MAAM,SAAU,QAAO;AAC3D,MAAI,MAAM,UAAU,MAAM,SAAU,QAAO;AAC3C,MAAI,MAAM,QAAQ,MAAM,OAAQ,QAAO;AACvC,SAAO;AACT;AAEA,SAAS,cAAc,QAAqC;AAC1D,MAAI,EAAE,kBAAkB,aAAc,QAAO;AAC7C,MAAI,OAAO,kBAAmB,QAAO;AACrC,SAAO,CAAC,SAAS,YAAY,QAAQ,EAAE,SAAS,OAAO,OAAO;AAChE;AAMA,SAAS,YAAY,OAA0C;;AAC7D,WAAO,WAAM,iBAAN,+BAAuB,OAAM,MAAM;AAC5C;AAEA,SAAS,UAAU,OAAsB;AACvC,MAAI,MAAM,oBAAoB,MAAM,YAAa;AAIjD,QAAM,SAAS,YAAY,KAAK;AAChC,MAAI;AACJ,aAAW,gBAAgB,eAAe;AACxC,QAAI,CAAC,QAAQ,OAAO,aAAa,KAAK,EAAG;AACzC,QAAI,CAAC,aAAa,wBAAwB,cAAc,MAAM,EAAG;AACjE,QAAI,CAAC,UAAU,aAAa,YAAY,OAAO,SAAU,UAAS;AAAA,EACpE;AACA,MAAI,CAAC,OAAQ;AAEb,QAAM,eAAA;AACN,SAAO,IAAI,KAAK;AAClB;AAEA,SAAS,iBAAiB;AACxB,MAAI,iBAAiB,OAAO,aAAa,YAAa;AACtD,kBAAgB;AAChB,gBAAc,iBAAiB,WAAW,SAAS;AACrD;AAEA,SAAS,WAAW,IAAY;AAC9B,QAAM,QAAQ,cAAc,UAAU,CAAC,UAAU,MAAM,OAAO,EAAE;AAChE,MAAI,UAAU,GAAI,eAAc,OAAO,OAAO,CAAC;AAE/C,MAAI,cAAc,WAAW,KAAK,eAAe;AAC/C,kBAAc,oBAAoB,WAAW,SAAS;AACtD,oBAAgB;AAAA,EAClB;AACF;AAwBO,SAAS,UACd,OACA,SACA,UAA4B,CAAA,GACtB;AACN,QAAM,KAAKA,MAAAA,MAAA;AACX,QAAM,aAAaC,MAAAA,OAAO,OAAO;AACjC,aAAW,UAAU;AAErB,QAAM,EAAE,UAAU,MAAM,WAAW,GAAG,yBAAyB;AAE/DC,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,SAAS,CAAC,QAAS;AACxB,UAAM,SAAS,YAAY,KAAK;AAEhC,mBAAA;AACA,kBAAc,KAAK;AAAA,MACjB;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,sBAAsB,wBAAwB,OAAO;AAAA,MACrD,KAAK,CAAC,UAAU,WAAW,QAAQ,KAAK;AAAA,IAAA,CACzC;AAED,WAAO,MAAM,WAAW,EAAE;AAAA,EAC5B,GAAG,CAAC,OAAO,SAAS,UAAU,sBAAsB,EAAE,CAAC;AACzD;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-hotkey.d.ts","sourceRoot":"","sources":["../../src/hooks/use-hotkey.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,YAAY,GAAG;IACzB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAOF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAavD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,CAc9E;AAqDD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACvC,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CAsBN"}
1
+ {"version":3,"file":"use-hotkey.d.ts","sourceRoot":"","sources":["../../src/hooks/use-hotkey.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,YAAY,GAAG;IACzB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAOF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAavD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,CAc9E;AA8DD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACvC,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CAsBN"}
@@ -46,12 +46,17 @@ function isFormElement(target) {
46
46
  if (target.isContentEditable) return true;
47
47
  return ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName);
48
48
  }
49
+ function eventOrigin(event) {
50
+ var _a;
51
+ return ((_a = event.composedPath) == null ? void 0 : _a.call(event)[0]) ?? event.target;
52
+ }
49
53
  function onKeyDown(event) {
50
54
  if (event.defaultPrevented || event.isComposing) return;
55
+ const origin = eventOrigin(event);
51
56
  let winner;
52
57
  for (const registration of registrations) {
53
58
  if (!matches(event, registration.combo)) continue;
54
- if (!registration.enableOnFormElements && isFormElement(event.target)) continue;
59
+ if (!registration.enableOnFormElements && isFormElement(origin)) continue;
55
60
  if (!winner || registration.priority >= winner.priority) winner = registration;
56
61
  }
57
62
  if (!winner) return;
@@ -1 +1 @@
1
- {"version":3,"file":"use-hotkey.js","sources":["../../src/hooks/use-hotkey.ts"],"sourcesContent":["import { useEffect, useId, useRef } from \"react\";\n\n// A process-wide registry of global keyboard shortcuts, modeled on the escape\n// layer in ../overlay/modalStack. Bindings mount independently (no shared\n// provider), so the registry lives at module scope. Exactly ONE binding wins a\n// given key combo — the highest `priority`, breaking ties toward the most\n// recently mounted. Without that discipline every mounted component that binds\n// the same combo fires on one keypress, which is how two ⌘K search fields end\n// up racing to focus themselves.\n//\n// The listener is attached to `document`, matching modalStack, so hotkeys and\n// escape layers agree on event target and ordering.\n\ntype Registration = {\n id: string;\n combo: ParsedHotkey;\n priority: number;\n enableOnFormElements: boolean;\n run: (event: KeyboardEvent) => void;\n};\n\nconst registrations: Registration[] = [];\nlet boundDocument: Document | null = null;\n\nexport type ParsedHotkey = {\n /** Bare key, lower-cased (e.g. \"k\"). */\n key: string;\n /** Requires cmd on macOS / ctrl elsewhere. */\n mod: boolean;\n shift: boolean;\n alt: boolean;\n};\n\nfunction isMacPlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);\n}\n\n/**\n * Parses a combo string such as `\"mod+k\"` or `\"mod+shift+p\"`. `mod` means ⌘ on\n * macOS and Ctrl elsewhere. The last segment is the key; order is irrelevant.\n */\nexport function parseHotkey(combo: string): ParsedHotkey {\n const parts = combo\n .split(\"+\")\n .map((part) => part.trim().toLowerCase())\n .filter(Boolean);\n const key = parts[parts.length - 1];\n if (!key) throw new Error(`useHotkey: empty combo \"${combo}\"`);\n return {\n key,\n mod: parts.includes(\"mod\") || parts.includes(\"cmd\") || parts.includes(\"ctrl\"),\n shift: parts.includes(\"shift\"),\n alt: parts.includes(\"alt\") || parts.includes(\"option\"),\n };\n}\n\n/**\n * Renders a combo for display — `\"mod+k\"` becomes `\"⌘K\"` on macOS and `\"Ctrl+K\"`\n * elsewhere. Deriving the label from the combo (rather than hand-authoring the\n * label and reverse-engineering the key from it) keeps the two in sync.\n */\nexport function formatHotkey(combo: string, platform?: \"mac\" | \"other\"): string {\n const parsed = parseHotkey(combo);\n const mac = platform ? platform === \"mac\" : isMacPlatform();\n const key = parsed.key.length === 1 ? parsed.key.toUpperCase() : titleCase(parsed.key);\n if (mac) {\n return `${parsed.mod ? \"⌘\" : \"\"}${parsed.alt ? \"⌥\" : \"\"}${parsed.shift ? \"⇧\" : \"\"}${key}`;\n }\n const segments = [\n ...(parsed.mod ? [\"Ctrl\"] : []),\n ...(parsed.alt ? [\"Alt\"] : []),\n ...(parsed.shift ? [\"Shift\"] : []),\n key,\n ];\n return segments.join(\"+\");\n}\n\nfunction titleCase(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction matches(event: KeyboardEvent, combo: ParsedHotkey): boolean {\n if (event.key.toLowerCase() !== combo.key) return false;\n if (combo.mod !== (event.metaKey || event.ctrlKey)) return false;\n if (combo.shift !== event.shiftKey) return false;\n if (combo.alt !== event.altKey) return false;\n return true;\n}\n\nfunction isFormElement(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n if (target.isContentEditable) return true;\n return [\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(target.tagName);\n}\n\nfunction onKeyDown(event: KeyboardEvent) {\n if (event.defaultPrevented || event.isComposing) return;\n\n // Highest priority wins; ties go to the most recently registered, so a\n // transient surface layered over the page takes precedence over the chrome.\n let winner: Registration | undefined;\n for (const registration of registrations) {\n if (!matches(event, registration.combo)) continue;\n if (!registration.enableOnFormElements && isFormElement(event.target)) continue;\n if (!winner || registration.priority >= winner.priority) winner = registration;\n }\n if (!winner) return;\n\n event.preventDefault();\n winner.run(event);\n}\n\nfunction ensureListener() {\n if (boundDocument || typeof document === \"undefined\") return;\n boundDocument = document;\n boundDocument.addEventListener(\"keydown\", onKeyDown);\n}\n\nfunction unregister(id: string) {\n const index = registrations.findIndex((entry) => entry.id === id);\n if (index !== -1) registrations.splice(index, 1);\n\n if (registrations.length === 0 && boundDocument) {\n boundDocument.removeEventListener(\"keydown\", onKeyDown);\n boundDocument = null;\n }\n}\n\nexport type UseHotkeyOptions = {\n /** Register the binding. Defaults to `true`. */\n enabled?: boolean | undefined;\n /**\n * Ordering among bindings for the same combo. Higher wins; ties break toward\n * the most recently mounted. Defaults to `0`.\n */\n priority?: number | undefined;\n /**\n * Fire while focus sits in an input, textarea, select, or contenteditable.\n * Defaults to `true` for combos carrying a modifier (⌘K should work while\n * typing) and `false` for bare keys (which would swallow ordinary typing).\n */\n enableOnFormElements?: boolean | undefined;\n};\n\n/**\n * Binds a global keyboard shortcut for as long as the component is mounted and\n * `enabled`. Pass `null`/`undefined` as the combo to bind nothing. Only the\n * winning registration for a combo runs, so overlapping bindings cannot both\n * fire on a single keypress.\n */\nexport function useHotkey(\n combo: string | null | undefined,\n handler: (event: KeyboardEvent) => void,\n options: UseHotkeyOptions = {},\n): void {\n const id = useId();\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n const { enabled = true, priority = 0, enableOnFormElements } = options;\n\n useEffect(() => {\n if (!combo || !enabled) return;\n const parsed = parseHotkey(combo);\n\n ensureListener();\n registrations.push({\n id,\n combo: parsed,\n priority,\n enableOnFormElements: enableOnFormElements ?? parsed.mod,\n run: (event) => handlerRef.current(event),\n });\n\n return () => unregister(id);\n }, [combo, enabled, priority, enableOnFormElements, id]);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-hotkey.js","sources":["../../src/hooks/use-hotkey.ts"],"sourcesContent":["import { useEffect, useId, useRef } from \"react\";\n\n// A process-wide registry of global keyboard shortcuts, modeled on the escape\n// layer in ../overlay/modalStack. Bindings mount independently (no shared\n// provider), so the registry lives at module scope. Exactly ONE binding wins a\n// given key combo — the highest `priority`, breaking ties toward the most\n// recently mounted. Without that discipline every mounted component that binds\n// the same combo fires on one keypress, which is how two ⌘K search fields end\n// up racing to focus themselves.\n//\n// The listener is attached to `document`, matching modalStack, so hotkeys and\n// escape layers agree on event target and ordering.\n\ntype Registration = {\n id: string;\n combo: ParsedHotkey;\n priority: number;\n enableOnFormElements: boolean;\n run: (event: KeyboardEvent) => void;\n};\n\nconst registrations: Registration[] = [];\nlet boundDocument: Document | null = null;\n\nexport type ParsedHotkey = {\n /** Bare key, lower-cased (e.g. \"k\"). */\n key: string;\n /** Requires cmd on macOS / ctrl elsewhere. */\n mod: boolean;\n shift: boolean;\n alt: boolean;\n};\n\nfunction isMacPlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);\n}\n\n/**\n * Parses a combo string such as `\"mod+k\"` or `\"mod+shift+p\"`. `mod` means ⌘ on\n * macOS and Ctrl elsewhere. The last segment is the key; order is irrelevant.\n */\nexport function parseHotkey(combo: string): ParsedHotkey {\n const parts = combo\n .split(\"+\")\n .map((part) => part.trim().toLowerCase())\n .filter(Boolean);\n const key = parts[parts.length - 1];\n if (!key) throw new Error(`useHotkey: empty combo \"${combo}\"`);\n return {\n key,\n mod: parts.includes(\"mod\") || parts.includes(\"cmd\") || parts.includes(\"ctrl\"),\n shift: parts.includes(\"shift\"),\n alt: parts.includes(\"alt\") || parts.includes(\"option\"),\n };\n}\n\n/**\n * Renders a combo for display — `\"mod+k\"` becomes `\"⌘K\"` on macOS and `\"Ctrl+K\"`\n * elsewhere. Deriving the label from the combo (rather than hand-authoring the\n * label and reverse-engineering the key from it) keeps the two in sync.\n */\nexport function formatHotkey(combo: string, platform?: \"mac\" | \"other\"): string {\n const parsed = parseHotkey(combo);\n const mac = platform ? platform === \"mac\" : isMacPlatform();\n const key = parsed.key.length === 1 ? parsed.key.toUpperCase() : titleCase(parsed.key);\n if (mac) {\n return `${parsed.mod ? \"⌘\" : \"\"}${parsed.alt ? \"⌥\" : \"\"}${parsed.shift ? \"⇧\" : \"\"}${key}`;\n }\n const segments = [\n ...(parsed.mod ? [\"Ctrl\"] : []),\n ...(parsed.alt ? [\"Alt\"] : []),\n ...(parsed.shift ? [\"Shift\"] : []),\n key,\n ];\n return segments.join(\"+\");\n}\n\nfunction titleCase(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction matches(event: KeyboardEvent, combo: ParsedHotkey): boolean {\n if (event.key.toLowerCase() !== combo.key) return false;\n if (combo.mod !== (event.metaKey || event.ctrlKey)) return false;\n if (combo.shift !== event.shiftKey) return false;\n if (combo.alt !== event.altKey) return false;\n return true;\n}\n\nfunction isFormElement(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n if (target.isContentEditable) return true;\n return [\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(target.tagName);\n}\n\n// Across a shadow boundary `event.target` is retargeted to the shadow HOST, so a\n// key typed into an input inside a shadow root looks like a bare keypress on a\n// <div> and would fire hotkeys that must not fire while typing. The composed\n// path's first entry is the true origin.\nfunction eventOrigin(event: KeyboardEvent): EventTarget | null {\n return event.composedPath?.()[0] ?? event.target;\n}\n\nfunction onKeyDown(event: KeyboardEvent) {\n if (event.defaultPrevented || event.isComposing) return;\n\n // Highest priority wins; ties go to the most recently registered, so a\n // transient surface layered over the page takes precedence over the chrome.\n const origin = eventOrigin(event);\n let winner: Registration | undefined;\n for (const registration of registrations) {\n if (!matches(event, registration.combo)) continue;\n if (!registration.enableOnFormElements && isFormElement(origin)) continue;\n if (!winner || registration.priority >= winner.priority) winner = registration;\n }\n if (!winner) return;\n\n event.preventDefault();\n winner.run(event);\n}\n\nfunction ensureListener() {\n if (boundDocument || typeof document === \"undefined\") return;\n boundDocument = document;\n boundDocument.addEventListener(\"keydown\", onKeyDown);\n}\n\nfunction unregister(id: string) {\n const index = registrations.findIndex((entry) => entry.id === id);\n if (index !== -1) registrations.splice(index, 1);\n\n if (registrations.length === 0 && boundDocument) {\n boundDocument.removeEventListener(\"keydown\", onKeyDown);\n boundDocument = null;\n }\n}\n\nexport type UseHotkeyOptions = {\n /** Register the binding. Defaults to `true`. */\n enabled?: boolean | undefined;\n /**\n * Ordering among bindings for the same combo. Higher wins; ties break toward\n * the most recently mounted. Defaults to `0`.\n */\n priority?: number | undefined;\n /**\n * Fire while focus sits in an input, textarea, select, or contenteditable.\n * Defaults to `true` for combos carrying a modifier (⌘K should work while\n * typing) and `false` for bare keys (which would swallow ordinary typing).\n */\n enableOnFormElements?: boolean | undefined;\n};\n\n/**\n * Binds a global keyboard shortcut for as long as the component is mounted and\n * `enabled`. Pass `null`/`undefined` as the combo to bind nothing. Only the\n * winning registration for a combo runs, so overlapping bindings cannot both\n * fire on a single keypress.\n */\nexport function useHotkey(\n combo: string | null | undefined,\n handler: (event: KeyboardEvent) => void,\n options: UseHotkeyOptions = {},\n): void {\n const id = useId();\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n const { enabled = true, priority = 0, enableOnFormElements } = options;\n\n useEffect(() => {\n if (!combo || !enabled) return;\n const parsed = parseHotkey(combo);\n\n ensureListener();\n registrations.push({\n id,\n combo: parsed,\n priority,\n enableOnFormElements: enableOnFormElements ?? parsed.mod,\n run: (event) => handlerRef.current(event),\n });\n\n return () => unregister(id);\n }, [combo, enabled, priority, enableOnFormElements, id]);\n}\n"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const react = require("react");
4
4
  const TaskSnapshot = require("../data/TaskSnapshot.cjs");
5
+ const taskQueryKeys = require("../data/task-query-keys.cjs");
5
6
  const DEFAULT_BASE = "/api/v1";
6
7
  const DEFAULT_POLL_MS = 2e3;
7
8
  function streamUrl(base, query) {
@@ -122,7 +123,7 @@ function useTaskRuns(options = {}) {
122
123
  pollMs = DEFAULT_POLL_MS,
123
124
  forcePoll = false
124
125
  } = options;
125
- const [runs, setRuns] = react.useState([]);
126
+ const [received, setReceived] = react.useState({ key: null, runs: [] });
126
127
  const [status, setStatus] = react.useState("idle");
127
128
  react.useEffect(() => {
128
129
  if (!enabled) return;
@@ -131,6 +132,8 @@ function useTaskRuns(options = {}) {
131
132
  if (statusFilter) params.set("status", statusFilter);
132
133
  for (const [k, v] of Object.entries(labels ?? {})) params.append("label", `${k}=${v}`);
133
134
  const query = params.toString();
135
+ const requestKey = taskQueryKeys.taskQueryKeys.runs({ basePath, kind, status: statusFilter, labels });
136
+ const receive = (next) => setReceived({ key: requestKey, runs: next });
134
137
  if (forcePoll || !hasEventSource()) {
135
138
  let stopped = false;
136
139
  let timer;
@@ -140,7 +143,7 @@ function useTaskRuns(options = {}) {
140
143
  headers: { Accept: "application/json" }
141
144
  });
142
145
  if (res.ok) {
143
- setRuns(await res.json());
146
+ receive(await res.json());
144
147
  setStatus("polling");
145
148
  }
146
149
  } catch {
@@ -158,14 +161,14 @@ function useTaskRuns(options = {}) {
158
161
  setStatus("connected");
159
162
  es.addEventListener("runs", (e) => {
160
163
  try {
161
- setRuns(JSON.parse(e.data));
164
+ receive(JSON.parse(e.data));
162
165
  } catch {
163
166
  }
164
167
  });
165
168
  es.onerror = () => setStatus("connection lost — retrying");
166
169
  return () => es.close();
167
170
  }, [kind, statusFilter, JSON.stringify(labels ?? {}), basePath, enabled, pollMs, forcePoll]);
168
- return { runs, status };
171
+ return { runs: received.runs, status, runsKey: received.key };
169
172
  }
170
173
  exports.useTaskRun = useTaskRun;
171
174
  exports.useTaskRuns = useTaskRuns;
@@ -1 +1 @@
1
- {"version":3,"file":"use-task-run.cjs","sources":["../../src/hooks/use-task-run.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n allGroupsTerminal,\n type TaskRunMeta,\n type TaskSnapshot,\n} from \"../data/TaskSnapshot\";\n\n// use-task-run / use-task-runs are the generic clicky-ui task clients. They are\n// SSE-first: they subscribe to clicky's SSEHandler (event: task / event: done)\n// and fall back to polling the JSON endpoints only when EventSource is\n// unavailable. They speak only TaskSnapshot / TaskRunMeta — no app concepts.\n\nexport interface TaskTransportOptions {\n /** Base path of the clicky task API, e.g. \"/api/v1\". */\n basePath?: string | undefined;\n /** Disable the subscription entirely (e.g. before an id is known). */\n enabled?: boolean | undefined;\n /** Poll interval (ms) for the fallback / runs listing. */\n pollMs?: number | undefined;\n /** Force the polling transport even when EventSource exists (mainly tests). */\n forcePoll?: boolean | undefined;\n}\n\nconst DEFAULT_BASE = \"/api/v1\";\nconst DEFAULT_POLL_MS = 2_000;\n\nfunction streamUrl(base: string, query: string): string {\n return `${base}/tasks/stream${query ? `?${query}` : \"\"}`;\n}\n\nfunction hasEventSource(): boolean {\n return typeof globalThis !== \"undefined\" && typeof globalThis.EventSource !== \"undefined\";\n}\n\nexport interface UseTaskRunResult {\n snapshots: TaskSnapshot[];\n status: string;\n isComplete: boolean;\n}\n\nexport interface UseTaskRunOptions extends TaskTransportOptions {\n /** Stable run id to follow (drill-down). Mutually exclusive with kind. */\n id?: string | undefined;\n /** Follow every run of a kind. */\n kind?: string | undefined;\n}\n\n// useTaskRun follows one run (by id) or a kind, SSE-first. It accumulates the\n// latest snapshot per task/group id and reports completion once every group is\n// terminal.\nexport function useTaskRun(options: UseTaskRunOptions = {}): UseTaskRunResult {\n const {\n id,\n kind,\n basePath = DEFAULT_BASE,\n enabled = true,\n pollMs = DEFAULT_POLL_MS,\n forcePoll = false,\n } = options;\n\n const [byId, setById] = useState<Record<string, TaskSnapshot>>({});\n const [status, setStatus] = useState(\"idle\");\n const [isComplete, setIsComplete] = useState(false);\n // Reset accumulator whenever the subscription target changes.\n const targetKey = `${id ?? \"\"}|${kind ?? \"\"}|${enabled}`;\n const prevKey = useRef(targetKey);\n if (prevKey.current !== targetKey) {\n prevKey.current = targetKey;\n }\n\n useEffect(() => {\n if (!enabled || (!id && !kind)) {\n return;\n }\n setById({});\n setIsComplete(false);\n\n const params = new URLSearchParams();\n if (id) params.set(\"tasks\", id);\n if (kind) params.set(\"kind\", kind);\n const query = params.toString();\n\n const merge = (incoming: TaskSnapshot[]) => {\n setById((prev) => {\n const next = { ...prev };\n for (const snap of incoming) next[snap.id] = { ...next[snap.id], ...snap };\n return next;\n });\n };\n\n const mergeOutput = (delta: {\n id: string;\n stream: \"stdout\" | \"stderr\";\n data: string;\n reset?: boolean;\n truncated?: boolean;\n }) => {\n setById((prev) => {\n const snapshot = prev[delta.id];\n if (!snapshot) return prev;\n const value = delta.reset ? delta.data : `${snapshot[delta.stream] ?? \"\"}${delta.data}`;\n const truncatedField = delta.stream === \"stdout\" ? \"stdoutTruncated\" : \"stderrTruncated\";\n return {\n ...prev,\n [delta.id]: {\n ...snapshot,\n [delta.stream]: value,\n [truncatedField]: delta.truncated ?? snapshot[truncatedField],\n },\n };\n });\n };\n\n // Polling fallback transport.\n if (forcePoll || !hasEventSource()) {\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = async () => {\n try {\n const res = await fetch(`${basePath}/tasks/${encodeURIComponent(id ?? \"\")}`, {\n headers: { Accept: \"application/json\" },\n });\n if (res.ok) {\n const snaps = (await res.json()) as TaskSnapshot[];\n merge(snaps);\n setStatus(\"polling\");\n if (allGroupsTerminal(snaps)) {\n setIsComplete(true);\n return; // stop polling\n }\n }\n } catch {\n setStatus(\"connection lost — retrying\");\n }\n if (!stopped) timer = setTimeout(tick, pollMs);\n };\n void tick();\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }\n\n // SSE transport (default).\n const es = new EventSource(streamUrl(basePath, query));\n setStatus(\"connected\");\n es.addEventListener(\"task\", (e) => {\n try {\n merge([JSON.parse((e as MessageEvent).data) as TaskSnapshot]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.addEventListener(\"output\", (e) => {\n try {\n mergeOutput(JSON.parse((e as MessageEvent).data) as Parameters<typeof mergeOutput>[0]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.addEventListener(\"done\", () => {\n setStatus(\"complete\");\n setIsComplete(true);\n es.close();\n });\n es.onerror = () => setStatus(\"connection lost — retrying\");\n return () => es.close();\n }, [id, kind, basePath, enabled, pollMs, forcePoll]);\n\n return { snapshots: Object.values(byId), status, isComplete };\n}\n\nexport interface UseTaskRunsOptions extends TaskTransportOptions {\n kind?: string | undefined;\n status?: string | undefined;\n /** Label equality filters (k=v). */\n labels?: Record<string, string> | undefined;\n}\n\nexport interface UseTaskRunsResult {\n runs: TaskRunMeta[];\n status: string;\n}\n\n// useTaskRuns lists all runs (TaskRunMeta) for the manager view. It is SSE-first:\n// it subscribes to clicky's runs stream (event: runs carrying the full listing)\n// and falls back to polling the JSON runs endpoint only when EventSource is\n// unavailable or forced off. The listing has no completion terminal of its own —\n// a manager view stays subscribed to observe new and changing runs.\nexport function useTaskRuns(options: UseTaskRunsOptions = {}): UseTaskRunsResult {\n const {\n kind,\n status: statusFilter,\n labels,\n basePath = DEFAULT_BASE,\n enabled = true,\n pollMs = DEFAULT_POLL_MS,\n forcePoll = false,\n } = options;\n\n const [runs, setRuns] = useState<TaskRunMeta[]>([]);\n const [status, setStatus] = useState(\"idle\");\n\n useEffect(() => {\n if (!enabled) return;\n\n const params = new URLSearchParams();\n if (kind) params.set(\"kind\", kind);\n if (statusFilter) params.set(\"status\", statusFilter);\n for (const [k, v] of Object.entries(labels ?? {})) params.append(\"label\", `${k}=${v}`);\n const query = params.toString();\n\n // Polling fallback transport.\n if (forcePoll || !hasEventSource()) {\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = async () => {\n try {\n const res = await fetch(`${basePath}/tasks${query ? `?${query}` : \"\"}`, {\n headers: { Accept: \"application/json\" },\n });\n if (res.ok) {\n setRuns((await res.json()) as TaskRunMeta[]);\n setStatus(\"polling\");\n }\n } catch {\n setStatus(\"connection lost — retrying\");\n }\n if (!stopped) timer = setTimeout(tick, pollMs);\n };\n void tick();\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }\n\n // SSE transport (default).\n const es = new EventSource(`${basePath}/tasks/runs/stream${query ? `?${query}` : \"\"}`);\n setStatus(\"connected\");\n es.addEventListener(\"runs\", (e) => {\n try {\n setRuns(JSON.parse((e as MessageEvent).data) as TaskRunMeta[]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.onerror = () => setStatus(\"connection lost — retrying\");\n return () => es.close();\n }, [kind, statusFilter, JSON.stringify(labels ?? {}), basePath, enabled, pollMs, forcePoll]);\n\n return { runs, status };\n}\n"],"names":["useState","useRef","useEffect","allGroupsTerminal"],"mappings":"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"}
1
+ {"version":3,"file":"use-task-run.cjs","sources":["../../src/hooks/use-task-run.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n allGroupsTerminal,\n type TaskRunMeta,\n type TaskSnapshot,\n} from \"../data/TaskSnapshot\";\nimport { taskQueryKeys } from \"../data/task-query-keys\";\n\n// use-task-run / use-task-runs are the generic clicky-ui task clients. They are\n// SSE-first: they subscribe to clicky's SSEHandler (event: task / event: done)\n// and fall back to polling the JSON endpoints only when EventSource is\n// unavailable. They speak only TaskSnapshot / TaskRunMeta — no app concepts.\n\nexport interface TaskTransportOptions {\n /** Base path of the clicky task API, e.g. \"/api/v1\". */\n basePath?: string | undefined;\n /** Disable the subscription entirely (e.g. before an id is known). */\n enabled?: boolean | undefined;\n /** Poll interval (ms) for the fallback / runs listing. */\n pollMs?: number | undefined;\n /** Force the polling transport even when EventSource exists (mainly tests). */\n forcePoll?: boolean | undefined;\n}\n\nconst DEFAULT_BASE = \"/api/v1\";\nconst DEFAULT_POLL_MS = 2_000;\n\nfunction streamUrl(base: string, query: string): string {\n return `${base}/tasks/stream${query ? `?${query}` : \"\"}`;\n}\n\nfunction hasEventSource(): boolean {\n return typeof globalThis !== \"undefined\" && typeof globalThis.EventSource !== \"undefined\";\n}\n\nexport interface UseTaskRunResult {\n snapshots: TaskSnapshot[];\n status: string;\n isComplete: boolean;\n}\n\nexport interface UseTaskRunOptions extends TaskTransportOptions {\n /** Stable run id to follow (drill-down). Mutually exclusive with kind. */\n id?: string | undefined;\n /** Follow every run of a kind. */\n kind?: string | undefined;\n}\n\n// useTaskRun follows one run (by id) or a kind, SSE-first. It accumulates the\n// latest snapshot per task/group id and reports completion once every group is\n// terminal.\nexport function useTaskRun(options: UseTaskRunOptions = {}): UseTaskRunResult {\n const {\n id,\n kind,\n basePath = DEFAULT_BASE,\n enabled = true,\n pollMs = DEFAULT_POLL_MS,\n forcePoll = false,\n } = options;\n\n const [byId, setById] = useState<Record<string, TaskSnapshot>>({});\n const [status, setStatus] = useState(\"idle\");\n const [isComplete, setIsComplete] = useState(false);\n // Reset accumulator whenever the subscription target changes.\n const targetKey = `${id ?? \"\"}|${kind ?? \"\"}|${enabled}`;\n const prevKey = useRef(targetKey);\n if (prevKey.current !== targetKey) {\n prevKey.current = targetKey;\n }\n\n useEffect(() => {\n if (!enabled || (!id && !kind)) {\n return;\n }\n setById({});\n setIsComplete(false);\n\n const params = new URLSearchParams();\n if (id) params.set(\"tasks\", id);\n if (kind) params.set(\"kind\", kind);\n const query = params.toString();\n\n const merge = (incoming: TaskSnapshot[]) => {\n setById((prev) => {\n const next = { ...prev };\n for (const snap of incoming) next[snap.id] = { ...next[snap.id], ...snap };\n return next;\n });\n };\n\n const mergeOutput = (delta: {\n id: string;\n stream: \"stdout\" | \"stderr\";\n data: string;\n reset?: boolean;\n truncated?: boolean;\n }) => {\n setById((prev) => {\n const snapshot = prev[delta.id];\n if (!snapshot) return prev;\n const value = delta.reset ? delta.data : `${snapshot[delta.stream] ?? \"\"}${delta.data}`;\n const truncatedField = delta.stream === \"stdout\" ? \"stdoutTruncated\" : \"stderrTruncated\";\n return {\n ...prev,\n [delta.id]: {\n ...snapshot,\n [delta.stream]: value,\n [truncatedField]: delta.truncated ?? snapshot[truncatedField],\n },\n };\n });\n };\n\n // Polling fallback transport.\n if (forcePoll || !hasEventSource()) {\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = async () => {\n try {\n const res = await fetch(`${basePath}/tasks/${encodeURIComponent(id ?? \"\")}`, {\n headers: { Accept: \"application/json\" },\n });\n if (res.ok) {\n const snaps = (await res.json()) as TaskSnapshot[];\n merge(snaps);\n setStatus(\"polling\");\n if (allGroupsTerminal(snaps)) {\n setIsComplete(true);\n return; // stop polling\n }\n }\n } catch {\n setStatus(\"connection lost — retrying\");\n }\n if (!stopped) timer = setTimeout(tick, pollMs);\n };\n void tick();\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }\n\n // SSE transport (default).\n const es = new EventSource(streamUrl(basePath, query));\n setStatus(\"connected\");\n es.addEventListener(\"task\", (e) => {\n try {\n merge([JSON.parse((e as MessageEvent).data) as TaskSnapshot]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.addEventListener(\"output\", (e) => {\n try {\n mergeOutput(JSON.parse((e as MessageEvent).data) as Parameters<typeof mergeOutput>[0]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.addEventListener(\"done\", () => {\n setStatus(\"complete\");\n setIsComplete(true);\n es.close();\n });\n es.onerror = () => setStatus(\"connection lost — retrying\");\n return () => es.close();\n }, [id, kind, basePath, enabled, pollMs, forcePoll]);\n\n return { snapshots: Object.values(byId), status, isComplete };\n}\n\nexport interface UseTaskRunsOptions extends TaskTransportOptions {\n kind?: string | undefined;\n status?: string | undefined;\n /** Label equality filters (k=v). */\n labels?: Record<string, string> | undefined;\n}\n\n/** The identity of the listing request that produced a given `runs` array. */\nexport type TaskRunsKey = ReturnType<typeof taskQueryKeys.runs>;\n\nexport interface UseTaskRunsResult {\n runs: TaskRunMeta[];\n status: string;\n /**\n * Query key of the request that actually produced `runs`, or null before the\n * first frame arrives. Changing `kind`/`status`/`labels` re-subscribes but\n * keeps the previous listing on screen until the new transport delivers, so\n * this key lags `taskQueryKeys.runs(options)` during that window. A consumer\n * mirroring `runs` into a cache must compare the two and skip the write while\n * they differ, or it publishes rows that do not match the requested filters.\n */\n runsKey: TaskRunsKey | null;\n}\n\n// useTaskRuns lists all runs (TaskRunMeta) for the manager view. It is SSE-first:\n// it subscribes to clicky's runs stream (event: runs carrying the full listing)\n// and falls back to polling the JSON runs endpoint only when EventSource is\n// unavailable or forced off. The listing has no completion terminal of its own —\n// a manager view stays subscribed to observe new and changing runs.\nexport function useTaskRuns(options: UseTaskRunsOptions = {}): UseTaskRunsResult {\n const {\n kind,\n status: statusFilter,\n labels,\n basePath = DEFAULT_BASE,\n enabled = true,\n pollMs = DEFAULT_POLL_MS,\n forcePoll = false,\n } = options;\n\n // Runs are stored together with the key of the request that delivered them, so\n // a stale listing can never be mistaken for the current filters' result.\n const [received, setReceived] = useState<{\n key: TaskRunsKey | null;\n runs: TaskRunMeta[];\n }>({ key: null, runs: [] });\n const [status, setStatus] = useState(\"idle\");\n\n useEffect(() => {\n if (!enabled) return;\n\n const params = new URLSearchParams();\n if (kind) params.set(\"kind\", kind);\n if (statusFilter) params.set(\"status\", statusFilter);\n for (const [k, v] of Object.entries(labels ?? {})) params.append(\"label\", `${k}=${v}`);\n const query = params.toString();\n const requestKey = taskQueryKeys.runs({ basePath, kind, status: statusFilter, labels });\n const receive = (next: TaskRunMeta[]) => setReceived({ key: requestKey, runs: next });\n\n // Polling fallback transport.\n if (forcePoll || !hasEventSource()) {\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = async () => {\n try {\n const res = await fetch(`${basePath}/tasks${query ? `?${query}` : \"\"}`, {\n headers: { Accept: \"application/json\" },\n });\n if (res.ok) {\n receive((await res.json()) as TaskRunMeta[]);\n setStatus(\"polling\");\n }\n } catch {\n setStatus(\"connection lost — retrying\");\n }\n if (!stopped) timer = setTimeout(tick, pollMs);\n };\n void tick();\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }\n\n // SSE transport (default).\n const es = new EventSource(`${basePath}/tasks/runs/stream${query ? `?${query}` : \"\"}`);\n setStatus(\"connected\");\n es.addEventListener(\"runs\", (e) => {\n try {\n receive(JSON.parse((e as MessageEvent).data) as TaskRunMeta[]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.onerror = () => setStatus(\"connection lost — retrying\");\n return () => es.close();\n }, [kind, statusFilter, JSON.stringify(labels ?? {}), basePath, enabled, pollMs, forcePoll]);\n\n return { runs: received.runs, status, runsKey: received.key };\n}\n"],"names":["useState","useRef","useEffect","allGroupsTerminal","taskQueryKeys"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { TaskRunMeta, TaskSnapshot } from '../data/TaskSnapshot';
2
+ import { taskQueryKeys } from '../data/task-query-keys';
2
3
  export interface TaskTransportOptions {
3
4
  /** Base path of the clicky task API, e.g. "/api/v1". */
4
5
  basePath?: string | undefined;
@@ -27,9 +28,20 @@ export interface UseTaskRunsOptions extends TaskTransportOptions {
27
28
  /** Label equality filters (k=v). */
28
29
  labels?: Record<string, string> | undefined;
29
30
  }
31
+ /** The identity of the listing request that produced a given `runs` array. */
32
+ export type TaskRunsKey = ReturnType<typeof taskQueryKeys.runs>;
30
33
  export interface UseTaskRunsResult {
31
34
  runs: TaskRunMeta[];
32
35
  status: string;
36
+ /**
37
+ * Query key of the request that actually produced `runs`, or null before the
38
+ * first frame arrives. Changing `kind`/`status`/`labels` re-subscribes but
39
+ * keeps the previous listing on screen until the new transport delivers, so
40
+ * this key lags `taskQueryKeys.runs(options)` during that window. A consumer
41
+ * mirroring `runs` into a cache must compare the two and skip the write while
42
+ * they differ, or it publishes rows that do not match the requested filters.
43
+ */
44
+ runsKey: TaskRunsKey | null;
33
45
  }
34
46
  export declare function useTaskRuns(options?: UseTaskRunsOptions): UseTaskRunsResult;
35
47
  //# sourceMappingURL=use-task-run.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-task-run.d.ts","sourceRoot":"","sources":["../../src/hooks/use-task-run.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAO9B,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAaD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAkB,SAAQ,oBAAoB;IAC7D,0EAA0E;IAC1E,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAKD,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAwH5E;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CAC7C;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAOD,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,CA+D/E"}
1
+ {"version":3,"file":"use-task-run.d.ts","sourceRoot":"","sources":["../../src/hooks/use-task-run.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAOxD,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAaD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAkB,SAAQ,oBAAoB;IAC7D,0EAA0E;IAC1E,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAKD,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAwH5E;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CAC7C;AAED,8EAA8E;AAC9E,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7B;AAOD,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,CAsE/E"}
@@ -1,5 +1,6 @@
1
1
  import { useState, useRef, useEffect } from "react";
2
2
  import { allGroupsTerminal } from "../data/TaskSnapshot.js";
3
+ import { taskQueryKeys } from "../data/task-query-keys.js";
3
4
  const DEFAULT_BASE = "/api/v1";
4
5
  const DEFAULT_POLL_MS = 2e3;
5
6
  function streamUrl(base, query) {
@@ -120,7 +121,7 @@ function useTaskRuns(options = {}) {
120
121
  pollMs = DEFAULT_POLL_MS,
121
122
  forcePoll = false
122
123
  } = options;
123
- const [runs, setRuns] = useState([]);
124
+ const [received, setReceived] = useState({ key: null, runs: [] });
124
125
  const [status, setStatus] = useState("idle");
125
126
  useEffect(() => {
126
127
  if (!enabled) return;
@@ -129,6 +130,8 @@ function useTaskRuns(options = {}) {
129
130
  if (statusFilter) params.set("status", statusFilter);
130
131
  for (const [k, v] of Object.entries(labels ?? {})) params.append("label", `${k}=${v}`);
131
132
  const query = params.toString();
133
+ const requestKey = taskQueryKeys.runs({ basePath, kind, status: statusFilter, labels });
134
+ const receive = (next) => setReceived({ key: requestKey, runs: next });
132
135
  if (forcePoll || !hasEventSource()) {
133
136
  let stopped = false;
134
137
  let timer;
@@ -138,7 +141,7 @@ function useTaskRuns(options = {}) {
138
141
  headers: { Accept: "application/json" }
139
142
  });
140
143
  if (res.ok) {
141
- setRuns(await res.json());
144
+ receive(await res.json());
142
145
  setStatus("polling");
143
146
  }
144
147
  } catch {
@@ -156,14 +159,14 @@ function useTaskRuns(options = {}) {
156
159
  setStatus("connected");
157
160
  es.addEventListener("runs", (e) => {
158
161
  try {
159
- setRuns(JSON.parse(e.data));
162
+ receive(JSON.parse(e.data));
160
163
  } catch {
161
164
  }
162
165
  });
163
166
  es.onerror = () => setStatus("connection lost — retrying");
164
167
  return () => es.close();
165
168
  }, [kind, statusFilter, JSON.stringify(labels ?? {}), basePath, enabled, pollMs, forcePoll]);
166
- return { runs, status };
169
+ return { runs: received.runs, status, runsKey: received.key };
167
170
  }
168
171
  export {
169
172
  useTaskRun,
@@ -1 +1 @@
1
- {"version":3,"file":"use-task-run.js","sources":["../../src/hooks/use-task-run.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n allGroupsTerminal,\n type TaskRunMeta,\n type TaskSnapshot,\n} from \"../data/TaskSnapshot\";\n\n// use-task-run / use-task-runs are the generic clicky-ui task clients. They are\n// SSE-first: they subscribe to clicky's SSEHandler (event: task / event: done)\n// and fall back to polling the JSON endpoints only when EventSource is\n// unavailable. They speak only TaskSnapshot / TaskRunMeta — no app concepts.\n\nexport interface TaskTransportOptions {\n /** Base path of the clicky task API, e.g. \"/api/v1\". */\n basePath?: string | undefined;\n /** Disable the subscription entirely (e.g. before an id is known). */\n enabled?: boolean | undefined;\n /** Poll interval (ms) for the fallback / runs listing. */\n pollMs?: number | undefined;\n /** Force the polling transport even when EventSource exists (mainly tests). */\n forcePoll?: boolean | undefined;\n}\n\nconst DEFAULT_BASE = \"/api/v1\";\nconst DEFAULT_POLL_MS = 2_000;\n\nfunction streamUrl(base: string, query: string): string {\n return `${base}/tasks/stream${query ? `?${query}` : \"\"}`;\n}\n\nfunction hasEventSource(): boolean {\n return typeof globalThis !== \"undefined\" && typeof globalThis.EventSource !== \"undefined\";\n}\n\nexport interface UseTaskRunResult {\n snapshots: TaskSnapshot[];\n status: string;\n isComplete: boolean;\n}\n\nexport interface UseTaskRunOptions extends TaskTransportOptions {\n /** Stable run id to follow (drill-down). Mutually exclusive with kind. */\n id?: string | undefined;\n /** Follow every run of a kind. */\n kind?: string | undefined;\n}\n\n// useTaskRun follows one run (by id) or a kind, SSE-first. It accumulates the\n// latest snapshot per task/group id and reports completion once every group is\n// terminal.\nexport function useTaskRun(options: UseTaskRunOptions = {}): UseTaskRunResult {\n const {\n id,\n kind,\n basePath = DEFAULT_BASE,\n enabled = true,\n pollMs = DEFAULT_POLL_MS,\n forcePoll = false,\n } = options;\n\n const [byId, setById] = useState<Record<string, TaskSnapshot>>({});\n const [status, setStatus] = useState(\"idle\");\n const [isComplete, setIsComplete] = useState(false);\n // Reset accumulator whenever the subscription target changes.\n const targetKey = `${id ?? \"\"}|${kind ?? \"\"}|${enabled}`;\n const prevKey = useRef(targetKey);\n if (prevKey.current !== targetKey) {\n prevKey.current = targetKey;\n }\n\n useEffect(() => {\n if (!enabled || (!id && !kind)) {\n return;\n }\n setById({});\n setIsComplete(false);\n\n const params = new URLSearchParams();\n if (id) params.set(\"tasks\", id);\n if (kind) params.set(\"kind\", kind);\n const query = params.toString();\n\n const merge = (incoming: TaskSnapshot[]) => {\n setById((prev) => {\n const next = { ...prev };\n for (const snap of incoming) next[snap.id] = { ...next[snap.id], ...snap };\n return next;\n });\n };\n\n const mergeOutput = (delta: {\n id: string;\n stream: \"stdout\" | \"stderr\";\n data: string;\n reset?: boolean;\n truncated?: boolean;\n }) => {\n setById((prev) => {\n const snapshot = prev[delta.id];\n if (!snapshot) return prev;\n const value = delta.reset ? delta.data : `${snapshot[delta.stream] ?? \"\"}${delta.data}`;\n const truncatedField = delta.stream === \"stdout\" ? \"stdoutTruncated\" : \"stderrTruncated\";\n return {\n ...prev,\n [delta.id]: {\n ...snapshot,\n [delta.stream]: value,\n [truncatedField]: delta.truncated ?? snapshot[truncatedField],\n },\n };\n });\n };\n\n // Polling fallback transport.\n if (forcePoll || !hasEventSource()) {\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = async () => {\n try {\n const res = await fetch(`${basePath}/tasks/${encodeURIComponent(id ?? \"\")}`, {\n headers: { Accept: \"application/json\" },\n });\n if (res.ok) {\n const snaps = (await res.json()) as TaskSnapshot[];\n merge(snaps);\n setStatus(\"polling\");\n if (allGroupsTerminal(snaps)) {\n setIsComplete(true);\n return; // stop polling\n }\n }\n } catch {\n setStatus(\"connection lost — retrying\");\n }\n if (!stopped) timer = setTimeout(tick, pollMs);\n };\n void tick();\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }\n\n // SSE transport (default).\n const es = new EventSource(streamUrl(basePath, query));\n setStatus(\"connected\");\n es.addEventListener(\"task\", (e) => {\n try {\n merge([JSON.parse((e as MessageEvent).data) as TaskSnapshot]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.addEventListener(\"output\", (e) => {\n try {\n mergeOutput(JSON.parse((e as MessageEvent).data) as Parameters<typeof mergeOutput>[0]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.addEventListener(\"done\", () => {\n setStatus(\"complete\");\n setIsComplete(true);\n es.close();\n });\n es.onerror = () => setStatus(\"connection lost — retrying\");\n return () => es.close();\n }, [id, kind, basePath, enabled, pollMs, forcePoll]);\n\n return { snapshots: Object.values(byId), status, isComplete };\n}\n\nexport interface UseTaskRunsOptions extends TaskTransportOptions {\n kind?: string | undefined;\n status?: string | undefined;\n /** Label equality filters (k=v). */\n labels?: Record<string, string> | undefined;\n}\n\nexport interface UseTaskRunsResult {\n runs: TaskRunMeta[];\n status: string;\n}\n\n// useTaskRuns lists all runs (TaskRunMeta) for the manager view. It is SSE-first:\n// it subscribes to clicky's runs stream (event: runs carrying the full listing)\n// and falls back to polling the JSON runs endpoint only when EventSource is\n// unavailable or forced off. The listing has no completion terminal of its own —\n// a manager view stays subscribed to observe new and changing runs.\nexport function useTaskRuns(options: UseTaskRunsOptions = {}): UseTaskRunsResult {\n const {\n kind,\n status: statusFilter,\n labels,\n basePath = DEFAULT_BASE,\n enabled = true,\n pollMs = DEFAULT_POLL_MS,\n forcePoll = false,\n } = options;\n\n const [runs, setRuns] = useState<TaskRunMeta[]>([]);\n const [status, setStatus] = useState(\"idle\");\n\n useEffect(() => {\n if (!enabled) return;\n\n const params = new URLSearchParams();\n if (kind) params.set(\"kind\", kind);\n if (statusFilter) params.set(\"status\", statusFilter);\n for (const [k, v] of Object.entries(labels ?? {})) params.append(\"label\", `${k}=${v}`);\n const query = params.toString();\n\n // Polling fallback transport.\n if (forcePoll || !hasEventSource()) {\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = async () => {\n try {\n const res = await fetch(`${basePath}/tasks${query ? `?${query}` : \"\"}`, {\n headers: { Accept: \"application/json\" },\n });\n if (res.ok) {\n setRuns((await res.json()) as TaskRunMeta[]);\n setStatus(\"polling\");\n }\n } catch {\n setStatus(\"connection lost — retrying\");\n }\n if (!stopped) timer = setTimeout(tick, pollMs);\n };\n void tick();\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }\n\n // SSE transport (default).\n const es = new EventSource(`${basePath}/tasks/runs/stream${query ? `?${query}` : \"\"}`);\n setStatus(\"connected\");\n es.addEventListener(\"runs\", (e) => {\n try {\n setRuns(JSON.parse((e as MessageEvent).data) as TaskRunMeta[]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.onerror = () => setStatus(\"connection lost — retrying\");\n return () => es.close();\n }, [kind, statusFilter, JSON.stringify(labels ?? {}), basePath, enabled, pollMs, forcePoll]);\n\n return { runs, status };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-task-run.js","sources":["../../src/hooks/use-task-run.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n allGroupsTerminal,\n type TaskRunMeta,\n type TaskSnapshot,\n} from \"../data/TaskSnapshot\";\nimport { taskQueryKeys } from \"../data/task-query-keys\";\n\n// use-task-run / use-task-runs are the generic clicky-ui task clients. They are\n// SSE-first: they subscribe to clicky's SSEHandler (event: task / event: done)\n// and fall back to polling the JSON endpoints only when EventSource is\n// unavailable. They speak only TaskSnapshot / TaskRunMeta — no app concepts.\n\nexport interface TaskTransportOptions {\n /** Base path of the clicky task API, e.g. \"/api/v1\". */\n basePath?: string | undefined;\n /** Disable the subscription entirely (e.g. before an id is known). */\n enabled?: boolean | undefined;\n /** Poll interval (ms) for the fallback / runs listing. */\n pollMs?: number | undefined;\n /** Force the polling transport even when EventSource exists (mainly tests). */\n forcePoll?: boolean | undefined;\n}\n\nconst DEFAULT_BASE = \"/api/v1\";\nconst DEFAULT_POLL_MS = 2_000;\n\nfunction streamUrl(base: string, query: string): string {\n return `${base}/tasks/stream${query ? `?${query}` : \"\"}`;\n}\n\nfunction hasEventSource(): boolean {\n return typeof globalThis !== \"undefined\" && typeof globalThis.EventSource !== \"undefined\";\n}\n\nexport interface UseTaskRunResult {\n snapshots: TaskSnapshot[];\n status: string;\n isComplete: boolean;\n}\n\nexport interface UseTaskRunOptions extends TaskTransportOptions {\n /** Stable run id to follow (drill-down). Mutually exclusive with kind. */\n id?: string | undefined;\n /** Follow every run of a kind. */\n kind?: string | undefined;\n}\n\n// useTaskRun follows one run (by id) or a kind, SSE-first. It accumulates the\n// latest snapshot per task/group id and reports completion once every group is\n// terminal.\nexport function useTaskRun(options: UseTaskRunOptions = {}): UseTaskRunResult {\n const {\n id,\n kind,\n basePath = DEFAULT_BASE,\n enabled = true,\n pollMs = DEFAULT_POLL_MS,\n forcePoll = false,\n } = options;\n\n const [byId, setById] = useState<Record<string, TaskSnapshot>>({});\n const [status, setStatus] = useState(\"idle\");\n const [isComplete, setIsComplete] = useState(false);\n // Reset accumulator whenever the subscription target changes.\n const targetKey = `${id ?? \"\"}|${kind ?? \"\"}|${enabled}`;\n const prevKey = useRef(targetKey);\n if (prevKey.current !== targetKey) {\n prevKey.current = targetKey;\n }\n\n useEffect(() => {\n if (!enabled || (!id && !kind)) {\n return;\n }\n setById({});\n setIsComplete(false);\n\n const params = new URLSearchParams();\n if (id) params.set(\"tasks\", id);\n if (kind) params.set(\"kind\", kind);\n const query = params.toString();\n\n const merge = (incoming: TaskSnapshot[]) => {\n setById((prev) => {\n const next = { ...prev };\n for (const snap of incoming) next[snap.id] = { ...next[snap.id], ...snap };\n return next;\n });\n };\n\n const mergeOutput = (delta: {\n id: string;\n stream: \"stdout\" | \"stderr\";\n data: string;\n reset?: boolean;\n truncated?: boolean;\n }) => {\n setById((prev) => {\n const snapshot = prev[delta.id];\n if (!snapshot) return prev;\n const value = delta.reset ? delta.data : `${snapshot[delta.stream] ?? \"\"}${delta.data}`;\n const truncatedField = delta.stream === \"stdout\" ? \"stdoutTruncated\" : \"stderrTruncated\";\n return {\n ...prev,\n [delta.id]: {\n ...snapshot,\n [delta.stream]: value,\n [truncatedField]: delta.truncated ?? snapshot[truncatedField],\n },\n };\n });\n };\n\n // Polling fallback transport.\n if (forcePoll || !hasEventSource()) {\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = async () => {\n try {\n const res = await fetch(`${basePath}/tasks/${encodeURIComponent(id ?? \"\")}`, {\n headers: { Accept: \"application/json\" },\n });\n if (res.ok) {\n const snaps = (await res.json()) as TaskSnapshot[];\n merge(snaps);\n setStatus(\"polling\");\n if (allGroupsTerminal(snaps)) {\n setIsComplete(true);\n return; // stop polling\n }\n }\n } catch {\n setStatus(\"connection lost — retrying\");\n }\n if (!stopped) timer = setTimeout(tick, pollMs);\n };\n void tick();\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }\n\n // SSE transport (default).\n const es = new EventSource(streamUrl(basePath, query));\n setStatus(\"connected\");\n es.addEventListener(\"task\", (e) => {\n try {\n merge([JSON.parse((e as MessageEvent).data) as TaskSnapshot]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.addEventListener(\"output\", (e) => {\n try {\n mergeOutput(JSON.parse((e as MessageEvent).data) as Parameters<typeof mergeOutput>[0]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.addEventListener(\"done\", () => {\n setStatus(\"complete\");\n setIsComplete(true);\n es.close();\n });\n es.onerror = () => setStatus(\"connection lost — retrying\");\n return () => es.close();\n }, [id, kind, basePath, enabled, pollMs, forcePoll]);\n\n return { snapshots: Object.values(byId), status, isComplete };\n}\n\nexport interface UseTaskRunsOptions extends TaskTransportOptions {\n kind?: string | undefined;\n status?: string | undefined;\n /** Label equality filters (k=v). */\n labels?: Record<string, string> | undefined;\n}\n\n/** The identity of the listing request that produced a given `runs` array. */\nexport type TaskRunsKey = ReturnType<typeof taskQueryKeys.runs>;\n\nexport interface UseTaskRunsResult {\n runs: TaskRunMeta[];\n status: string;\n /**\n * Query key of the request that actually produced `runs`, or null before the\n * first frame arrives. Changing `kind`/`status`/`labels` re-subscribes but\n * keeps the previous listing on screen until the new transport delivers, so\n * this key lags `taskQueryKeys.runs(options)` during that window. A consumer\n * mirroring `runs` into a cache must compare the two and skip the write while\n * they differ, or it publishes rows that do not match the requested filters.\n */\n runsKey: TaskRunsKey | null;\n}\n\n// useTaskRuns lists all runs (TaskRunMeta) for the manager view. It is SSE-first:\n// it subscribes to clicky's runs stream (event: runs carrying the full listing)\n// and falls back to polling the JSON runs endpoint only when EventSource is\n// unavailable or forced off. The listing has no completion terminal of its own —\n// a manager view stays subscribed to observe new and changing runs.\nexport function useTaskRuns(options: UseTaskRunsOptions = {}): UseTaskRunsResult {\n const {\n kind,\n status: statusFilter,\n labels,\n basePath = DEFAULT_BASE,\n enabled = true,\n pollMs = DEFAULT_POLL_MS,\n forcePoll = false,\n } = options;\n\n // Runs are stored together with the key of the request that delivered them, so\n // a stale listing can never be mistaken for the current filters' result.\n const [received, setReceived] = useState<{\n key: TaskRunsKey | null;\n runs: TaskRunMeta[];\n }>({ key: null, runs: [] });\n const [status, setStatus] = useState(\"idle\");\n\n useEffect(() => {\n if (!enabled) return;\n\n const params = new URLSearchParams();\n if (kind) params.set(\"kind\", kind);\n if (statusFilter) params.set(\"status\", statusFilter);\n for (const [k, v] of Object.entries(labels ?? {})) params.append(\"label\", `${k}=${v}`);\n const query = params.toString();\n const requestKey = taskQueryKeys.runs({ basePath, kind, status: statusFilter, labels });\n const receive = (next: TaskRunMeta[]) => setReceived({ key: requestKey, runs: next });\n\n // Polling fallback transport.\n if (forcePoll || !hasEventSource()) {\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = async () => {\n try {\n const res = await fetch(`${basePath}/tasks${query ? `?${query}` : \"\"}`, {\n headers: { Accept: \"application/json\" },\n });\n if (res.ok) {\n receive((await res.json()) as TaskRunMeta[]);\n setStatus(\"polling\");\n }\n } catch {\n setStatus(\"connection lost — retrying\");\n }\n if (!stopped) timer = setTimeout(tick, pollMs);\n };\n void tick();\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }\n\n // SSE transport (default).\n const es = new EventSource(`${basePath}/tasks/runs/stream${query ? `?${query}` : \"\"}`);\n setStatus(\"connected\");\n es.addEventListener(\"runs\", (e) => {\n try {\n receive(JSON.parse((e as MessageEvent).data) as TaskRunMeta[]);\n } catch {\n /* ignore malformed frame */\n }\n });\n es.onerror = () => setStatus(\"connection lost — retrying\");\n return () => es.close();\n }, [kind, statusFilter, JSON.stringify(labels ?? {}), basePath, enabled, pollMs, forcePoll]);\n\n return { runs: received.runs, status, runsKey: received.key };\n}\n"],"names":[],"mappings":"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"}
@@ -588,4 +588,5 @@ export { UiCloudUploadFilled } from './components/UiCloudUpload';
588
588
  export type { IconProps, IconComponent } from './types';
589
589
  export { changeIconAliases, getChangeIcon } from './changeIconAliases';
590
590
  export type { ChangeIconEntry } from './changeIconAliases';
591
+ export { clickyIconProvider, iconsByConsumerName } from './registry';
591
592
  //# sourceMappingURL=index.d.ts.map